Server IP : 180.180.241.3 / Your IP : 216.73.216.252 Web Server : Microsoft-IIS/7.5 System : Windows NT NETWORK-NHRC 6.1 build 7601 (Windows Server 2008 R2 Standard Edition Service Pack 1) i586 User : IUSR ( 0) PHP Version : 5.3.28 Disable Function : NONE MySQL : ON | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : C:/Program Files/MySQL/MySQL Workbench 6.3 CE/modules/ |
Upload File : |
# Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; version 2 of the # License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA import os import re import sys import subprocess import threading import thread import time import tempfile import platform import StringIO import grt import wb_admin_export_options import wb_common try: import _subprocess except ImportError: pass from wb_server_management import local_run_cmd from workbench.db_utils import QueryError, ConnectionTunnel, escape_sql_identifier from wb_admin_utils import not_running_warning_label, make_panel_header from collections import deque from workbench.utils import Version from workbench.log import log_warning, log_error, log_debug from mforms import newBox, newButton, newPanel, newTextBox, newRadioButton, newLabel, newTreeView, newProgressBar, newTextEntry, newCheckBox, newScrollPanel, newTabView, newSelector from mforms import Utilities, FileChooser import mforms def local_quote_shell_token(s): if sys.platform.lower() == "win32": t = '"%s"' % s.replace('\\', '\\\\').replace('"', '\\"') else: t = '"%s"' % s.replace('\\', '\\\\').replace('"', '\\"').replace('$', '\\$') if t[:5] == '"\\\\\\\\': t = t[3:] t = '\"' + t return t def normalize_filename(s): s = s.replace(":", "_").replace("/", "_").replace("\\", "_") return s def get_path_to_mysqldump(): """get path to mysqldump from options""" try: path = grt.root.wb.options.options["mysqldump"] if path: if os.path.exists(path): return path if any(os.path.exists(os.path.join(p, path)) for p in os.getenv("PATH").split(os.pathsep)): return path if path != "mysqldump": log_error("mysqldump path specified in configurations is invalid: %s" % path) return None except: return None if sys.platform == "darwin": # if path is not specified, use bundled one return mforms.App.get().get_executable_path("mysqldump").encode("utf8") elif sys.platform == "win32": return mforms.App.get().get_executable_path("mysqldump.exe").encode("utf8") else: # if path is not specified, use bundled one path = mforms.App.get().get_executable_path("mysqldump").encode("utf8") if path: return path # just pick default if any(os.path.exists(os.path.join(p,"mysqldump")) for p in os.getenv("PATH").split(os.pathsep)): return "mysqldump" return None def get_mysqldump_version(): path = get_path_to_mysqldump() if not path: log_error("mysqldump command was not found, please install it or configure it in Edit -> Preferences -> MySQL") return None output = StringIO.StringIO() rc = local_run_cmd('"%s" --version' % path, output_handler=output.write) output = output.getvalue() if rc or not output: log_error("Error retrieving version from %s:\n%s (exit %s)"%(path, output, rc)) return None s = re.match(".*Distrib ([\d.a-z]+).*", output) if not s: log_error("Could not parse version number from %s:\n%s"%(path, output)) return None version_group = s.groups()[0] major, minor, revision = [int(i) for i in version_group.split(".")[:3]] return Version(major, minor, revision) #################################################################################################### class DumpThread(threading.Thread): class TaskData: def __init__(self, title, table_count, extra_arguments, objec_names, tables_to_ignore, make_pipe = lambda:None): """description, object_count, pipe_factory, extra_args, objects operations.append((title, len(tables), lambda schema=schema:self.dump_to_file([schema]), params, objects))""" self.title = title self.table_count = table_count self.extra_arguments = extra_arguments self.objec_names = objec_names self.tables_to_ignore = tables_to_ignore self.make_pipe = make_pipe def __init__(self, command, operations, pwd, owner, log_queue): self.owner = owner self.pwd = pwd self.logging_lock, self.log = log_queue self.is_import = False self.command = command self.operations = operations self.done = False self.progress = 0 self.status_text = "Starting" self.error_count = 0 self.process_handle = None self.abort_requested = False self.e = None threading.Thread.__init__(self) def process_db(self, respipe, extra_arguments, object_names, tables_to_ignore): pwdfilename = None tmpdir = None try: if '<' in self.command: index = self.command.find('<') params = [self.command[:index] + ' '.join(extra_arguments) + ' ' + self.command[index:]] else: params = [self.command] + extra_arguments for arg in object_names: params.append(local_quote_shell_token(arg)) strcmd = " ".join(params) logstr = strcmd.partition("--password=")[0] if platform.system() == 'Windows': pwdfile = tempfile.NamedTemporaryFile(delete=False, suffix=".cnf") pwdfilename = pwdfile.name else: tmpdir = tempfile.mkdtemp() pwdfilename = os.path.join(tmpdir, 'extraparams.cnf') os.mkfifo(pwdfilename) logstr += "--defaults-file=\"" + pwdfilename + "\" " logstr += strcmd.partition("--password=")[2] log_debug("Executing command: %s\n" % logstr) self.print_log_message("Running: " + logstr) if platform.system() != 'Windows': try: p1 = subprocess.Popen(logstr,stdout=respipe,stdin=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) except OSError, exc: log_error("Error executing command %s\n%s\n" % (logstr, exc)) import traceback traceback.print_exc() self.print_log_message("Error executing task: %s" % str(exc)) pwdfile = open(pwdfilename, 'w') else: pwdfile = open(pwdfilename, 'w') pwdfile.write('[client]\npassword="') pwdfile.write(self.pwd.replace("\\", "\\\\")) pwdfile.write('"') # When there are tables to ignore they are added as ignored entries # On the configuration file if tables_to_ignore: pwdfile.write('\n\n[mysqldump]\n') for s, t in tables_to_ignore: pwdfile.write("ignore-table=%s.%s\n" % (s,t)) pwdfile.close() if platform.system() == 'Windows': try: info = subprocess.STARTUPINFO() info.dwFlags |= _subprocess.STARTF_USESHOWWINDOW info.wShowWindow = _subprocess.SW_HIDE # Command line can contain object names in case of export and filename in case of import # Object names must be in utf-8 but filename must be encoded in the filesystem encoding, # which probably isn't utf-8 in windows. if self.is_import: fse = sys.getfilesystemencoding() cmd = logstr.encode(fse) if isinstance(arg,unicode) else logstr else: cmd = logstr.encode("utf8") if isinstance(arg,unicode) else logstr log_debug("Executing command: %s\n" % logstr) p1 = subprocess.Popen(cmd,stdout=respipe or subprocess.PIPE,stdin=subprocess.PIPE, stderr=subprocess.PIPE,startupinfo=info,shell=logstr[0] != '"') except OSError, exc: log_error("Error executing command %s\n%s\n" % (logstr, exc)) import traceback traceback.print_exc() self.print_log_message("Error executing task: %s" % str(exc)) p1 = None # finally: # pass self.process_handle = p1 while p1 and p1.poll() == None and not self.abort_requested: err = p1.stderr.read() if err != "": log_error("Error from task: %s\n" % err) self.print_log_message(err) if 'Access denied for user' in err: self.e = wb_common.InvalidPasswordError('Wrong username/password!') result = "" except Exception, exc: import traceback traceback.print_exc() log_error("Error executing task: %s\n" % exc) self.print_log_message("Error executing task: %s" % str(exc)) finally: pass if pwdfilename: os.remove(pwdfilename) if platform.system() != 'Windows' and tmpdir: os.rmdir(tmpdir) err = p1.stderr.read() if err != "": result += err exitcode = p1.poll() if exitcode != 0: log_warning("Task exited with code %s\n" % exitcode) self.print_log_message("Operation failed with exitcode " + str(exitcode)) else: log_debug("Task exited with code %s\n" % exitcode) self.print_log_message("") if result: log_debug("Task output: %s\n" % result) self.print_log_message(result) return p1.poll() def kill(self): self.abort_requested = True if self.process_handle: if platform.system() == 'Windows': cmd = "taskkill /F /T /PID %i" % self.process_handle.pid log_debug("Killing task: %s\n" % cmd) subprocess.Popen(cmd , shell=True) else: import signal try: log_debug("Sending SIGTERM to task %s\n" % self.process_handle.pid) os.kill(self.process_handle.pid, signal.SIGTERM) except OSError, exc: log_error("Exception sending SIGTERM to task: %s\n" % exc) self.print_log_message("kill task: %s" % str(exc)) def print_log_message(self,message): if message: self.logging_lock.acquire() self.log.append(message) self.logging_lock.release() def run(self): try: self.progress = 0 tables_processed = 0.0 tables_total = 0.0 # for title, count, make_pipe, args, objs in self.operations: for task in self.operations: tables_total += task.table_count or 1 # for title, table_count, make_pipe, arguments, objects in self.operations: for task in self.operations: self.print_log_message(time.strftime(u'%X ') + task.title.encode('utf-8')) tables_processed += task.table_count or 1 pipe = task.make_pipe() exitcode = self.process_db(pipe, task.extra_arguments, task.objec_names, task.tables_to_ignore) if exitcode == 0: if self.is_import: self.status_text = "%i of %i imported." % (tables_processed, tables_total) else: self.status_text = "%i of %i exported." % (tables_processed, tables_total) else: self.owner.fail_callback() self.error_count += 1 if self.abort_requested: break self.progress = float(tables_processed) / tables_total # print self.progress # Emulate slow dump # import time # time.sleep(1) except Exception, exc: import traceback traceback.print_exc() self.print_log_message("Error executing task %s" % str(exc) ) # finally: if not self.abort_requested: self.progress = 1 self.done = True class TableListModel(object): def __init__(self): self.tables_by_schema = {} self.selected_schemas = set() self.routines_placeholder = None def get_full_selection(self): result = [] for schema, (tables, selection) in self.tables_by_schema.items(): for table in selection: result.append((schema,table)) result.sort() return result def get_schema_names(self): return self.tables_by_schema.keys() def set_schema_selected(self, schema, flag): tables = self.get_tables(schema) selection = self.get_selection(schema) if flag: selection.update(set(tables)) self.selected_schemas.add(schema) else: selection.clear() if schema in self.selected_schemas: self.selected_schemas.remove(schema) def set_tables_by_schema(self, tables_by_schema): self.tables_by_schema = tables_by_schema def set_routines_placeholder(self, placeholder): self.routines_placeholder = placeholder def get_tables(self, schema): tables, selection = self.tables_by_schema[schema] return tables def is_view(self, schema, table): return False def list_icon_for_table(self, schema, table): if (schema, table) == self.routines_placeholder: return "db.RoutineGroup.16x16.png" else: return "db.Table.16x16.png" def get_selection(self, schema): tables, selection = self.tables_by_schema[schema] return selection def count_selected_tables(self): count = 0 for tlist, selected in self.tables_by_schema.values(): count += len(selected) return count def get_count(self): return sum([len(item[1]) for item in self.tables_by_schema.values()]) def get_objects_to_dump(self, include_empty_schemas=False): schemas_to_dump = [] #names = self.tables_by_schema.keys() #names.sort() schemas_with_selection = set([key for key, value in self.tables_by_schema.items() if value[1]]) for schema in self.selected_schemas | schemas_with_selection: #No tables selected for schema so skip it tables, selection = self.tables_by_schema[schema] if not selection and not include_empty_schemas: continue schemas_to_dump.append((schema, list(selection))) return schemas_to_dump def get_tables_to_ignore(self): ignore_list = [] names = self.tables_by_schema.keys() names.sort() for schema in names: #No tables selected for schema so skip it tables, selection = self.tables_by_schema[schema] if not selection or len(selection) == len(tables): continue for t in tables: if not t in selection: ignore_list.append((schema, t)) return ignore_list #################################################################################################### class WbAdminSchemaListTab(mforms.Box): def __init__(self, owner, server_profile, progress_tab, is_importing = False): self.savefile_path = None self.savefolder_path = None super(WbAdminSchemaListTab, self).__init__(False) self.skip_data_check = False self.suspend_layout() progress_tab.operation_tab = self self.owner = owner self.progress_tab = progress_tab self.is_importing = is_importing self.dump_thread = None self.bad_password_detected = False self.server_profile = server_profile self.out_pipe = None if self.savefolder_path is None: self.savefolder_path = self.get_default_dump_folder() if self.savefile_path is None: self.savefile_path = os.path.join(self.savefolder_path, "export.sql") self.schema_list = newTreeView(mforms.TreeFlatList) self.schema_list.add_column(mforms.CheckColumnType, is_importing and "Import" or "Export", 40, True) self.schema_list.add_column(mforms.IconColumnType, "Schema", 300, False) self.schema_list.set_cell_edited_callback(self.schema_list_edit) self.schema_list.end_columns() self.schema_list.set_allow_sorting(True) self.table_list = newTreeView(mforms.TreeFlatList) self.table_list.add_column(mforms.CheckColumnType, is_importing and "Import" or "Export", 40, True) self.table_list.add_column(mforms.IconColumnType, "Schema Objects", 300, False) self.table_list.end_columns() self.table_list.set_allow_sorting(True) self.table_list.set_cell_edited_callback(self.table_list_edit) self.schema_list.add_changed_callback(self.schema_selected) self.set_padding(8) self.set_spacing(10) box = newBox(True) box.set_spacing(12) optionspanel = newPanel(mforms.TitledBoxPanel) if is_importing: self.export_objects_panel = None optionspanel.set_title("Import Options") else: self.export_objects_panel = newPanel(mforms.TitledBoxPanel) self.export_objects_panel.set_title("Objects to Export") optionspanel.set_title("Export Options") optionsbox = newBox(False) optionsbox.set_padding(8) optionsbox.set_spacing(6) self.file_btn = newButton() self.file_btn.set_text("...") self.file_btn.enable_internal_padding(False) self.file_btn.set_enabled(False) self._radio_group = mforms.RadioButton.new_id() if is_importing: self.folderlabel = newLabel("Select the Dump Project Folder to import. You can do a selective restore.") self.folderradio = newRadioButton(self._radio_group) self.statlabel = newLabel("Press [Start Import] to start...") self.filelabel = newLabel("Select the SQL/dump file to import. Please note that the whole file will be imported.") self.single_transaction_check = None self.include_schema_check = None self.dump_triggers_check = None #self.dump_view_check = None self.dump_routines_check = None self.dump_events_check = None else: self.filelabel = newLabel("All selected database objects will be exported into a single, self-contained file.") self.folderlabel = newLabel("Each table will be exported into a separate file. This allows a selective restore, but may be slower.") self.folderradio = newRadioButton(self._radio_group) self.statlabel = newLabel("Press [Start Export] to start...") self.single_transaction_check = newCheckBox() self.include_schema_check = newCheckBox() self.dump_triggers_check = newCheckBox() #self.dump_view_check = newCheckBox() self.dump_routines_check = newCheckBox() self.dump_events_check = newCheckBox() self.filelabel.set_enabled(False) self.filelabel.set_style(mforms.SmallStyle) if is_importing: self.fileradio = newRadioButton(self._radio_group) self.fileradio.set_text("Import from Self-Contained File") else: self.fileradio = newRadioButton(self._radio_group) self.fileradio.set_text("Export to Self-Contained File") self.fileradio.set_size(260,-1) self.fileradio.add_clicked_callback(self.set_save_option) file_path = newBox(True) file_path.set_spacing(4) self.file_te = newTextEntry() self.file_te.set_value(self.savefile_path) file_path.add(self.fileradio,False,True) file_path.add(self.file_te, True, True) file_path.add(self.file_btn, False, True) self.folderradio.add_clicked_callback(self.set_save_option) self.folderradio.set_active(True) self.folderradio.set_size(260,-1) self.folderlabel.set_style(mforms.SmallStyle) folder_path = newBox(True) folder_path.set_spacing(4) self.folder_te = newTextEntry() self.folder_te.set_value(self.savefolder_path) self.folder_btn = newButton() self.folder_btn.set_text("...") self.folder_btn.enable_internal_padding(False) self.folder_btn.add_clicked_callback(self.open_folder_chooser) folder_path.add(self.folderradio, False,True) folder_path.add(self.folder_te, True, True) folder_path.add(self.folder_btn, False, True) optionsbox.add(folder_path, False, True) optionsbox.add(self.folderlabel, False, True) if is_importing: self.folder_te.add_changed_callback(self.folder_path_changed) self.folder_load_btn = newButton() self.folder_load_btn.set_text("Load Folder Contents") self.folder_load_btn.add_clicked_callback(self.refresh_table_list) tbox = newBox(True) tbox.add(self.folder_load_btn, False, True) optionsbox.add(tbox, False, True) optionsbox.add(file_path, False, True) optionsbox.add(self.filelabel, False, True) if self.single_transaction_check or self.dump_routines_check: export_objects_opts = mforms.newTable() export_objects_opts.set_homogeneous(True) export_objects_opts.set_padding(4) export_objects_opts.set_row_count(1) export_objects_opts.set_column_count(3) export_objects_opts.set_row_spacing(2) export_objects_opts.set_column_spacing(2) self.export_objects_panel.add(export_objects_opts) export_options = mforms.newTable() export_options.set_homogeneous(True) export_options.set_padding(4) export_options.set_row_count(1) export_options.set_column_count(2) export_options.set_row_spacing(2) export_options.set_column_spacing(2) optionsbox.add(export_options, False, True) if self.single_transaction_check: export_options.add(self.single_transaction_check,0,1,0,1) if self.include_schema_check: export_options.add(self.include_schema_check,1,2,0,1) #if self.dump_view_check: # suboptionsbox.add(self.dump_view_check, False, True) if self.dump_routines_check: export_objects_opts.add(self.dump_routines_check,0,1,0,1) if self.dump_events_check: export_objects_opts.add(self.dump_events_check,1,2,0,1) if self.dump_triggers_check: export_objects_opts.add(self.dump_triggers_check,2,3,0,1) self.file_te.set_enabled(False) #spanel = newScrollPanel(mforms.ScrollPanelNoFlags) #spanel.add(optionsbox) #spanel.set_autohide_scrollers(True) #optionspanel.add(spanel) optionspanel.add(optionsbox) selectionpanel = newPanel(mforms.TitledBoxPanel) if is_importing: selectionpanel.set_title("Select Database Objects to Import (only available for Project Folders)") else: selectionpanel.set_title("Tables to Export") selectionvbox = newBox(False) selectionvbox.set_padding(8) selectionvbox.set_spacing(8) selectionbox = newBox(True) selectionvbox.add(selectionbox, True, True) selectionbox.set_spacing(12) selectionbox.add(self.schema_list, True, True) selectionbox.add(self.table_list, True, True) selectionbbox = newBox(True) selectionbbox.set_spacing(8) if not is_importing: self.refresh_button = newButton() self.refresh_button.set_text("Refresh") selectionbbox.add(self.refresh_button, False, True) self.refresh_button.add_clicked_callback(self.refresh_table_list) self.select_summary_label = newLabel("") selectionbbox.add(self.select_summary_label, True, True) self.select_all_views_btn = newButton() self.select_all_views_btn.set_text("Select Views") self.select_all_views_btn.add_clicked_callback(self.select_all_views) self.select_all_views_btn.set_enabled(False) self.select_all_btn = newButton() self.select_all_btn.set_text("Select Tables") self.select_all_btn.add_clicked_callback(self.select_all_tables) self.select_all_btn.set_enabled(False) self.unselect_all_btn = newButton() self.unselect_all_btn.set_text("Unselect All") self.unselect_all_btn.add_clicked_callback(self.unselect_all_tables) self.unselect_all_btn.set_enabled(False) self.dump_type_selector = newSelector() self.dump_type_selector.add_items(["Dump Structure and Data", "Dump Data Only", "Dump Structure Only"]); selectionbbox.add_end(self.unselect_all_btn, False, True) selectionbbox.add_end(self.select_all_btn, False, True) selectionbbox.add_end(self.select_all_views_btn, False, True) selectionbbox.add_end(self.dump_type_selector, False, True) selectionvbox.add(selectionbbox, False, True) selectionpanel.add(selectionvbox) #box.set_homogeneous(True) if is_importing: self.add(optionspanel, False, True) self.import_target_schema_panel = targetpanel = newPanel(mforms.TitledBoxPanel) targetpanel.set_title("Default Schema to be Imported To") hbox = newBox(True) hbox.set_spacing(8) hbox.add(newLabel("Default Target Schema:"), False, True) self.import_target_schema = newSelector() hbox.add(self.import_target_schema, True, True) b = newButton() b.set_text("New...") b.add_clicked_callback(self.new_target_schema) hbox.add(b, False, True) help = newLabel("The default schema to import the dump into.\nNOTE: this is only used if the dump file doesn't contain its schema,\notherwise it is ignored.") help.set_style(mforms.SmallHelpTextStyle) hbox.add(help, False, True) hbox.set_padding(12) targetpanel.add(hbox) self.add(targetpanel, False, True) self.add(selectionpanel, True, True) if not is_importing: self.add(self.export_objects_panel, False, True) self.add(optionspanel, False, True) box = newBox(True) self.add(box, False, True) box.add(self.statlabel, True, True) box.set_spacing(8) box.set_padding(0) self.export_button = newButton() if is_importing: self.export_button.set_enabled(False) box.add_end(self.export_button, False, True) self.export_button.add_clicked_callback(self.start) #self.stop_button = newButton() #self.stop_button.set_text("Stop") #self.stop_button.set_enabled(False) #self.stop_button.add_clicked_callback(self.stop) #box.add_end(self.stop_button, False, True) if is_importing: self.file_btn.add_clicked_callback(lambda: self.open_file_chooser(mforms.OpenFile)) self.folderradio.set_text("Import from Dump Project Folder") self.export_button.set_text("Start Import") else: self.file_btn.add_clicked_callback(lambda: self.open_file_chooser(mforms.SaveFile)) self.single_transaction_check.set_text("Create Dump in a Single Transaction (self-contained file only)") self.single_transaction_check.set_enabled(False) self.single_transaction_check.add_clicked_callback(self.single_transaction_clicked) self.include_schema_check.set_text("Include Create Schema") self.dump_triggers_check.set_text("Dump Triggers") #self.dump_view_check.set_text("Dump Views") self.dump_routines_check.set_text("Dump Stored Procedures and Functions") self.dump_events_check.set_text("Dump Events") self.folderradio.set_text("Export to Dump Project Folder") self.export_button.set_text("Start Export") self.resume_layout() def print_log_message(self, msg): self.progress_tab.print_log_message(msg) def get_default_dump_folder(self): try: path = grt.root.wb.options.options["dumpdirectory"] or os.path.join("~", "dumps") except: path = os.path.join("~", "dumps") path = os.path.expanduser(path) return os.path.normpath(path) def schema_list_edit(self, node, col, data): if col == 0: node.set_bool(0, int(data) != 0) schema = node.get_string(1) self.table_list_model.set_schema_selected(schema, int(data)) self.schema_selected() def table_list_edit(self, node, col, data): node.set_bool(col, int(data) != 0) self.update_table_selection() if int(data): # select the schema if its not sel = self.schema_list.get_selected_node() if sel and not sel.get_bool(0): sel.set_bool(col, True) self.schema_selected() def update_table_selection(self): if not self.get_selected_schema(): return schema = self.get_selected_schema() selection = self.table_list_model.get_selection(schema) for r in range(self.table_list.count()): node = self.table_list.node_at_row(r) table_name = node.get_tag() if node.get_bool(0): selection.add(table_name) else: selection.discard(table_name) self.select_summary_label.set_text("%i tables/views selected" % self.table_list_model.count_selected_tables()) def get_selected_schema(self): sel = self.schema_list.get_selected_node() if not sel: return None return sel.get_string(1) def schema_selected(self): sel = self.schema_list.get_selected_node() self.table_list.freeze_refresh() self.table_list.clear() if not sel: self.unselect_all_btn.set_enabled(False) self.select_all_btn.set_enabled(False) self.select_all_views_btn.set_enabled(False) self.table_list.thaw_refresh() return schema = self.get_selected_schema() tables = self.table_list_model.get_tables(schema) selection = self.table_list_model.get_selection(schema) for table in tables: r = self.table_list.add_node() r.set_bool(0, table in selection) r.set_icon_path(1, self.table_list_model.list_icon_for_table(schema, table)) r.set_string(1, table) r.set_tag(table) self.table_list.thaw_refresh() self.unselect_all_btn.set_enabled(True) self.select_all_btn.set_enabled(True) self.select_all_views_btn.set_enabled(True) self.select_summary_label.set_text("%i tables selected" % self.table_list_model.count_selected_tables()) def select_all_views(self): sel = self.schema_list.get_selected_node() if not sel: return sel.set_bool(0, True) schema = self.get_selected_schema() for row in range(self.table_list.count()): node = self.table_list.node_at_row(row) table = node.get_string(1) node.set_bool(0, self.table_list_model.is_view(schema, table)) self.update_table_selection() def select_all_tables(self, exclude_views=True): sel = self.schema_list.get_selected_node() if not sel: return sel.set_bool(0, True) schema = self.get_selected_schema() for row in range(self.table_list.count()): node = self.table_list.node_at_row(row) table = node.get_string(1) node.set_bool(0, not self.table_list_model.is_view(schema, table)) self.update_table_selection() def unselect_all_tables(self): for row in range(self.table_list.count()): self.table_list.node_at_row(row).set_bool(0, False) self.update_table_selection() def set_save_option(self): folder_selected = self.folderradio.get_active() self.folder_te.set_enabled(folder_selected) self.folder_btn.set_enabled(folder_selected) self.folderlabel.set_enabled(folder_selected) self.file_te.set_enabled(not folder_selected) self.file_btn.set_enabled(not folder_selected) self.filelabel.set_enabled(not folder_selected) if self.is_importing: if folder_selected: count = self.table_list_model.get_count() self.progress_tab.set_start_enabled(count > 0) self.import_target_schema_panel.set_enabled(False) else: self.progress_tab.set_start_enabled(True) self.import_target_schema_panel.set_enabled(True) self.schema_list.set_enabled(folder_selected) self.table_list.set_enabled(folder_selected) else: if folder_selected: self.single_transaction_check.set_active(False) self.single_transaction_check.set_enabled(False) else: self.single_transaction_check.set_enabled(True) def refresh(self): pass def update_progress(self): completed = True progress = 0 progress_info = "" if self.dump_thread != None: if not self.dump_thread.done: completed = False progress = self.dump_thread.progress self.progress_tab.flush_queued_logs() progress_info = self.dump_thread.status_text if isinstance(self.dump_thread.e, wb_common.InvalidPasswordError): self.dump_thread = None self.bad_password_detected = True self.start() return False self.progress_tab.set_progress(progress, progress_info) # Python 2.6 needed # completed = self.dump_thread.is_alive() if completed: # print progress self.close_pipe() if self.dump_thread.abort_requested: self.tasks_aborted() else: self.tasks_completed() self.dump_thread = None return not completed def open_folder_chooser(self): filechooser = FileChooser(mforms.OpenDirectory) filechooser.set_directory(self.folder_te.get_string_value()) if filechooser.run_modal(): self.savefolder_path = filechooser.get_path() self.folder_te.set_value(self.savefolder_path) if self.is_importing: self.refresh_table_list() def open_file_chooser(self, chooser_type=mforms.SaveFile): filechooser = FileChooser(chooser_type) filechooser.set_directory(os.path.dirname(self.file_te.get_string_value())) filechooser.set_extensions("SQL Files (*.sql)|*.sql","sql"); if filechooser.run_modal(): self.savefile_path = filechooser.get_path() self.file_te.set_value(self.savefile_path) if self.is_importing: self.refresh_table_list() else: if len(os.path.splitext(self.savefile_path)[1][1:]) == 0: self.file_te.set_value("%s.sql" % self.savefile_path) def get_mysql_password(self, reset_password=False): parameterValues = self.server_profile.db_connection_params.parameterValues pwd = parameterValues["password"] if not pwd or reset_password: username = parameterValues["userName"] host = self.server_profile.db_connection_params.hostIdentifier title = self.is_importing and "Import" or "Export" if self.bad_password_detected: title += ' (type the correct password)' self.bad_password_detected = False if not reset_password and not self.bad_password_detected: pwd = self.owner.ctrl_be.get_mysql_password() if pwd is None: accepted, pwd = mforms.Utilities.find_or_ask_for_password(title, host, username, reset_password) if not accepted: return None return pwd def stop(self): if self.dump_thread: self.dump_thread.kill() def failed(self, message): self.progress_tab.did_fail(message) def cancelled(self, message): self.progress_tab.did_cancel(message) #################################################################################################### ## Import #################################################################################################### class WbAdminImportTab(WbAdminSchemaListTab): def __init__(self, owner, server_profile, progress_tab): WbAdminSchemaListTab.__init__(self, owner, server_profile, progress_tab, True) self.table_list_model = TableListModel() self.export_button.set_text("Start Import") self.tables_paths = {} self.views_paths = {} self._update_schema_list_tm = None self._update_progress_tm = None def folder_path_changed(self): self.folder_load_btn.set_enabled(True) self.savefolder_path = self.folder_te.get_string_value() def new_target_schema(self): ret, name = Utilities.request_input("Create Schema", "Name of schema to create:", "newschema") if ret: if not self.owner.ctrl_be.is_sql_connected(): Utilities.show_error("Create Schema", "Cannot create schema because there is no connection to the DB server.", "OK", "", "") return name = name.replace("`", "``") try: self.print_log_message("Creating schema %s\n" % name) self.owner.ctrl_be.exec_sql("CREATE DATABASE `%s`" % name, auto_reconnect=False) except QueryError, err: self.print_log_message("Error creating schema %s: %s\n" % (name, err)) Utilities.show_error("Create Schema", str(err), "OK", "", "") if err.is_connection_error(): self.owner.ctrl_be.handle_sql_disconnection(err) return self.refresh_schema_list() self.import_target_schema_selection = name def _refresh_schema_list_thread(self): self.schema_names = [] try: result = self.owner.ctrl_be.exec_query("SHOW DATABASES", auto_reconnect=False) while result.nextRow(): value = result.unicodeByName("Database") if value == "information_schema": continue self.schema_names.append(value) del result self.schema_refresh_done = True except QueryError, exc: self.print_log_message("Error fetching schema list: %s" % str(exc)) if exc.is_connection_error(): if self.owner.ctrl_be.handle_sql_disconnection(exc): self.schema_refresh_cancelled = "Error fetching schema list:\n%s\nReconnected successfully." % str(exc) else: self.schema_refresh_cancelled = "Error fetching schema list:\n%s\nCould not reconnect." % str(exc) else: self.schema_refresh_cancelled = "Error fetching schema list:\n%s" % str(exc) except Exception, exc: self.print_log_message("Error fetching schema list: %s" % str(exc) ) self.schema_refresh_cancelled = "Error fetching schema list:\n%s" % str(exc) def refresh_schema_list(self): if not self.owner.ctrl_be.is_sql_connected(): return class SchemaRefreshThread(threading.Thread): def __init__(self, owner): self.owner = owner threading.Thread.__init__(self) def run(self): self.owner._refresh_schema_list_thread() self.schema_refresh_thread = SchemaRefreshThread(self) self.schema_refresh_thread.start() self.schema_refresh_done = False self.schema_refresh_cancelled = None self.import_target_schema_selection = self.import_target_schema.get_string_value() self._update_schema_list_tm = Utilities.add_timeout(float(0.4), self._update_schema_list) def _update_schema_list(self): if self.schema_refresh_cancelled: Utilities.show_error("Refresh Schema List", self.schema_refresh_cancelled, "OK", "", "") self.schema_refresh_cancelled = None self._update_schema_list_tm = None return False if not self.schema_refresh_done: return True self.import_target_schema.clear() self.import_target_schema.add_items([""]+self.schema_names) if self.import_target_schema_selection: self.import_target_schema.set_value(self.import_target_schema_selection) self._update_schema_list_tm = None return False def close(self): if self._update_schema_list_tm: Utilities.cancel_timeout(self._update_schema_list_tm) if self._update_progress_tm: Utilities.cancel_timeout(self._update_progress_tm) def refresh_table_list(self): def parse_name_from_single_table_dump(path): import codecs f = codecs.open(path, encoding="utf-8") schema = None table = None is_view = False for line in f: if line.startswith("-- Host:"): schema = line.partition("Database: ")[-1].strip() if table: break elif not table and line.startswith("-- Table structure for table"): table = line.partition("-- Table structure for table")[-1].strip() if table[0] == '`': table = table[1:-1] if schema: break elif not table and line.startswith("-- Dumping data for table"): table = line.partition("-- Dumping data for table")[-1].strip() if table[0] == '`': table = table[1:-1] if schema: break elif line.startswith( ("/*!50001 VIEW", "/*!50003 CREATE*/ /*!50020 DEFINER=","/*!50106 CREATE*/ /*!50117 DEFINER=") ): is_view = True table = "Views, routines, events etc" if schema: break return schema, table, is_view self.folder_load_btn.set_enabled(False) tables_by_schema = {} # (schema, table) -> path self.tables_paths = {} self.views_paths = {} self.schema_list.freeze_refresh() self.schema_list.clear() try: save_to_folder = not self.fileradio.get_active() if save_to_folder: self.progress_tab.set_start_enabled(False) path = self.savefolder_path dirList=os.listdir(path) for fname in dirList: fullname = os.path.join(path, fname) if os.path.isfile(fullname) and os.path.splitext(fullname)[1] == ".sql": # open the backup file and look for schema and table name in it schema, table, is_view = parse_name_from_single_table_dump(fullname) if not schema or not table: self.progress_tab.print_log_message("%s does not contain schema/table information" % fullname) continue if tables_by_schema.has_key(schema): tables, selection = tables_by_schema[schema] tables.append(table) tables.sort() selection.add(table) # select all by default else: tables_by_schema[schema] = ([table], set([table])) if is_view: self.views_paths[(schema, table)] = fullname self.table_list_model.set_routines_placeholder((schema, table)) else: self.tables_paths[(schema, table)] = fullname if not tables_by_schema: Utilities.show_message("Open Dump Folder", "There were no dump files in the selected folder.", "OK", "", "") else: names = tables_by_schema.keys() names.sort() for schema in names: row = self.schema_list.add_node() row.set_bool(0, True) row.set_icon_path(1, "db.Schema.16x16.png") row.set_string(1, schema) self.progress_tab.set_start_enabled(True) self.schema_list.thaw_refresh() except Exception, exc: import traceback self.schema_list.thaw_refresh() traceback.print_exc() Utilities.show_error("Error Opening Dump", str(exc), "OK", "", "") self.folder_load_btn.set_enabled(True) self.export_button.set_enabled(False) self.failed(str(exc)) self.table_list_model.set_tables_by_schema(tables_by_schema) for schema in tables_by_schema.keys(): self.table_list_model.set_schema_selected(schema, True) def get_path_to_mysql(self): # get path to mysql client from options try: path = grt.root.wb.options.options["mysqlclient"] if path: if os.path.exists(path): return path if any(os.path.exists(os.path.join(p,path)) for p in os.getenv("PATH").split(os.pathsep)): return path if path != "mysql": return None except: return None if sys.platform.lower() == "darwin": # if path is not specified, use bundled one return mforms.App.get().get_executable_path("mysql").encode("utf8") elif sys.platform.lower() == "win32": return mforms.App.get().get_executable_path("mysql.exe").encode("utf8") else: # if path is not specified, use bundled one path = mforms.App.get().get_executable_path("mysql").encode("utf8") if path: return path # just pick default if any(os.path.exists(os.path.join(p,"mysql")) for p in os.getenv("PATH").split(os.pathsep)): return "mysql" return None def start(self): self.progress_tab.set_start_enabled(False) self.progress_tab.did_start() self.progress_tab.set_status("Import is running...") connection_params = self.server_profile.db_connection_params tunnel = ConnectionTunnel(connection_params) conn = connection_params.parameterValues from_folder = not self.fileradio.get_active() operations = [] if from_folder: self.path = self.folder_te.get_string_value() else: self.path = self.file_te.get_string_value() #self.path = self.folder_te.get_string_value() if from_folder else self.file_te.get_string_value() if from_folder: selection = self.table_list_model.get_full_selection() # make sure routines, views and stuffs get imported last if self.table_list_model.routines_placeholder in selection: selection.remove(self.table_list_model.routines_placeholder) selection.append(self.table_list_model.routines_placeholder) for schema, table in selection: logmsg = "Restoring %s (%s)" % (schema, table) path = self.tables_paths.get((schema, table)) extra_args = ["--database=%s" % schema] # description, object_count, extra_args, objects, pipe_factory if path != None: task = DumpThread.TaskData(logmsg, 1, extra_args, [path], None, lambda:None) #operations.insert(0,task) operations.append(task) else: path = self.views_paths.get((schema, table)) task = DumpThread.TaskData(logmsg, 1, extra_args, [path], None, lambda:None) if path != None: operations.append(task) else: if not os.path.exists(self.path): Utilities.show_message("Dump file not found", u"File %s doesn't exist" % self.path, "OK", "", "") self.failed(u"Dump file not found: File %s doesn't exist" % self.path) return logmsg = "Restoring " + self.path # description, object_count, pipe_factory, extra_args, objects extra_args = [] task = DumpThread.TaskData(logmsg, 1, extra_args, [self.path], None, lambda:None) operations.append(task) # operations.append((logmsg, 1, lambda:None, [], [self.path])) if connection_params.driver.name == "MysqlNativeSocket": host_option = "--protocol="+("pipe" if sys.platform == "win32" else "socket") if conn["socket"]: port_option = "--socket=" + [conn["socket"]][0] else: port_option = "" else: if tunnel.port or conn["port"]: port_option = "--port=" + str(tunnel.port or conn["port"]) else: port_option = "" if (tunnel.port and ["localhost"] or [conn["hostName"]])[0]: host_option = "--host=" + (tunnel.port and ["localhost"] or [conn["hostName"]])[0] else: host_option = "" params = [ "--password=" ] if conn.get("useSSL", 0): if conn.get("sslCert", ""): params.append("--ssl-cert=%s" % conn["sslCert"]) if conn.get("sslCA", ""): params.append("--ssl-ca=%s" % conn["sslCA"]) if conn.get("sslKey", ""): params.append("--ssl-key=%s" % conn["sslKey"]) if conn.get("sslCipher", ""): params.append("--ssl-cipher=%s" % conn["sslCipher"]) params += [ host_option, "--user=" + conn["userName"], port_option, "--default-character-set=utf8", "--comments", "<" # the rest of the params will be redirected from stdin ] if not from_folder: target_db = self.import_target_schema.get_string_value() if target_db: params.insert(-1, "--database=%s" % target_db) params = [item for item in params if item] if connection_params.driver.name != "MysqlNativeSocket": params.insert(1, "--protocol=tcp") if conn.get("OPT_ENABLE_CLEARTEXT_PLUGIN", ""): params.insert(1, "--enable-cleartext-plugin") cmd = self.get_path_to_mysql() if cmd == None: self.failed("mysql command was not found, please install it or configure it in Preferences -> Administrator") return # if cmd[0] != '"': # cmd = '"' + cmd + '"' #cmd += " " + (" ".join(params)) cmd = subprocess.list2cmdline([cmd] + params) password = self.get_mysql_password(self.bad_password_detected) if password is None: self.cancelled("Password Input Cancelled") return self.dump_thread = DumpThread(cmd, operations, password, self, (self.progress_tab.logging_lock, self.progress_tab.log_queue)) self.dump_thread.is_import = True self.dump_thread.start() self._update_progress_tm = Utilities.add_timeout(float(0.4), self._update_progress) def _update_progress(self): r = self.update_progress() if not r: self._update_progress_tm = None return r def fail_callback(self): pass def close_pipe(self): pass def tasks_aborted(self): self.cancelled(time.strftime('%X ') + "Aborted by User") self.progress_tab.print_log_message("Restored database(s) maybe in an inconsistent state") def tasks_completed(self): logmsg = time.strftime('%X ') + "Import of %s has finished" % self.path.encode("utf8") if self.dump_thread.error_count > 0: self.progress_tab.set_status("Import Completed With %i Errors" % self.dump_thread.error_count) logmsg += " with %i errors" % self.dump_thread.error_count else: self.progress_tab.set_status("Import Completed") self.progress_tab.print_log_message(logmsg) self.progress_tab.did_complete() #################################################################################################### ## Export #################################################################################################### class WbAdminExportTab(WbAdminSchemaListTab): class ExportTableListModel(TableListModel): def __init__(self): TableListModel.__init__(self) self.views_by_schema = {} self.schemasqls = {} self.schemas_to_load = {} self.schemas = [] self.load_schema_data = lambda:None def reset(self): self.tables_by_schema = {} self.views_by_schema = {} self.schemasqls = {} def get_schema_names(self): return self.schemas def set_schema_data(self, schema, schematables_and_views, viewlist, dbsql): self.tables_by_schema[schema] = schematables_and_views, set() self.views_by_schema[schema] = set(viewlist) self.schemasqls[schema] = dbsql def get_schema_sql(self, schema): return self.schemasqls[schema] def is_view(self, schema, table): return table in self.views_by_schema[schema] def list_icon_for_table(self, schema, table): return "db.View.16x16.png" if self.is_view(schema, table) else "db.Table.16x16.png" def set_schema_list(self,schemas_to_load): self.schemas = schemas_to_load self.schemas_to_load = schemas_to_load def get_tables(self, schema): if schema in self.schemas_to_load: # print "Loading: ",schema,self.load_schema_data(schema) schema,schematables,viewlist,dbsql = self.load_schema_data(schema) self.set_schema_data(schema,schematables,viewlist,dbsql) self.schemas_to_load.remove(schema) tables, selection = self.tables_by_schema[schema] return tables def validate_single_transaction(self, schemas_to_dump): return True class TableRefreshThread(threading.Thread): def __init__(self, owner): self.owner = owner threading.Thread.__init__(self) def run(self): self.owner.refresh_table_list_thread() def __init__(self, owner, server_profile, progress_tab): self.table_list_model = self.ExportTableListModel() WbAdminSchemaListTab.__init__(self, owner, server_profile, progress_tab, False) self.schemasqls = {} self._update_refresh_tm = None self._update_progress_tm = None self.savefolder_path = os.path.join(self.get_default_dump_folder(), time.strftime("Dump%Y%m%d")) self.savefile_path = self.savefolder_path + ".sql" self.basepath = self.savefolder_path self.update_paths() self.file_te.set_value(self.savefile_path) self.folder_te.set_value(self.savefolder_path) self.table_list_model.load_schema_data = self.load_schema_tables # self.filefolder_label.set_text("Save to") # run mysqldump --help to get default option values self.mysqldump_defaults = self.check_mysqldump_defaults() self.ignore_internal_log_tables = True self.internal_log_tables = ["apply_status", "general_log", "slow_log", "schema"] self._compatibility_params = False self.show_internal_schemas = False def close(self): if self._update_refresh_tm: Utilities.cancel_timeout(self._update_refresh_tm) self._update_refresh_tm = None if self._update_progress_tm: Utilities.cancel_timeout(self._update_progress_tm) self._update_progress_tm = None def load_schema_tables(self, schema): schematables_and_views = [] viewlist = [] dbsql = "" try: self.refresh_state= "Retrieving tables data for schema " + schema dbcreate = self.owner.ctrl_be.exec_query("SHOW CREATE DATABASE `"+escape_sql_identifier(schema)+"`") tableset = self.owner.ctrl_be.exec_query("SHOW FULL TABLES FROM `"+escape_sql_identifier(schema)+"`") dbcreate.nextRow() dbsql = dbcreate.unicodeByName("Create Database") parts = dbsql.partition("CREATE DATABASE ") dbsql = u"%s%s IF NOT EXISTS %s;\nUSE `%s`;\n" % (parts[0], parts[1], parts[2], escape_sql_identifier(schema)) while tableset.nextRow(): tabletype = tableset.unicodeByName("Table_type") tablename = tableset.unicodeByName("Tables_in_"+schema) if self.ignore_internal_log_tables and schema == "mysql" and tablename in self.internal_log_tables: continue if tabletype == "VIEW": viewlist.append(tablename) schematables_and_views.append(tablename) del tableset except Exception, exc: import traceback traceback.print_exc() print "Error retrieving table list form schema '",schema,"'" self.progress_tab.print_log_message("Error Fetching Table List From %s (%s)" % (schema, str(exc)) ) return schema,schematables_and_views,viewlist,dbsql def refresh_table_list_thread(self): self.table_list_model.reset() try: result = self.owner.ctrl_be.exec_query("SHOW DATABASES") schema_names = [] while result.nextRow(): value = result.unicodeByName("Database") if not self.show_internal_schemas and value in ["information_schema", "performance_schema", "mysql"]: continue schema_names.append(value) del result self.table_list_model.set_schema_list(schema_names) schema_cntr = 1 if schema_names: self.refresh_progress = float(schema_cntr) / len(schema_names) for schema in schema_names: # schematables,viewlist,dbsql = self.load_schema_tables(schema) # finally: schema_cntr += 1 self.refresh_progress = float(schema_cntr) / len(schema_names) # self.table_list_model.set_schema_data(schema,(schematables, set()),viewlist,dbsql) else: self.refresh_progress = 1 except Exception, exc: self.print_log_message("Error updating DB: %s" % str(exc) ) # finally: self.refresh_completed = True def refresh_table_list(self): self.table_list_model.reset() ####self.refresh_progressbar.set_value(0) if not self.owner.ctrl_be.is_sql_connected(): return #self.hintlabel.set_text("Schema list update...") self.refresh_state = "Retrieving schema list" self.refresh_progress = 0 self.schema_list.clear() self.refresh_button.set_enabled(False) self.refresh_thread = self.TableRefreshThread(self) # refresh_thread.run() self.refresh_completed = False self.refresh_thread.start() if not self._update_refresh_tm: self._update_refresh_tm = Utilities.add_timeout(float(0.4), self.update_refresh) def update_refresh(self): self.progress_tab.flush_queued_logs() if self.refresh_progress > 1: self.refresh_progress = float(1) ####self.refresh_progressbar.set_value(self.refresh_progress) self.select_summary_label.set_text(self.refresh_state) if not self.refresh_completed: return True ####self.refresh_progressbar.set_value(0) names = self.table_list_model.get_schema_names() names.sort() self.schema_list.freeze_refresh() for schema in names: r = self.schema_list.add_node() r.set_icon_path(1, "db.Schema.16x16.png") r.set_string(1, schema) r.set_bool(0, False) self.schema_list.thaw_refresh() self.refresh_button.set_enabled(True) self.select_summary_label.set_text("") ###self.hintlabel.set_text("Press [Start Export] to start...") self._update_refresh_tm = None return False def update_paths(self): pathcntr = 1 while os.path.exists(self.savefolder_path): self.savefolder_path = self.basepath + "-" + str(pathcntr) pathcntr += 1 pathcntr = 1 while os.path.exists(self.savefile_path): self.savefile_path = self.basepath + "-" + str(pathcntr) + ".sql" pathcntr += 1 def check_mysqldump_version(self, about_to_run=False): mysqldump_version = get_mysqldump_version() if not mysqldump_version: if about_to_run: mforms.Utilities.show_error("Could not get mysqldump version", "Workbench was unable to get mysqldump version. Please verify the log for more information.", "OK", "", "") else: self.print_log_message("Workbench was unable to get mysqldump version") return False if mysqldump_version < self.owner.ctrl_be.target_version: msg = "%s is version %s, but the MySQL Server to be dumped has version %s.\nBecause the version of mysqldump is older than the server, some features may not be backed up properly.\nIt is recommended you upgrade your local MySQL client programs, including mysqldump, to a version equal to or newer than that of the target server.\nThe path to the dump tool must then be set in Preferences -> Administrator -> Path to mysqldump Tool:" % (get_path_to_mysqldump(), mysqldump_version, self.owner.ctrl_be.target_version) if about_to_run: if not mforms.Utilities.show_warning("mysqldump Version Mismatch", msg, "Continue Anyway", "Cancel", ""): return False else: self.print_log_message(msg) # When using mysqldump >=5.6 and a server < 5.6, an additional parameter needs to be added # for backwards compatibility if (mysqldump_version >= Version(5, 6) and self.owner.ctrl_be.target_version < Version(5, 6)): self._compatibility_params = True return True def check_mysqldump_defaults(self): defaults = {} # check mysqldump default values path = get_path_to_mysqldump() if path: output = [] local_run_cmd('"%s" --help' % path, output_handler= lambda line,l=output: l.append(line)) ok = False for line in ("\n".join(output)).split("\n"): line = line.strip() if line.startswith("-----------") and line.endswith("-----------"): ok = True continue if ok: t = line.split() if len(t) == 2: k, v = t if v in ("TRUE", "FALSE"): defaults[k] = v return defaults def validate_single_transaction(self, starting): if self.single_transaction_check.get_active() and self.owner.get_lock_tables() == {'lock-tables': 'TRUE'}: r = mforms.Utilities.show_warning("Export to Disk", "Single transaction with --lock-tables is not supported.\n" "Disable --lock-tables?", "Disable", "Cancel", "") if r == mforms.ResultOk: self.owner.set_lock_tables(False) return True else: return False return True def single_transaction_clicked(self): self.validate_single_transaction(False) def set_show_internal_schemas(self, show_internal_schemas): self.show_internal_schemas = show_internal_schemas class ViewDumpData(DumpThread.TaskData): def __init__(self,schema,views,make_pipe): title = "Dumping " + schema + " views" DumpThread.TaskData.__init__(self, title, len(views), [], [schema] + views, None, make_pipe) class TableDumpData(DumpThread.TaskData): def __init__(self,schema,table,args, make_pipe): title = "Dumping " + schema title += " (%s)" % table DumpThread.TaskData.__init__(self,title, 1, [] + args, [schema, table], None, make_pipe) class TableDumpNoData(DumpThread.TaskData): def __init__(self,schema,table,args, make_pipe): title = "Dumping " + schema title += " (%s)" % table DumpThread.TaskData.__init__(self,title, 1, ["--no-data"] + args, [schema, table], None, make_pipe) class ViewsRoutinesEventsDumpData(DumpThread.TaskData): def __init__(self, schema, views, args, make_pipe): title = "Dumping " + schema + " views and/or routines and/or events" if not views: extra_args = ["--no-create-info"] else: extra_args = [] DumpThread.TaskData.__init__(self,title, len(views), ["--skip-triggers", " --no-data" ," --no-create-db"] + extra_args + args, [schema] + views, None, make_pipe) def dump_to_folder(self, schemaname, tablename): self.close_pipe() path = os.path.join(self.path, normalize_filename(schemaname) + "_" + normalize_filename(tablename) + '.sql') i = 0 # check if the path already exists (they could become duplicated because of normalization) while os.path.exists(path): path = os.path.join(self.path, normalize_filename(schemaname) + "_" + normalize_filename(tablename) + ('%i.sql'%i)) self.out_pipe = open(path,"w") if self.include_schema_check.get_active(): data = self.table_list_model.get_schema_sql(schemaname) if type(data) is unicode: data = data.encode("utf-8") self.out_pipe.write(data) self.out_pipe.flush() return self.out_pipe def start(self): self.progress_tab.set_start_enabled(False) if not self.check_mysqldump_version(True): self.progress_tab.set_start_enabled(True) return if not self.validate_single_transaction(True): self.progress_tab.set_start_enabled(True) return connection_params = self.server_profile.db_connection_params tunnel = ConnectionTunnel(connection_params) conn = connection_params.parameterValues single_transaction = self.single_transaction_check.get_active() #dump_views = self.dump_view_check.get_active() sel_index = self.dump_type_selector.get_selected_index() skip_data = True if sel_index == 2 else False skip_table_structure = True if sel_index == 1 else False dump_routines = self.dump_routines_check.get_active() dump_events = self.dump_events_check.get_active() dump_triggers = self.dump_triggers_check.get_active() save_to_folder = not self.fileradio.get_active() if save_to_folder: self.path = self.folder_te.get_string_value() else: self.path = self.file_te.get_string_value() # gather objects to dump schemas_to_dump = self.table_list_model.get_objects_to_dump(include_empty_schemas=True) tables_to_ignore = self.table_list_model.get_tables_to_ignore() if len(schemas_to_dump) == 0: self.progress_tab.print_log_message(time.strftime('%X ') + "Nothing to do, no schemas or tables selected." + "\n") self.progress_tab.set_start_enabled(True) return # assemble list of operations/command calls to be performed operations = [] if save_to_folder: if not os.path.exists(self.path): try: os.makedirs(self.path, mode=0700) except: Utilities.show_error('Error', 'Access to "%s" failed' % self.path, "OK", "", "") self.export_button.set_enabled(True) return for schema, tables in schemas_to_dump: views = [] for table in tables: if self.table_list_model.is_view(schema, table): views.append(table) else: title = "Dumping " + schema title += " (%s)" % table # description, object_count, pipe_factory, extra_args, objects args = [] if not dump_triggers: args.append('--skip-triggers') if skip_table_structure: args.append('--no-create-info') if skip_data: task = self.TableDumpNoData(schema,table, args, lambda schema=schema,table=table:self.dump_to_folder(schema, table)) else: task = self.TableDumpData(schema,table, args, lambda schema=schema,table=table:self.dump_to_folder(schema, table)) operations.append(task) # dump everything non-tables to file for routines #if views: # task = self.ViewDumpData(schema, views, lambda schema=schema, table=table:self.dump_to_folder(schema, "routines")) # operations.append(task) #if dump_events: # task = self.EventDumpData(schema, lambda schema=schema, table=table:self.dump_to_folder(schema, "routines")) # operations.append(task) if views or dump_routines or dump_events: args = [] if dump_routines: args.append("--routines") if dump_events: args.append("--events") task = self.ViewsRoutinesEventsDumpData(schema, views, args, lambda schema=schema, table=None:self.dump_to_folder(schema, "routines")) operations.append(task) else: # single file if not os.path.exists(os.path.dirname(self.path)): try: os.makedirs(os.path.dirname(self.path)) except: Utilities.show_error('Error', 'Access to "%s" failed' % self.path, "OK", "", "") self.export_button.set_enabled(True) return # if there is a single schema to dump or single-transaction is off we allow selecting the individual tables, otherwise we need to bulk dump the whole db #if (len(schemas_to_dump) != 1 and not single_transaction) or (len(schemas_to_dump) == 1 not self.table_list_model.validate_single_transaction(schemas_to_dump)): if len(schemas_to_dump) == 1 or (len(schemas_to_dump) > 1 and (not single_transaction or not self.table_list_model.validate_single_transaction(schemas_to_dump))): for schema, tables in schemas_to_dump: # don't list the tables explicitly if everything is dumped # this is to workaround a problem with mysqldump where functions are dumped after # tables if the table names are specified # see bug #14359349 title = "Dumping " + schema if set(tables) == set(self.table_list_model.get_tables(schema)): title += " (all tables)" else: title += " (%s)" % ", ".join(tables) objects = [schema] if single_transaction: params = ["--single-transaction=TRUE"] else: params = [] if dump_routines: params.append("--routines") if dump_events: params.append("--events") if skip_data or not tables: params.append("--no-data") if not tables or skip_table_structure: params.append("--no-create-info=TRUE") if not tables or not dump_triggers: params.append("--skip-triggers") # description, object_count, pipe_factory, extra_args, objects task = DumpThread.TaskData(title, len(tables), params, objects, tables_to_ignore, lambda schema=schema:self.dump_to_file([schema])) operations.append(task) # operations.append((title, len(tables), lambda schema=schema:self.dump_to_file([schema]), params, objects)) else: params = [] schema_names = [s[0] for s in schemas_to_dump] count = sum([len(s[1]) for s in schemas_to_dump]) title = "Dumping " + ", ".join(schema_names) if dump_routines: params.append("--routines") if dump_events: params.append("--events") if skip_data: params.append("--no-data") if single_transaction: params += ["--single-transaction=TRUE", "--databases"] else: params += ["--databases"] # --databases includes CREATE DATABASE info, so it's not needed for dump_to_file() # description, object_count, pipe_factory, extra_args, objects task = DumpThread.TaskData(title, count, params, schema_names, tables_to_ignore, lambda:self.dump_to_file([])) operations.append(task) # operations.append((title, count, lambda:self.dump_to_file([]), params, schema_names)) if connection_params.driver.name == "MysqlNativeSocket": params = { "protocol":"pipe" if sys.platform == "win32" else "socket", "socket":([conn["socket"]])[0], "default-character-set":"utf8", "user":conn["userName"] } if not params["socket"]: del params["socket"] else: params = { "host":(tunnel.port and ["localhost"] or [conn["hostName"]])[0], "port":(tunnel.port and [str(tunnel.port)] or [conn["port"]])[0], "default-character-set":"utf8", "user":conn["userName"] } params["protocol"] = "tcp" if not params["port"]: del params["port"] if not params["host"]: del params["host"] options = {} for key, value in self.owner.get_export_options(self.mysqldump_defaults).items(): if not key.upper().startswith('$INTERNAL$'): options[key] = value params.update(options) cmd = get_path_to_mysqldump() if cmd == None: self.failed("mysqldump command was not found, please install it or configure it in Edit -> Preferences -> MySQL") return #if cmd[0] != '"': # cmd = '"' + cmd + '"' #cmd += " --password=" args = [cmd, "--password="] if conn.get("useSSL", 0): if conn.get("sslCert", ""): args.append("--ssl-cert=%s" % conn["sslCert"]) if conn.get("sslCA", ""): args.append("--ssl-ca=%s" % conn["sslCA"]) if conn.get("sslKey", ""): args.append("--ssl-key=%s" % conn["sslKey"]) if conn.get("sslCipher", ""): args.append("--ssl-cipher=%s" % conn["sslCipher"]) # Sets the compatibility parameters if needed if self._compatibility_params: args.append("--set-gtid-purged=OFF") if conn.get("OPT_ENABLE_CLEARTEXT_PLUGIN", ""): args.append("--enable-cleartext-plugin") for paramname, paramvalue in params.items(): args.append("--"+paramname+((paramvalue != None and ["="+str(paramvalue)] or [""])[0])) cmd = subprocess.list2cmdline(args) password = self.get_mysql_password(self.bad_password_detected) if password is None: self.cancelled("Password Input Cancelled") return self.progress_tab.did_start() self.progress_tab.set_status("Export is running...") self.dump_thread = DumpThread(cmd, operations, password, self, (self.progress_tab.logging_lock, self.progress_tab.log_queue)) self.dump_thread.is_import = False self.dump_thread.start() self._update_progress_tm = Utilities.add_timeout(float(0.4), self._update_progress) def _update_progress(self): r = self.update_progress() if not r: self._update_progress_tm = None return r def dump_to_file(self, schemanames): if self.out_pipe == None: self.out_pipe = open(self.path,"w") if self.include_schema_check.get_active(): for schema in schemanames: self.out_pipe.write(self.table_list_model.get_schema_sql(schema).encode('utf-8')) self.out_pipe.flush() return self.out_pipe def fail_callback(self): fname = self.out_pipe.name self.close_pipe() os.remove(fname) def close_pipe(self): if self.out_pipe != None: self.out_pipe.close() self.out_pipe = None def tasks_aborted(self): if self.path: try: os.rename(self.path, self.path+".cancelled") self.progress_tab.print_log_message("Partial backup file renamed to %s.cancelled" % self.path) except Exception, exc: self.progress_tab.print_log_message("Error renaming partial backup file %s: %s" % (self.path, exc)) self.cancelled(time.strftime('%X ') + "Aborted by User") def tasks_completed(self): self.update_paths() self.file_te.set_value(self.savefile_path) self.folder_te.set_value(self.savefolder_path) logmsg = time.strftime(u'%X ') + "Export of %s has finished" % self.path.encode('utf-8') if self.dump_thread.error_count > 0: self.progress_tab.set_status("Export Completed With %i Errors" % self.dump_thread.error_count) logmsg += " with %i errors" % self.dump_thread.error_count else: self.progress_tab.set_status("Export Completed") self.progress_tab.print_log_message(logmsg) self.progress_tab.did_complete() #################################################################################################### ## Options #################################################################################################### class WbAdminExportOptionsTab(mforms.Box): class Check_option_model: def __init__(self,optname,checkbox,default): self.optname = optname self.checkbox = checkbox self.default = default def get_option(self, defaults): is_bool_option = defaults.has_key(self.optname) value = self.checkbox.get_active() and "TRUE" or "FALSE" if is_bool_option: if defaults[self.optname] != value: return {self.optname: value} return {} else: if self.default == "TRUE" and not self.checkbox.get_active(): return {"skip-"+self.optname:"TRUE"} else: return {self.optname:(self.checkbox.get_active() and ["TRUE"] or ["FALSE"])[0]} def set_option(self, value): if value in ("TRUE", "FALSE"): self.checkbox.set_active(value == "TRUE") else: self.checkbox.set_active(value) class Text_option_model: def __init__(self, optname, textentry, default): self.optname = optname self.entry = textentry self.default = default def get_option(self, defaults): if self.entry.get_string_value() == self.default: return {} return {self.optname:self.entry.get_string_value() or self.default} def set_option(self, value): self.entry.set_value(value) def __init__(self, target_version, defaults_from_mysqldump): mforms.Box.__init__(self, False) self.set_managed() self.set_release_on_add() mysqldump_version = get_mysqldump_version() self.options = {} button_box = newBox(True) button_box.set_padding(8) button_box.set_spacing(12) self.restore_defaults_button = newButton() self.restore_defaults_button.set_text('Restore Defaults') self.restore_defaults_button.add_clicked_callback(self.restore_default_options) button_box.add_end(self.restore_defaults_button, False) self.add_end(button_box, False) outerbox = newBox(False) outerbox.set_padding(8) outerbox.set_spacing(12) for groupname, options in reversed(wb_admin_export_options.export_options.items()): box = newBox(False) box.set_padding(8) box.set_spacing(8) panel = newPanel(mforms.TitledBoxPanel) panel.set_title(groupname) # print groupname for optname, option_info in reversed(options.items()): option_type = "BOOL" if len(option_info) == 2: (option, default) = option_info elif len(option_info) == 4: # includes type and (min_version, max_version) tuple (option, default, option_type, (min_version, max_version)) = option_info if min_version and target_version: if not target_version.is_supported_mysql_version_at_least(Version.fromstr(min_version)): log_debug("Skip option %s because it's for version %s\n" % (optname, min_version)) continue if max_version and target_version: if target_version.is_supported_mysql_version_at_least(Version.fromstr(max_version)): log_debug("Skip option %s because it's deprecated in version %s\n" % (optname, max_version)) continue if min_version and mysqldump_version < min_version: log_debug("Skip option %s because it's for mysqldump %s\n" % (optname, min_version)) continue if max_version and mysqldump_version > max_version: log_debug("Skip option %s because it's deprecated in mysqldump %s\n" % (optname, max_version)) continue # get the default value from mysqldump --help, if we don't have that data, use the stored default default = defaults_from_mysqldump.get(optname, default) if option_type == "BOOL": checkbox = newCheckBox() checkbox.set_text("%s - %s"% (optname, option)) checkbox.set_active(default == "TRUE") box.add(checkbox, False, True) self.options[optname] = self.Check_option_model(optname,checkbox,default) else: hbox = newBox(True) hbox.set_spacing(4) label = newLabel("%s - %s"% (optname, option)) hbox.add(label, False, True) entry = newTextEntry() hbox.add(entry, True, True) entry.set_value(default) box.add(hbox, False, True) self.options[optname] = self.Text_option_model(optname,entry,default) if groupname == "Other": max_allowed_packet_box = newBox(True) self.max_allowed_packet_te = newTextEntry() self.max_allowed_packet_te.set_value("1G") self.max_allowed_packet_te.set_size(40, -1) label = newLabel(" The maximum size of one packet or any generated/intermediate string. ") max_allowed_packet_box.add(label,False,False) max_allowed_packet_box.add(self.max_allowed_packet_te,False,True) max_allowed_packet_box.add(newBox(True),True,True) max_allowed_packet_box.add(newBox(True),True,True) max_allowed_packet_box.add(newBox(True),True,True) box.add(max_allowed_packet_box,False,True) self.options['max_allowed_packet'] = self.Text_option_model('max_allowed_packet', self.max_allowed_packet_te, "1G") panel.add(box) outerbox.add(panel, True, True) scrollpan = newScrollPanel(mforms.ScrollPanelNoFlags) scrollpan.add(outerbox) self.add(scrollpan, True, True) def get_lock_tables(self): return self.options["lock-tables"].get_option({'lock-tables': 'TRUE'}) def set_lock_tables(self, value): return self.options["lock-tables"].set_option(value) def get_options(self, defaults): options = {} for optname, getter in self.options.items(): result = getter.get_option(defaults) if result != None: options.update(result) #options.update({"max_allowed_packet":self.max_allowed_packet_te.get_string_value()}) return options def set_options(self, values): for k, v in values.items(): if self.options.has_key(k): self.options[k].set_option(v) def restore_default_options(self): for option in self.options.values(): option.set_option(option.default) def add_clicked_callback_to_checkbox(self, optname, callback_function): opt = self.options[optname] if opt: opt.checkbox.add_clicked_callback(callback_function) #################################################################################################### class WbAdminProgressTab(mforms.Box): def __init__(self, owner_tab, is_export): mforms.Box.__init__(self, False) self.set_managed() self.set_release_on_add() self.set_spacing(12) self.set_padding(8) self.owner_tab = owner_tab self.operation_tab = None self.is_export = is_export self.logging_lock = thread.allocate_lock() self.log_queue = deque([]) statusbox = newBox(False) statusbox.set_spacing(2) self.dump_progressbar = newProgressBar() self.statlabel = newLabel("") statusbox.set_size(400, -1) if is_export: self.hintlabel = newLabel("Press [Start Export] to start...") else: self.hintlabel = newLabel("Press [Start Import] to start...") statusbox.add(self.hintlabel, False, True) statusbox.add(self.dump_progressbar, False, True) statusbox.add(newLabel("Status:"), False, True) statusbox.add(self.statlabel, False, True) self.progress_log = newTextBox(mforms.VerticalScrollBar) self.progress_log.set_read_only(True) self.add(statusbox, False, True) label = newLabel("Log:") self.add(label, False, True) self.add(self.progress_log, True, True) box = newBox(True) self.add(box, False, True) box.set_spacing(8) box.set_padding(0) self.export_button = newButton() if is_export: self.export_button.set_text("Start Export") else: self.export_button.set_text("Start Import") self.export_button.set_enabled(False) box.add_end(self.export_button, False, True) self.export_button.add_clicked_callback(self.start) self.stop_button = newButton() self.stop_button.set_text("Stop") self.stop_button.set_enabled(False) self.stop_button.add_clicked_callback(self.stop) box.add_end(self.stop_button, False, True) def set_progress(self, progress, progress_text): self.statlabel.set_text(progress_text) self.dump_progressbar.set_value(progress) def set_start_enabled(self, flag): self.export_button.set_enabled(bool(flag)) self.operation_tab.export_button.set_enabled(bool(flag)) def set_status(self, text): self.hintlabel.set_text(text) self.operation_tab.statlabel.set_text(text) def flush_queued_logs(self): self.logging_lock.acquire() while len(self.log_queue) > 0: self.progress_log.append_text_and_scroll(self.log_queue.popleft()+"\n", True) self.logging_lock.release() def print_log_message(self, message): if mforms.Utilities.in_main_thread(): self.progress_log.append_text_and_scroll(message+"\n", True) else: self.logging_lock.acquire() self.log_queue.append(message+"\n") self.logging_lock.release() def start(self): self.operation_tab.start() def stop(self): self.operation_tab.stop() def did_start(self): self.owner_tab.switch_to_progress() self.set_start_enabled(False) self.stop_button.set_enabled(True) self.set_status("Export running...") def did_complete(self): self.set_start_enabled(True) self.stop_button.set_enabled(False) self.print_log_message("\n\n\n") if self.is_export: self.export_button.set_text("Export Again") else: self.export_button.set_text("Import Again") def did_fail(self, message): self.progress_log.append_text_and_scroll(message+"\n", True) self.set_status("Operation Failed") self.set_start_enabled(True) self.stop_button.set_enabled(False) def did_cancel(self, message): self.progress_log.append_text_and_scroll(message+"\n", True) self.set_status("Operation Cancelled") self.dump_progressbar.set_value(0) self.set_start_enabled(True) self.stop_button.set_enabled(False) def close(self): pass #################################################################################################### class WbAdminExport(mforms.Box): ui_created = False @classmethod def wba_register(cls, admin_context): admin_context.register_page(cls, "wba_management", "Data Export") @classmethod def identifier(cls): return "admin_export" def __init__(self, ctrl_be, server_profile, main_view): mforms.Box.__init__(self, False) self.ctrl_be = ctrl_be self.set_managed() self.set_release_on_add() self.server_profile = server_profile self.main_view = main_view def page_activated(self): if not self.ui_created: self.suspend_layout() self.create_ui() self.resume_layout() self.ui_created = True self.export_tab.check_mysqldump_version() self.export_tab.set_show_internal_schemas(self.get_export_options({})['$internal$show-internal-schemas'] == 'TRUE') self.options_tab.add_clicked_callback_to_checkbox('$internal$show-internal-schemas', self.show_internal_schemas_changed) self.export_tab.refresh_table_list() if self.ctrl_be.is_sql_connected(): self.warning.show(False) self.tabview.show(True) else: self.warning.show(True) self.tabview.show(False) def switch_to_progress(self): self.tabview.set_active_tab(1) def show_options(self): self.showing_options = not self.showing_options if self.showing_options: self.tabview.show(False) self.options_tab.show(True) self.advanced_options_btn.set_text("< Return") else: self.tabview.show(True) self.options_tab.show(False) self.advanced_options_btn.set_text("Advanced Options...") def create_ui(self): self.suspend_layout() self.showing_options = False self.advanced_options_btn = mforms.newButton() self.advanced_options_btn.set_text("Advanced Options...") self.advanced_options_btn.add_clicked_callback(self.show_options) self.set_padding(12) self.set_spacing(8) self.heading = make_panel_header("title_export.png", self.server_profile.name, "Data Export", self.advanced_options_btn) self.add(self.heading, False, True) self.warning = not_running_warning_label() self.add(self.warning, False, True) self.tabview = newTabView(False) self.add(self.tabview, True, True) self.tabview.show(False) self.progress_tab = WbAdminProgressTab(self, True) self.export_tab = WbAdminExportTab(self, self.server_profile, self.progress_tab) self.tabview.add_page(self.export_tab, "Object Selection") self.options_tab = WbAdminExportOptionsTab(self.ctrl_be.target_version, self.export_tab.mysqldump_defaults) self.add(self.options_tab, True, True) self.options_tab.show(False) self.tabview.add_page(self.progress_tab, "Export Progress") self.resume_layout() self.recall_options() def shutdown(self): # called when admin tab is closed self.remember_options() if self.ui_created: self.export_tab.close() self.progress_tab.close() def get_lock_tables(self): return self.options_tab.get_lock_tables() def set_lock_tables(self, value): return self.options_tab.set_lock_tables(value) def get_export_options(self, defaults): options = self.options_tab.get_options(defaults) return options def remember_options(self): if self.ui_created: dic = grt.root.wb.options.options dic["wb.admin.export:exportType"] = self.export_tab.folderradio.get_active() and "folder" or "file" dic["wb.admin.export:selectedFolder"] = self.export_tab.folder_te.get_string_value() dic["wb.admin.export:selectedFile"] = self.export_tab.file_te.get_string_value() dic["wb.admin.export:singleTransaction"] = self.export_tab.single_transaction_check.get_active() dic["wb.admin.export:dumpRoutines"] = self.export_tab.dump_routines_check.get_active() dic["wb.admin.export:dumpEvents"] = self.export_tab.dump_events_check.get_active() dic["wb.admin.export:dumpTriggers"] = self.export_tab.dump_triggers_check.get_active() dic["wb.admin.export:skipData"] = self.export_tab.dump_type_selector.get_selected_index() for key, value in self.get_export_options({}).items(): dic["wb.admin.export.option:"+key] = value def recall_options(self): dic = grt.root.wb.options.options if dic.has_key("wb.admin.export:exportType"): if dic["wb.admin.export:exportType"] == "folder": self.export_tab.folderradio.set_active(True) else: self.export_tab.fileradio.set_active(True) self.export_tab.set_save_option() # if dic.has_key("wb.admin.export:selectedFolder"): # self.export_tab.folder_te.set_value(dic["wb.admin.export:selectedFolder"]) # if dic.has_key("wb.admin.export:selectedFile"): # self.export_tab.file_te.set_value(dic["wb.admin.export:selectedFile"]) if dic.has_key("wb.admin.export:singleTransaction"): self.export_tab.single_transaction_check.set_active(dic["wb.admin.export:singleTransaction"] != 0) if dic.has_key("wb.admin.export:dumpRoutines"): self.export_tab.dump_routines_check.set_active(dic["wb.admin.export:dumpRoutines"] != 0) if dic.has_key("wb.admin.export:dumpEvents"): self.export_tab.dump_events_check.set_active(dic["wb.admin.export:dumpEvents"] != 0) if dic.has_key("wb.admin.export:dumpTriggers"): self.export_tab.dump_triggers_check.set_active(dic["wb.admin.export:dumpTriggers"] != 0) if dic.has_key("wb.admin.export:skipData"): self.export_tab.dump_type_selector.set_selected(dic["wb.admin.export:skipData"] != 0) values = {} for key in self.get_export_options({}).keys(): if dic.has_key("wb.admin.export.option:"+key): values[key] = dic["wb.admin.export.option:"+key] self.options_tab.set_options(values) def show_internal_schemas_changed(self): self.export_tab.set_show_internal_schemas(self.get_export_options({})['$internal$show-internal-schemas'] == 'TRUE') self.export_tab.refresh_table_list() #################################################################################################### class WbAdminImport(mforms.Box): ui_created = False @classmethod def wba_register(cls, admin_context): admin_context.register_page(cls, "wba_management", "Data Import/Restore") @classmethod def identifier(cls): return "admin_restore_data" def __init__(self, ctrl_be, server_profile, main_view): mforms.Box.__init__(self, False) self.ctrl_be = ctrl_be self.set_managed() self.set_release_on_add() self.server_profile = server_profile self.main_view = main_view def shutdown(self): if self.ui_created: self.import_tab.close() self.progress_tab.close() def page_activated(self): if not self.ui_created: self.suspend_layout() self.create_ui() self.resume_layout() self.ui_created = True if self.ctrl_be.is_sql_connected(): self.warning.show(False) self.tabview.show(True) self.import_tab.refresh_schema_list() self.import_tab.set_save_option() else: self.warning.show(True) self.tabview.show(False) def switch_to_progress(self): self.tabview.set_active_tab(1) def create_ui(self): self.suspend_layout() self.set_padding(12) self.set_spacing(8) self.heading = make_panel_header("title_import.png", self.server_profile.name, "Data Import") self.add(self.heading, False, True) self.warning = not_running_warning_label() self.add(self.warning, False, True) self.tabview = newTabView(False) self.add(self.tabview, True, True) self.tabview.show(False) self.progress_tab = WbAdminProgressTab(self, False) self.import_tab = WbAdminImportTab(self, self.server_profile, self.progress_tab) self.tabview.add_page(self.import_tab, "Import from Disk") self.tabview.add_page(self.progress_tab, "Import Progress") self.resume_layout() self.ui_created = True