class LightDMManager: def __init__(self): self.scriptDir = os.path.dirname(os.path.realpath(__file__)) # Load window and widgets self.builder = Gtk.Builder() self.builder.add_from_file( join(self.scriptDir, '../../share/lightdm-manager/lightdm-manager.glade')) # Main window objects go = self.builder.get_object self.window = go('ldmWindow') self.swUsers = go('swUsers') self.tvUsers = go('tvUsers') self.btnSave = go('btnSave') self.imgBackground = go('imgBackground') self.btnUsers = go('btnUsers') self.btnAppearance = go('btnAppearance') self.chkHideUsers = go('chkHideUsers') self.ebFace = go('ebFace') self.imgFace = go('imgFace') self.nbLightDM = go('nbLightDM') self.cmbThemes = go('cmbThemes') # Read from config file self.cfg = Config('lightdm-manager.conf') self.lightdmConf = self.cfg.getValue('CONFIG', 'lightdmConf') self.desktopbaseDir = self.cfg.getValue('CONFIG', 'desktopbaseDir') gktGreeterConf = self.cfg.getValue('CONFIG', 'gtkGreeterConf') kdeGreeterConf = self.cfg.getValue('CONFIG', 'kdeGreeterConf') if exists(gktGreeterConf): self.greeterConf = gktGreeterConf else: self.greeterConf = kdeGreeterConf # Translations title = _("LightDM Manager") self.window.set_title(title) self.btnUsers.set_label("_{}".format(_("Users"))) self.btnAppearance.set_label("_{}".format(_("Appearance"))) go('lblBackground').set_label(_("Background")) go('lblTheme').set_label(_("Theme")) go('lblLightDmMenu').set_label(_("Menu")) self.chkHideUsers.set_label(_("Hide users")) go('lblUsersFace').set_label(_("User icon")) go('lblUsersAutologin').set_label(_("Auto-login")) # Get current background image self.cfgGreeter = Config(self.greeterConf) try: self.curBgPath = self.cfgGreeter.getValue('greeter', 'background') self.curTheme = self.cfgGreeter.getValue('greeter', 'theme-name') except: self.curBgPath = None self.curTheme = None # Get current auto-login user self.cfgLightdm = Config(self.lightdmConf) try: self.curAutoUser = self.cfgLightdm.getValue( 'SeatDefaults', 'autologin-user').strip() self.curHideUsers = False ghu = self.cfgLightdm.getValue('SeatDefaults', 'greeter-hide-users').strip() if 'true' in ghu: self.curHideUsers = True except: self.curAutoUser = None self.curHideUsers = False # Init self.usr = User() self.newbgImg = self.curBgPath self.newAutoUser = self.curAutoUser self.newTheme = self.curTheme self.themes = [] self.selectedMenuItem = None self.debug = False self.logPath = '' self.prevPath = None self.tempFace = "/tmp/face" self.newFaces = [] self.loggedUser = functions.getUserLoginName() self.curUser = self.loggedUser self.selectImg = join(self.scriptDir, '../../share/lightdm-manager/select.png') # Handle arguments try: opts, args = getopt.getopt(sys.argv[1:], 'dl:', ['debug', 'log=']) except getopt.GetoptError: print(("Arguments cannot be parsed: %s" % str(sys.argv[1:]))) sys.exit(1) for opt, arg in opts: if opt in ('-d', '--debug'): self.debug = True elif opt in ('-l', '--log'): self.logPath = arg # Initialize logging if self.debug: if not self.logPath: self.logPath = 'lightdm-manager.log' self.log = Logger(self.logPath, 'debug', True, None, self.window) # Backup config files because ConfigParser does not preserve commented lines if not exists("%s.org" % self.greeterConf): copy(self.greeterConf, "%s.org" % self.greeterConf) self.log.write( "%(conf1)s copied to %(conf2)s.org" % { "conf1": self.greeterConf, "conf2": self.greeterConf }, 'LightDMManager.main', 'debug') if not exists("%s.org" % self.lightdmConf): copy(self.lightdmConf, "%s.org" % self.lightdmConf) self.log.write( "%(conf1)s copied to %(conf2)s.org" % { "conf1": self.lightdmConf, "conf2": self.lightdmConf }, 'LightDMManager.main', 'debug') # Initiate the treeview handler and connect the custom toggle event with usersCheckBoxToggled self.tvHandler = TreeViewHandler(self.tvUsers, self.log) self.tvHandler.connect('checkbox-toggled', self.usersCheckBoxToggled) # Get users self.users = self.usr.getUsers() self.fillUsers() self.tvHandler.selectValue(self.curUser, 1) self.setBackground(self.curBgPath) self.cmbHandlerThemes = ComboBoxHandler(self.cmbThemes) self.listThemes() self.chkHideUsers.set_active(self.curHideUsers) # Show users menu self.on_btnUsers_clicked(None) self.on_tvUsers_cursor_changed(None) self.version = functions.getPackageVersion('lightdm-manager') # Connect the signals and show the window self.builder.connect_signals(self) self.window.show() # =============================================== # Menu section functions # =============================================== def on_btnUsers_clicked(self, widget, event=None): if self.selectedMenuItem != menuItems[0]: self.selectedMenuItem = menuItems[0] self.nbLightDM.set_current_page(0) def on_btnAppearance_clicked(self, widget, event=None): if self.selectedMenuItem != menuItems[1]: self.selectedMenuItem = menuItems[1] self.nbLightDM.set_current_page(1) # =============================================== # Functions # =============================================== def on_ebFace_enter_notify_event(self, widget, event): self.window.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2)) def on_ebFace_leave_notify_event(self, widget, event): self.window.get_window().set_cursor(None) def on_ebFace_button_release_event(self, widget, event): home = self.usr.getUserHomeDir(self.curUser) primaryGroup = self.usr.getUserPrimaryGroupName(self.curUser) imagePath = SelectImageDialog(_('Select user image'), home, self.window).show() if imagePath is not None: tempUserImg = "%(tempFace)s.%(curUser)s" % { "tempFace": self.tempFace, "curUser": self.curUser } self.newFaces.append( [tempUserImg, join(home, ".face"), self.curUser, primaryGroup]) print((">>> self.newFaces = %s" % self.newFaces)) ih = ImageHandler(imagePath) ih.makeFaceImage(tempUserImg) if exists(tempUserImg): self.imgFace.set_from_pixbuf(ih.pixbuf) else: # This should never happen self.imgFace.set_from_file(self.selectImg) def on_tvUsers_cursor_changed(self, widget): self.curUser = self.tvHandler.getSelectedValue(1) showFace = None if self.newFaces: for face in self.newFaces: if face[2] == self.curUser and exists(face[0]): showFace = GdkPixbuf.Pixbuf.new_from_file(face[0]) if showFace is None: showFace = self.usr.getUserFacePixbuf(self.curUser) if showFace is None: # Still no user icon found: show select image self.imgFace.set_from_file(self.selectImg) else: self.imgFace.set_from_pixbuf(showFace) def on_btnSave_clicked(self, widget): saved = False saveHideUsers = False saveAutoUser = False saveFaces = False saveBackground = False saveTheme = False if self.chkHideUsers.get_active() != self.curHideUsers: saveHideUsers = True if self.curAutoUser != self.newAutoUser: saveAutoUser = True if self.newFaces: saveFaces = True if self.curBgPath != self.newbgImg: saveBackground = True self.newTheme = self.cmbHandlerThemes.getValue() if self.curTheme != self.newTheme: saveTheme = True if saveHideUsers or saveAutoUser or saveFaces or saveBackground or saveTheme: qd = QuestionDialog( _("LightDM settings"), _("Settings have changed\n\nDo you want to save the new settings?" ), self.window) answer = qd.show() if answer: if saveAutoUser: if self.newAutoUser is not None: # Save the auto-login user self.cfgLightdm.setValue('SeatDefaults', 'autologin-user', self.newAutoUser) self.cfgLightdm.setValue('SeatDefaults', 'autologin-user-timeout', '0') self.curAutoUser = self.newAutoUser self.log.write( "New auto-login user: %(usr)s" % {"usr": self.curAutoUser}, 'LightDMManager.saveSettings', 'debug') else: self.cfgLightdm.removeOption('SeatDefaults', 'autologin-user') self.cfgLightdm.removeOption('SeatDefaults', 'autologin-user-timeout') self.curAutoUser = None self.log.write("Auto-login disabled", 'LightDMManager.saveSettings', 'debug') if saveHideUsers: hideUsers = str(self.chkHideUsers.get_active()).lower() self.cfgLightdm.setValue('SeatDefaults', 'greeter-hide-users', hideUsers) self.log.write( "Hide users saved: %(users)s" % {"users": hideUsers}, 'LightDMManager.saveSettings', 'debug') if saveFaces: for face in self.newFaces: if exists(face[0]): copy(face[0], face[1]) if exists(face[1]): os.system( "chown %(owner)s:%(group)s %(path)s" % { "owner": face[2], "group": face[3], "path": face[1] }) self.log.write("User icons saved", 'LightDMManager.saveSettings', 'debug') if saveTheme: self.cfgGreeter.setValue('greeter', 'theme-name', self.newTheme) self.curTheme = self.newTheme self.log.write( "Theme saved: %(theme)s" % {"theme": self.curTheme}, 'LightDMManager.saveSettings', 'debug') if saveBackground: if os.path.exists(self.newbgImg): self.cfgGreeter.setValue('greeter', 'background', self.newbgImg) self.curBgPath = self.newbgImg self.log.write( "Background saved: %(background)s" % {"background": self.curBgPath}, 'LightDMManager.saveSettings', 'debug') saved = True else: if os.path.exists(self.curBgPath): self.setBackground(self.curBgPath) self.log.write( "Current background: %(background)s" % {"background": self.curBgPath}, 'LightDMManager.saveSettings', 'debug') else: self.imgBackground.set_from_file( join(self.scriptDir, '../../share/lightdm-manager/select.png')) self.log.write("No background set", 'LightDMManager.saveSettings', 'debug') self.fillUsers() if saved: self.curHideUsers = self.chkHideUsers.get_active() self.curAutoUser = self.newAutoUser self.newFaces = [] self.curBgPath = self.newbgImg self.curTheme = self.newTheme MessageDialogSafe(_("Saved"), _("LightDM settings saved successfully."), Gtk.MessageType.INFO, self.window).show() def on_ebBackground_button_release_event(self, widget, event): self.newbgImg = SelectImageDialog(_("Choose background image"), self.desktopbaseDir, self.window).show() if exists(self.newbgImg) and self.newbgImg != self.curBgPath: self.setBackground(self.newbgImg) self.log.write( _("New background: %(bg)s") % {"bg": self.newbgImg}, 'LightDMManager.chooseFile', 'info') def on_ebBackground_enter_notify_event(self, widget, event): self.window.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2)) def on_ebBackground_leave_notify_event(self, widget, event): self.window.get_window().set_cursor(None) # This method is fired by the TreeView.checkbox-toggled event def usersCheckBoxToggled(self, obj, path, colNr, toggleValue): path = int(path) model = self.tvUsers.get_model() itr = model.get_iter(path) user = model[itr][1] if self.prevPath != path or toggleValue: # Only one toggle box can be selected (or none) self.tvHandler.treeviewToggleAll([0], False, 1, user) # Save current path self.prevPath = path # Save selected user self.newAutoUser = user self.log.write( _("Auto-login user selected: %(usr)s") % {"usr": user}, 'LightDMManager.usersCheckBoxToggled', 'info') elif self.prevPath == path and not toggleValue: self.newAutoUser = None def listThemes(self): themeDir = '/usr/share/themes' themeDirLocal = '~/.local/share/themes' dirs = functions.locate('gtk-*', themeDir, True) + functions.locate( 'gtk-*', themeDirLocal, True) for path in dirs: dirList = path.split('/') for d in dirList: if 'gtk-' in d: break themeName = d if themeName not in self.themes: self.themes.append(themeName) if self.themes: self.cmbHandlerThemes.fillComboBox(self.themes) if self.curTheme in self.themes: self.cmbHandlerThemes.selectValue(self.curTheme) def fillUsers(self): selUsr = False contentList = [] i = 0 for usr in self.users: if usr == self.curAutoUser: selUsr = True self.prevPath = i else: selUsr = False contentList.append([selUsr, usr]) i += 1 # Fill treeview with users #fillTreeview(contentList, columnTypesList, columnHideList=[-1], setCursor=0, setCursorWeight=400, firstItemIsColName=False, appendToExisting=False, appendToTop=False) columnTypesList = ['bool', 'str'] self.tvHandler.fillTreeview(contentList, columnTypesList) def setBackground(self, path): # Set Background if path is not None: if exists(path): ih = ImageHandler(path) ih.resizeImage(height=200) self.imgBackground.set_from_pixbuf(ih.pixbuf) else: self.imgBackground.set_from_file(self.selectImg) else: self.imgBackground.set_from_file(self.selectImg) # =============================================== # General functions # =============================================== def on_ldmWindow_destroy(self, widget, data=None): # Close the app self.on_btnSave_clicked(None) for tmp in self.newFaces: os.remove(tmp[0]) Gtk.main_quit()
class UpdateManager(object): def __init__(self): # Check if script is running self.scriptName = basename(__file__) self.umglobal = UmGlobal() self.user = self.umglobal.getLoginName() # Initiate logging self.logFile = join('/var/log', self.umglobal.settings['log']) print(("UM log = %s" % self.logFile)) self.log = Logger(self.logFile, maxSizeKB=5120) # Remove scripts self.deleteScripts(self.umglobal.localUpdVersion) # Initialize self.ec = ExecCmd(loggerObject=self.log) self.apt = UmApt(self.umglobal) self.kernelVersion = self.umglobal.getKernelVersion() self.upgradables = [] self.upgradableUM = [] self.window = None # Handle arguments parser = argparse.ArgumentParser(description='SolydXK Update Manager') parser.add_argument('-q','--quick', action="store_true", help='Quick upgrade') parser.add_argument('-r','--reload', action="store_true", help='') args, extra = parser.parse_known_args() self.quickUpdate = False if args.quick and not self.umglobal.newUpd: self.quickUpdate = True if args.reload: pids = self.umglobal.getProcessPids("updatemanager.py") if len(pids) > 1: print(("updatemanager.py already running - kill pid {}".format(pids[0]))) os.system("kill {}".format(pids[0])) # Set some global translations self.aptErrorText = _("Apt error") self.upgradablePackagesText = _("The following packages will be upgraded:") self.newPackagesText = _("The following NEW packages will be installed:") self.removedPackagesText = _("The following packages will be REMOVED:") self.heldbackPackagesText = _("The following packages have been kept back:") self.downgradePackagesText = _("The following packages are going to be downgraded:") # Cleanup first for fle in glob(join(self.umglobal.filesDir, '.um*')): remove(fle) # Load window and widgets self.builder = Gtk.Builder() self.builder.add_from_file(join(self.umglobal.shareDir, 'updatemanager.glade')) go = self.builder.get_object # Quick update if self.quickUpdate: # Refresh data self.refresh() self.umglobal.collectData() self.apt.createPackagesInfoList() self.apt.createPackageLists() self.fillTreeView() # Run upgrade nid = self.run_upgrade() if nid != "": self.on_command_done(None, 0, nid) sys.exit(2) # Make sure the files directory is set correctly self.checkFilesDir() # Main window objects self.window = go("windowMain") #self.window.set_icon_from_file(join(self.umglobal.iconsDir, self.umglobal.settings["icon-connected"])) self.tvPck = go("tvPck") self.swTerminal = go("swTerminal") self.statusbar = go("statusbar") self.btnInstall = go("btnInstall") self.btnRefresh = go("btnRefresh") self.btnPackages = go("btnPackages") self.btnOutput = go("btnOutput") self.btnInfo = go("btnInfo") self.btnPreferences = go("btnPreferences") self.nbMain = go("nbMain") self.swInfo = go("swInfo") self.btnMaintenance = go("btnMaintenance") self.lblMaintenance = go("lblMaintenance") self.tvMaintenance = go("tvMaintenance") self.btnMaintenanceExecute = go("btnMaintenanceExecute") self.chkMaintenanceSelectAll = go("chkMaintenanceSelectAll") self.radUnneeded = go("radUnneeded") self.radCleanCache = go("radCleanCache") self.radDowngradable = go("radDowngradable") self.radNotavailable = go("radNotavailable") self.radOldKernel = go("radOldKernel") self.lblMaintenanceHelp = go("lblMaintenanceHelp") # Translations self.window.set_title(_("SolydXK Update Manager")) self.btnInstall.set_label(_("Install")) self.btnRefresh.set_label(_("Refresh")) self.btnOutput.set_label(_("Output")) self.btnInfo.set_label(_("Information")) self.btnPreferences.set_label(_("Preferences")) self.btnMaintenance.set_label(_("Maintenance")) self.btnPackages.set_label(_("Packages")) self.uptodateText = self.umglobal.connectedText self.lblMaintenance.set_label(self.btnMaintenance.get_label()) self.btnMaintenanceExecute.set_label(_("Execute")) self.chkMaintenanceSelectAll.set_label(_("Select all")) self.radCleanCache.set_label(_("Clean up the apt cache")) self.radUnneeded.set_label(_("Remove unneeded packages")) self.radNotavailable.set_label(_("Remove packages not available\nin the repositories")) self.radOldKernel.set_label(_("Remove old kernels")) self.radDowngradable.set_label(_("Downgrade packages with\nonly lower versions available")) self.lblMaintenanceHelp.set_label(_("Make sure you create\n" "a system image before you\n" "continue (e.g. Clonezilla).")) # VTE Terminal self.terminal = VirtualTerminal(userInputAllowed=self.umglobal.settings["allow-terminal-user-input"]) self.swTerminal.add(self.terminal) self.terminal.set_vexpand(True) self.terminal.set_hexpand(True) self.terminal.connect('command-done', self.on_command_done) self.terminal.connect('line-added', self.on_line_added) palletList = ['#4A4A4A', '#BD1919', '#118011', '#CE6800', '#1919BC', '#8D138D', '#139494', '#A7A7A7'] self.terminal.setTerminalColors("#000000", "#FFFFFF", palletList) self.swTerminal.modify_bg(Gtk.StateType.NORMAL, Gdk.color_parse("#FFFFFF")) # Disable all buttons self.btnInfo.set_sensitive(False) self.btnPreferences.set_sensitive(False) self.btnOutput.set_sensitive(False) self.btnRefresh.set_sensitive(False) self.btnInstall.set_sensitive(False) self.btnPackages.set_sensitive(False) self.btnMaintenance.set_sensitive(False) # Hide tabs if needed for tab in self.umglobal.settings["hide-tabs"]: if tab == "packages": self.nbMain.get_nth_page(0).set_visible(False) self.btnPackages.set_visible(False) elif tab == "output": self.nbMain.get_nth_page(1).set_visible(False) self.btnOutput.set_visible(False) elif tab == "info": self.nbMain.get_nth_page(2).set_visible(False) self.btnInfo.set_visible(False) elif tab == "maintenance": self.nbMain.get_nth_page(3).set_visible(False) self.btnMaintenance.set_visible(False) # Connect the signals and show the window self.builder.connect_signals(self) self.window.show() # Force the window to show while Gtk.events_pending(): Gtk.main_iteration() # Just show something that we're busy msg = _("Gathering information...") self.terminal.executeCommand('echo "%s"' % msg, 'init') self.showOutput() # Treeview handlers self.tvHandler = TreeViewHandler(self.tvPck) self.tvMaintenanceHandler = TreeViewHandler(self.tvMaintenance) # Version information ver = _("Version") pckVer = self.apt.getPackageVersion('updatemanager') versionInfo = "%(ver)s: %(pckVer)s" % { "ver": ver, "pckVer": pckVer } if self.umglobal.localUpdVersion != "2000.01.01": versionInfo = "%(ver)s: %(pckVer)s" % { "ver": ver, "pckVer": pckVer } self.pushMessage(versionInfo) # Log basic information self.log.write("==============================================", "UM.init", "debug") self.log.write("UM version = %s" % versionInfo, "UM.init", "debug") self.log.write("==============================================", "UM.init", "debug") mirrorsList = join(self.umglobal.filesDir, basename(self.umglobal.settings["mirrors-list"])) if exists(mirrorsList): self.log.write("Mirrors list", "UM.init", "debug") with open(mirrorsList, 'r') as f: for line in f.readlines(): self.log.write(line, "UM.init", "debug") self.log.write("==============================================", "UM.init", "debug") # Refresh apt cache self.refresh() # Initialize maintenance screen self.fillTreeViewMaintenance() # =============================================== # Main window functions # =============================================== def on_btnInstall_clicked(self, widget): self.run_upgrade() def run_upgrade(self): nid = "" aptHasErrors = self.apt.aptHasErrors() if aptHasErrors is not None: MessageDialog(self.aptErrorText, aptHasErrors) elif self.upgradables: if self.apt.upgradablePackages: self.log.write("=================== upgradable pacages ====================", "UM.run_upgrade", "debug") self.log.write(self.createLogString(self.apt.upgradablePackages), "UM.run_upgrade", "debug") if self.apt.removedPackages: self.log.write("==================== removed packages =====================", "UM.run_upgrade", "debug") self.log.write(self.createLogString(self.apt.removedPackages), "UM.run_upgrade", "debug") if self.apt.newPackages: self.log.write("======================= new packages =======================", "UM.run_upgrade", "debug") self.log.write(self.createLogString(self.apt.newPackages), "UM.run_upgrade", "debug") if self.apt.heldbackPackages: self.log.write("=================== kept back packages =====================", "UM.run_upgrade", "debug") self.log.write(self.createLogString(self.apt.heldbackPackages), "UM.run_upgrade", "debug") if not self.quickUpdate: self.showOutput() contMsg = _("Continue installation?") if self.upgradableUM: cmd = "%s install updatemanager" % self.umglobal.settings['apt-get-string'] cmd += "; %s install %s" % (self.umglobal.settings['apt-get-string'], " ".join(self.apt.getPackageDependencies('updatemanager'))) nid = 'uminstallum' self.prepForCommand(nid) if self.quickUpdate: self.ec.run(cmd) else: self.terminal.executeCommand(cmd, nid) self.log.write("Execute command: %s (%s)" % (cmd, nid), "UM.on_btnInstall_clicked", "debug") else: msg = self.getDistUpgradeInfo() answer = True if msg != "": answer = self.showConfirmationDlg(contMsg, msg) if answer: cmd = "%s dist-upgrade" % self.umglobal.settings['apt-get-string'] #if self.umglobal.newUpd: pre = join(self.umglobal.filesDir, self.umglobal.settings['pre-upd'].replace("[VERSION]", self.umglobal.serverUpdVersion)) post = join(self.umglobal.filesDir, self.umglobal.settings['post-upd'].replace("[VERSION]", self.umglobal.serverUpdVersion)) if exists(pre): cmd = "/bin/bash %(pre)s; %(cmd)s" % { "pre": pre, "cmd": cmd } if exists(post): cmd = "%(cmd)s; /bin/bash %(post)s" % { "cmd": cmd, "post": post } nid = 'umupd' self.prepForCommand(nid) if self.quickUpdate: self.ec.run(cmd) else: self.terminal.executeCommand(cmd, nid) self.log.write("Execute command: %s (%s)" % (cmd, nid), "UM.on_btnInstall_clicked", "debug") else: if not self.quickUpdate: MessageDialog(self.btnInstall.get_label(), self.uptodateText) return nid def on_btnRefresh_clicked(self, widget): self.refresh() def on_btnPackages_clicked(self, widget): self.showPackages() def on_btnOutput_clicked(self, widget): self.showOutput() def on_btnInfo_clicked(self, widget): self.showInfo() def on_btnPreferences_clicked(self, widget): # Run preferences in its own thread pref_thread = threading.Thread(target=self.openPreferences) pref_thread.setDaemon(True) pref_thread.start() def openPreferences(self): os.system("updatemanager -p") def on_btnMaintenance_clicked(self, widget): self.showMaintenance() def on_radCleanCache_toggled(self, widget): if widget.get_active(): self.fillTreeViewMaintenance() def on_radUnneeded_toggled(self, widget): if widget.get_active(): message = "%s\n\n%s" % (_("You might need to run this several times."), self.lblMaintenanceHelp.get_label().replace("\n", " ")) WarningDialog(self.btnMaintenance.get_label(), message) self.fillTreeViewMaintenance() def on_radNotavailable_toggled(self, widget): if widget.get_active(): message = "%s\n\n%s" % (_("Removing not available packages may break your system!"), self.lblMaintenanceHelp.get_label().replace("\n", " ")) WarningDialog(self.btnMaintenance.get_label(), message) self.fillTreeViewMaintenance() def on_radOldKernel_toggled(self, widget): if widget.get_active(): message = "%s\n\n%s" % (_("Once removed you will not be able to boot these kernels!"), self.lblMaintenanceHelp.get_label().replace("\n", " ")) WarningDialog(self.btnMaintenance.get_label(), message) self.fillTreeViewMaintenance() def on_radDowngradable_toggled(self, widget): if widget.get_active(): message = "%s\n\n%s" % (_("Downgrading packages may break your system!"), self.lblMaintenanceHelp.get_label().replace("\n", " ")) WarningDialog(self.btnMaintenance.get_label(), message) self.fillTreeViewMaintenance() def on_btnMaintenanceExecute_clicked(self, widget): self.executeMaintenance() def on_chkMaintenanceSelectAll_toggled(self, widget): self.tvMaintenanceHandler.treeviewToggleAll(toggleColNrList=[0], toggleValue=widget.get_active()) # =============================================== # Maintenance functions # =============================================== def enableMaintenance(self, enable=True): self.btnMaintenanceExecute.set_sensitive(enable) self.radUnneeded.set_sensitive(enable) self.radCleanCache.set_sensitive(enable) self.radDowngradable.set_sensitive(enable) self.radOldKernel.set_sensitive(enable) self.radNotavailable.set_sensitive(enable) self.chkMaintenanceSelectAll.set_sensitive(enable) if enable: self.chkMaintenanceSelectAll.set_active(False) def fillTreeViewMaintenance(self): blnCleanCache = self.radCleanCache.get_active() blnUnneeded = self.radUnneeded.get_active() blnDowngradable = self.radDowngradable.get_active() blnNotavailable = self.radNotavailable.get_active() blnOldKernels = self.radOldKernel.get_active() self.enableMaintenance(False) columnTypesList = ['bool', 'str', 'str', 'str'] packages = [["", _("Package"), _("Installed"), _("Available")]] # Clear the treeview first self.tvMaintenanceHandler.fillTreeview(packages, columnTypesList, 0, 400, True) msg = "" if blnCleanCache: msg = _("Hit the Execute button to clean the cache.") columnTypesList = ['str'] packages.append([msg]) elif blnUnneeded: msg = self.radUnneeded.get_label() self.apt.createPackageLists("apt-get autoremove") for pck in self.apt.removedPackages: packages.append([False, pck[0], pck[1], pck[2]]) self.apt.createPackageLists() # Add orphaned files self.apt.fillOrphanedPackages() for pck in self.apt.orphanedPackages: packages.append([False, pck[0], pck[1], pck[2]]) elif blnNotavailable: msg = self.radNotavailable.get_label() self.apt.fillNotAvailablePackages() for pck in self.apt.notavailablePackages: if pck[0][0:6] != "linux-": packages.append([False, pck[0], pck[1], ""]) elif blnOldKernels: msg = self.radOldKernel.get_label() self.apt.fillKernelPackages() for pck in self.apt.kernelPackages: if "headers-486" not in pck[0] \ and "headers-586" not in pck[0] \ and "headers-686" not in pck[0] \ and "headers-amd64" not in pck[0] \ and "image-486" not in pck[0] \ and "image-586" not in pck[0] \ and "image-686" not in pck[0] \ and "image-amd64" not in pck[0]: checkVersion = self.kernelVersion if "kbuild" in pck[0]: indMinus = self.kernelVersion.index("-") indZero = self.kernelVersion.index("0") if indZero > 0 and indZero < indMinus: ind = indZero - 1 else: ind = indMinus if ind > 0: checkVersion = self.kernelVersion[0:ind] if checkVersion not in pck[0]: packages.append([False, pck[0], pck[1], ""]) elif blnDowngradable: msg = self.radDowngradable.get_label() self.apt.fillDowngradablePackages() for pck in self.apt.downgradablePackages: packages.append([False, pck[0], pck[1], pck[2]]) if len(packages) > 1: self.tvMaintenanceHandler.fillTreeview(packages, columnTypesList, 0, 400, True) else: if not blnCleanCache: msg = _("\"%s\"\n did not return any results.") % msg MessageDialog(self.btnMaintenance.get_label(), msg) self.enableMaintenance(True) def executeMaintenance(self): blnCleanCache = self.radCleanCache.get_active() blnDowngradable = self.radDowngradable.get_active() blnNotNeeded = self.radUnneeded.get_active() downgradeString = "" deleteString = "" updateGrub = False cmd = "" self.enableMaintenance(False) if blnCleanCache: safe = False msg = _("Do you want to completely clean the apt cache?\n\n" "When No, only unavailable installation packages are removed.") answer = QuestionDialog(self.radCleanCache.get_label(), msg) if answer: safe = True self.apt.cleanCache(safe) msg = _("Apt cache has been cleaned.") MessageDialog(self.radCleanCache.get_label(), msg) else: # Get user selected packages model = self.tvMaintenance.get_model() itr = model.get_iter_first() while itr is not None: sel = model.get_value(itr, 0) if sel: pck = model.get_value(itr, 1) avVer = model.get_value(itr, 3) if blnDowngradable: downgradeString += " %(pck)s=%(avVer)s" % {"pck": pck, "avVer": avVer} else: deleteString += " %s" % pck if "linux-image" in pck: updateGrub = True itr = model.iter_next(itr) if downgradeString != "": cmd = "%s install %s" % (self.umglobal.settings['apt-get-string'], downgradeString) elif deleteString != "": cmd = "%s purge %s" % (self.umglobal.settings['apt-get-string'], deleteString) if cmd != "": self.apt.createPackageLists(cmd) msg = self.getDistUpgradeInfo() answer = True if msg != "": contMsg = _("Execute maintenance changes?") answer = self.showConfirmationDlg(contMsg, msg) if answer: if updateGrub: cmd += "; update-grub" if blnNotNeeded: cmd += "; %s purge $(COLUMNS=132 dpkg -l | grep ^rc | awk '{ print $2 }')" % self.umglobal.settings['apt-get-string'] self.showOutput() nid = 'ummaintenance' self.prepForCommand(nid) self.terminal.executeCommand(cmd, nid) self.log.write("Execute command: %s (%s)" % (cmd, nid), "UM.executeMaintenance", "debug") self.enableMaintenance(True) # =============================================== # General functions # =============================================== def prepForCommand(self, nid): os.system("touch %s" % self.umglobal.umfiles[nid]) if not self.quickUpdate: self.btnRefresh.set_sensitive(False) self.btnInstall.set_sensitive(False) self.btnMaintenance.set_sensitive(False) def on_line_added(self, terminal, line): if line.strip()[0:2].upper() == "E:": self.log.write(line, "UM.on_line_added", "error") else: self.log.write(line, "UM.on_line_added", "info") def on_command_done(self, terminal, pid, nid): if nid != "init": self.log.write("Command finished (pid=%s, nid=%s)" % (pid, nid), "UM.on_command_done", "info") if nid == "uminstallum": # Reload UM self.log.write("Updating UM: kill process of updatemanagerpref.py", "UM.on_command_done", "debug") self.umglobal.killScriptProcess("updatemanagerpref.py") # Reload tray as user self.log.write("Updating UM: kill process of updatemanagertray.py", "UM.on_command_done", "debug") self.umglobal.killScriptProcess("updatemanagertray.py") cmd = "sudo -u {} updatemanager -t -r".format(self.user) os.system(cmd) self.log.write("UM updated: reload tray as user {}".format(self.user), "UM.on_command_done", "debug") # Reload UM window cmd = join(self.umglobal.scriptDir, "updatemanager.py") if self.quickUpdate: cmd = join(self.umglobal.scriptDir, "updatemanager.py -q") self.umglobal.reloadWindow(cmd, self.user) self.log.write("UM updated: reload {0} as user {1}".format(cmd, self.user), "UM.on_command_done", "debug") elif nid == "umrefresh": # Build installed packages info list self.apt.createPackagesInfoList() # Run post update when needed self.postUpdate() elif nid == "ummaintenance": self.enableMaintenance(True) self.fillTreeViewMaintenance() self.btnInstall.set_sensitive(True) self.btnRefresh.set_sensitive(True) self.btnPackages.set_sensitive(True) self.btnMaintenance.set_sensitive(True) self.showMaintenance() elif nid == 'umupd': # Save update version in hist file self.umglobal.saveHistVersion("upd", self.umglobal.serverUpdVersion) self.log.write("Save history upd=%s" % self.umglobal.serverUpdVersion, "UM.on_command_done", "debug") self.deleteScripts() # Refresh data after install or update self.umglobal.collectData() self.apt.createPackageLists() self.fillTreeView() # Enable the buttons and load the info page self.log.write("Re-initiate window after terminal command: %s" % str(not self.quickUpdate), "UM.on_command_done", "debug") if not self.quickUpdate: self.btnInstall.set_sensitive(True) self.btnRefresh.set_sensitive(True) self.btnPackages.set_sensitive(True) self.btnMaintenance.set_sensitive(True) self.btnInfo.set_sensitive(True) self.loadInfo() if self.umglobal.newUpd: self.showInfo() else: # This throws a lock file error in Plasma5 #aptHasErrors = self.apt.aptHasErrors() #if aptHasErrors is not None: #MessageDialog(self.aptErrorText, aptHasErrors) #el if self.upgradables: self.showPackages() else: self.showInfo() MessageDialog(self.btnInfo.get_label(), self.uptodateText) self.log.write("Re-initiate window complete", "UM.on_command_done", "debug") # Cleanup name file(s) for fle in glob(join(self.umglobal.filesDir, '.um*')): remove(fle) def createLogString(self, packagesList): lst = [] for data in packagesList: lst.append(data[0]) return ' '.join(lst) def refresh(self): # Refresh server info print((self.umglobal.hasInternet)) self.umglobal.getServerInfo() print((self.umglobal.hasInternet)) # Check of programs locking apt prog = self.apt.getAptCacheLockedProgram(self.umglobal.settings["apt-packages"]) if prog is not None: msg = _("Another program is locking the apt cache\n\n" "Please, close the program before refreshing:\n" "* %s" % prog) MessageDialog(self.btnRefresh.get_label(), msg) self.log.write("%s is locking the apt cache" % prog, "UM.refresh", "warning") elif self.umglobal.hasInternet: if not self.quickUpdate: # Update the apt cache self.btnPreferences.set_sensitive(True) self.btnOutput.set_sensitive(True) self.btnRefresh.set_sensitive(False) self.btnInstall.set_sensitive(False) self.btnMaintenance.set_sensitive(False) self.btnPackages.set_sensitive(True) self.showOutput() cmd = "dpkg --configure -a; %s -f install; apt-get update" % self.umglobal.settings['apt-get-string'] nid = 'umrefresh' self.prepForCommand(nid) if self.quickUpdate: self.ec.run(cmd) else: self.terminal.executeCommand(cmd, nid) self.apt.initAptShowVersions() self.log.write("Execute command: %s (%s)" % (cmd, nid), "UM.refresh", "debug") else: if not self.quickUpdate: # No internet connection self.btnInstall.set_sensitive(True) self.btnRefresh.set_sensitive(True) self.btnPackages.set_sensitive(True) self.btnMaintenance.set_sensitive(True) self.btnInfo.set_sensitive(True) self.btnOutput.set_sensitive(True) self.btnPreferences.set_sensitive(True) self.loadInfo() self.showInfo() def postUpdate(self): # Check for changed version information if self.umglobal.newUpd and self.umglobal.serverUpdVersion is not None: self.getScripts([self.umglobal.settings['pre-upd'].replace("[VERSION]", self.umglobal.serverUpdVersion), self.umglobal.settings['post-upd'].replace("[VERSION]", self.umglobal.serverUpdVersion)]) def fillTreeView(self): # First check if this application is upgradable self.upgradableUM = self.getUpgradablePackages(packageNames=["updatemanager"]) if self.upgradableUM: self.upgradables = self.upgradableUM else: # Get a list of packages that can be upgraded self.upgradableUM = [] self.upgradables = self.getUpgradablePackages() #if not self.upgradables: ## Check for black listed packages #cmd = "dpkg --get-selections | grep hold$ | awk '{print $1}'" #lst = self.ec.run(cmd, False) #for pck in lst: #self.upgradables.append([pck.strip(), _("blacklisted"), ""]) if not self.quickUpdate: contentList = [[_("Package"), _("Current version"), _("New version")]] + self.upgradables self.tvHandler.fillTreeview(contentList=contentList, columnTypesList=['str', 'str', 'str'], firstItemIsColName=True) def getUpgradablePackages(self, packageNames=[]): upckList = [] if packageNames: upckList = [] for packageName in packageNames: for upck in self.apt.upgradablePackages: if upck[0] == packageName: upckList.append(upck) break else: upckList = self.apt.upgradablePackages return upckList def getDistUpgradeInfo(self, upgradablesOnly=False): info = "" if upgradablesOnly: if self.apt.upgradablePackages: info = "<strong>%s</strong><br>" % self.apt.upgradablePackagesText for pck in self.apt.upgradablePackages: info += "%s " % pck[0] else: if self.apt.removedPackages: info = "<strong>%s</strong><br>" % self.removedPackagesText for pck in self.apt.removedPackages: info += "%s " % pck[0] if self.apt.newPackages: if info != "": info += "<p> </p>" info += "<strong>%s</strong><br>" % self.newPackagesText for pck in self.apt.newPackages: info += "%s " % pck[0] if self.apt.heldbackPackages: if info != "": info += "<p> </p>" info += "<strong>%s</strong><br>" % self.heldbackPackagesText for pck in self.apt.heldbackPackages: info += "%s " % pck[0] if self.apt.downgradablePackages: if info != "": info += "<p> </p>" info += "<strong>%s</strong><br>" % self.downgradePackagesText for pck in self.apt.downgradablePackages: info += "%s " % pck[0] return info def showPackages(self): self.nbMain.set_current_page(0) def showOutput(self): self.nbMain.set_current_page(1) self.terminal.grab_focus() def showInfo(self): self.nbMain.set_current_page(2) def showMaintenance(self): self.nbMain.set_current_page(3) def showConfirmationDlg(self, title, message): head = "<html><head><style>body { font-family: Arial, Helvetica, Verdana, Sans-serif; font-size: 12px; color: #555555; background: #ffffff; }</style></head><body>" end = "</body></html>" html = "%s%s%s" % (head, message, end) sw = Gtk.ScrolledWindow() sw.add(SimpleBrowser(html)) return CustomQuestionDialog(title, sw, 550, 300, self.window).show() # Get pre-install script and post-install script from the server def getScripts(self, files): for fle in files: flePath = join(self.umglobal.filesDir, fle) if not exists(flePath): # Get the new scripts if they exist url = "%s/%s/%s" % (self.umglobal.settings['solydxk'], self.umglobal.settings["umfilesdir"], fle) try: txt = urlopen(url).read().decode('utf-8') if txt != '': # Save to a file and make executable self.log.write("Save script = %s" % flePath, "UM.getScripts", "debug") with open(flePath, 'w') as f: f.write(txt) chmod(flePath, 0o755) except: pass def loadInfo(self): languageDir = self.get_language_dir() url = join("file://%s" % languageDir, self.umglobal.settings['up-to-date']) self.btnInfo.set_icon_name("help-about") if self.upgradables: url = join("file://%s" % languageDir, self.umglobal.settings['updates']) if self.umglobal.newUpd: url = "%s/%s/%s" % (self.umglobal.settings['solydxk'], self.umglobal.settings["umfilesdir"], self.umglobal.settings['upd-info']) elif self.umglobal.serverUpdVersion is None: url = join("file://%s" % languageDir, self.umglobal.settings['not-found']) self.log.write("Load info url: %s" % url, "UM.loadInfo", "debug") children = self.swInfo.get_children() if children: children[0].openUrl(url) else: self.swInfo.add(SimpleBrowser(url)) def get_language_dir(self): # First test if full locale directory exists, e.g. html/pt_BR, # otherwise perhaps at least the language is there, e.g. html/pt # and if that doesn't work, try html/pt_PT lang = self.get_current_language() path = join(self.umglobal.htmlDir, lang) if not isdir(path): base_lang = lang.split('_')[0].lower() path = join(self.umglobal.htmlDir, base_lang) if not isdir(path): path = join(self.umglobal.htmlDir, "{}_{}".format(base_lang, base_lang.upper())) if not isdir(path): path = join(self.umglobal.htmlDir, 'en') return path def get_current_language(self): lang = os.environ.get('LANG', 'US').split('.')[0] if lang == '': lang = 'en' return lang def pushMessage(self, message): if message is not None: context = self.statusbar.get_context_id('message') self.statusbar.push(context, message) def checkFilesDir(self): if not exists(self.umglobal.filesDir): makedirs(self.umglobal.filesDir) oldFiles = glob(join(self.umglobal.scriptDir, 'pre-*')) + \ glob(join(self.umglobal.scriptDir, 'post-*')) + \ [join(self.umglobal.scriptDir, 'updatemanager.hist')] + \ [join(self.umglobal.scriptDir, 'mirrors.list')] for fle in oldFiles: if exists(fle): fleName = basename(fle) if not exists(join(self.umglobal.filesDir, fleName)): move(fle, self.umglobal.filesDir) else: remove(fle) chmod(self.umglobal.filesDir, 0o777) def deleteScripts(self, UpdVersion=None): UpdVersion = "*" if UpdVersion is not None: UpdVersion = "*%s" % UpdVersion oldFiles = glob(join(self.umglobal.filesDir, "pre-%s" % UpdVersion)) + glob(join(self.umglobal.filesDir, "post-%s" % UpdVersion)) for fle in oldFiles: remove(fle) self.log.write("Cleanup file: %s" % fle, "UM.deleteScripts", "debug") # Close the gui def on_windowMain_destroy(self, widget): # Close the app Gtk.main_quit()
class LightDMManager: def __init__(self): self.scriptDir = os.path.dirname(os.path.realpath(__file__)) # Load window and widgets self.builder = Gtk.Builder() self.builder.add_from_file(join(self.scriptDir, '../../share/lightdm-manager/lightdm-manager.glade')) # Main window objects go = self.builder.get_object self.window = go('ldmWindow') self.swUsers = go('swUsers') self.tvUsers = go('tvUsers') self.btnSave = go('btnSave') self.imgBackground = go('imgBackground') self.btnUsers = go('btnUsers') self.btnAppearance = go('btnAppearance') self.chkHideUsers = go('chkHideUsers') self.ebFace = go('ebFace') self.imgFace = go('imgFace') self.nbLightDM = go('nbLightDM') self.cmbThemes = go('cmbThemes') # Read from config file self.cfg = Config('lightdm-manager.conf') self.lightdmConf = self.cfg.getValue('CONFIG', 'lightdmConf') self.desktopbaseDir = self.cfg.getValue('CONFIG', 'desktopbaseDir') gktGreeterConf = self.cfg.getValue('CONFIG', 'gtkGreeterConf') kdeGreeterConf = self.cfg.getValue('CONFIG', 'kdeGreeterConf') if exists(gktGreeterConf): self.greeterConf = gktGreeterConf else: self.greeterConf = kdeGreeterConf # Translations title = _("LightDM Manager") self.window.set_title(title) self.btnUsers.set_label("_{}".format(_("Users"))) self.btnAppearance.set_label("_{}".format(_("Appearance"))) go('lblBackground').set_label(_("Background")) go('lblTheme').set_label(_("Theme")) go('lblLightDmMenu').set_label(_("Menu")) self.chkHideUsers.set_label(_("Hide users")) go('lblUsersFace').set_label(_("User icon")) go('lblUsersAutologin').set_label(_("Auto-login")) # Get current background image self.cfgGreeter = Config(self.greeterConf) try: self.curBgPath = self.cfgGreeter.getValue('greeter', 'background') self.curTheme = self.cfgGreeter.getValue('greeter', 'theme-name') except: self.curBgPath = None self.curTheme = None # Get current auto-login user self.cfgLightdm = Config(self.lightdmConf) try: self.curAutoUser = self.cfgLightdm.getValue('SeatDefaults', 'autologin-user').strip() self.curHideUsers = False ghu = self.cfgLightdm.getValue('SeatDefaults', 'greeter-hide-users').strip() if 'true' in ghu: self.curHideUsers = True except: self.curAutoUser = None self.curHideUsers = False # Init self.usr = User() self.newbgImg = self.curBgPath self.newAutoUser = self.curAutoUser self.newTheme = self.curTheme self.themes = [] self.selectedMenuItem = None self.debug = False self.logPath = '' self.prevPath = None self.tempFace = "/tmp/face" self.newFaces = [] self.loggedUser = functions.getUserLoginName() self.curUser = self.loggedUser self.selectImg = join(self.scriptDir, '../../share/lightdm-manager/select.png') # Handle arguments try: opts, args = getopt.getopt(sys.argv[1:], 'dl:', ['debug', 'log=']) except getopt.GetoptError: print(("Arguments cannot be parsed: %s" % str(sys.argv[1:]))) sys.exit(1) for opt, arg in opts: if opt in ('-d', '--debug'): self.debug = True elif opt in ('-l', '--log'): self.logPath = arg # Initialize logging if self.debug: if not self.logPath: self.logPath = 'lightdm-manager.log' self.log = Logger(self.logPath, 'debug', True, None, self.window) # Backup config files because ConfigParser does not preserve commented lines if not exists("%s.org" % self.greeterConf): copy(self.greeterConf, "%s.org" % self.greeterConf) self.log.write("%(conf1)s copied to %(conf2)s.org" % { "conf1": self.greeterConf, "conf2": self.greeterConf }, 'LightDMManager.main', 'debug') if not exists("%s.org" % self.lightdmConf): copy(self.lightdmConf, "%s.org" % self.lightdmConf) self.log.write("%(conf1)s copied to %(conf2)s.org" % { "conf1": self.lightdmConf, "conf2": self.lightdmConf }, 'LightDMManager.main', 'debug') # Initiate the treeview handler and connect the custom toggle event with usersCheckBoxToggled self.tvHandler = TreeViewHandler(self.tvUsers, self.log) self.tvHandler.connect('checkbox-toggled', self.usersCheckBoxToggled) # Get users self.users = self.usr.getUsers() self.fillUsers() self.tvHandler.selectValue(self.curUser, 1) self.setBackground(self.curBgPath) self.cmbHandlerThemes = ComboBoxHandler(self.cmbThemes) self.listThemes() self.chkHideUsers.set_active(self.curHideUsers) # Show users menu self.on_btnUsers_clicked(None) self.on_tvUsers_cursor_changed(None) self.version = functions.getPackageVersion('lightdm-manager') # Connect the signals and show the window self.builder.connect_signals(self) self.window.show() # =============================================== # Menu section functions # =============================================== def on_btnUsers_clicked(self, widget, event=None): if self.selectedMenuItem != menuItems[0]: self.selectedMenuItem = menuItems[0] self.nbLightDM.set_current_page(0) def on_btnAppearance_clicked(self, widget, event=None): if self.selectedMenuItem != menuItems[1]: self.selectedMenuItem = menuItems[1] self.nbLightDM.set_current_page(1) # =============================================== # Functions # =============================================== def on_ebFace_enter_notify_event(self, widget, event): self.window.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2)) def on_ebFace_leave_notify_event(self, widget, event): self.window.get_window().set_cursor(None) def on_ebFace_button_release_event(self, widget, event): home = self.usr.getUserHomeDir(self.curUser) primaryGroup = self.usr.getUserPrimaryGroupName(self.curUser) imagePath = SelectImageDialog(_('Select user image'), home, self.window).show() if imagePath is not None: tempUserImg = "%(tempFace)s.%(curUser)s" % {"tempFace": self.tempFace, "curUser": self.curUser} self.newFaces.append([tempUserImg, join(home, ".face"), self.curUser, primaryGroup]) print((">>> self.newFaces = %s" % self.newFaces)) ih = ImageHandler(imagePath) ih.makeFaceImage(tempUserImg) if exists(tempUserImg): self.imgFace.set_from_pixbuf(ih.pixbuf) else: # This should never happen self.imgFace.set_from_file(self.selectImg) def on_tvUsers_cursor_changed(self, widget): self.curUser = self.tvHandler.getSelectedValue(1) showFace = None if self.newFaces: for face in self.newFaces: if face[2] == self.curUser and exists(face[0]): showFace = GdkPixbuf.Pixbuf.new_from_file(face[0]) if showFace is None: showFace = self.usr.getUserFacePixbuf(self.curUser) if showFace is None: # Still no user icon found: show select image self.imgFace.set_from_file(self.selectImg) else: self.imgFace.set_from_pixbuf(showFace) def on_btnSave_clicked(self, widget): saved = False saveHideUsers = False saveAutoUser = False saveFaces = False saveBackground = False saveTheme = False if self.chkHideUsers.get_active() != self.curHideUsers: saveHideUsers = True if self.curAutoUser != self.newAutoUser: saveAutoUser = True if self.newFaces: saveFaces = True if self.curBgPath != self.newbgImg: saveBackground = True self.newTheme = self.cmbHandlerThemes.getValue() if self.curTheme != self.newTheme: saveTheme = True if saveHideUsers or saveAutoUser or saveFaces or saveBackground or saveTheme: qd = QuestionDialog(_("LightDM settings"), _("Settings have changed\n\nDo you want to save the new settings?"), self.window) answer = qd.show() if answer: if saveAutoUser: if self.newAutoUser is not None: # Save the auto-login user self.cfgLightdm.setValue('SeatDefaults', 'autologin-user', self.newAutoUser) self.cfgLightdm.setValue('SeatDefaults', 'autologin-user-timeout', '0') self.curAutoUser = self.newAutoUser self.log.write("New auto-login user: %(usr)s" % { "usr": self.curAutoUser }, 'LightDMManager.saveSettings', 'debug') else: self.cfgLightdm.removeOption('SeatDefaults', 'autologin-user') self.cfgLightdm.removeOption('SeatDefaults', 'autologin-user-timeout') self.curAutoUser = None self.log.write("Auto-login disabled", 'LightDMManager.saveSettings', 'debug') if saveHideUsers: hideUsers = str(self.chkHideUsers.get_active()).lower() self.cfgLightdm.setValue('SeatDefaults', 'greeter-hide-users', hideUsers) self.log.write("Hide users saved: %(users)s" % {"users": hideUsers}, 'LightDMManager.saveSettings', 'debug') if saveFaces: for face in self.newFaces: if exists(face[0]): copy(face[0], face[1]) if exists(face[1]): os.system("chown %(owner)s:%(group)s %(path)s" % {"owner": face[2], "group": face[3], "path": face[1]}) self.log.write("User icons saved", 'LightDMManager.saveSettings', 'debug') if saveTheme: self.cfgGreeter.setValue('greeter', 'theme-name', self.newTheme) self.curTheme = self.newTheme self.log.write("Theme saved: %(theme)s" % { "theme": self.curTheme }, 'LightDMManager.saveSettings', 'debug') if saveBackground: if os.path.exists(self.newbgImg): self.cfgGreeter.setValue('greeter', 'background', self.newbgImg) self.curBgPath = self.newbgImg self.log.write("Background saved: %(background)s" % { "background": self.curBgPath }, 'LightDMManager.saveSettings', 'debug') saved = True else: if os.path.exists(self.curBgPath): self.setBackground(self.curBgPath) self.log.write("Current background: %(background)s" % { "background": self.curBgPath }, 'LightDMManager.saveSettings', 'debug') else: self.imgBackground.set_from_file(join(self.scriptDir, '../../share/lightdm-manager/select.png')) self.log.write("No background set", 'LightDMManager.saveSettings', 'debug') self.fillUsers() if saved: self.curHideUsers = self.chkHideUsers.get_active() self.curAutoUser = self.newAutoUser self.newFaces = [] self.curBgPath = self.newbgImg self.curTheme = self.newTheme MessageDialogSafe(_("Saved"), _("LightDM settings saved successfully."), Gtk.MessageType.INFO, self.window).show() def on_ebBackground_button_release_event(self, widget, event): self.newbgImg = SelectImageDialog(_("Choose background image"), self.desktopbaseDir, self.window).show() if exists(self.newbgImg) and self.newbgImg != self.curBgPath: self.setBackground(self.newbgImg) self.log.write(_("New background: %(bg)s") % { "bg": self.newbgImg }, 'LightDMManager.chooseFile', 'info') def on_ebBackground_enter_notify_event(self, widget, event): self.window.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2)) def on_ebBackground_leave_notify_event(self, widget, event): self.window.get_window().set_cursor(None) # This method is fired by the TreeView.checkbox-toggled event def usersCheckBoxToggled(self, obj, path, colNr, toggleValue): path = int(path) model = self.tvUsers.get_model() itr = model.get_iter(path) user = model[itr][1] if self.prevPath != path or toggleValue: # Only one toggle box can be selected (or none) self.tvHandler.treeviewToggleAll([0], False, 1, user) # Save current path self.prevPath = path # Save selected user self.newAutoUser = user self.log.write(_("Auto-login user selected: %(usr)s") % { "usr": user }, 'LightDMManager.usersCheckBoxToggled', 'info') elif self.prevPath == path and not toggleValue: self.newAutoUser = None def listThemes(self): themeDir = '/usr/share/themes' themeDirLocal = '~/.local/share/themes' dirs = functions.locate('gtk-*', themeDir, True) + functions.locate('gtk-*', themeDirLocal, True) for path in dirs: dirList = path.split('/') for d in dirList: if 'gtk-' in d: break themeName = d if themeName not in self.themes: self.themes.append(themeName) if self.themes: self.cmbHandlerThemes.fillComboBox(self.themes) if self.curTheme in self.themes: self.cmbHandlerThemes.selectValue(self.curTheme) def fillUsers(self): selUsr = False contentList = [] i = 0 for usr in self.users: if usr == self.curAutoUser: selUsr = True self.prevPath = i else: selUsr = False contentList.append([selUsr, usr]) i += 1 # Fill treeview with users #fillTreeview(contentList, columnTypesList, columnHideList=[-1], setCursor=0, setCursorWeight=400, firstItemIsColName=False, appendToExisting=False, appendToTop=False) columnTypesList = ['bool', 'str'] self.tvHandler.fillTreeview(contentList, columnTypesList) def setBackground(self, path): # Set Background if path is not None: if exists(path): ih = ImageHandler(path) ih.resizeImage(height=200) self.imgBackground.set_from_pixbuf(ih.pixbuf) else: self.imgBackground.set_from_file(self.selectImg) else: self.imgBackground.set_from_file(self.selectImg) # =============================================== # General functions # =============================================== def on_ldmWindow_destroy(self, widget, data=None): # Close the app self.on_btnSave_clicked(None) for tmp in self.newFaces: os.remove(tmp[0]) Gtk.main_quit()
class Constructor(object): def __init__(self): self.scriptDir = abspath(dirname(__file__)) self.shareDir = join(self.scriptDir, '../../../share/solydxk/constructor') self.userAppDir = join(get_user_home_dir(), ".constructor") self.distroFile = join(self.userAppDir, "distros.list") # Create the user's application directory if it doesn't exist if not isdir(self.userAppDir): user_name = getUserLoginName() makedirs(self.userAppDir) old_distro_file = join(self.scriptDir, "distros.list") if exists(old_distro_file): move(old_distro_file, self.distroFile) system("chown -R %s:%s %s" % (user_name, user_name, self.userAppDir)) # Load window and widgets self.builder = Gtk.Builder() self.builder.add_from_file(join(self.shareDir, 'constructor.glade')) # Main window objects go = self.builder.get_object self.window = go('constructorWindow') self.tvDistros = go('tvDistros') self.lblOutput = go('lblOutput') self.statusbar = go('statusbar') self.btnAdd = go('btnAdd') self.chkSelectAll = go('chkSelectAll') self.btnRemove = go('btnRemove') self.btnEdit = go('btnEdit') self.btnUpgrade = go('btnUpgrade') self.btnLocalize = go('btnLocalize') self.btnBuildIso = go('btnBuildIso') # Add iso window objects self.windowAddDistro = go('addDistroWindow') self.txtIso = go('txtIso') self.txtDir = go('txtDir') self.btnDir = go('btnDir') self.btnSave = go('btnSave') self.btnHelp = go('btnHelp') self.lblIso = go('lblIso') self.boxIso = go('boxIso') self.lblDir = go('lblDir') self.chkFromIso = go('chkFromIso') # Main window translations self.window.set_title(_("SolydXK Constructor")) self.chkSelectAll.set_label(_("Select all")) self.btnAdd.set_label("_{}".format(_("Add"))) self.btnRemove.set_label("_{}".format(_("Remove"))) self.btnEdit.set_label("_{}".format(_("Edit"))) self.btnUpgrade.set_label("_{}".format(_("Upgrade"))) self.btnLocalize.set_label("_{}".format(_("Localize"))) self.btnBuildIso.set_label("_{}".format(_("Build"))) self.btnHelp.set_label("_{}".format(_("Help"))) # Add iso window translations self.windowAddDistro.set_title(_("Add Distribution")) self.lblIso.set_text(_("ISO")) go('lblFromIso').set_label("Create from ISO") go('btnCancel').set_label("_{}".format(_("Cancel"))) # Init self.ec = ExecCmd() self.ec.run("modprobe loop", False) self.queue = Queue() self.mountDir = "/mnt/constructor" self.distroAdded = False self.iso = None self.dir = None self.isoName = None self.doneWav = join(self.shareDir, 'done.wav') self.htmlDir = join(self.shareDir, "html") self.help = join(self.get_language_dir(), "help.html") self.chkFromIso.set_active(True) self.toggleGuiElements(False) # Treeviews self.tvHandlerDistros = TreeViewHandler(self.tvDistros) self.fillTreeViewDistros() # Version information ver = _("Version") self.version = "%s: %s" % (ver, getPackageVersion('solydxk-constructor')) self.showOutput(self.version) # Connect the signals and show the window self.builder.connect_signals(self) self.window.show() # =============================================== # Main Window Functions # =============================================== def on_btnAdd_clicked(self, widget): self.windowAddDistro.show() def on_btnRemove_clicked(self, widget): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) for path in selected: qd = QuestionDialog(self.btnRemove.get_label(), _("Are you sure you want to remove the selected distribution from the list?\n" \ "(This will not remove the directory and its data)"), self.window) answer = qd.show() if answer: self.saveDistroFile(distroPath=path, addDistro=False) self.fillTreeViewDistros() def on_btnEdit_clicked(self, widget): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) for path in selected: de = EditDistro(path) services = [] if exists(join(path, 'root/etc/apache2/apache2.conf')): services.append("apache2") if exists(join(path, 'root/etc/mysql/debian.cnf')): services.append("mysql") if services: msg = "If you need to update packages that depend on these services,\n" \ "you will need to manually start them:\n" for service in services: msg += "\nservice %s start" % service msg += "\n\nWhen done:\n" for service in services: msg += "\nservice %s stop" % service self.showInfo(_("Services detected"), msg, self.window) repaintGui() de.openTerminal() def on_btnUpgrade_clicked(self, widget): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) upgraded = False for path in selected: upgraded = True rootPath = "%s/root" % path force = get_apt_force(rootPath) de = EditDistro(path) de.openTerminal("apt-get update") if exists(join(rootPath, 'etc/apache2/apache2.conf')): de.openTerminal("service apache2 start") if exists(join(rootPath, 'etc/mysql/debian.cnf')): de.openTerminal("service mysql start") de.openTerminal("apt-get -y %s -o Dpkg::Options::=\"--force-confnew\" dist-upgrade" % force) if exists(join(rootPath, 'etc/apache2/apache2.conf')): de.openTerminal("service apache2 stop") if exists(join(rootPath, 'etc/mysql/debian.cnf')): de.openTerminal("service mysql stop") # Cleanup old kernel and headers script = "rmoldkernel.sh" scriptSource = join(self.scriptDir, "files/{}".format(script)) scriptTarget = join(rootPath, script) if exists(scriptSource): copy(scriptSource, scriptTarget) self.ec.run("chmod a+x '%s'" % scriptTarget) de.openTerminal("/bin/bash %s" % script) silent_remove(scriptTarget) # Download offline packages print(">> Start downloading offline packages") self.download_offline_packages(path) if upgraded and exists("/usr/bin/aplay") and exists(self.doneWav): self.ec.run("/usr/bin/aplay '%s'" % self.doneWav, False) def on_btnLocalize_clicked(self, widget): # Set locale selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) for path in selected: rootPath = "%s/root" % path de = EditDistro(path) script = "setlocale.sh" scriptSource = join(self.scriptDir, "files/{}".format(script)) scriptTarget = join(rootPath, script) if exists(scriptSource): copy(scriptSource, scriptTarget) self.ec.run("chmod a+x '%s'" % scriptTarget) de.openTerminal("/bin/bash %s" % script) silent_remove(scriptTarget) # Copy Grub locale files to ISO boot directory and configure grub.cfg grub_path = "%s/boot/boot/grub/" % path grubcfg_path = "%s/grub.cfg" % grub_path locale_path = "%s/root/boot/grub/locale" % path default_path = "%s/root/etc/default" % path locale = self.ec.run("grep -oP '(?<=LANG=).*?(?=\.)' %s/locale" % default_path)[0] if exists(locale_path) and \ exists(grubcfg_path) and \ locale: self.ec.run("cp -rf %s %s" % (locale_path, grub_path)) self.ec.run("sed -i 's/set lang=.*/set lang=%s/' %s" % (locale, grubcfg_path)) def download_offline_packages(self, path): rootPath = "%s/root" % path arch = getGuestEfiArchitecture(rootPath) de = EditDistro(path) script = "offline.sh" scriptSource = join(self.scriptDir, "files/{}".format(script)) scriptTarget = join(rootPath, script) offlineSource = join(rootPath, "offline") offlineTarget = join(rootPath, "../boot/offline") if exists(scriptSource): try: copy(scriptSource, scriptTarget) self.ec.run("chmod a+x '%s'" % scriptTarget) # Run the script de.openTerminal("/bin/bash {} {}".format(script, arch)) # Remove script silent_remove(scriptTarget) # Move offline directory to boot directory if exists(offlineSource): print(("%s exists" % offlineSource)) if exists(offlineTarget): print((">> Remove %s" % offlineTarget)) silent_remove(offlineTarget) print((">> Move %s to %s" % (offlineSource, offlineTarget))) move(offlineSource, offlineTarget) else: print((">> Cannot find: %s" % offlineSource)) except Exception as detail: self.showError("Error: getting offline packages", detail, self.window) else: print((">> Cannot find: %s" % scriptSource)) def on_btnBuildIso_clicked(self, widget): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) msg = "" for path in selected: self.toggleGuiElements(True) self.showOutput("Start building ISO in: %s" % path) repaintGui() # Start building the ISO in a thread t = BuildIso(path, self.queue) t.start() self.queue.join() # Thread is done # Get the data from the queue ret = self.queue.get() self.queue.task_done() if ret is not None: self.showOutput(ret) if "error" in ret.lower(): self.showError("Error", ret, self.window) else: msg += "%s\n" % ret if msg != "": if exists("/usr/bin/aplay") and exists(self.doneWav): self.ec.run("/usr/bin/aplay '%s'" % self.doneWav, False) self.showInfo("", msg, self.window) self.toggleGuiElements(False) def on_chkSelectAll_toggled(self, widget): self.tvHandlerDistros.treeviewToggleAll(toggleColNrList=[0], toggleValue=widget.get_active()) def on_tvDistros_row_activated(self, widget, path, column): self.tvHandlerDistros.treeviewToggleRows(toggleColNrList=[0]) def on_btnHelp_clicked(self, widget): system("open-as-user %s" % self.help) def on_btnOpenDir_clicked(self, widget): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) for path in selected: system("open-as-user %s" % path) def fillTreeViewDistros(self, selectDistros=[]): contentList = [[_("Select"), _("Distribution"), _("Working directory")]] distros = self.getDistros() for distro in distros: select = False for selectDistro in selectDistros: if distro[0] == selectDistro: select = True contentList.append([select, distro[0], distro[1]]) self.tvHandlerDistros.fillTreeview(contentList=contentList, columnTypesList=['bool', 'str', 'str'], firstItemIsColName=True) def getDistros(self): distros = [] if exists(self.distroFile): with open(self.distroFile, 'r') as f: lines = f.readlines() for line in lines: line = line.strip().rstrip('/') print(line) if exists(line): dg = DistroGeneral(line) isoName = dg.description distros.append([isoName, line]) # Sort on iso name if distros: distros = sorted(distros, key=operator.itemgetter(0)) return distros # =============================================== # Add ISO Window Functions # =============================================== def on_btnIso_clicked(self, widget): fleFilter = Gtk.FileFilter() fleFilter.set_name("ISO") fleFilter.add_mime_type("application/x-cd-image") fleFilter.add_pattern("*.iso") startDir = None if exists(dirname(self.txtIso.get_text())): startDir = dirname(self.txtIso.get_text()) filePath = SelectFileDialog(title=_('Select SolydXK ISO'), start_directory=startDir, parent=self.window, gtkFileFilter=fleFilter).show() if filePath is not None: self.txtIso.set_text(filePath) def on_btnDir_clicked(self, widget): startDir = None if exists(self.txtDir.get_text()): startDir = self.txtDir.get_text() dirText = SelectDirectoryDialog(title=_('Select directory'), start_directory=startDir, parent=self.window).show() if dirText is not None: self.txtDir.set_text(dirText) def on_btnSave_clicked(self, widget): self.iso = "" if self.chkFromIso.get_active(): self.iso = self.txtIso.get_text() self.dir = self.txtDir.get_text() title = _("Save existing working directory") if self.iso != "": title = _("Unpack ISO and save") if not exists(self.dir): makedirs(self.dir) if not exists(self.dir): self.showError(title, _("Could not create directory %(dir)s: exiting" % {"dir": self.dir}), self.window) else: self.windowAddDistro.hide() if self.iso != "": if not exists(self.iso): self.showInfo(self.btnSave.get_label(), _("The path to the ISO file does not exist:\n{}".format(self.iso)), self.window) return if listdir(self.dir): qd = QuestionDialog(self.btnSave.get_label(), _("The destination directory is not empty.\n" "Are you sure you want to overwrite all data in {}?".format(self.dir)), self.window) answer = qd.show() if not answer: return self.showOutput("Start unpacking the ISO...") self.toggleGuiElements(True) t = IsoUnpack(self.mountDir, self.iso, self.dir, self.queue) t.start() self.queue.join() GObject.timeout_add(1000, self.checkThread, True) else: self.saveDistroFile(self.dir, True) self.fillTreeViewDistros() self.showOutput(_("Existing working directory added")) #self.toggleGuiElements(False) def on_btnCancel_clicked(self, widget): self.windowAddDistro.hide() def on_addDistroWindow_delete_event(self, widget, data=None): self.windowAddDistro.hide() return True def on_txtIso_changed(self, widget): path = self.txtIso.get_text() if exists(path): self.txtDir.set_sensitive(True) self.btnDir.set_sensitive(True) if exists(self.txtDir.get_text()): self.btnSave.set_sensitive(True) else: self.txtDir.set_sensitive(False) self.btnDir.set_sensitive(False) self.btnSave.set_sensitive(False) def on_txtDir_changed(self, widget): blnFromIso = self.chkFromIso.get_active() isoPath = self.txtIso.get_text() dirText = self.txtDir.get_text() self.btnSave.set_sensitive(False) if exists(dirText): if blnFromIso: if exists(isoPath): self.btnSave.set_sensitive(True) else: self.btnSave.set_sensitive(True) def on_chkFromIso_toggled(self, widget): if widget.get_active(): self.lblIso.set_visible(True) self.boxIso.set_visible(True) self.txtDir.set_sensitive(False) self.btnDir.set_sensitive(False) self.btnSave.set_sensitive(False) self.lblDir.set_text(_("Unpack ISO to directory")) self.btnSave.set_label(_("Unpack & Save")) else: self.txtIso.set_text("") self.lblIso.set_visible(False) self.boxIso.set_visible(False) self.txtDir.set_sensitive(True) self.btnDir.set_sensitive(True) self.btnSave.set_sensitive(True) self.lblDir.set_text(_("Work directory")) self.btnSave.set_label(_("Save")) # =============================================== # General functions # =============================================== def showInfo(self, title, message, parent=None): MessageDialogSafe(title, message, Gtk.MessageType.INFO, parent).show() def showError(self, title, message, parent=None): MessageDialogSafe(title, message, Gtk.MessageType.ERROR, parent).show() def showOutput(self, message): print(message) pushMessage(self.statusbar, message) def checkThread(self, addDistro=None): #print 'Thread count = ' + str(threading.active_count()) # As long there's a thread active, keep spinning if threading.active_count() > 1: return True # Thread is done # Get the data from the queuez ret = self.queue.get() self.queue.task_done() # Thread is done if addDistro is not None: self.saveDistroFile(self.dir, addDistro) self.fillTreeViewDistros(self.isoName) self.toggleGuiElements(False) if exists("/usr/bin/aplay") and exists(self.doneWav): self.ec.run("/usr/bin/aplay '%s'" % self.doneWav, False) if ret is not None: self.showOutput(ret) if "error" in ret.lower(): self.showError("Error", ret, self.window) else: self.showInfo("", ret, self.window) return False def toggleGuiElements(self, startThread): if startThread: self.chkSelectAll.set_sensitive(False) self.tvDistros.set_sensitive(False) self.btnAdd.set_sensitive(False) self.btnBuildIso.set_sensitive(False) self.btnEdit.set_sensitive(False) self.btnRemove.set_sensitive(False) self.btnUpgrade.set_sensitive(False) self.btnLocalize.set_sensitive(False) self.btnDir.set_sensitive(False) self.btnHelp.set_sensitive(False) else: self.chkSelectAll.set_sensitive(True) self.tvDistros.set_sensitive(True) self.btnAdd.set_sensitive(True) self.btnBuildIso.set_sensitive(True) self.btnEdit.set_sensitive(True) self.btnRemove.set_sensitive(True) self.btnUpgrade.set_sensitive(True) self.btnLocalize.set_sensitive(True) self.btnDir.set_sensitive(True) self.btnHelp.set_sensitive(True) def saveDistroFile(self, distroPath, addDistro=True): newCont = [] dg = DistroGeneral(distroPath) self.isoName = dg.description cfg = [] if exists(self.distroFile): with open(self.distroFile, 'r') as f: cfg = f.readlines() for line in cfg: line = line.strip() if distroPath != line and exists(line): newCont.append(line) if addDistro: newCont.append(distroPath) with open(self.distroFile, 'w') as f: f.write('\n'.join(newCont)) self.iso = "" self.dir = "" # Close the gui def on_constructorWindow_destroy(self, widget): # Close the app Gtk.main_quit() # =============================================== # Language specific functions # =============================================== def get_language_dir(self): # First test if full locale directory exists, e.g. html/pt_BR, # otherwise perhaps at least the language is there, e.g. html/pt # and if that doesn't work, try html/pt_PT lang = self.get_current_language() path = join(self.htmlDir, lang) if not isdir(path): base_lang = lang.split('_')[0].lower() path = join(self.htmlDir, base_lang) if not isdir(path): path = join(self.htmlDir, "{}_{}".format(base_lang, base_lang.upper())) if not isdir(path): path = join(self.htmlDir, 'en') return path def get_current_language(self): lang = environ.get('LANG', 'US').split('.')[0] if lang == '': lang = 'en' return lang
class UpdateManager(object): def __init__(self): # Check if script is running self.scriptName = basename(__file__) self.umglobal = UmGlobal() self.user = self.umglobal.getLoginName() # Initiate logging self.logFile = join('/var/log', self.umglobal.settings['log']) print(("UM log = %s" % self.logFile)) self.log = Logger(self.logFile, maxSizeKB=5120) # Remove scripts self.deleteScripts(self.umglobal.localUpdVersion) # Initialize self.ec = ExecCmd(loggerObject=self.log) self.apt = UmApt(self.umglobal) self.kernelVersion = self.umglobal.getKernelVersion() self.upgradables = [] self.upgradableUM = [] self.window = None # Handle arguments parser = argparse.ArgumentParser(description='SolydXK Update Manager') parser.add_argument('-q', '--quick', action="store_true", help='Quick upgrade') parser.add_argument('-r', '--reload', action="store_true", help='') args, extra = parser.parse_known_args() self.quickUpdate = False if args.quick and not self.umglobal.newUpd: self.quickUpdate = True if args.reload: pids = self.umglobal.getProcessPids("updatemanager.py") if len(pids) > 1: print(("updatemanager.py already running - kill pid {}".format( pids[0]))) os.system("kill {}".format(pids[0])) # Set some global translations self.aptErrorText = _("Apt error") self.upgradablePackagesText = _( "The following packages will be upgraded:") self.newPackagesText = _( "The following NEW packages will be installed:") self.removedPackagesText = _("The following packages will be REMOVED:") self.heldbackPackagesText = _( "The following packages have been kept back:") self.downgradePackagesText = _( "The following packages are going to be downgraded:") # Cleanup first for fle in glob(join(self.umglobal.filesDir, '.um*')): remove(fle) # Load window and widgets self.builder = Gtk.Builder() self.builder.add_from_file( join(self.umglobal.shareDir, 'updatemanager.glade')) go = self.builder.get_object # Quick update if self.quickUpdate: # Refresh data self.refresh() self.umglobal.collectData() self.apt.createPackagesInfoList() self.apt.createPackageLists() self.fillTreeView() # Run upgrade nid = self.run_upgrade() if nid != "": self.on_command_done(None, 0, nid) sys.exit(2) # Make sure the files directory is set correctly self.checkFilesDir() # Main window objects self.window = go("windowMain") #self.window.set_icon_from_file(join(self.umglobal.iconsDir, self.umglobal.settings["icon-connected"])) self.tvPck = go("tvPck") self.swTerminal = go("swTerminal") self.statusbar = go("statusbar") self.btnInstall = go("btnInstall") self.btnRefresh = go("btnRefresh") self.btnPackages = go("btnPackages") self.btnOutput = go("btnOutput") self.btnInfo = go("btnInfo") self.btnPreferences = go("btnPreferences") self.nbMain = go("nbMain") self.swInfo = go("swInfo") self.btnMaintenance = go("btnMaintenance") self.lblMaintenance = go("lblMaintenance") self.tvMaintenance = go("tvMaintenance") self.btnMaintenanceExecute = go("btnMaintenanceExecute") self.chkMaintenanceSelectAll = go("chkMaintenanceSelectAll") self.radUnneeded = go("radUnneeded") self.radCleanCache = go("radCleanCache") self.radDowngradable = go("radDowngradable") self.radNotavailable = go("radNotavailable") self.radOldKernel = go("radOldKernel") self.lblMaintenanceHelp = go("lblMaintenanceHelp") # Translations self.window.set_title(_("SolydXK Update Manager")) self.btnInstall.set_label(_("Install")) self.btnRefresh.set_label(_("Refresh")) self.btnOutput.set_label(_("Output")) self.btnInfo.set_label(_("Information")) self.btnPreferences.set_label(_("Preferences")) self.btnMaintenance.set_label(_("Maintenance")) self.btnPackages.set_label(_("Packages")) self.uptodateText = self.umglobal.connectedText self.lblMaintenance.set_label(self.btnMaintenance.get_label()) self.btnMaintenanceExecute.set_label(_("Execute")) self.chkMaintenanceSelectAll.set_label(_("Select all")) self.radCleanCache.set_label(_("Clean up the apt cache")) self.radUnneeded.set_label(_("Remove unneeded packages")) self.radNotavailable.set_label( _("Remove packages not available\nin the repositories")) self.radOldKernel.set_label(_("Remove old kernels")) self.radDowngradable.set_label( _("Downgrade packages with\nonly lower versions available")) self.lblMaintenanceHelp.set_label( _("Make sure you create\n" "a system image before you\n" "continue (e.g. Clonezilla).")) # VTE Terminal self.terminal = VirtualTerminal(userInputAllowed=self.umglobal. settings["allow-terminal-user-input"]) self.swTerminal.add(self.terminal) self.terminal.set_vexpand(True) self.terminal.set_hexpand(True) self.terminal.connect('command-done', self.on_command_done) self.terminal.connect('line-added', self.on_line_added) palletList = [ '#4A4A4A', '#BD1919', '#118011', '#CE6800', '#1919BC', '#8D138D', '#139494', '#A7A7A7' ] self.terminal.setTerminalColors("#000000", "#FFFFFF", palletList) self.swTerminal.modify_bg(Gtk.StateType.NORMAL, Gdk.color_parse("#FFFFFF")) # Disable all buttons self.btnInfo.set_sensitive(False) self.btnPreferences.set_sensitive(False) self.btnOutput.set_sensitive(False) self.btnRefresh.set_sensitive(False) self.btnInstall.set_sensitive(False) self.btnPackages.set_sensitive(False) self.btnMaintenance.set_sensitive(False) # Hide tabs if needed for tab in self.umglobal.settings["hide-tabs"]: if tab == "packages": self.nbMain.get_nth_page(0).set_visible(False) self.btnPackages.set_visible(False) elif tab == "output": self.nbMain.get_nth_page(1).set_visible(False) self.btnOutput.set_visible(False) elif tab == "info": self.nbMain.get_nth_page(2).set_visible(False) self.btnInfo.set_visible(False) elif tab == "maintenance": self.nbMain.get_nth_page(3).set_visible(False) self.btnMaintenance.set_visible(False) # Connect the signals and show the window self.builder.connect_signals(self) self.window.show() # Force the window to show while Gtk.events_pending(): Gtk.main_iteration() # Just show something that we're busy msg = _("Gathering information...") self.terminal.executeCommand('echo "%s"' % msg, 'init') self.showOutput() # Treeview handlers self.tvHandler = TreeViewHandler(self.tvPck) self.tvMaintenanceHandler = TreeViewHandler(self.tvMaintenance) # Version information ver = _("Version") pckVer = self.apt.getPackageVersion('updatemanager') versionInfo = "%(ver)s: %(pckVer)s" % {"ver": ver, "pckVer": pckVer} if self.umglobal.localUpdVersion != "2000.01.01": versionInfo = "%(ver)s: %(pckVer)s" % { "ver": ver, "pckVer": pckVer } self.pushMessage(versionInfo) # Log basic information self.log.write("==============================================", "UM.init", "debug") self.log.write("UM version = %s" % versionInfo, "UM.init", "debug") self.log.write("==============================================", "UM.init", "debug") mirrorsList = join(self.umglobal.filesDir, basename(self.umglobal.settings["mirrors-list"])) if exists(mirrorsList): self.log.write("Mirrors list", "UM.init", "debug") with open(mirrorsList, 'r') as f: for line in f.readlines(): self.log.write(line, "UM.init", "debug") self.log.write("==============================================", "UM.init", "debug") # Refresh apt cache self.refresh() # Initialize maintenance screen self.fillTreeViewMaintenance() # =============================================== # Main window functions # =============================================== def on_btnInstall_clicked(self, widget): self.run_upgrade() def run_upgrade(self): nid = "" aptHasErrors = self.apt.aptHasErrors() if aptHasErrors is not None: MessageDialog(self.aptErrorText, aptHasErrors) elif self.upgradables: if self.apt.upgradablePackages: self.log.write( "=================== upgradable pacages ====================", "UM.run_upgrade", "debug") self.log.write( self.createLogString(self.apt.upgradablePackages), "UM.run_upgrade", "debug") if self.apt.removedPackages: self.log.write( "==================== removed packages =====================", "UM.run_upgrade", "debug") self.log.write(self.createLogString(self.apt.removedPackages), "UM.run_upgrade", "debug") if self.apt.newPackages: self.log.write( "======================= new packages =======================", "UM.run_upgrade", "debug") self.log.write(self.createLogString(self.apt.newPackages), "UM.run_upgrade", "debug") if self.apt.heldbackPackages: self.log.write( "=================== kept back packages =====================", "UM.run_upgrade", "debug") self.log.write(self.createLogString(self.apt.heldbackPackages), "UM.run_upgrade", "debug") if not self.quickUpdate: self.showOutput() contMsg = _("Continue installation?") if self.upgradableUM: cmd = "%s install updatemanager" % self.umglobal.settings[ 'apt-get-string'] cmd += "; %s install %s" % ( self.umglobal.settings['apt-get-string'], " ".join( self.apt.getPackageDependencies('updatemanager'))) nid = 'uminstallum' self.prepForCommand(nid) if self.quickUpdate: self.ec.run(cmd) else: self.terminal.executeCommand(cmd, nid) self.log.write("Execute command: %s (%s)" % (cmd, nid), "UM.on_btnInstall_clicked", "debug") else: msg = self.getDistUpgradeInfo() answer = True if msg != "": answer = self.showConfirmationDlg(contMsg, msg) if answer: cmd = "%s dist-upgrade" % self.umglobal.settings[ 'apt-get-string'] #if self.umglobal.newUpd: pre = join( self.umglobal.filesDir, self.umglobal.settings['pre-upd'].replace( "[VERSION]", self.umglobal.serverUpdVersion)) post = join( self.umglobal.filesDir, self.umglobal.settings['post-upd'].replace( "[VERSION]", self.umglobal.serverUpdVersion)) if exists(pre): cmd = "/bin/bash %(pre)s; %(cmd)s" % { "pre": pre, "cmd": cmd } if exists(post): cmd = "%(cmd)s; /bin/bash %(post)s" % { "cmd": cmd, "post": post } nid = 'umupd' self.prepForCommand(nid) if self.quickUpdate: self.ec.run(cmd) else: self.terminal.executeCommand(cmd, nid) self.log.write("Execute command: %s (%s)" % (cmd, nid), "UM.on_btnInstall_clicked", "debug") else: if not self.quickUpdate: MessageDialog(self.btnInstall.get_label(), self.uptodateText) return nid def on_btnRefresh_clicked(self, widget): self.refresh() def on_btnPackages_clicked(self, widget): self.showPackages() def on_btnOutput_clicked(self, widget): self.showOutput() def on_btnInfo_clicked(self, widget): self.showInfo() def on_btnPreferences_clicked(self, widget): # Run preferences in its own thread pref_thread = threading.Thread(target=self.openPreferences) pref_thread.setDaemon(True) pref_thread.start() def openPreferences(self): os.system("updatemanager -p") def on_btnMaintenance_clicked(self, widget): self.showMaintenance() def on_radCleanCache_toggled(self, widget): if widget.get_active(): self.fillTreeViewMaintenance() def on_radUnneeded_toggled(self, widget): if widget.get_active(): message = "%s\n\n%s" % ( _("You might need to run this several times."), self.lblMaintenanceHelp.get_label().replace("\n", " ")) WarningDialog(self.btnMaintenance.get_label(), message) self.fillTreeViewMaintenance() def on_radNotavailable_toggled(self, widget): if widget.get_active(): message = "%s\n\n%s" % ( _("Removing not available packages may break your system!"), self.lblMaintenanceHelp.get_label().replace("\n", " ")) WarningDialog(self.btnMaintenance.get_label(), message) self.fillTreeViewMaintenance() def on_radOldKernel_toggled(self, widget): if widget.get_active(): message = "%s\n\n%s" % ( _("Once removed you will not be able to boot these kernels!"), self.lblMaintenanceHelp.get_label().replace("\n", " ")) WarningDialog(self.btnMaintenance.get_label(), message) self.fillTreeViewMaintenance() def on_radDowngradable_toggled(self, widget): if widget.get_active(): message = "%s\n\n%s" % ( _("Downgrading packages may break your system!"), self.lblMaintenanceHelp.get_label().replace("\n", " ")) WarningDialog(self.btnMaintenance.get_label(), message) self.fillTreeViewMaintenance() def on_btnMaintenanceExecute_clicked(self, widget): self.executeMaintenance() def on_chkMaintenanceSelectAll_toggled(self, widget): self.tvMaintenanceHandler.treeviewToggleAll( toggleColNrList=[0], toggleValue=widget.get_active()) # =============================================== # Maintenance functions # =============================================== def enableMaintenance(self, enable=True): self.btnMaintenanceExecute.set_sensitive(enable) self.radUnneeded.set_sensitive(enable) self.radCleanCache.set_sensitive(enable) self.radDowngradable.set_sensitive(enable) self.radOldKernel.set_sensitive(enable) self.radNotavailable.set_sensitive(enable) self.chkMaintenanceSelectAll.set_sensitive(enable) if enable: self.chkMaintenanceSelectAll.set_active(False) def fillTreeViewMaintenance(self): blnCleanCache = self.radCleanCache.get_active() blnUnneeded = self.radUnneeded.get_active() blnDowngradable = self.radDowngradable.get_active() blnNotavailable = self.radNotavailable.get_active() blnOldKernels = self.radOldKernel.get_active() self.enableMaintenance(False) columnTypesList = ['bool', 'str', 'str', 'str'] packages = [["", _("Package"), _("Installed"), _("Available")]] # Clear the treeview first self.tvMaintenanceHandler.fillTreeview(packages, columnTypesList, 0, 400, True) msg = "" if blnCleanCache: msg = _("Hit the Execute button to clean the cache.") columnTypesList = ['str'] packages.append([msg]) elif blnUnneeded: msg = self.radUnneeded.get_label() self.apt.createPackageLists("apt-get autoremove") for pck in self.apt.removedPackages: packages.append([False, pck[0], pck[1], pck[2]]) self.apt.createPackageLists() # Add orphaned files self.apt.fillOrphanedPackages() for pck in self.apt.orphanedPackages: packages.append([False, pck[0], pck[1], pck[2]]) elif blnNotavailable: msg = self.radNotavailable.get_label() self.apt.fillNotAvailablePackages() for pck in self.apt.notavailablePackages: if pck[0][0:6] != "linux-": packages.append([False, pck[0], pck[1], ""]) elif blnOldKernels: msg = self.radOldKernel.get_label() self.apt.fillKernelPackages() for pck in self.apt.kernelPackages: if "headers-486" not in pck[0] \ and "headers-586" not in pck[0] \ and "headers-686" not in pck[0] \ and "headers-amd64" not in pck[0] \ and "image-486" not in pck[0] \ and "image-586" not in pck[0] \ and "image-686" not in pck[0] \ and "image-amd64" not in pck[0]: checkVersion = self.kernelVersion if "kbuild" in pck[0]: indMinus = self.kernelVersion.index("-") indZero = self.kernelVersion.index("0") if indZero > 0 and indZero < indMinus: ind = indZero - 1 else: ind = indMinus if ind > 0: checkVersion = self.kernelVersion[0:ind] if checkVersion not in pck[0]: packages.append([False, pck[0], pck[1], ""]) elif blnDowngradable: msg = self.radDowngradable.get_label() self.apt.fillDowngradablePackages() for pck in self.apt.downgradablePackages: packages.append([False, pck[0], pck[1], pck[2]]) if len(packages) > 1: self.tvMaintenanceHandler.fillTreeview(packages, columnTypesList, 0, 400, True) else: if not blnCleanCache: msg = _("\"%s\"\n did not return any results.") % msg MessageDialog(self.btnMaintenance.get_label(), msg) self.enableMaintenance(True) def executeMaintenance(self): blnCleanCache = self.radCleanCache.get_active() blnDowngradable = self.radDowngradable.get_active() blnNotNeeded = self.radUnneeded.get_active() downgradeString = "" deleteString = "" updateGrub = False cmd = "" self.enableMaintenance(False) if blnCleanCache: safe = False msg = _( "Do you want to completely clean the apt cache?\n\n" "When No, only unavailable installation packages are removed.") answer = QuestionDialog(self.radCleanCache.get_label(), msg) if answer: safe = True self.apt.cleanCache(safe) msg = _("Apt cache has been cleaned.") MessageDialog(self.radCleanCache.get_label(), msg) else: # Get user selected packages model = self.tvMaintenance.get_model() itr = model.get_iter_first() while itr is not None: sel = model.get_value(itr, 0) if sel: pck = model.get_value(itr, 1) avVer = model.get_value(itr, 3) if blnDowngradable: downgradeString += " %(pck)s=%(avVer)s" % { "pck": pck, "avVer": avVer } else: deleteString += " %s" % pck if "linux-image" in pck: updateGrub = True itr = model.iter_next(itr) if downgradeString != "": cmd = "%s install %s" % ( self.umglobal.settings['apt-get-string'], downgradeString) elif deleteString != "": cmd = "%s purge %s" % ( self.umglobal.settings['apt-get-string'], deleteString) if cmd != "": self.apt.createPackageLists(cmd) msg = self.getDistUpgradeInfo() answer = True if msg != "": contMsg = _("Execute maintenance changes?") answer = self.showConfirmationDlg(contMsg, msg) if answer: if updateGrub: cmd += "; update-grub" if blnNotNeeded: cmd += "; %s purge $(COLUMNS=132 dpkg -l | grep ^rc | awk '{ print $2 }')" % self.umglobal.settings[ 'apt-get-string'] self.showOutput() nid = 'ummaintenance' self.prepForCommand(nid) self.terminal.executeCommand(cmd, nid) self.log.write("Execute command: %s (%s)" % (cmd, nid), "UM.executeMaintenance", "debug") self.enableMaintenance(True) # =============================================== # General functions # =============================================== def prepForCommand(self, nid): os.system("touch %s" % self.umglobal.umfiles[nid]) if not self.quickUpdate: self.btnRefresh.set_sensitive(False) self.btnInstall.set_sensitive(False) self.btnMaintenance.set_sensitive(False) def on_line_added(self, terminal, line): if line.strip()[0:2].upper() == "E:": self.log.write(line, "UM.on_line_added", "error") else: self.log.write(line, "UM.on_line_added", "info") def on_command_done(self, terminal, pid, nid): if nid != "init": self.log.write("Command finished (pid=%s, nid=%s)" % (pid, nid), "UM.on_command_done", "info") if nid == "uminstallum": # Reload UM self.log.write( "Updating UM: kill process of updatemanagerpref.py", "UM.on_command_done", "debug") self.umglobal.killScriptProcess("updatemanagerpref.py") # Reload tray as user self.log.write( "Updating UM: kill process of updatemanagertray.py", "UM.on_command_done", "debug") self.umglobal.killScriptProcess("updatemanagertray.py") cmd = "sudo -u {} updatemanager -t -r".format(self.user) os.system(cmd) self.log.write( "UM updated: reload tray as user {}".format(self.user), "UM.on_command_done", "debug") # Reload UM window cmd = join(self.umglobal.scriptDir, "updatemanager.py") if self.quickUpdate: cmd = join(self.umglobal.scriptDir, "updatemanager.py -q") self.umglobal.reloadWindow(cmd, self.user) self.log.write( "UM updated: reload {0} as user {1}".format( cmd, self.user), "UM.on_command_done", "debug") elif nid == "umrefresh": # Build installed packages info list self.apt.createPackagesInfoList() # Run post update when needed self.postUpdate() elif nid == "ummaintenance": self.enableMaintenance(True) self.fillTreeViewMaintenance() self.btnInstall.set_sensitive(True) self.btnRefresh.set_sensitive(True) self.btnPackages.set_sensitive(True) self.btnMaintenance.set_sensitive(True) self.showMaintenance() elif nid == 'umupd': # Save update version in hist file self.umglobal.saveHistVersion("upd", self.umglobal.serverUpdVersion) self.log.write( "Save history upd=%s" % self.umglobal.serverUpdVersion, "UM.on_command_done", "debug") self.deleteScripts() # Refresh data after install or update self.umglobal.collectData() self.apt.createPackageLists() self.fillTreeView() # Enable the buttons and load the info page self.log.write( "Re-initiate window after terminal command: %s" % str(not self.quickUpdate), "UM.on_command_done", "debug") if not self.quickUpdate: self.btnInstall.set_sensitive(True) self.btnRefresh.set_sensitive(True) self.btnPackages.set_sensitive(True) self.btnMaintenance.set_sensitive(True) self.btnInfo.set_sensitive(True) self.loadInfo() if self.umglobal.newUpd: self.showInfo() else: # This throws a lock file error in Plasma5 #aptHasErrors = self.apt.aptHasErrors() #if aptHasErrors is not None: #MessageDialog(self.aptErrorText, aptHasErrors) #el if self.upgradables: self.showPackages() else: self.showInfo() MessageDialog(self.btnInfo.get_label(), self.uptodateText) self.log.write("Re-initiate window complete", "UM.on_command_done", "debug") # Cleanup name file(s) for fle in glob(join(self.umglobal.filesDir, '.um*')): remove(fle) def createLogString(self, packagesList): lst = [] for data in packagesList: lst.append(data[0]) return ' '.join(lst) def refresh(self): # Refresh server info print((self.umglobal.hasInternet)) self.umglobal.getServerInfo() print((self.umglobal.hasInternet)) # Check of programs locking apt prog = self.apt.getAptCacheLockedProgram( self.umglobal.settings["apt-packages"]) if prog is not None: msg = _("Another program is locking the apt cache\n\n" "Please, close the program before refreshing:\n" "* %s" % prog) MessageDialog(self.btnRefresh.get_label(), msg) self.log.write("%s is locking the apt cache" % prog, "UM.refresh", "warning") elif self.umglobal.hasInternet: if not self.quickUpdate: # Update the apt cache self.btnPreferences.set_sensitive(True) self.btnOutput.set_sensitive(True) self.btnRefresh.set_sensitive(False) self.btnInstall.set_sensitive(False) self.btnMaintenance.set_sensitive(False) self.btnPackages.set_sensitive(True) self.showOutput() cmd = "dpkg --configure -a; %s -f install; apt-get update" % self.umglobal.settings[ 'apt-get-string'] nid = 'umrefresh' self.prepForCommand(nid) if self.quickUpdate: self.ec.run(cmd) else: self.terminal.executeCommand(cmd, nid) self.apt.initAptShowVersions() self.log.write("Execute command: %s (%s)" % (cmd, nid), "UM.refresh", "debug") else: if not self.quickUpdate: # No internet connection self.btnInstall.set_sensitive(True) self.btnRefresh.set_sensitive(True) self.btnPackages.set_sensitive(True) self.btnMaintenance.set_sensitive(True) self.btnInfo.set_sensitive(True) self.btnOutput.set_sensitive(True) self.btnPreferences.set_sensitive(True) self.loadInfo() self.showInfo() def postUpdate(self): # Check for changed version information if self.umglobal.newUpd and self.umglobal.serverUpdVersion is not None: self.getScripts([ self.umglobal.settings['pre-upd'].replace( "[VERSION]", self.umglobal.serverUpdVersion), self.umglobal.settings['post-upd'].replace( "[VERSION]", self.umglobal.serverUpdVersion) ]) def fillTreeView(self): # First check if this application is upgradable self.upgradableUM = self.getUpgradablePackages( packageNames=["updatemanager"]) if self.upgradableUM: self.upgradables = self.upgradableUM else: # Get a list of packages that can be upgraded self.upgradableUM = [] self.upgradables = self.getUpgradablePackages() #if not self.upgradables: ## Check for black listed packages #cmd = "dpkg --get-selections | grep hold$ | awk '{print $1}'" #lst = self.ec.run(cmd, False) #for pck in lst: #self.upgradables.append([pck.strip(), _("blacklisted"), ""]) if not self.quickUpdate: contentList = [[ _("Package"), _("Current version"), _("New version") ]] + self.upgradables self.tvHandler.fillTreeview(contentList=contentList, columnTypesList=['str', 'str', 'str'], firstItemIsColName=True) def getUpgradablePackages(self, packageNames=[]): upckList = [] if packageNames: upckList = [] for packageName in packageNames: for upck in self.apt.upgradablePackages: if upck[0] == packageName: upckList.append(upck) break else: upckList = self.apt.upgradablePackages return upckList def getDistUpgradeInfo(self, upgradablesOnly=False): info = "" if upgradablesOnly: if self.apt.upgradablePackages: info = "<strong>%s</strong><br>" % self.apt.upgradablePackagesText for pck in self.apt.upgradablePackages: info += "%s " % pck[0] else: if self.apt.removedPackages: info = "<strong>%s</strong><br>" % self.removedPackagesText for pck in self.apt.removedPackages: info += "%s " % pck[0] if self.apt.newPackages: if info != "": info += "<p> </p>" info += "<strong>%s</strong><br>" % self.newPackagesText for pck in self.apt.newPackages: info += "%s " % pck[0] if self.apt.heldbackPackages: if info != "": info += "<p> </p>" info += "<strong>%s</strong><br>" % self.heldbackPackagesText for pck in self.apt.heldbackPackages: info += "%s " % pck[0] if self.apt.downgradablePackages: if info != "": info += "<p> </p>" info += "<strong>%s</strong><br>" % self.downgradePackagesText for pck in self.apt.downgradablePackages: info += "%s " % pck[0] return info def showPackages(self): self.nbMain.set_current_page(0) def showOutput(self): self.nbMain.set_current_page(1) self.terminal.grab_focus() def showInfo(self): self.nbMain.set_current_page(2) def showMaintenance(self): self.nbMain.set_current_page(3) def showConfirmationDlg(self, title, message): head = "<html><head><style>body { font-family: Arial, Helvetica, Verdana, Sans-serif; font-size: 12px; color: #555555; background: #ffffff; }</style></head><body>" end = "</body></html>" html = "%s%s%s" % (head, message, end) sw = Gtk.ScrolledWindow() sw.add(SimpleBrowser(html)) return CustomQuestionDialog(title, sw, 550, 300, self.window).show() # Get pre-install script and post-install script from the server def getScripts(self, files): for fle in files: flePath = join(self.umglobal.filesDir, fle) if not exists(flePath): # Get the new scripts if they exist url = "%s/%s/%s" % (self.umglobal.settings['solydxk'], self.umglobal.settings["umfilesdir"], fle) try: txt = urlopen(url).read().decode('utf-8') if txt != '': # Save to a file and make executable self.log.write("Save script = %s" % flePath, "UM.getScripts", "debug") with open(flePath, 'w') as f: f.write(txt) chmod(flePath, 0o755) except: pass def loadInfo(self): languageDir = self.get_language_dir() url = join("file://%s" % languageDir, self.umglobal.settings['up-to-date']) self.btnInfo.set_icon_name("help-about") if self.upgradables: url = join("file://%s" % languageDir, self.umglobal.settings['updates']) if self.umglobal.newUpd: url = "%s/%s/%s" % (self.umglobal.settings['solydxk'], self.umglobal.settings["umfilesdir"], self.umglobal.settings['upd-info']) elif self.umglobal.serverUpdVersion is None: url = join("file://%s" % languageDir, self.umglobal.settings['not-found']) self.log.write("Load info url: %s" % url, "UM.loadInfo", "debug") children = self.swInfo.get_children() if children: children[0].openUrl(url) else: self.swInfo.add(SimpleBrowser(url)) def get_language_dir(self): # First test if full locale directory exists, e.g. html/pt_BR, # otherwise perhaps at least the language is there, e.g. html/pt # and if that doesn't work, try html/pt_PT lang = self.get_current_language() path = join(self.umglobal.htmlDir, lang) if not isdir(path): base_lang = lang.split('_')[0].lower() path = join(self.umglobal.htmlDir, base_lang) if not isdir(path): path = join(self.umglobal.htmlDir, "{}_{}".format(base_lang, base_lang.upper())) if not isdir(path): path = join(self.umglobal.htmlDir, 'en') return path def get_current_language(self): lang = os.environ.get('LANG', 'US').split('.')[0] if lang == '': lang = 'en' return lang def pushMessage(self, message): if message is not None: context = self.statusbar.get_context_id('message') self.statusbar.push(context, message) def checkFilesDir(self): if not exists(self.umglobal.filesDir): makedirs(self.umglobal.filesDir) oldFiles = glob(join(self.umglobal.scriptDir, 'pre-*')) + \ glob(join(self.umglobal.scriptDir, 'post-*')) + \ [join(self.umglobal.scriptDir, 'updatemanager.hist')] + \ [join(self.umglobal.scriptDir, 'mirrors.list')] for fle in oldFiles: if exists(fle): fleName = basename(fle) if not exists(join(self.umglobal.filesDir, fleName)): move(fle, self.umglobal.filesDir) else: remove(fle) chmod(self.umglobal.filesDir, 0o777) def deleteScripts(self, UpdVersion=None): UpdVersion = "*" if UpdVersion is not None: UpdVersion = "*%s" % UpdVersion oldFiles = glob(join( self.umglobal.filesDir, "pre-%s" % UpdVersion)) + glob( join(self.umglobal.filesDir, "post-%s" % UpdVersion)) for fle in oldFiles: remove(fle) self.log.write("Cleanup file: %s" % fle, "UM.deleteScripts", "debug") # Close the gui def on_windowMain_destroy(self, widget): # Close the app Gtk.main_quit()
class Constructor(object): def __init__(self): self.scriptDir = abspath(dirname(__file__)) self.shareDir = join(self.scriptDir, '../../../share/solydxk/constructor') # Load window and widgets self.builder = Gtk.Builder() self.builder.add_from_file(join(self.shareDir, 'constructor.glade')) # Main window objects go = self.builder.get_object self.window = go('constructorWindow') self.tvDistros = go('tvDistros') self.lblOutput = go('lblOutput') self.statusbar = go('statusbar') self.btnAdd = go('btnAdd') self.chkSelectAll = go('chkSelectAll') self.btnRemove = go('btnRemove') self.btnEdit = go('btnEdit') self.btnUpgrade = go('btnUpgrade') self.btnLocalize = go('btnLocalize') self.btnBuildIso = go('btnBuildIso') # Add iso window objects self.windowAddDistro = go('addDistroWindow') self.txtIso = go('txtIso') self.txtDir = go('txtDir') self.btnDir = go('btnDir') self.btnSave = go('btnSave') self.btnHelp = go('btnHelp') self.lblIso = go('lblIso') self.boxIso = go('boxIso') self.lblDir = go('lblDir') self.chkFromIso = go('chkFromIso') # Main window translations self.window.set_title(_("SolydXK Constructor")) self.chkSelectAll.set_label(_("Select all")) self.btnAdd.set_label("_{}".format(_("Add"))) self.btnRemove.set_label("_{}".format(_("Remove"))) self.btnEdit.set_label("_{}".format(_("Edit"))) self.btnUpgrade.set_label("_{}".format(_("Upgrade"))) self.btnLocalize.set_label("_{}".format(_("Localize"))) self.btnBuildIso.set_label("_{}".format(_("Build"))) self.btnHelp.set_label("_{}".format(_("Help"))) # Add iso window translations self.lblIso.set_text(_("ISO")) go('btnCancel').set_label("_{}".format(_("Cancel"))) # Init self.ec = ExecCmd() self.ec.run("modprobe loop", False) self.queue = Queue() self.mountDir = "/mnt/constructor" self.distroFile = join(self.scriptDir, "distros.list") self.distroAdded = False self.iso = None self.dir = None self.isoName = None self.doneWav = join(self.shareDir, 'done.wav') self.help = join(self.shareDir, 'help.html') self.chkFromIso.set_active(True) self.toggleGuiElements(False) self.hostEfiArchitecture = functions.getHostEfiArchitecture() # Treeviews self.tvHandlerDistros = TreeViewHandler(self.tvDistros) self.fillTreeViewDistros() # Version information ver = _("Version") self.version = "%s: %s" % (ver, functions.getPackageVersion('solydxk-constructor')) self.showOutput(self.version) # Connect the signals and show the window self.builder.connect_signals(self) self.window.show() # =============================================== # Main Window Functions # =============================================== def on_btnAdd_clicked(self, widget): self.windowAddDistro.show() def on_btnRemove_clicked(self, widget): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) for path in selected: qd = QuestionDialog(self.btnRemove.get_label(), _("Are you sure you want to remove the selected distribution from the list?\n" \ "(This will not remove the directory and its data)"), self.window) answer = qd.show() if answer: self.saveDistroFile(distroPath=path, addDistro=False) self.fillTreeViewDistros() def on_btnEdit_clicked(self, widget): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) for path in selected: de = EditDistro(path) services = [] if exists(join(path, 'root/etc/apache2/apache2.conf')): services.append("apache2") if exists(join(path, 'root/etc/mysql/debian.cnf')): services.append("mysql") if services: msg = "If you need to update packages that depend on these services,\n" \ "you will need to manually start them:\n" for service in services: msg += "\nservice %s start" % service msg += "\n\nWhen done:\n" for service in services: msg += "\nservice %s stop" % service self.showInfo(_("Services detected"), msg, self.window) functions.repaintGui() de.openTerminal() def on_btnUpgrade_clicked(self, widget): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) upgraded = False for path in selected: upgraded = True rootPath = "%s/root" % path de = EditDistro(path) de.openTerminal("apt-get update") if exists(join(rootPath, 'etc/apache2/apache2.conf')): de.openTerminal("service apache2 start") if exists(join(rootPath, 'etc/mysql/debian.cnf')): de.openTerminal("service mysql start") de.openTerminal("apt-get -y --force-yes -o Dpkg::Options::=\"--force-confnew\" dist-upgrade") if exists(join(rootPath, 'etc/apache2/apache2.conf')): de.openTerminal("service apache2 stop") if exists(join(rootPath, 'etc/mysql/debian.cnf')): de.openTerminal("service mysql stop") # Cleanup old kernel and headers script = "rmoldkernel.sh" scriptSource = join(self.scriptDir, "files/{}".format(script)) scriptTarget = join(rootPath, script) if exists(scriptSource): copy(scriptSource, scriptTarget) self.ec.run("chmod a+x %s" % scriptTarget) de.openTerminal("/bin/bash %s" % script) remove(scriptTarget) # Build EFI files if self.hostEfiArchitecture != "": print(">> Start building EFI files") self.build_efi_files() # Download offline packages print(">> Start downloading offline packages") self.download_offline_packages() if upgraded and exists("/usr/bin/aplay") and exists(self.doneWav): self.ec.run("/usr/bin/aplay '%s'" % self.doneWav, False) def on_btnLocalize_clicked(self, widget): # Set locale selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) for path in selected: rootPath = "%s/root" % path de = EditDistro(path) script = "setlocale.sh" scriptSource = join(self.scriptDir, "files/{}".format(script)) scriptTarget = join(rootPath, script) if exists(scriptSource): copy(scriptSource, scriptTarget) self.ec.run("chmod a+x %s" % scriptTarget) de.openTerminal("/bin/bash %s" % script) remove(scriptTarget) def build_efi_files(self): # TODO - also 32-bit installs (haven't tested this) modules = "part_gpt part_msdos ntfs ntfscomp hfsplus fat ext2 normal chain boot configfile linux " \ "multiboot iso9660 gfxmenu gfxterm loadenv efi_gop efi_uga loadbios fixvideo png " \ "ext2 ntfscomp loopback search minicmd cat cpuid appleldr elf usb videotest " \ "halt help ls reboot echo test normal sleep memdisk tar font video_fb video " \ "gettext true video_bochs video_cirrus multiboot2 acpi gfxterm_background gfxterm_menu" selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) for path in selected: rootPath = "%s/root" % path bootPath = "{}/boot".format(path) arch = functions.getGuestEfiArchitecture(rootPath) grubEfiName = "bootx64" efiName = "x64" if arch != "x86_64": arch = "i386" grubEfiName = "bootia32" efiName = "ia32" try: if not exists("{}/efi/boot".format(bootPath)): makedirs("{}/efi/boot".format(bootPath)) self.ec.run("efi-image {}/~tmp {}-efi {}".format(bootPath, arch, efiName)) if exists("{}/~tmp/efi.img".format(bootPath) and exists("{}/~tmp/boot/grub/{}-efi".format(bootPath, arch))): self.ec.run("rm -r {}/boot/grub/{}-efi".format(bootPath, arch)) self.ec.run("mv -vf {}/~tmp/boot/grub/{}-efi {}/boot/grub/".format(bootPath, arch, bootPath)) self.ec.run("mv -vf {}/~tmp/efi.img {}/boot/grub/".format(bootPath, bootPath)) self.ec.run("rm -r {}/~tmp".format(bootPath)) self.ec.run("grub-mkimage -O {}-efi -d /usr/lib/grub/{}-efi " "-o {}/efi/boot/{}.efi " "-p \"/boot/grub\" {}".format(arch, arch, bootPath, grubEfiName, modules)) print((">> Finished building EFI files")) except Exception as detail: self.showError("Error: build EFI files", detail, self.window) def download_offline_packages(self): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) for path in selected: rootPath = "%s/root" % path arch = functions.getGuestEfiArchitecture(rootPath) de = EditDistro(path) script = "offline.sh" scriptSource = join(self.scriptDir, "files/{}".format(script)) scriptTarget = join(rootPath, script) offlineSource = join(rootPath, "offline") offlineTarget = join(rootPath, "../boot/offline") if exists(scriptSource): try: copy(scriptSource, scriptTarget) self.ec.run("chmod a+x %s" % scriptTarget) # Run the script de.openTerminal("/bin/bash {} {}".format(script, arch)) # Remove script remove(scriptTarget) # Move offline directory to boot directory if exists(offlineSource): print(("%s exists" % offlineSource)) if exists(offlineTarget): print((">> Remove %s" % offlineTarget)) rmtree(offlineTarget) print((">> Move %s to %s" % (offlineSource, offlineTarget))) move(offlineSource, offlineTarget) else: print((">> Cannot find: %s" % offlineSource)) except Exception as detail: self.showError("Error: getting offline packages", detail, self.window) else: print((">> Cannot find: %s" % scriptSource)) def on_btnBuildIso_clicked(self, widget): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) msg = "" for path in selected: self.toggleGuiElements(True) self.showOutput("Start building ISO in: %s" % path) functions.repaintGui() # Start building the ISO in a thread t = BuildIso(path, self.queue) t.start() self.queue.join() # Thread is done # Get the data from the queue ret = self.queue.get() self.queue.task_done() if ret is not None: self.showOutput(ret) if "error" in ret.lower(): self.showError("Error", ret, self.window) else: msg += "%s\n" % ret if msg != "": if exists("/usr/bin/aplay") and exists(self.doneWav): self.ec.run("/usr/bin/aplay '%s'" % self.doneWav, False) self.showInfo("", msg, self.window) self.toggleGuiElements(False) def on_chkSelectAll_toggled(self, widget): self.tvHandlerDistros.treeviewToggleAll(toggleColNrList=[0], toggleValue=widget.get_active()) def on_tvDistros_row_activated(self, widget, path, column): self.tvHandlerDistros.treeviewToggleRows(toggleColNrList=[0]) def on_btnHelp_clicked(self, widget): if functions.isPackageInstalled("firefox"): system("firefox file://%s &" % self.help) else: system("xdg-open file://%s &" % self.help) def on_btnOpenDir_clicked(self, widget): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) for path in selected: system("xdg-open %s &" % path) def fillTreeViewDistros(self, selectDistros=[]): contentList = [[_("Select"), _("Distribution"), _("Working directory")]] distros = self.getDistros() for distro in distros: select = False for selectDistro in selectDistros: if distro[0] == selectDistro: select = True contentList.append([select, distro[0], distro[1]]) self.tvHandlerDistros.fillTreeview(contentList=contentList, columnTypesList=['bool', 'str', 'str'], firstItemIsColName=True) def getDistros(self): distros = [] if exists(self.distroFile): with open(self.distroFile, 'r') as f: lines = f.readlines() for line in lines: line = line.strip().rstrip('/') print(line) if exists(line): dg = DistroGeneral(line) isoName = dg.description distros.append([isoName, line]) # Sort on iso name if distros: distros = sorted(distros, key=operator.itemgetter(0)) return distros # =============================================== # Add ISO Window Functions # =============================================== def on_btnIso_clicked(self, widget): fleFilter = Gtk.FileFilter() fleFilter.set_name("ISO") fleFilter.add_mime_type("application/x-cd-image") fleFilter.add_pattern("*.iso") startDir = None if exists(dirname(self.txtIso.get_text())): startDir = dirname(self.txtIso.get_text()) filePath = SelectFileDialog(title=_('Select SolydXK ISO'), start_directory=startDir, parent=self.window, gtkFileFilter=fleFilter).show() if filePath is not None: self.txtIso.set_text(filePath) def on_btnDir_clicked(self, widget): startDir = None if exists(self.txtDir.get_text()): startDir = self.txtDir.get_text() dirText = SelectDirectoryDialog(title=_('Select directory'), start_directory=startDir, parent=self.window).show() if dirText is not None: self.txtDir.set_text(dirText) def on_btnSave_clicked(self, widget): self.iso = "" if self.chkFromIso.get_active(): self.iso = self.txtIso.get_text() self.dir = self.txtDir.get_text() title = _("Save existing working directory") if self.iso != "": title = _("Unpack ISO and save") if not exists(self.dir): makedirs(self.dir) if not exists(self.dir): self.showError(title, _("Could not create directory %(dir)s: exiting" % {"dir": self.dir}), self.window) else: self.windowAddDistro.hide() if self.iso != "": if not exists(self.iso): self.showInfo(self.btnSave.get_label(), _("The path to the ISO file does not exist:\n{}".format(self.iso)), self.window) return if listdir(self.dir): qd = QuestionDialog(self.btnSave.get_label(), _("The destination directory is not empty.\n" "Are you sure you want to overwrite all data in {}?".format(self.dir)), self.window) answer = qd.show() if not answer: return self.showOutput("Start unpacking the ISO...") self.toggleGuiElements(True) t = IsoUnpack(self.mountDir, self.iso, self.dir, self.queue) t.start() self.queue.join() GObject.timeout_add(1000, self.checkThread, True) else: self.saveDistroFile(self.dir, True) self.fillTreeViewDistros() self.showOutput(_("Existing working directory added")) #self.toggleGuiElements(False) def on_btnCancel_clicked(self, widget): self.windowAddDistro.hide() def on_addDistroWindow_delete_event(self, widget, data=None): self.windowAddDistro.hide() return True def on_txtIso_changed(self, widget): path = self.txtIso.get_text() if exists(path): self.txtDir.set_sensitive(True) self.btnDir.set_sensitive(True) if exists(self.txtDir.get_text()): self.btnSave.set_sensitive(True) else: self.txtDir.set_sensitive(False) self.btnDir.set_sensitive(False) self.btnSave.set_sensitive(False) def on_txtDir_changed(self, widget): blnFromIso = self.chkFromIso.get_active() isoPath = self.txtIso.get_text() dirText = self.txtDir.get_text() self.btnSave.set_sensitive(False) if exists(dirText): if blnFromIso: if exists(isoPath): self.btnSave.set_sensitive(True) else: self.btnSave.set_sensitive(True) def on_chkFromIso_toggled(self, widget): if widget.get_active(): self.lblIso.set_visible(True) self.boxIso.set_visible(True) self.txtDir.set_sensitive(False) self.btnDir.set_sensitive(False) self.btnSave.set_sensitive(False) self.lblDir.set_text(_("Unpack ISO to directory")) self.btnSave.set_label(_("Unpack & Save")) else: self.txtIso.set_text("") self.lblIso.set_visible(False) self.boxIso.set_visible(False) self.txtDir.set_sensitive(True) self.btnDir.set_sensitive(True) self.btnSave.set_sensitive(True) self.lblDir.set_text(_("Work directory")) self.btnSave.set_label(_("Save")) # =============================================== # General functions # =============================================== def showInfo(self, title, message, parent=None): MessageDialogSafe(title, message, Gtk.MessageType.INFO, parent).show() def showError(self, title, message, parent=None): MessageDialogSafe(title, message, Gtk.MessageType.ERROR, parent).show() def showOutput(self, message): print(message) functions.pushMessage(self.statusbar, message) def checkThread(self, addDistro=None): #print 'Thread count = ' + str(threading.active_count()) # As long there's a thread active, keep spinning if threading.active_count() > 1: return True # Thread is done # Get the data from the queuez ret = self.queue.get() self.queue.task_done() # Thread is done if addDistro is not None: self.saveDistroFile(self.dir, addDistro) self.fillTreeViewDistros(self.isoName) self.toggleGuiElements(False) if exists("/usr/bin/aplay") and exists(self.doneWav): self.ec.run("/usr/bin/aplay '%s'" % self.doneWav, False) if ret is not None: self.showOutput(ret) if "error" in ret.lower(): self.showError("Error", ret, self.window) else: self.showInfo("", ret, self.window) return False def toggleGuiElements(self, startThread): if startThread: self.chkSelectAll.set_sensitive(False) self.tvDistros.set_sensitive(False) self.btnAdd.set_sensitive(False) self.btnBuildIso.set_sensitive(False) self.btnEdit.set_sensitive(False) self.btnRemove.set_sensitive(False) self.btnUpgrade.set_sensitive(False) else: self.chkSelectAll.set_sensitive(True) self.tvDistros.set_sensitive(True) self.btnAdd.set_sensitive(True) self.btnBuildIso.set_sensitive(True) self.btnEdit.set_sensitive(True) self.btnRemove.set_sensitive(True) self.btnUpgrade.set_sensitive(True) def saveDistroFile(self, distroPath, addDistro=True): newCont = [] dg = DistroGeneral(distroPath) self.isoName = dg.description cfg = [] if exists(self.distroFile): with open(self.distroFile, 'r') as f: cfg = f.readlines() for line in cfg: line = line.strip() if distroPath not in line and exists(line): newCont.append(line) if addDistro: newCont.append(distroPath) with open(self.distroFile, 'w') as f: f.write('\n'.join(newCont)) self.iso = "" self.dir = "" # Close the gui def on_constructorWindow_destroy(self, widget): # Close the app Gtk.main_quit()
class Constructor(object): def __init__(self): self.scriptDir = abspath(dirname(__file__)) self.shareDir = join(self.scriptDir, '../../../share/trail/constructor') self.userAppDir = join(get_user_home_dir(), ".constructor") self.distroFile = join(self.userAppDir, "distros.list") # Create the user's application directory if it doesn't exist if not isdir(self.userAppDir): user_name = getUserLoginName() makedirs(self.userAppDir) old_distro_file = join(self.scriptDir, "distros.list") if exists(old_distro_file): move(old_distro_file, self.distroFile) system("chown -R %s:%s %s" % (user_name, user_name, self.userAppDir)) # Load window and widgets self.builder = Gtk.Builder() self.builder.add_from_file(join(self.shareDir, 'constructor.glade')) # Main window objects go = self.builder.get_object self.window = go('constructorWindow') self.tvDistros = go('tvDistros') self.lblOutput = go('lblOutput') self.statusbar = go('statusbar') self.btnAdd = go('btnAdd') self.chkSelectAll = go('chkSelectAll') self.btnRemove = go('btnRemove') self.btnEdit = go('btnEdit') self.btnUpgrade = go('btnUpgrade') self.btnLocalize = go('btnLocalize') self.btnBuildIso = go('btnBuildIso') # Add iso window objects self.windowAddDistro = go('addDistroWindow') self.txtIso = go('txtIso') self.txtDir = go('txtDir') self.btnDir = go('btnDir') self.btnSave = go('btnSave') self.lblIso = go('lblIso') self.boxIso = go('boxIso') self.lblDir = go('lblDir') self.chkFromIso = go('chkFromIso') # Main window translations self.window.set_title(_("Constructor")) self.chkSelectAll.set_label(_("Select all")) self.btnAdd.set_label("_{}".format(_("Add"))) self.btnRemove.set_label("_{}".format(_("Remove"))) self.btnEdit.set_label("_{}".format(_("Edit"))) self.btnUpgrade.set_label("_{}".format(_("Upgrade"))) self.btnLocalize.set_label("_{}".format(_("Localize"))) self.btnBuildIso.set_label("_{}".format(_("Build"))) # Add iso window translations self.lblIso.set_text(_("ISO")) go('btnCancel').set_label("_{}".format(_("Cancel"))) # Init self.ec = ExecCmd() self.ec.run("modprobe loop", False) self.queue = Queue() self.mountDir = "/mnt/constructor" self.distroAdded = False self.iso = None self.dir = None self.isoName = None self.chkFromIso.set_active(True) self.toggleGuiElements(False) # Treeviews self.tvHandlerDistros = TreeViewHandler(self.tvDistros) self.fillTreeViewDistros() # Version information ver = _("Version") self.version = "%s: %s" % (ver, getPackageVersion('constructor')) self.showOutput(self.version) # Connect the signals and show the window self.builder.connect_signals(self) self.window.show() # =============================================== # Main Window Functions # =============================================== def on_btnAdd_clicked(self, widget): self.windowAddDistro.show() def on_btnRemove_clicked(self, widget): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) for path in selected: qd = QuestionDialog(self.btnRemove.get_label(), _("Are you sure you want to remove the selected distribution from the list?\n" \ "(This will not remove the directory and its data)"), self.window) answer = qd.show() if answer: self.saveDistroFile(distroPath=path, addDistro=False) self.fillTreeViewDistros() def on_btnEdit_clicked(self, widget): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) for path in selected: de = EditDistro(path) services = [] if exists(join(path, 'root/etc/apache2/apache2.conf')): services.append("apache2") if exists(join(path, 'root/etc/mysql/debian.cnf')): services.append("mysql") if services: msg = "If you need to update packages that depend on these services,\n" \ "you will need to manually start them:\n" for service in services: msg += "\nservice %s start" % service msg += "\n\nWhen done:\n" for service in services: msg += "\nservice %s stop" % service self.showInfo(_("Services detected"), msg, self.window) repaintGui() de.openTerminal() def on_btnUpgrade_clicked(self, widget): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) upgraded = False for path in selected: upgraded = True rootPath = "%s/root" % path force = get_apt_force(rootPath) de = EditDistro(path) de.openTerminal("apt-get update") if exists(join(rootPath, 'etc/apache2/apache2.conf')): de.openTerminal("service apache2 start") if exists(join(rootPath, 'etc/mysql/debian.cnf')): de.openTerminal("service mysql start") de.openTerminal( "apt-get -y %s -o Dpkg::Options::=\"--force-confnew\" dist-upgrade" % force) if exists(join(rootPath, 'etc/apache2/apache2.conf')): de.openTerminal("service apache2 stop") if exists(join(rootPath, 'etc/mysql/debian.cnf')): de.openTerminal("service mysql stop") # Cleanup old kernel and headers script = "rmoldkernel.sh" scriptSource = join(self.scriptDir, "files/{}".format(script)) scriptTarget = join(rootPath, script) if exists(scriptSource): copy(scriptSource, scriptTarget) self.ec.run("chmod a+x '%s'" % scriptTarget) de.openTerminal("/bin/bash %s" % script) silent_remove(scriptTarget) # Download offline packages print(">> Start downloading offline packages") self.download_offline_packages() if upgraded and exists("/usr/bin/aplay") and exists(self.doneWav): self.ec.run("/usr/bin/aplay '%s'" % self.doneWav, False) def on_btnLocalize_clicked(self, widget): # Set locale selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) for path in selected: rootPath = "%s/root" % path de = EditDistro(path) script = "setlocale.sh" scriptSource = join(self.scriptDir, "files/{}".format(script)) scriptTarget = join(rootPath, script) if exists(scriptSource): copy(scriptSource, scriptTarget) self.ec.run("chmod a+x '%s'" % scriptTarget) de.openTerminal("/bin/bash %s" % script) silent_remove(scriptTarget) def download_offline_packages(self): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) for path in selected: rootPath = "%s/root" % path arch = getGuestEfiArchitecture(rootPath) de = EditDistro(path) script = "offline.sh" scriptSource = join(self.scriptDir, "files/{}".format(script)) scriptTarget = join(rootPath, script) offlineSource = join(rootPath, "offline") offlineTarget = join(rootPath, "../boot/offline") if exists(scriptSource): try: copy(scriptSource, scriptTarget) self.ec.run("chmod a+x '%s'" % scriptTarget) # Run the script de.openTerminal("/bin/bash {} {}".format(script, arch)) # Remove script silent_remove(scriptTarget) # Move offline directory to boot directory if exists(offlineSource): print(("%s exists" % offlineSource)) if exists(offlineTarget): print((">> Remove %s" % offlineTarget)) silent_remove(offlineTarget) print((">> Move %s to %s" % (offlineSource, offlineTarget))) move(offlineSource, offlineTarget) else: print((">> Cannot find: %s" % offlineSource)) except Exception as detail: self.showError("Error: getting offline packages", detail, self.window) else: print((">> Cannot find: %s" % scriptSource)) def on_btnBuildIso_clicked(self, widget): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) msg = "" for path in selected: self.toggleGuiElements(True) self.showOutput("Start building ISO in: %s" % path) repaintGui() # Start building the ISO in a thread t = BuildIso(path, self.queue) t.start() self.queue.join() # Thread is done # Get the data from the queue ret = self.queue.get() self.queue.task_done() if ret is not None: self.showOutput(ret) if "error" in ret.lower(): self.showError("Error", ret, self.window) else: msg += "%s\n" % ret if msg != "": if exists("/usr/bin/aplay") and exists(self.doneWav): self.ec.run("/usr/bin/aplay '%s'" % self.doneWav, False) self.showInfo("", msg, self.window) self.toggleGuiElements(False) def on_chkSelectAll_toggled(self, widget): self.tvHandlerDistros.treeviewToggleAll( toggleColNrList=[0], toggleValue=widget.get_active()) def on_tvDistros_row_activated(self, widget, path, column): self.tvHandlerDistros.treeviewToggleRows(toggleColNrList=[0]) def on_btnOpenDir_clicked(self, widget): selected = self.tvHandlerDistros.getToggledValues(toggleColNr=0, valueColNr=2) for path in selected: system("open-as-user %s root" % path) def fillTreeViewDistros(self, selectDistros=[]): contentList = [[ _("Select"), _("Distribution"), _("Working directory") ]] distros = self.getDistros() for distro in distros: select = False for selectDistro in selectDistros: if distro[0] == selectDistro: select = True contentList.append([select, distro[0], distro[1]]) self.tvHandlerDistros.fillTreeview( contentList=contentList, columnTypesList=['bool', 'str', 'str'], firstItemIsColName=True) def getDistros(self): distros = [] if exists(self.distroFile): with open(self.distroFile, 'r') as f: lines = f.readlines() for line in lines: line = line.strip().rstrip('/') print(line) if exists(line): dg = DistroGeneral(line) isoName = dg.description distros.append([isoName, line]) # Sort on iso name if distros: distros = sorted(distros, key=operator.itemgetter(0)) return distros # =============================================== # Add ISO Window Functions # =============================================== def on_btnIso_clicked(self, widget): fleFilter = Gtk.FileFilter() fleFilter.set_name("ISO") fleFilter.add_mime_type("application/x-cd-image") fleFilter.add_pattern("*.iso") startDir = None if exists(dirname(self.txtIso.get_text())): startDir = dirname(self.txtIso.get_text()) filePath = SelectFileDialog(title=_('Select ISO'), start_directory=startDir, parent=self.window, gtkFileFilter=fleFilter).show() if filePath is not None: self.txtIso.set_text(filePath) def on_btnDir_clicked(self, widget): startDir = None if exists(self.txtDir.get_text()): startDir = self.txtDir.get_text() dirText = SelectDirectoryDialog(title=_('Select directory'), start_directory=startDir, parent=self.window).show() if dirText is not None: self.txtDir.set_text(dirText) def on_btnSave_clicked(self, widget): self.iso = "" if self.chkFromIso.get_active(): self.iso = self.txtIso.get_text() self.dir = self.txtDir.get_text() title = _("Save existing working directory") if self.iso != "": title = _("Unpack ISO and save") if not exists(self.dir): makedirs(self.dir) if not exists(self.dir): self.showError( title, _("Could not create directory %(dir)s: exiting" % {"dir": self.dir}), self.window) else: self.windowAddDistro.hide() if self.iso != "": if not exists(self.iso): self.showInfo( self.btnSave.get_label(), _("The path to the ISO file does not exist:\n{}". format(self.iso)), self.window) return if listdir(self.dir): qd = QuestionDialog( self.btnSave.get_label(), _("The destination directory is not empty.\n" "Are you sure you want to overwrite all data in {}?". format(self.dir)), self.window) answer = qd.show() if not answer: return self.showOutput("Start unpacking the ISO...") self.toggleGuiElements(True) t = IsoUnpack(self.mountDir, self.iso, self.dir, self.queue) t.start() self.queue.join() GObject.timeout_add(1000, self.checkThread, True) else: self.saveDistroFile(self.dir, True) self.fillTreeViewDistros() self.showOutput(_("Existing working directory added")) #self.toggleGuiElements(False) def on_btnCancel_clicked(self, widget): self.windowAddDistro.hide() def on_addDistroWindow_delete_event(self, widget, data=None): self.windowAddDistro.hide() return True def on_txtIso_changed(self, widget): path = self.txtIso.get_text() if exists(path): self.txtDir.set_sensitive(True) self.btnDir.set_sensitive(True) if exists(self.txtDir.get_text()): self.btnSave.set_sensitive(True) else: self.txtDir.set_sensitive(False) self.btnDir.set_sensitive(False) self.btnSave.set_sensitive(False) def on_txtDir_changed(self, widget): blnFromIso = self.chkFromIso.get_active() isoPath = self.txtIso.get_text() dirText = self.txtDir.get_text() self.btnSave.set_sensitive(False) if exists(dirText): if blnFromIso: if exists(isoPath): self.btnSave.set_sensitive(True) else: self.btnSave.set_sensitive(True) def on_chkFromIso_toggled(self, widget): if widget.get_active(): self.lblIso.set_visible(True) self.boxIso.set_visible(True) self.txtDir.set_sensitive(False) self.btnDir.set_sensitive(False) self.btnSave.set_sensitive(False) self.lblDir.set_text(_("Unpack ISO to directory")) self.btnSave.set_label(_("Unpack & Save")) else: self.txtIso.set_text("") self.lblIso.set_visible(False) self.boxIso.set_visible(False) self.txtDir.set_sensitive(True) self.btnDir.set_sensitive(True) self.btnSave.set_sensitive(True) self.lblDir.set_text(_("Work directory")) self.btnSave.set_label(_("Save")) # =============================================== # General functions # =============================================== def showInfo(self, title, message, parent=None): MessageDialogSafe(title, message, Gtk.MessageType.INFO, parent).show() def showError(self, title, message, parent=None): MessageDialogSafe(title, message, Gtk.MessageType.ERROR, parent).show() def showOutput(self, message): print(message) pushMessage(self.statusbar, message) def checkThread(self, addDistro=None): #print 'Thread count = ' + str(threading.active_count()) # As long there's a thread active, keep spinning if threading.active_count() > 1: return True # Thread is done # Get the data from the queuez ret = self.queue.get() self.queue.task_done() # Thread is done if addDistro is not None: self.saveDistroFile(self.dir, addDistro) self.fillTreeViewDistros(self.isoName) self.toggleGuiElements(False) if exists("/usr/bin/aplay") and exists(self.doneWav): self.ec.run("/usr/bin/aplay '%s'" % self.doneWav, False) if ret is not None: self.showOutput(ret) if "error" in ret.lower(): self.showError("Error", ret, self.window) else: self.showInfo("", ret, self.window) return False def toggleGuiElements(self, startThread): if startThread: self.chkSelectAll.set_sensitive(False) self.tvDistros.set_sensitive(False) self.btnAdd.set_sensitive(False) self.btnBuildIso.set_sensitive(False) self.btnEdit.set_sensitive(False) self.btnRemove.set_sensitive(False) self.btnUpgrade.set_sensitive(False) self.btnLocalize.set_sensitive(False) self.btnDir.set_sensitive(False) else: self.chkSelectAll.set_sensitive(True) self.tvDistros.set_sensitive(True) self.btnAdd.set_sensitive(True) self.btnBuildIso.set_sensitive(True) self.btnEdit.set_sensitive(True) self.btnRemove.set_sensitive(True) self.btnUpgrade.set_sensitive(True) self.btnLocalize.set_sensitive(True) self.btnDir.set_sensitive(True) def saveDistroFile(self, distroPath, addDistro=True): newCont = [] dg = DistroGeneral(distroPath) self.isoName = dg.description cfg = [] if exists(self.distroFile): with open(self.distroFile, 'r') as f: cfg = f.readlines() for line in cfg: line = line.strip() if distroPath not in line and exists(line): newCont.append(line) if addDistro: newCont.append(distroPath) with open(self.distroFile, 'w') as f: f.write('\n'.join(newCont)) self.iso = "" self.dir = "" # Close the gui def on_constructorWindow_destroy(self, widget): # Close the app Gtk.main_quit()