def Set(self, data): preinst = data.split(u'<<PREINST>>\n')[1].split(u'\n<</PREINST>>')[0] postinst = data.split(u'<<POSTINST>>\n')[1].split( u'\n<</POSTINST>>')[0] prerm = data.split(u'<<PRERM>>\n')[1].split(u'\n<</PRERM>>')[0] postrm = data.split(u'<<POSTRM>>\n')[1].split(u'\n<</POSTRM>>')[0] def format_script(script): return u'\n'.join( script.split(u'\n')[2:]) # Use '2' to remove first two lines if GS(preinst[0]).isnumeric(): if int(preinst[0]): self.script_objects[0][0].SetValue(format_script(preinst)) if GS(postinst[0]).isnumeric(): if int(postinst[0]): self.script_objects[1][0].SetValue(format_script(postinst)) if GS(prerm[0]).isnumeric(): if int(prerm[0]): self.script_objects[2][0].SetValue(format_script(prerm)) if GS(postrm[0]).isnumeric(): if int(postrm[0]): self.script_objects[3][0].SetValue(format_script(postrm))
def GetLauncherInfo(self): desktop_list = [u'[Desktop Entry]'] name = GetField(self, inputid.NAME).GetValue() if not TextIsEmpty(name): desktop_list.append(u'Name={}'.format(name)) desktop_list.append(u'Version=1.0') executable = GetField(self, inputid.EXEC).GetValue() if not TextIsEmpty(executable): desktop_list.append(u'Exec={}'.format(executable)) comment = GetField(self, inputid.DESCR).GetValue() if not TextIsEmpty(comment): desktop_list.append(u'Comment={}'.format(comment)) icon = GetField(self, inputid.ICON).GetValue() if not TextIsEmpty(icon): desktop_list.append(u'Icon={}'.format(icon)) launcher_type = GetField(self, inputid.TYPE).GetValue() if not TextIsEmpty(launcher_type): desktop_list.append(u'Type={}'.format(launcher_type)) desktop_list.append(u'Terminal={}'.format( GS(self.sel_term.GetSelection() == 0).lower())) desktop_list.append(u'StartupNotify={}'.format( GS(self.sel_notify.GetSelection() == 0).lower())) encoding = GetField(self, inputid.ENC).GetValue() if not TextIsEmpty(encoding): desktop_list.append(u'Encoding={}'.format(encoding)) lst_categories = GetField(self, listid.CAT) categories = [] cat_total = lst_categories.GetItemCount() count = 0 while count < cat_total: C = lst_categories.GetItemText(count) if not TextIsEmpty(C): categories.append(lst_categories.GetItemText(count)) count += 1 # Add a final semi-colon if categories is not empty if categories: categories = u';'.join(categories) if categories[-1] != u';': categories = u'{};'.format(categories) desktop_list.append(u'Categories={}'.format(categories)) ''' other = self.ti_other.GetValue() if not TextIsEmpty(other): desktop_list.append(other) ''' return u'\n'.join(desktop_list)
def GetInteger(value): if isinstance(value, (int, float,)): return int(value) # Will always use there very first value, even for nested items elif isinstance(value,(tuple, list,)): # Recursive check lists & tuples return GetInteger(value[0]) elif value and IsString(value): # Convert because of unsupported methods in str class value = GS(value) if HasAlpha(value): return None # Check for negative if value[0] == u'-': if value.count(u'-') <= 1: value = GetInteger(value[1:]) if value != None: return -value # Check for tuple elif u'.' in value: value = value.split(u'.')[0] return GetInteger(value) elif StringIsNumeric(value): return int(value) return None
def CreateStage(): stage = u'/tmp' # Use current working directory if no write access to /tmp if not os.access(stage, os.W_OK): stage = os.getcwd() #suffix = u'{}{}{}_'.format(GetYear(), GetMonthInt(), GetDayInt()) #suffix = u'_temp' suffix = GetDate(dtfmt.STAMP) stage = u'{}/{}-{}_{}'.format(stage, GS(APP_name).lower(), VERSION_string, suffix) if os.access(os.path.dirname(stage), os.W_OK): # Start with fresh directory if os.path.isdir(stage): shutil.rmtree(stage) elif os.path.isfile(stage): os.remove(stage) os.makedirs(stage) if os.path.isdir(stage): return stage
def Get(self, getModule=False): # 'install after build' is not exported to project for safety fields = {} omit_options = (self.chk_install, ) for O in self.build_options: # Leave options out that should not be saved if O not in omit_options: fields[O.GetName()] = GS(O.GetValue()) page = wx.EmptyString for F in fields: if page == wx.EmptyString: page = u'{}={}'.format(F, fields[F]) else: page = u'{}\n{}={}'.format(page, F, fields[F]) if page == wx.EmptyString: page = None if getModule: page = ( __name__, page, ) return page
def GetDayInt(string_value=False): day = GS(strftime(u'%d')) if not string_value: day = int(day) return day
def GetMonthInt(string_value=False): month = GS(strftime(u'%m')) if not string_value: month = int(month) return month
def GetYear(fmt=dtfmt.DEFAULT, string_value=True): year = GS(strftime(u'%Y')) if not string_value: year = int(year) return year
def OnAddCustom(self, event=None): custom_label = GS( self.input_add_custom.GetValue()).strip(u' ').replace(u' ', u'_') if not TextIsEmpty(custom_label) and not self.check_list.LabelExists( custom_label): self.check_list.AddItem(custom_label, True) self.check_list.ScrollToEnd()
def GetTime(fmt=dtfmt.DEFAULT): ms = None current_time = None if fmt in ( dtfmt.LOG, dtfmt.STAMP, ): ms = GS(datetime.now().strftime(u'%f'))[:3] if fmt == dtfmt.STAMP: # HHMMSSmmm current_time = u'{}{}'.format(GS(strftime(u'%H%M%S')), ms) else: # HH:MM:SS.mmm current_time = u'{}.{}'.format(GS(strftime(u'%T')), ms) return current_time
def CreateButton(parent, btnId=wx.ID_ANY, label=wx.EmptyString, image=None, size=32, tooltip=None, name=None, commands=None, requireAll=False): if not image: image = btnid.GetImage(btnId) # Use titleized version of the image name for the label if not label and image: label = image.title() if not name: name = label button = None if image: image = ConcatPaths( (PATH_bitmaps, u'button', GS(size), u'{}.png'.format(image))) if not os.path.isfile(image): Logger.Warn( __name__, u'CreateButton: Attempted to set not-existent image for button (ID {}):' .format(btnId), details=image) else: button = CustomButton(parent, image, btnId, name=name, commands=commands, requireAll=requireAll) if not tooltip: tooltip = label button.SetToolTipString(tooltip) # Use a standard button if not button: button = Button(parent, btnId, label, name=name, commands=commands, requireAll=requireAll) return button
def GetImagePath(name, size=16, cat=None, img_type=u'png'): name = u'{}.{}'.format(name, img_type) if cat: paths = (PATH_bitmaps, cat, GS(size), name) else: paths = (PATH_bitmaps, GS(size), name) image_path = ConcatPaths(paths) # Attempt to use failsafe image if file does not exists if not os.path.isfile(image_path): image_path = ConcatPaths((PATH_bitmaps, GS(size), u'failsafe.png')) # Last resort is to retrun None if a failsafe image was not found if not os.path.isfile(image_path): return None return image_path
def GetInteger(value): if isinstance(value, ( int, float, )): return int(value) # Will always use there very first value, even for nested items elif isinstance(value, ( tuple, list, )): # Recursive check lists & tuples return GetInteger(value[0]) elif value and IsString(value): # Convert because of unsupported methods in str class value = GS(value) if HasAlpha(value): return None # Check for negative if value[0] == u'-': if value.count(u'-') <= 1: value = GetInteger(value[1:]) if value != None: return -value # Check for tuple elif u'.' in value: value = value.split(u'.')[0] return GetInteger(value) elif StringIsNumeric(value): return int(value) return None
def OnCheckUpdate(self, event=None): #@UnusedVariable update_test = u'update-fail' in GetTestList() if UsingDevelopmentVersion() and not update_test: DetailedMessageDialog( self, GT(u'Update'), text=GT(u'Update checking is disabled in development versions' )).ShowModal() return wx.SafeYield() if update_test: # Set a bad url to force error current = GetCurrentVersion(u'http://dummyurl.blah/') else: current = GetCurrentVersion() Logger.Debug(__name__, GT(u'URL request result: {}').format(current)) error_remote = GT( u'An error occurred attempting to contact remote website') if isinstance(current, (URLError, HTTPError)): current = GS(current) ShowErrorDialog(error_remote, current) elif isinstance(current, tuple) and current > VERSION_tuple: current = u'{}.{}.{}'.format(current[0], current[1], current[2]) l1 = GT(u'Version {} is available!').format(current) l2 = GT(u'Would you like to go to Debreate\'s website?') if ConfirmationDialog(self, GT(u'Update'), u'{}\n\n{}'.format(l1, l2)).Confirmed(): wx.LaunchDefaultBrowser(APP_homepage) elif isinstance(current, (unicode, str)): ShowErrorDialog(error_remote, current) else: DetailedMessageDialog( self, GT(u'Debreate'), text=GT(u'Debreate is up to date!')).ShowModal()
def RefreshLog(self, event=None): if self.LogFile.IsFile(): log_data = self.LogFile.Read() if not self.DspLog.IsEmpty(): self.DspLog.Clear() self.DspLog.SetValue(log_data) try: # Yield here to make sure last line is displayed # FIXME: Causes delay when debug enabled wx.SafeYield() self.DspLog.ShowPosition(self.DspLog.GetLastPosition()) except wx.PyDeadObjectError: tb_error = GS(traceback.format_exc()) Logger.Warn(__name__, u'Error refreshing log window. Details below:\n\n{}'.format(tb_error))
# FIXME: How to add 'absolute' argument with ambiguous arg count for 'tail' absolute = True if absolute and not path.startswith(u'/'): path = u'/' + path return path # *** System paths *** # ## Directory where app is installed # HACK: test # HACK: Call os.path.dirname twice to get root directory. # This is necessary because this variable is # declared from a sub-directory. PATH_app = GS(os.path.dirname(os.path.dirname(__file__))) ## User's home directory # # Used to set config directory. PATH_home = GS(os.getenv(u'HOME')) ## Local folder to store files such as custom templates PATH_local = ConcatPaths((PATH_home, u'.local/share/debreate')) ## Directory where cache files are stored PATH_cache = ConcatPaths((PATH_local, u'cache')) ## Directory where log files are stored PATH_logs = ConcatPaths((PATH_local, u'logs'))
def GetTimeZone(fmt=dtfmt.DEFAULT): return GS(strftime(u'%z'))
sys.exit(0) if u'help' in parsed_args_s: if INSTALLED: help_output = commands.getstatusoutput(u'man debreate') else: help_output = commands.getstatusoutput( u'man --manpath="{}/man" debreate'.format(PATH_app)) if help_output[0]: print(u'ERROR: Could not locate manpage') sys.exit(help_output[0]) help_output = GS(help_output[1]) print(u'\n'.join(help_output.split(u'\n')[2:-1])) sys.exit(0) if u'log-level' in parsed_args_v: Logger.SetLogLevel(parsed_args_v[u'log-level']) Logger.Info(script_name, u'Python version: {}'.format(PY_VER_STRING)) Logger.Info(script_name, u'wx.Python version: {}'.format(WX_VER_STRING)) Logger.Info(script_name, u'Debreate version: {}'.format(VERSION_string)) Logger.Info(script_name, u'Logging level: {}'.format(Logger.GetLogLevel())) # Check for & parse existing configuration conf_values = GetAllConfigKeys()
def WriteConfig(k_name, k_value, conf=default_config, sectLabel=None): conf_dir = os.path.dirname(conf) if not os.path.isdir(conf_dir): if os.path.exists(conf_dir): print(u'{}: {}: {}'.format( GT(u'Error'), GT(u'Cannot create config directory, file exists'), conf_dir)) return ConfCode.ERR_WRITE os.makedirs(conf_dir) # Only write pre-defined keys if k_name not in default_config_values: print(u'{}: {}: {}'.format(GT(u'Error'), GT(u'Configuration key not found'), k_name)) return ConfCode.KEY_NOT_DEFINED # Make sure we are writing the correct type k_value = default_config_values[k_name][0](k_value) if k_value == None: print(u'{}: {}: {}'.format( GT(u'Error'), GT(u'Wrong value type for configuration key'), k_name)) return ConfCode.WRONG_TYPE # tuple is the only type we need to format if isinstance(k_value, tuple): k_value = u'{},{}'.format(GS(k_value[0]), GS(k_value[1])) else: k_value = GS(k_value) conf_text = wx.EmptyString # Save current config to buffer if os.path.exists(conf): if not os.path.isfile(conf): print(u'{}: {}: {}'.format( GT(u'Error'), GT(u'Cannot open config for writing, directory exists'), conf)) return ConfCode.ERR_WRITE conf_text = ReadFile(conf) # FIXME: ReadFile returns None type if config file exists but is empty if conf_text == None: conf_text = u'' else: conf_text = u'[CONFIG-{}.{}]'.format(GS(config_version[0]), GS(config_version[1])) conf_lines = conf_text.split(u'\n') key_exists = False for L in conf_lines: l_index = conf_lines.index(L) if u'=' in L: key = L.split(u'=')[0] if k_name == key: key_exists = True conf_lines[l_index] = u'{}={}'.format(k_name, k_value) if not key_exists: conf_lines.append(u'{}={}'.format(k_name, k_value)) conf_text = u'\n'.join(conf_lines) if TextIsEmpty(conf_text): print(u'{}: {}'.format(GT(u'Warning'), GT(u'Not writing empty text to configuration'))) return ConfCode.ERR_WRITE # Actual writing to configuration WriteFile(conf, conf_text) if os.path.isfile(conf): return ConfCode.SUCCESS return ConfCode.ERR_WRITE
def HasAlpha(value): return (re.search(u'[a-zA-Z]', GS(value)) != None)
def _digit_to_string(number): if number < 10: return GS(u'0{}'.format(number)) return GS(number)
def Get(self, getModule=False): l_lines = [u'[Desktop Entry]'] categories = [] id_list = ( inputid.VERSION, inputid.ENC, inputid.NAME, inputid.EXEC, inputid.DESCR, inputid.ICON, inputid.TYPE, inputid.TERM, inputid.NOTIFY, inputid.MIME, listid.CAT, inputid.CAT2, inputid.OTHER, ) for ID in id_list: field = GetField(self, ID) if field: if isinstance(field, ErrorTuple): Logger.Warn(__name__, field.GetMessage()) continue if ID == inputid.OTHER: for INDEX in range(field.GetSectionCount()): section = field.GetSection(INDEX) if isinstance(section, CustomSection): key = section.GetKey().strip() value = section.GetValue().strip() elif ID in (listid.CAT, inputid.CAT2): if ID == inputid.CAT2: custom_cats = [] for C1 in field.GetValue().split(u','): for C2 in C1.split(u';'): if not TextIsEmpty(C2): custom_cats.append(C2.strip()) if GetField(self, chkid.CAT).GetValue(): for LABEL in reversed(custom_cats): categories.insert(0, LABEL) else: for LABEL in custom_cats: categories.append(LABEL) else: for LABEL in field.GetCheckedLabels(): categories.append(LABEL) else: if isinstance(field, OutputField): key = field.GetOutLabel() else: key = field.GetName() value = wx.EmptyString if isinstance(field, (wx.TextCtrl, OwnerDrawnComboBox,)): value = field.GetValue().strip() elif isinstance(field, wx.CheckBox): value = GS(field.GetValue()).lower() elif isinstance(field, (ListCtrlBase, ListCtrl,)): value = u';'.join(field.GetListTuple()) if not value.endswith(u';'): value = u'{};'.format(value) if not TextIsEmpty(key) and not TextIsEmpty(value): l_lines.append(u'{}={}'.format(key, value)) # FIXME: Categories should be organized manually by user if categories: categories = u';'.join(categories) if not categories.endswith(u';'): categories = u'{};'.format(categories) l_lines.append(u'Categories={}'.format(categories)) l_text = u'\n'.join(l_lines) if getModule: # FIXME: 'MENU' needed? l_text = (__name__, l_text, u'MENU') return l_text
if u'help' in parsed_args_s: if INSTALLED: help_output = commands.getstatusoutput(u'man debreate') else: help_output = commands.getstatusoutput(u'man --manpath="{}/man" debreate'.format(PATH_app)) if help_output[0]: print(u'ERROR: Could not locate manpage') sys.exit(help_output[0]) help_output = GS(help_output[1]) print(u'\n'.join(help_output.split(u'\n')[2:-1])) sys.exit(0) if u'log-level' in parsed_args_v: Logger.SetLogLevel(parsed_args_v[u'log-level']) Logger.Info(script_name, u'Python version: {}'.format(PY_VER_STRING)) Logger.Info(script_name, u'wx.Python version: {}'.format(WX_VER_STRING)) Logger.Info(script_name, u'Debreate version: {}'.format(VERSION_string)) Logger.Info(script_name, u'Logging level: {}'.format(Logger.GetLogLevel())) # Check for & parse existing configuration
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 Get(self, getModule=False): l_lines = [u'[Desktop Entry]'] categories = [] id_list = ( inputid.VERSION, inputid.ENC, inputid.NAME, inputid.EXEC, inputid.DESCR, inputid.ICON, inputid.TYPE, inputid.TERM, inputid.NOTIFY, inputid.MIME, listid.CAT, inputid.CAT2, inputid.OTHER, ) for ID in id_list: field = GetField(self, ID) if field: if isinstance(field, ErrorTuple): Logger.Warn(__name__, field.GetMessage()) continue if ID == inputid.OTHER: for INDEX in range(field.GetSectionCount()): section = field.GetSection(INDEX) if isinstance(section, CustomSection): key = section.GetKey().strip() value = section.GetValue().strip() elif ID in (listid.CAT, inputid.CAT2): if ID == inputid.CAT2: custom_cats = [] for C1 in field.GetValue().split(u','): for C2 in C1.split(u';'): if not TextIsEmpty(C2): custom_cats.append(C2.strip()) if GetField(self, chkid.CAT).GetValue(): for LABEL in reversed(custom_cats): categories.insert(0, LABEL) else: for LABEL in custom_cats: categories.append(LABEL) else: for LABEL in field.GetCheckedLabels(): categories.append(LABEL) else: if isinstance(field, OutputField): key = field.GetOutLabel() else: key = field.GetName() value = wx.EmptyString if isinstance(field, ( wx.TextCtrl, OwnerDrawnComboBox, )): value = field.GetValue().strip() elif isinstance(field, wx.CheckBox): value = GS(field.GetValue()).lower() elif isinstance(field, ( ListCtrlBase, ListCtrl, )): value = u';'.join(field.GetListTuple()) if not value.endswith(u';'): value = u'{};'.format(value) if not TextIsEmpty(key) and not TextIsEmpty(value): l_lines.append(u'{}={}'.format(key, value)) # FIXME: Categories should be organized manually by user if categories: categories = u';'.join(categories) if not categories.endswith(u';'): categories = u'{};'.format(categories) l_lines.append(u'Categories={}'.format(categories)) l_text = u'\n'.join(l_lines) if getModule: # FIXME: 'MENU' needed? l_text = (__name__, l_text, u'MENU') return l_text
def GT(str_value): return _(GS(str_value))