def OnBuild(self, event=None): # Build preparation ret_code, build_prep = self.BuildPrep() if ret_code == dbrerrno.ECNCLD: return if ret_code == dbrerrno.FEMPTY: err_dia = DetailedMessageDialog( GetMainWindow(), GT(u'Cannot Continue'), ICON_EXCLAMATION, text=u'{}\n{}'.format( GT(u'One of the required fields is empty:'), build_prep)) err_dia.ShowModal() err_dia.Destroy() return if ret_code == dbrerrno.SUCCESS: task_list, build_path, filename = build_prep # Actual build ret_code, result = self.Build(task_list, build_path, filename) # FIXME: Check .deb package timestamp to confirm build success if ret_code == dbrerrno.SUCCESS: DetailedMessageDialog( GetMainWindow(), GT(u'Success'), ICON_INFORMATION, text=GT(u'Package created successfully')).ShowModal() # Installing the package if FieldEnabled( self.chk_install) and self.chk_install.GetValue(): self.InstallPackage(result) return if result: ShowErrorDialog(GT(u'Package build failed'), result) else: ShowErrorDialog(GT(u'Package build failed with unknown error')) return if build_prep: ShowErrorDialog(GT(u'Build preparation failed'), build_prep) else: ShowErrorDialog(GT(u'Build preparation failed with unknown error'))
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 ImportFromFile(self, filename): Logger.Debug(__name__, GT(u'Importing page info from {}').format(filename)) if not os.path.isfile(filename): return dbrerrno.ENOENT files_data = ReadFile(filename, split=True) # Lines beginning with these characters will be ignored ignore_characters = ( u'', u' ', u'#', ) target = None targets_list = [] for L in files_data: if not TextIsEmpty(L) and L[0] not in ignore_characters: if u'[' in L and u']' in L: target = L.split(u'[')[-1].split(u']')[0] continue if target: executable = (len(L) > 1 and L[-2:] == u' *') if executable: L = L[:-2] targets_list.append((target, L, executable)) missing_files = [] for T in targets_list: # FIXME: Create method in FileList class to retrieve all missing files if not os.path.exists(T[1]): missing_files.append(T[1]) source_file = os.path.basename(T[1]) source_dir = os.path.dirname(T[1]) self.lst_files.AddFile(source_file, source_dir, T[0], executable=T[2]) if len(missing_files): main_window = GetMainWindow() err_line1 = GT(u'The following files/folders are missing from the filesystem.') err_line2 = GT(u'They will be highlighted on the Files page.') DetailedMessageDialog(main_window, title=GT(u'Warning'), icon=ICON_ERROR, text=u'\n'.join((err_line1, err_line2)), details=u'\n'.join(missing_files)).ShowModal() return 0
def AddInfo(self, event=None): new_changes = self.ti_changes.GetValue() if TextIsEmpty(new_changes): DetailedMessageDialog( GetMainWindow(), GT(u'Warning'), ICON_WARNING, GT(u'"Changes" section is empty')).ShowModal() self.ti_changes.SetInsertionPointEnd() self.ti_changes.SetFocus() return package = self.ti_package.GetValue() version = self.ti_version.GetValue() dist = self.ti_dist.GetValue() urgency = self.sel_urgency.GetStringSelection() maintainer = self.ti_maintainer.GetValue() email = self.ti_email.GetValue() new_changes = FormatChangelog(new_changes, package, version, dist, urgency, maintainer, email, self.chk_indentation.GetValue()) # Clean up leading & trailing whitespace in old changes old_changes = self.dsp_changes.GetValue().strip(u' \t\n\r') # Only append newlines if log isn't already empty if not TextIsEmpty(old_changes): new_changes = u'{}\n\n\n{}'.format(new_changes, old_changes) # Add empty line to end of log if not new_changes.endswith(u'\n'): new_changes = u'{}\n'.format(new_changes) self.dsp_changes.SetValue(new_changes) # Clear "Changes" text self.ti_changes.Clear() self.ti_changes.SetFocus()
def OnGenerate(self, event=None): main_window = GetMainWindow() # Get the amount of links to be created total = self.Executables.GetCount() if total > 0: non_empty_scripts = [] for DS in self.script_objects[1][0], self.script_objects[2][0]: if not TextIsEmpty(DS.GetValue()): non_empty_scripts.append(DS.GetName()) # Warn about overwriting previous post-install & pre-remove scripts if non_empty_scripts: warn_msg = GT(u'The following scripts will be overwritten if you continue: {}') warn_msg = u'{}\n\n{}'.format(warn_msg.format(u', '.join(non_empty_scripts)), GT(u'Continue?')) overwrite = ConfirmationDialog(main_window, text=warn_msg) if not overwrite.Confirmed(): return overwrite.Destroy() del warn_msg, overwrite # Get destination for link from Auto-Link input textctrl link_path = self.ti_autolink.GetValue() # Warn about linking in a directory that does not exist on the current filesystem if not os.path.isdir(link_path): warn_msg = GT(u'Path "{}" does not exist.') warn_msg = u'{}\n\n{}'.format(warn_msg, GT(u'Continue?')) overwrite = ConfirmationDialog(main_window, text=warn_msg.format(link_path)) if not overwrite.Confirmed(): return overwrite.Destroy() del warn_msg, overwrite # Create a list of commands to put into the script postinst_list = [] prerm_list = [] for INDEX in range(total): source_path = self.Executables.GetPath(INDEX) filename = self.Executables.GetBasename(INDEX) if u'.' in filename: linkname = u'.'.join(filename.split(u'.')[:-1]) link = u'{}/{}'.format(link_path, linkname) else: link = u'{}/{}'.format(link_path, filename) postinst_list.append(u'ln -fs "{}" "{}"'.format(source_path, link)) prerm_list.append(u'rm -f "{}"'.format(link)) postinst = u'\n\n'.join(postinst_list) prerm = u'\n\n'.join(prerm_list) self.script_objects[1][0].SetValue(postinst) self.script_objects[2][0].SetValue(prerm) DetailedMessageDialog(main_window, GT(u'Success'), text=GT(u'Post-Install and Pre-Remove scripts generated')).ShowModal()
def Set(self, data): # Clear files list self.lst_files.DeleteAllItems() files_data = data.split(u'\n') if int(files_data[0]): # Get file count from list minus first item "1" files_total = len(files_data) # Store missing files here missing_files = [] progress = None if files_total >= efficiency_threshold: progress = ProgressDialog(GetMainWindow(), GT(u'Adding Files'), maximum=files_total, style=PD_DEFAULT_STYLE|wx.PD_CAN_ABORT) wx.Yield() progress.Show() current_file = files_total while current_file > 1: if progress and progress.WasCancelled(): progress.Destroy() # Project continues opening even if file import is cancelled msg = ( GT(u'File import did not complete.'), GT(u'Project files may be missing in file list.'), ) ShowMessageDialog(u'\n'.join(msg), GT(u'Import Cancelled')) return False current_file -= 1 executable = False file_info = files_data[current_file].split(u' -> ') absolute_filename = file_info[0] if absolute_filename[-1] == u'*': # Set executable flag and remove "*" executable = True absolute_filename = absolute_filename[:-1] filename = file_info[1] source_dir = absolute_filename[:len(absolute_filename) - len(filename)] target_dir = file_info[2] if not self.lst_files.AddFile(filename, source_dir, target_dir, executable): Logger.Warn(__name__, GT(u'File not found: {}').format(absolute_filename)) missing_files.append(absolute_filename) if progress: update_value = files_total - current_file wx.Yield() progress.Update(update_value+1, GT(u'Imported file {} of {}').format(update_value, files_total)) if progress: progress.Destroy() Logger.Debug(__name__, u'Missing file count: {}'.format(len(missing_files))) # If files are missing show a message if missing_files: alert = DetailedMessageDialog(GetMainWindow(), GT(u'Missing Files'), ICON_EXCLAMATION, GT(u'Could not locate the following files:'), u'\n'.join(missing_files)) alert.ShowModal() return True
def OnBuild(self, event=None): if event: event.Skip() # Show control file preview for editing if UsingTest(u'alpha') and self.chk_editctrl.GetValue(): self.EditControl() wizard = GetWizard() pg_control = wizard.GetPage(pgid.CONTROL) pg_files = wizard.GetPage(pgid.FILES) pg_launcher = wizard.GetPage(pgid.LAUNCHERS) required_fields = { GT(u'Control'): pg_control.GetRequiredFields(), } # Check if launchers are enabled for build if pg_launcher.GetLaunchersCount(): required_fields[GT( u'Menu Launcher')] = pg_launcher.GetRequiredFields() # FIXME: Old code won't work with multiple launchers for RF in required_fields[GT(u'Menu Launcher')]: Logger.Debug( __name__, GT(u'Required field (Menu Launcher): {}').format( RF.GetName())) for p_name in required_fields: Logger.Debug(__name__, GT(u'Page name: {}').format(p_name)) for F in required_fields[p_name]: if not isinstance(F, wx.StaticText) and TextIsEmpty( F.GetValue()): f_name = F.GetName() msg_l1 = GT(u'One of the required fields is empty:') msg_full = u'{}: {} ➜ {}'.format(msg_l1, p_name, f_name) Logger.Warn(__name__, msg_full) DetailedMessageDialog(GetMainWindow(), GT(u'Cannot Continue'), ICON_EXCLAMATION, text=msg_full).ShowModal() for P in wizard.GetAllPages(): if P.GetTitle() == p_name: Logger.Debug( __name__, GT(u'Showing page with required field: {}'). format(p_name)) wizard.ShowPage(P.GetId()) return if GetField(pg_files, inputid.LIST).MissingFiles(): ShowErrorDialog(GT(u'Files are missing in file list'), warn=True, title=GT(u'Warning')) wizard.ShowPage(pgid.FILES) return ttype = GT(u'Debian Packages') save_dialog = GetFileSaveDialog(GetMainWindow(), GT(u'Build Package'), u'{} (*.deb)|*.deb'.format(ttype), u'deb') package = GetFieldValue(pg_control, inputid.PACKAGE) version = GetFieldValue(pg_control, inputid.VERSION) arch = GetFieldValue(pg_control, inputid.ARCH) save_dialog.SetFilename(u'{}_{}_{}.deb'.format(package, version, arch)) if ShowDialog(save_dialog): self.Build(save_dialog.GetPath())
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
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())