def OnBuildCreatePackage(self, stage, targetFile): Logger.Debug(__name__, GT(u'Creating {} from {}').format(targetFile, stage)) packager = GetExecutable(u'dpkg-deb') fakeroot = GetExecutable(u'fakeroot') if not fakeroot or not packager: return (dbrerrno.ENOENT, GT(u'Cannot run "fakeroot dpkg')) packager = os.path.basename(packager) Logger.Debug(__name__, GT(u'System packager: {}').format(packager)) # DEBUG: cmd = u'{} {} -b "{}" "{}"'.format(fakeroot, packager, stage, targetFile) Logger.Debug(__name__, GT(u'Executing: {}').format(cmd)) output = GetCommandOutput(fakeroot, ( packager, u'-b', stage, targetFile, )) Logger.Debug(__name__, GT(u'Build output: {}').format(output)) return output
def Set(self, data): # ???: Redundant self.Reset() build_data = data.split(u'\n') if GetExecutable(u'md5sum'): try: self.chk_md5.SetValue(int(build_data[0])) except IndexError: pass try: self.chk_rmstage.SetValue(int(build_data[1])) except IndexError: pass if GetExecutable(u'lintian'): try: self.chk_lint.SetValue(int(build_data[2])) except IndexError: pass self.chk_strip.SetValue( GetExecutable(u'strip') and u'strip' in build_data)
def Set(self, data): # ???: Redundant self.Reset() build_data = data.split(u'\n') if GetExecutable(u'md5sum'): self.chk_md5.SetValue(int(build_data[0])) self.chk_rmstage.SetValue(int(build_data[1])) if GetExecutable(u'lintian'): self.chk_lint.SetValue(int(build_data[2]))
def WriteMD5(stage_dir, parent=None): CMD_md5sum = GetExecutable(u'md5sum') # Show an error if the 'md5sum' command does not exist # This is only a failsafe & should never actually occur if not CMD_md5sum: if not parent: parent = GetMainWindow() md5_label = GetField(pgid.BUILD, chkid.MD5).GetLabel() err_msg1 = GT(u'The "md5sum" command was not found on the system.') err_msg2 = GT(u'Uncheck the "{}" box.').format(md5_label) err_msg3 = GT( u'Please report this error to one of the following addresses:') err_url1 = u'https://github.com/AntumDeluge/debreate/issues' err_url2 = u'https://sourceforge.net/p/debreate/bugs/' Logger.Error( __name__, u'{} {} {}\n\t{}\n\t{}'.format(err_msg1, err_msg2, err_msg3, err_url1, err_url2)) md5_error = ErrorDialog(parent, text=u'{}\n{}\n\n{}'.format( err_msg1, err_msg2, err_msg3)) md5_error.AddURL(err_url1) md5_error.AddURL(err_url2) md5_error.ShowModal() return None temp_list = [] md5_list = [] # Final list used to write the md5sum file for ROOT, DIRS, FILES in os.walk(stage_dir): # Ignore the 'DEBIAN' directory if os.path.basename(ROOT) == u'DEBIAN': continue for F in FILES: F = u'{}/{}'.format(ROOT, F) md5 = GetCommandOutput(CMD_md5sum, (u'-t', F)) Logger.Debug(__name__, u'WriteMD5: GetCommandOutput: {}'.format(md5)) temp_list.append(md5) for item in temp_list: # Remove [stage_dir] from the path name in the md5sum so that it has a # true unix path # e.g., instead of "/myfolder_temp/usr/local/bin", "/usr/local/bin" sum_split = item.split(u'{}/'.format(stage_dir)) sum_join = u''.join(sum_split) md5_list.append(sum_join) # Create the md5sums file in the "DEBIAN" directory return WriteFile(u'{}/DEBIAN/md5sums'.format(stage_dir), u'{}\n'.format(u'\n'.join(md5_list)))
def BuildDebPackage(stage_dir, target_file): packager = GetExecutable(u'dpkg-deb') fakeroot = GetExecutable(u'fakeroot') if not fakeroot or not packager: return (dbrerrno.ENOENT, GT(u'Cannot run "fakeroot dpkg"')) packager = os.path.basename(packager) try: output = subprocess.check_output( [fakeroot, packager, u'-b', stage_dir, target_file], stderr=subprocess.STDOUT) except: return (dbrerrno.EAGAIN, traceback.format_exc()) return (dbrerrno.SUCCESS, output)
def GetFileMimeType(filename): CMD_file = GetExecutable(u'file') if not CMD_file: return None return GetCommandOutput(CMD_file, ( u'--mime-type', u'--brief', filename, ))
def OnBuildCheckPackage(self, targetPackage): Logger.Debug( __name__, GT(u'Checking package "{}" for lintian errors ...').format( os.path.basename(targetPackage))) # FIXME: commands module deprecated? output = commands.getoutput(u'{} "{}"'.format( GetExecutable(u'lintian'), targetPackage)) return output
def Export(self, out_dir, out_name=wx.EmptyString, compress=False): ret_value = WizardPage.Export(self, out_dir, out_name=out_name) absolute_filename = u'{}/{}'.format(out_dir, out_name).replace(u'//', u'/') CMD_gzip = GetExecutable(u'gzip') if compress and CMD_gzip: commands.getstatusoutput(u'{} -n9 "{}"'.format( CMD_gzip, absolute_filename)) return ret_value
def InitDefaultSettings(self): self.build_options = [] option_list = ( ( self.chk_md5, GetExecutable(u'md5sum'), ), ( self.chk_strip, GetExecutable(u'strip'), ), ( self.chk_rmstage, True, ), ( self.chk_lint, GetExecutable(u'lintian'), ), ( self.chk_install, GetSystemInstaller(), ), ) for option, command in option_list: # FIXME: Commands should be updated globally if not isinstance(command, bool): command = CommandExists(command) option.Enable(bool(command)) option.SetValue(FieldEnabled(option) and option.Default) if bool(command): self.build_options.append(option)
def FileUnstripped(file_name): CMD_file = GetExecutable(u'file') if CMD_file: output = commands.getoutput(u'{} "{}"'.format(CMD_file, file_name)) if u': ' in output: output = output.split(u': ')[1] output = output.split(u', ') if u'not stripped' in output: return True return False print(u'ERROR: "file" command does not exist on system') return False
def OnOpenPath(self, event=None): CMD_open = GetExecutable(u'xdg-open') if CMD_open: path = self.GetLicensePath() if not path: ShowErrorDialog(GT(u'Error retrieving template path: {}').format(self.GetSelectedName())) return False path = os.path.dirname(path) if os.path.isdir(path): ExecuteCommand(CMD_open, (path,)) return True return False
def SendToTrash(self, item_list): path_list = [] for I in item_list: if not os.access(I.Path, os.W_OK): ShowErrorDialog( GT(u'Cannot move "{}" to trash, no write access').format( I.Path), warn=True) return False path_list.append(I.Path) msg_l1 = GT(u'Move the following items to trash?') msg_l2 = u'\n'.join(path_list) if ConfirmationDialog(GetMainWindow(), GT(u'Delete'), u'{}\n\n{}'.format(msg_l1, msg_l2)).Confirmed(): arg_list = list(path_list) # Use 'force' argument to avoid crash on non-existing paths arg_list.insert(0, u'-f') ExecuteCommand(GetExecutable(u'gvfs-trash'), arg_list) Logger.Debug(__name__, u'Paths deleted') self.DeleteItems(item_list) Logger.Debug(__name__, u'Items deleted') # Confirm that paths were removed for P in path_list: if os.path.exists(P): Logger.Debug(__name__, u'Failed to remove "{}"'.format(P)) return False Logger.Debug(__name__, u'Items successfully moved to trash') return True return False
def __init__(self, parent, w_id=wx.ID_ANY, path=PATH_home, exclude_pattern=[ u'.*', ], pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.TR_DEFAULT_STYLE, validator=wx.DefaultValidator, name=wx.TreeCtrlNameStr): wx.TreeCtrl.__init__(self, parent, w_id, pos, size, style=style | wx.TR_HAS_BUTTONS | wx.TR_MULTIPLE | wx.BORDER_NONE, validator=validator, name=name) self.AssignImageList() # FIXME: Use regular expressions #self.exclude_pattern = list(exclude_pattern) self.exclude_pattern = [u'.'] self.current_path = path # NOTE: Use individual items children??? self.item_list = [] self.root_item = self.AddRoot(GT(u'System'), ImageList.GetImageIndex(u'computer')) self.COLOR_default = self.GetItemBackgroundColour(self.root_item) # List of sub-root items that shouldn't be deleted if they exist on filesystem # FIXME: Should not need to use a root list now with GetDeviceMountPoints function self.mount_list = [] self.ctx_menu = wx.Menu() mitm_add = wx.MenuItem(self.ctx_menu, wx.ID_ADD, GT(u'Add to project')) mitm_expand = wx.MenuItem(self.ctx_menu, menuid.EXPAND, GT(u'Expand')) mitm_rename = wx.MenuItem(self.ctx_menu, menuid.RENAME, GT(u'Rename')) mitm_refresh = wx.MenuItem(self.ctx_menu, wx.ID_REFRESH, GT(u'Refresh')) self.ctx_menu.AppendItem(mitm_add) self.ctx_menu.AppendItem(mitm_expand) self.ctx_menu.AppendItem(mitm_rename) self.ctx_menu.AppendSeparator() self.ctx_menu.AppendItem(mitm_refresh) # FIXME: Hack self.trash = False if GetExecutable(u'gvfs-trash'): mitm_delete = wx.MenuItem(self.ctx_menu, wx.ID_DELETE, GT(u'Trash')) self.ctx_menu.InsertItem(2, mitm_delete) self.trash = True # Tells app if user is currently dragging an item from tree self.dragging = False # *** Event handlers *** # self.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) wx.EVT_KEY_DOWN(self, self.OnDoubleClick) self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) self.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.OnExpand) self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnCollapse) self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelect) self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu) wx.EVT_MENU(self, menuid.EXPAND, self.OnMenuSelect) wx.EVT_MENU(self, menuid.RENAME, self.OnMenuSelect) wx.EVT_MENU(self, wx.ID_DELETE, self.OnMenuSelect) wx.EVT_MENU(self, wx.ID_REFRESH, self.OnRefresh) self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnEndLabelEdit) self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnDragBegin) self.Bind(wx.EVT_LEFT_UP, self.OnDragEnd) # *** Post-layout/event actions *** # self.InitMountItems() # Expand the user's home directory if self.GetHomeItem(): self.InitDirectoryLayout()
def Build(self, task_list, build_path, filename): # Declare this here in case of error before progress dialog created build_progress = None try: # Other mandatory tasks that will be processed mandatory_tasks = ( u'stage', u'install_size', u'control', u'build', ) # Add other mandatory tasks for T in mandatory_tasks: task_list[T] = None task_count = len(task_list) # Add each file for updating progress dialog if u'files' in task_list: task_count += len(task_list[u'files']) # Add each script for updating progress dialog if u'scripts' in task_list: task_count += len(task_list[u'scripts']) if DebugEnabled(): task_msg = GT(u'Total tasks: {}').format(task_count) print(u'DEBUG: [{}] {}'.format(__name__, task_msg)) for T in task_list: print(u'\t{}'.format(T)) create_changelog = u'changelog' in task_list create_copyright = u'copyright' in task_list pg_control = GetPage(pgid.CONTROL) pg_menu = GetPage(pgid.MENU) stage_dir = u'{}/{}__dbp__'.format(build_path, filename) if os.path.isdir(u'{}/DEBIAN'.format(stage_dir)): try: shutil.rmtree(stage_dir) except OSError: ShowErrorDialog( GT(u'Could not free stage directory: {}').format( stage_dir), title=GT(u'Cannot Continue')) return (dbrerrno.EEXIST, None) # Actual path to new .deb deb = u'"{}/{}.deb"'.format(build_path, filename) progress = 0 task_msg = GT(u'Preparing build tree') Logger.Debug(__name__, task_msg) wx.Yield() build_progress = ProgressDialog( GetMainWindow(), GT(u'Building'), task_msg, maximum=task_count, style=PD_DEFAULT_STYLE | wx.PD_ELAPSED_TIME | wx.PD_ESTIMATED_TIME | wx.PD_CAN_ABORT) DIR_debian = ConcatPaths((stage_dir, u'DEBIAN')) # Make a fresh build tree os.makedirs(DIR_debian) progress += 1 if build_progress.WasCancelled(): build_progress.Destroy() return (dbrerrno.ECNCLD, None) def UpdateProgress(current_task, message=None): task_eval = u'{} / {}'.format(current_task, task_count) if message: Logger.Debug(__name__, u'{} ({})'.format(message, task_eval)) wx.Yield() build_progress.Update(current_task, message) return wx.Yield() build_progress.Update(current_task) # *** Files *** # if u'files' in task_list: UpdateProgress(progress, GT(u'Copying files')) no_follow_link = GetField(GetPage(pgid.FILES), chkid.SYMLINK).IsChecked() # TODO: move this into a file functions module def _copy(f_src, f_tgt, exe=False): # NOTE: Python 3 appears to have follow_symlinks option for shutil.copy # FIXME: copying nested symbolic link may not work if os.path.isdir(f_src): if os.path.islink(f_src) and no_follow_link: Logger.Debug( __name__, u'Adding directory symbolic link to stage: {}'. format(f_tgt)) os.symlink(os.readlink(f_src), f_tgt) else: Logger.Debug( __name__, u'Adding directory to stage: {}'.format(f_tgt)) shutil.copytree(f_src, f_tgt) os.chmod(f_tgt, 0o0755) elif os.path.isfile(f_src): if os.path.islink(f_src) and no_follow_link: Logger.Debug( __name__, u'Adding file symbolic link to stage: {}'. format(f_tgt)) os.symlink(os.readlink(f_src), f_tgt) else: if exe: Logger.Debug( __name__, u'Adding executable to stage: {}'.format( f_tgt)) else: Logger.Debug( __name__, u'Adding file to stage: {}'.format(f_tgt)) shutil.copy(f_src, f_tgt) # Set FILE permissions if exe: os.chmod(f_tgt, 0o0755) else: os.chmod(f_tgt, 0o0644) files_data = task_list[u'files'] for FILE in files_data: file_defs = FILE.split(u' -> ') source_file = file_defs[0] target_file = u'{}{}/{}'.format(stage_dir, file_defs[2], file_defs[1]) target_dir = os.path.dirname(target_file) if not os.path.isdir(target_dir): os.makedirs(target_dir) # Remove asteriks from exectuables exe = False if source_file[-1] == u'*': exe = True source_file = source_file[:-1] _copy( source_file, u'{}/{}'.format(target_dir, os.path.basename(source_file)), exe) # Individual files progress += 1 UpdateProgress(progress) # Entire file task progress += 1 if build_progress.WasCancelled(): build_progress.Destroy() return (dbrerrno.ECNCLD, None) # *** Strip files ***# # FIXME: Needs only be run if 'files' step is used if u'strip' in task_list: UpdateProgress(progress, GT(u'Stripping binaries')) for ROOT, DIRS, FILES in os.walk(stage_dir): #@UnusedVariable for F in FILES: # Don't check files in DEBIAN directory if ROOT != DIR_debian: F = ConcatPaths((ROOT, F)) if FileUnstripped(F): Logger.Debug(__name__, u'Unstripped file: {}'.format(F)) # FIXME: Strip command should be set as class member? ExecuteCommand(GetExecutable(u'strip'), F) progress += 1 if build_progress.WasCancelled(): build_progress.Destroy() return (dbrerrno.ECNCLD, None) package = GetField(pg_control, inputid.PACKAGE).GetValue() # Make sure that the directory is available in which to place documentation if create_changelog or create_copyright: doc_dir = u'{}/usr/share/doc/{}'.format(stage_dir, package) if not os.path.isdir(doc_dir): os.makedirs(doc_dir) # *** Changelog *** # if create_changelog: UpdateProgress(progress, GT(u'Creating changelog')) # If changelog will be installed to default directory changelog_target = task_list[u'changelog'][0] if changelog_target == u'STANDARD': changelog_target = ConcatPaths( (u'{}/usr/share/doc'.format(stage_dir), package)) else: changelog_target = ConcatPaths( (stage_dir, changelog_target)) if not os.path.isdir(changelog_target): os.makedirs(changelog_target) WriteFile(u'{}/changelog'.format(changelog_target), task_list[u'changelog'][1]) CMD_gzip = GetExecutable(u'gzip') if CMD_gzip: UpdateProgress(progress, GT(u'Compressing changelog')) c = u'{} -n --best "{}/changelog"'.format( CMD_gzip, changelog_target) clog_status = commands.getstatusoutput(c.encode(u'utf-8')) if clog_status[0]: ShowErrorDialog(GT(u'Could not compress changelog'), clog_status[1], warn=True, title=GT(u'Warning')) progress += 1 if build_progress.WasCancelled(): build_progress.Destroy() return (dbrerrno.ECNCLD, None) # *** Copyright *** # if create_copyright: UpdateProgress(progress, GT(u'Creating copyright')) WriteFile( u'{}/usr/share/doc/{}/copyright'.format( stage_dir, package), task_list[u'copyright']) progress += 1 if build_progress.WasCancelled(): build_progress.Destroy() return (dbrerrno.ECNCLD, None) # Characters that should not be in filenames invalid_chars = (u' ', u'/') # *** Menu launcher *** # if u'launcher' in task_list: UpdateProgress(progress, GT(u'Creating menu launcher')) # This might be changed later to set a custom directory menu_dir = u'{}/usr/share/applications'.format(stage_dir) menu_filename = pg_menu.GetOutputFilename() # Remove invalid characters from filename for char in invalid_chars: menu_filename = menu_filename.replace(char, u'_') if not os.path.isdir(menu_dir): os.makedirs(menu_dir) WriteFile(u'{}/{}.desktop'.format(menu_dir, menu_filename), task_list[u'launcher']) progress += 1 if build_progress.WasCancelled(): build_progress.Destroy() return (dbrerrno.ECNCLD, None) # *** md5sums file *** # # Good practice to create hashes before populating DEBIAN directory if u'md5sums' in task_list: UpdateProgress(progress, GT(u'Creating md5sums')) if not WriteMD5(stage_dir, parent=build_progress): # Couldn't call md5sum command build_progress.Cancel() progress += 1 if build_progress.WasCancelled(): build_progress.Destroy() return (dbrerrno.ECNCLD, None) # *** Scripts *** # if u'scripts' in task_list: UpdateProgress(progress, GT(u'Creating scripts')) scripts = task_list[u'scripts'] for SCRIPT in scripts: script_name = SCRIPT script_text = scripts[SCRIPT] script_filename = ConcatPaths( (stage_dir, u'DEBIAN', script_name)) WriteFile(script_filename, script_text) # Make sure scipt path is wrapped in quotes to avoid whitespace errors os.chmod(script_filename, 0755) os.system((u'chmod +x "{}"'.format(script_filename))) # Individual scripts progress += 1 UpdateProgress(progress) # Entire script task progress += 1 if build_progress.WasCancelled(): build_progress.Destroy() return (dbrerrno.ECNCLD, None) # *** Control file *** # UpdateProgress(progress, GT(u'Getting installed size')) # Get installed-size installed_size = os.popen( (u'du -hsk "{}"'.format(stage_dir))).readlines() installed_size = installed_size[0].split(u'\t') installed_size = installed_size[0] # Insert Installed-Size into control file control_data = pg_control.Get().split(u'\n') control_data.insert(2, u'Installed-Size: {}'.format(installed_size)) progress += 1 if build_progress.WasCancelled(): build_progress.Destroy() return (dbrerrno.ECNCLD, None) # Create final control file UpdateProgress(progress, GT(u'Creating control file')) # dpkg fails if there is no newline at end of file control_data = u'\n'.join(control_data).strip(u'\n') # Ensure there is only one empty trailing newline # Two '\n' to show physical empty line, but not required # Perhaps because string is not null terminated??? control_data = u'{}\n\n'.format(control_data) WriteFile(u'{}/DEBIAN/control'.format(stage_dir), control_data, noStrip=u'\n') progress += 1 if build_progress.WasCancelled(): build_progress.Destroy() return (dbrerrno.ECNCLD, None) # *** Final build *** # UpdateProgress(progress, GT(u'Running dpkg')) working_dir = os.path.split(stage_dir)[0] c_tree = os.path.split(stage_dir)[1] deb_package = u'{}.deb'.format(filename) # Move the working directory becuase dpkg seems to have problems with spaces in path os.chdir(working_dir) # HACK to fix file/dir permissions for ROOT, DIRS, FILES in os.walk(stage_dir): for D in DIRS: D = u'{}/{}'.format(ROOT, D) os.chmod(D, 0o0755) for F in FILES: F = u'{}/{}'.format(ROOT, F) if os.access(F, os.X_OK): os.chmod(F, 0o0755) else: os.chmod(F, 0o0644) # FIXME: Should check for working fakeroot & dpkg-deb executables build_status = commands.getstatusoutput( (u'{} {} -b "{}" "{}"'.format(GetExecutable(u'fakeroot'), GetExecutable(u'dpkg-deb'), c_tree, deb_package))) progress += 1 if build_progress.WasCancelled(): build_progress.Destroy() return (dbrerrno.ECNCLD, None) # *** Delete staged directory *** # if u'rmstage' in task_list: UpdateProgress(progress, GT(u'Removing temp directory')) try: shutil.rmtree(stage_dir) except OSError: ShowErrorDialog(GT( u'An error occurred when trying to delete the build tree' ), parent=build_progress) progress += 1 if build_progress.WasCancelled(): build_progress.Destroy() return (dbrerrno.ECNCLD, None) # *** ERROR CHECK if u'lintian' in task_list: UpdateProgress(progress, GT(u'Checking package for errors')) # FIXME: Should be set as class memeber? CMD_lintian = GetExecutable(u'lintian') errors = commands.getoutput((u'{} {}'.format(CMD_lintian, deb))) if errors != wx.EmptyString: e1 = GT(u'Lintian found some issues with the package.') e2 = GT(u'Details saved to {}').format(filename) WriteFile(u'{}/{}.lintian'.format(build_path, filename), errors) DetailedMessageDialog(build_progress, GT(u'Lintian Errors'), ICON_INFORMATION, u'{}\n{}.lintian'.format(e1, e2), errors).ShowModal() progress += 1 # Close progress dialog wx.Yield() build_progress.Update(progress) build_progress.Destroy() # Build completed successfullly if not build_status[0]: return (dbrerrno.SUCCESS, deb_package) if PY_VER_MAJ <= 2: # Unicode decoder has trouble with certain characters. Replace any # non-decodable characters with � (0xFFFD). build_output = list(build_status[1]) # String & unicode string incompatibilities index = 0 for C in build_output: try: GS(C) except UnicodeDecodeError: build_output[index] = u'�' index += 1 build_status = (build_status[0], u''.join(build_output)) # Build failed return (build_status[0], build_status[1]) except: if build_progress: build_progress.Destroy() return (dbrerrno.EUNKNOWN, traceback.format_exc())
def SetChangelog(self): ## Defines where the changelog is located # # By default it is located in the folder 'doc' # under the applications root directory. The # install script or Makefile should change this # to reflect installed path. if INSTALLED: # FIXME: Read compressed .gz changelog CHANGELOG = u'{}/share/doc/debreate/changelog.gz'.format(PREFIX) else: CHANGELOG = u'{}/docs/changelog'.format(PREFIX) if os.path.isfile(CHANGELOG): changelog_mimetype = GetFileMimeType(CHANGELOG) Logger.Debug( __name__, GT(u'Changelog mimetype: {}').format(changelog_mimetype)) # Set log text in case of read error log_text = GT(u'Error reading changelog: {}\n\t').format(CHANGELOG) log_text = u'{}{}'.format( log_text, GT(u'Cannot decode, unrecognized mimetype: {}').format( changelog_mimetype)) if changelog_mimetype == u'application/gzip': temp_dir = CreateStage() shutil.copy(CHANGELOG, temp_dir) CMD_gzip = GetExecutable(u'gzip') if CMD_gzip: prev_dir = os.getcwd() os.chdir(temp_dir) gzip_output = commands.getstatusoutput(u'{} -fd {}'.format( CMD_gzip, os.path.basename(CHANGELOG))) Logger.Debug( __name__, GT(u'gzip decompress; Code: {}, Output: {}').format( gzip_output[0], gzip_output[1])) os.chdir(prev_dir) changelog_file = os.path.basename(CHANGELOG).split(u'.')[0] changelog_file = u'{}/{}'.format(temp_dir, changelog_file) if os.path.isfile(changelog_file): log_text = ReadFile(changelog_file) RemoveStage(temp_dir) elif changelog_mimetype == u'text/plain': log_text = ReadFile(CHANGELOG) else: ShowErrorDialog(log_text, parent=self) else: log_text = GT( u'ERROR: Could not locate changelog file:\n\t\'{}\' not found'. format(CHANGELOG)) self.changelog.SetValue(log_text) self.changelog.SetInsertionPoint(0)
def __init__(self, pos, size): wx.Frame.__init__(self, None, wx.ID_ANY, default_title, pos, size) # Make sure that this frame is set as the top window if not wx.GetApp().GetTopWindow() == self: Logger.Debug(__name__, GT(u'Setting MainWindow instance as top window')) wx.GetApp().SetTopWindow(self) testing = u'alpha' in GetTestList() or DebugEnabled() if DebugEnabled(): self.SetTitle(u'{} ({})'.format(default_title, GT(u'debugging'))) self.SetMinSize(wx.Size(640, 400)) # ----- Set Titlebar Icon self.SetIcon(Icon(LOGO)) # *** Status Bar *** # StatusBar(self) # *** Menus *** # menubar = MenuBar(self) menu_file = wx.Menu() menubar.Append(menu_file, GT(u'File'), menuid.FILE) # This menu is filled from wiz.wizard.Wizard.SetPages menubar.Append(wx.Menu(), GT(u'Page'), menuid.PAGE) # *** File Menu *** # mitems_file = [ ( menuid.NEW, GT(u'New project'), GT(u'Start a new project'), ), ( menuid.OPEN, GT(u'Open'), GT(u'Open a previously saved project'), ), ( menuid.SAVE, GT(u'Save'), GT(u'Save current project'), ), ( menuid.SAVEAS, GT(u'Save as'), GT(u'Save current project with a new filename'), ), None, ( menuid.QBUILD, GT(u'Quick Build'), GT(u'Build a package from an existing build tree'), ICON_CLOCK, ), None, ( menuid.EXIT, GT(u'Quit'), GT(u'Exit Debreate'), ), ] if testing: mitems_file.append((menuid.ALIEN, GT(u'Convert packages'), GT(u'Convert between package types'))) # Adding all menus to menu bar mitems = (mitems_file, ) for menu_list in mitems: for mitem in menu_list: if not mitem: menu_file.AppendSeparator() else: itm = wx.MenuItem(menu_file, mitem[0], mitem[1], mitem[2]) if len(mitem) > 3: itm.SetBitmap(mitem[3]) menu_file.AppendItem(itm) # *** Action Menu *** # menu_action = wx.Menu() mitm_build = wx.MenuItem(menu_action, menuid.BUILD, GT(u'Build'), GT(u'Start building .deb package')) menu_action.AppendItem(mitm_build) # ----- Options Menu menu_opt = wx.Menu() # Show/Hide tooltips self.opt_tooltips = wx.MenuItem(menu_opt, menuid.TOOLTIPS, GT(u'Show tooltips'), GT(u'Show or hide tooltips'), kind=wx.ITEM_CHECK) # A bug with wx 2.8 does not allow tooltips to be toggled off if wx.MAJOR_VERSION > 2: menu_opt.AppendItem(self.opt_tooltips) if menu_opt.FindItemById(menuid.TOOLTIPS): show_tooltips = ReadConfig(u'tooltips') if show_tooltips != ConfCode.KEY_NO_EXIST: self.opt_tooltips.Check(show_tooltips) else: self.opt_tooltips.Check(GetDefaultConfigValue(u'tooltips')) self.OnToggleToolTips() # Project compression options self.menu_compress = wx.Menu() opt_z_none = wx.MenuItem( self.menu_compress, ident.ZIP_NONE, GT(u'Uncompressed'), GT(u'Use uncompressed tarball for project save format'), kind=wx.ITEM_RADIO) opt_z_gz = wx.MenuItem( self.menu_compress, ident.ZIP_GZ, GT(u'Gzip'), GT(u'Use compressed Gzip tarball for project save format'), kind=wx.ITEM_RADIO) opt_z_bz2 = wx.MenuItem( self.menu_compress, ident.ZIP_BZ2, GT(u'Bzip2'), GT(u'Use compressed Bzip2 tarball for project save format'), kind=wx.ITEM_RADIO) opt_z_zip = wx.MenuItem( self.menu_compress, ident.ZIP_ZIP, GT(u'Zip'), GT(u'Use compressed zip file for project save format'), kind=wx.ITEM_RADIO) opts_compress = [ opt_z_none, opt_z_gz, opt_z_bz2, opt_z_zip, ] if GetExecutable(u'tar') != None: opt_z_xz = wx.MenuItem( self.menu_compress, ident.ZIP_XZ, GT(u'XZ'), GT(u'Use compressed xz tarball for project save format'), kind=wx.ITEM_RADIO) opts_compress.insert(3, opt_z_xz) for OPT in opts_compress: self.menu_compress.AppendItem(OPT) wx.EVT_MENU(self.menu_compress, OPT.GetId(), self.OnSetCompression) # Default compression self.menu_compress.Check(ident.ZIP_BZ2, True) menu_opt.AppendSubMenu( self.menu_compress, GT(u'Project Compression'), GT(u'Set the compression type for project save output')) # *** Option Menu: open logs directory *** # if GetExecutable(u'xdg-open'): mitm_logs_open = wx.MenuItem(menu_opt, menuid.OPENLOGS, GT(u'Open logs directory')) menu_opt.AppendItem(mitm_logs_open) wx.EVT_MENU(menu_opt, menuid.OPENLOGS, self.OnLogDirOpen) # *** OS distribution names cache *** # opt_distname_cache = wx.MenuItem( menu_opt, menuid.DIST, GT(u'Update dist names cache'), GT(u'Creates/Updates list of distribution names for changelog page' )) menu_opt.AppendItem(opt_distname_cache) # ----- Help Menu menu_help = wx.Menu() # ----- Version update mitm_update = wx.MenuItem( menu_help, menuid.UPDATE, GT(u'Check for update'), GT(u'Check if a new version is available for download')) mitm_update.SetBitmap(ICON_LOGO) menu_help.AppendItem(mitm_update) menu_help.AppendSeparator() # Menu with links to the Debian Policy Manual webpages self.menu_policy = wx.Menu() policy_links = ( ( refid.DPM, GT(u'Debian Policy Manual'), u'https://www.debian.org/doc/debian-policy', ), ( refid.DPMCtrl, GT(u'Control files'), u'https://www.debian.org/doc/debian-policy/ch-controlfields.html', ), ( refid.DPMLog, GT(u'Changelog'), u'https://www.debian.org/doc/debian-policy/ch-source.html#s-dpkgchangelog', ), ( refid.UPM, GT(u'Ubuntu Policy Manual'), u'http://people.canonical.com/~cjwatson/ubuntu-policy/policy.html/', ), ( refid.LINT_TAGS, GT(u'Lintian Tags Explanation'), u'https://lintian.debian.org/tags-all.html', ), ( refid.LINT_OVERRIDE, GT(u'Overriding Lintian Tags'), u'https://lintian.debian.org/manual/section-2.4.html', ), ( refid.LAUNCHERS, GT(u'Launchers / Desktop entries'), u'https://www.freedesktop.org/wiki/Specifications/desktop-entry-spec/', ), # Unofficial links None, ( refid.DEBSRC, GT(u'Building debs from Source'), u'http://www.quietearth.us/articles/2006/08/16/Building-deb-package-from-source', ), # This is here only temporarily for reference ( refid.MAN, GT(u'Writing manual pages'), u'https://liw.fi/manpages/', ), ) for LINK in policy_links: if not LINK: self.menu_policy.AppendSeparator() elif len(LINK) > 2: link_id = LINK[0] label = LINK[1] url = LINK[2] if len(LINK) > 3: icon = LINK[3] else: icon = ICON_GLOBE mitm = wx.MenuItem(self.menu_policy, link_id, label, url) mitm.SetBitmap(icon) self.menu_policy.AppendItem(mitm) wx.EVT_MENU(self, link_id, self.OpenPolicyManual) mitm_help = wx.MenuItem(menu_help, wx.ID_HELP, GT(u'Help'), GT(u'Open a usage document')) mitm_about = wx.MenuItem(menu_help, wx.ID_ABOUT, GT(u'About'), GT(u'About Debreate')) menu_help.AppendMenu(-1, GT(u'Reference'), self.menu_policy) menu_help.AppendSeparator() menu_help.AppendItem(mitm_help) menu_help.AppendItem(mitm_about) menubar.Append(menu_action, GT(u'Action'), menuid.ACTION) if menu_opt.GetMenuItemCount(): menubar.Append(menu_opt, GT(u'Options'), menuid.OPTIONS) menubar.Append(menu_help, GT(u'Help'), menuid.HELP) self.Wizard = Wizard(self) # Menu for debugging & running tests if DebugEnabled(): self.menu_debug = wx.Menu() menubar.Append(self.menu_debug, GT(u'Debug'), menuid.DEBUG) self.menu_debug.AppendItem( wx.MenuItem(self.menu_debug, menuid.LOG, GT(u'Show log'), GT(u'Toggle debug log window'), kind=wx.ITEM_CHECK)) if u'log-window' in parsed_args_s: self.menu_debug.Check(menuid.LOG, True) self.log_window = None # Window colors self.menu_debug.AppendItem( wx.MenuItem(self.menu_debug, menuid.THEME, GT(u'Toggle window colors'))) wx.EVT_MENU(self, menuid.THEME, self.OnToggleTheme) # *** Current Project Status *** # self.LoadedProject = None self.ProjectDirty = False self.dirty_mark = u' *' menu_file.Enable(wx.ID_SAVE, self.ProjectDirty) # *** Event Handling *** # wx.EVT_MENU(self, menuid.NEW, self.OnProjectNew) wx.EVT_MENU(self, menuid.OPEN, self.OnProjectOpen) wx.EVT_MENU(self, menuid.SAVE, self.OnProjectSave) wx.EVT_MENU(self, menuid.SAVEAS, self.OnProjectSaveAs) wx.EVT_MENU(self, menuid.QBUILD, self.OnQuickBuild) wx.EVT_MENU(self, menuid.EXIT, self.OnQuit) wx.EVT_MENU(self, menuid.TOOLTIPS, self.OnToggleToolTips) wx.EVT_MENU(self, menuid.DIST, self.OnUpdateDistNamesCache) wx.EVT_MENU(self, menuid.UPDATE, self.OnCheckUpdate) wx.EVT_MENU(self, menuid.HELP, self.OnHelp) wx.EVT_MENU(self, menuid.ABOUT, self.OnAbout) self.Bind(EVT_CHANGE_PAGE, self.OnWizardBtnPage) # Custom close event shows a dialog box to confirm quit wx.EVT_CLOSE(self, self.OnQuit) # *** Layout *** # lyt_main = BoxSizer(wx.VERTICAL) lyt_main.Add(self.Wizard, 1, wx.EXPAND) self.SetAutoLayout(True) self.SetSizer(lyt_main) self.Layout()
def OnLogDirOpen(self, event=None): #@UnusedVariable Logger.Debug(__name__, GT(u'Opening log directory ...')) subprocess.check_output( [GetExecutable(u'xdg-open'), u'{}/logs'.format(PATH_local)], stderr=subprocess.STDOUT)
def createMenuBar(parent): testing = u'alpha' in GetTestList() or DebugEnabled() menubar = MenuBar(parent) menu_file = wx.Menu() menubar.Append(menu_file, GT(u'File'), menuid.FILE) # This menu is filled from wiz.wizard.Wizard.SetPages menubar.Append(wx.Menu(), GT(u'Page'), menuid.PAGE) # *** File Menu *** # mitems_file = [ ( menuid.NEW, GT(u'New project'), GT(u'Start a new project'), ), ( menuid.OPEN, GT(u'Open'), GT(u'Open a previously saved project'), ), ( menuid.SAVE, GT(u'Save'), GT(u'Save current project'), ), ( menuid.SAVEAS, GT(u'Save as'), GT(u'Save current project with a new filename'), ), None, ( menuid.QBUILD, GT(u'Quick Build'), GT(u'Build a package from an existing build tree'), ICON_CLOCK, ), None, ( menuid.EXIT, GT(u'Quit'), GT(u'Exit Debreate'), ), ] if testing: mitems_file.append((menuid.ALIEN, GT(u'Convert packages'), GT(u'Convert between package types'))) # Adding all menus to menu bar mitems = (mitems_file, ) for menu_list in mitems: for mitem in menu_list: if not mitem: menu_file.AppendSeparator() else: itm = wx.MenuItem(menu_file, mitem[0], mitem[1], mitem[2]) if len(mitem) > 3: itm.SetBitmap(mitem[3]) menu_file.AppendItem(itm) # ----- Options Menu parent.menu_opt = wx.Menu() # Show/Hide tooltips parent.opt_tooltips = wx.MenuItem(parent.menu_opt, menuid.TOOLTIPS, GT(u'Show tooltips'), GT(u'Show or hide tooltips'), kind=wx.ITEM_CHECK) # A bug with wx 2.8 does not allow tooltips to be toggled off if wx.MAJOR_VERSION > 2: parent.menu_opt.AppendItem(parent.opt_tooltips) if parent.menu_opt.FindItemById(menuid.TOOLTIPS): show_tooltips = ReadConfig(u'tooltips') if show_tooltips != ConfCode.KEY_NO_EXIST: parent.opt_tooltips.Check(show_tooltips) else: parent.opt_tooltips.Check(GetDefaultConfigValue(u'tooltips')) parent.OnToggleToolTips() # *** Option Menu: open logs directory *** # if GetExecutable(u'xdg-open'): mitm_logs_open = wx.MenuItem(parent.menu_opt, menuid.OPENLOGS, GT(u'Open logs directory')) parent.menu_opt.AppendItem(mitm_logs_open) wx.EVT_MENU(parent, menuid.OPENLOGS, parent.OnLogDirOpen) # *** OS distribution names cache *** # opt_distname_cache = wx.MenuItem( parent.menu_opt, menuid.DIST, GT(u'Update dist names cache'), GT(u'Creates/Updates list of distribution names for changelog page')) parent.menu_opt.AppendItem(opt_distname_cache) mitm_ccache = wx.MenuItem(parent.menu_opt, menuid.CCACHE, GT(u'Clear local cache')) parent.menu_opt.AppendItem(mitm_ccache) # ----- Help Menu menu_help = wx.Menu() # ----- Version update mitm_update = wx.MenuItem( menu_help, menuid.UPDATE, GT(u'Check for update'), GT(u'Check if a new version is available for download')) mitm_update.SetBitmap(ICON_LOGO) menu_help.AppendItem(mitm_update) menu_help.AppendSeparator() # Menu with links to the Debian Policy Manual webpages parent.menu_policy = wx.Menu() policy_links = ( ( refid.DPM, GT(u'Debian Policy Manual'), u'https://www.debian.org/doc/debian-policy', ), ( refid.DPMCtrl, GT(u'Control files'), u'https://www.debian.org/doc/debian-policy/ch-controlfields.html', ), ( refid.DPMLog, GT(u'Changelog'), u'https://www.debian.org/doc/debian-policy/ch-source.html#s-dpkgchangelog', ), ( refid.UPM, GT(u'Ubuntu Policy Manual'), u'http://people.canonical.com/~cjwatson/ubuntu-policy/policy.html/', ), ( refid.LINT_TAGS, GT(u'Lintian Tags Explanation'), u'https://lintian.debian.org/tags-all.html', ), ( refid.LINT_OVERRIDE, GT(u'Overriding Lintian Tags'), u'https://lintian.debian.org/manual/section-2.4.html', ), ( refid.LAUNCHERS, GT(u'Launchers / Desktop entries'), u'https://www.freedesktop.org/wiki/Specifications/desktop-entry-spec/', ), # Unofficial links None, ( refid.DEBSRC, GT(u'Building debs from Source'), u'http://www.quietearth.us/articles/2006/08/16/Building-deb-package-from-source', ), # This is here only temporarily for reference ( refid.MAN, GT(u'Writing manual pages'), u'https://liw.fi/manpages/', ), ) for LINK in policy_links: if not LINK: parent.menu_policy.AppendSeparator() elif len(LINK) > 2: link_id = LINK[0] label = LINK[1] url = LINK[2] if len(LINK) > 3: icon = LINK[3] else: icon = ICON_GLOBE mitm = wx.MenuItem(parent.menu_policy, link_id, label, url) mitm.SetBitmap(icon) parent.menu_policy.AppendItem(mitm) wx.EVT_MENU(parent, link_id, parent.OpenPolicyManual) mitm_manual = wx.MenuItem(menu_help, wx.ID_HELP, GT(u'Manual'), GT(u'Open a usage document')) mitm_about = wx.MenuItem(menu_help, wx.ID_ABOUT, GT(u'About'), GT(u'About Debreate')) menu_help.AppendMenu(-1, GT(u'Reference'), parent.menu_policy) menu_help.AppendSeparator() menu_help.AppendItem(mitm_manual) menu_help.AppendItem(mitm_about) if parent.menu_opt.GetMenuItemCount(): menubar.Append(parent.menu_opt, GT(u'Options'), menuid.OPTIONS) menubar.Append(menu_help, GT(u'Help'), menuid.HELP) # catching menu events wx.EVT_MENU(parent, menuid.CCACHE, parent.OnClearCache) return menubar
def GetPrimaryDisplayRect(): rect = None # wx 3.0 does not recognize primary display correctly # TODO: File bug report if wx.MAJOR_VERSION <= 2: primary = None # Try to find the primary display within first 10 displays for X in range(10): try: dsp = wx.Display(X) if dsp.IsPrimary(): primary = dsp break except AssertionError: pass if primary: rect = primary.GetGeometry() # Reorder for compatibility with xrandr output rect = ( rect[2], rect[3], rect[0], rect[1], ) Logger.Debug(__name__, u'GetPrimaryDisplayRect: Using wx.Display') # Fall back to using xrandr if not rect: CMD_xrand = GetExecutable(u'xrandr') if not CMD_xrand: return None output = GetCommandOutput(CMD_xrand).split(u'\n') for LINE in output: LINE = LINE.lower() if u'primary' in LINE: LINE = LINE.split(u'primary')[1].strip().split(u' ')[0] posX = LINE.split(u'x') posY = posX[1].split(u'+') posX = posX[0] width = posY[1] height = posY[2] posY = posY[0] rect = [ posX, posY, width, height, ] for INDEX in range(len(rect)): X = rect[INDEX] if not StringIsNumeric(X): # FIXME: Break out of second loop & call continue on first? return None rect[INDEX] = int(X) Logger.Debug(__name__, u'GetPrimaryDisplayRect: Using xrandr') break if rect: return tuple(rect)
def Build(self, outFile): def log_message(msg, current_step, total_steps): return u'{} ({}/{})'.format(msg, current_step, total_steps) wizard = GetWizard() pages_build_ids = self.BuildPrep() if pages_build_ids != None: main_window = GetMainWindow() # Reported at the end of build build_summary = [] steps_count = len(pages_build_ids) current_step = 0 # Steps from build page for chk in self.chk_md5, self.chk_lint, self.chk_rmstage: if chk.IsChecked(): steps_count += 1 # Control file & .deb build step steps_count += 2 stage = CreateStage() log_msg = GT(u'Starting build') wx.YieldIfNeeded() # FIXME: Enable PD_CAN_ABORT build_progress = ProgressDialog(main_window, GT(u'Building'), log_msg, maximum=steps_count) build_summary.append(u'{}:'.format(log_msg)) try: for P in wizard.GetAllPages(): if build_progress.WasCancelled(): break if P.GetId() in pages_build_ids: p_label = P.GetTitle() log_msg = log_message( GT(u'Processing page "{}"').format(p_label), current_step + 1, steps_count) # FIXME: Progress bar not updating??? wx.YieldIfNeeded() build_progress.Update(current_step, log_msg) ret_code, ret_value = P.ExportBuild(stage) build_summary.append(u'\n{}:\n{}'.format( log_msg, ret_value)) if ret_code > 0: build_progress.Destroy() ShowErrorDialog(GT(u'Error occurred during build'), ret_value) return current_step += 1 # *** Control File *** # if not build_progress.WasCancelled(): wx.YieldIfNeeded() log_msg = log_message(GT(u'Creating control file'), current_step + 1, steps_count) build_progress.Update(current_step, log_msg) Logger.Debug(__name__, log_msg) # Retrieve control page pg_control = wizard.GetPage(pgid.CONTROL) if not pg_control: build_progress.Destroy() ShowErrorDialog( GT(u'Could not retrieve control page'), GT(u'Please contact the developer: {}').format( AUTHOR_email), title=u'Fatal Error') return installed_size = self.OnBuildGetInstallSize(stage) Logger.Debug( __name__, GT(u'Installed size: {}').format(installed_size)) build_summary.append(u'\n{}:'.format(log_msg)) build_summary.append( pg_control.ExportBuild( u'{}/DEBIAN'.format(stage).replace(u'//', u'/'), installed_size)) current_step += 1 # *** MD5 Checksum *** # if not build_progress.WasCancelled(): if self.chk_md5.GetValue() and GetExecutable(u'md5sum'): log_msg = log_message(GT(u'Creating MD5 checksum'), current_step + 1, steps_count) #log_msg = GT(u'Creating MD5 checksum') #step = u'{}/{}'.format(current_step+1, steps_count) Logger.Debug(__name__, log_msg) wx.YieldIfNeeded() build_progress.Update(current_step, log_msg) build_summary.append(u'\n{}:'.format(log_msg)) build_summary.append(self.OnBuildMD5Sum(stage)) current_step += 1 # *** Create .deb from Stage *** # if not build_progress.WasCancelled(): log_msg = log_message(GT(u'Creating .deb package'), current_step + 1, steps_count) wx.YieldIfNeeded() build_progress.Update(current_step, log_msg) build_summary.append(u'\n{}:'.format(log_msg)) build_summary.append( self.OnBuildCreatePackage(stage, outFile)) current_step += 1 # *** Lintian *** # if not build_progress.WasCancelled(): if self.chk_lint.IsChecked(): log_msg = log_message( GT(u'Checking package with lintian'), current_step + 1, steps_count) wx.YieldIfNeeded() build_progress.Update(current_step, log_msg) build_summary.append(u'\n{}:'.format(log_msg)) build_summary.append(self.OnBuildCheckPackage(outFile)) current_step += 1 # *** Delete Stage *** # if not build_progress.WasCancelled(): if self.chk_rmstage.IsChecked(): log_msg = log_message( GT(u'Removing staged build tree'), current_step + 1, steps_count) wx.YieldIfNeeded() build_progress.Update(current_step, log_msg) build_summary.append(u'\n{}:'.format(log_msg)) RemoveStage(stage) if not os.path.isdir(stage): build_summary.append( GT(u'Staged build tree removed successfully')) else: build_summary.append( GT(u'Failed to remove staged build tree')) current_step += 1 # *** Show Completion Status *** # wx.YieldIfNeeded() build_progress.Update(steps_count, GT(u'Build completed')) # Show finished dialog for short moment time.sleep(1) # TODO: Add error count to build summary build_progress.Destroy() build_summary = u'\n'.join(build_summary) summary_dialog = DetailedMessageDialog(main_window, GT(u'Build Summary'), ICON_INFORMATION, GT(u'Build completed'), build_summary) summary_dialog.ShowModal() except: build_progress.Destroy() ShowErrorDialog(GT(u'Error occurred during build'), traceback.format_exc()) return