def check(self, what, text): """ Checks the username/hostname. """ string = self.entry(text) result = self.moduleclass.check(what, string) if result == True: return string else: warn(_("You can't use these chars in the %s, please re-try: ") % (what) + str(result)) return self.check(what, text)
def question(self, text, default=None): """ A simple yes/no prompt. if default == None; the user should insert y or n if default == False; the user can press ENTER to say n if default == True; the user can press ENTER to say y """ if default != None: # We can enable blank on entry. blank = True if default == True: # Modify suffix: prompt_suffix = _("[Y/n]") else: # default = False prompt_suffix = _("[y/N]") else: # Nothing default... prompt_suffix = _("[y/n]") blank = False result = self.entry("%s %s" % (text, prompt_suffix), blank=blank) if not result: # result is "", so blank == True... we should set to "y" or "n" according to default. if default: # = yes result = True else: # = no result = False else: # result is populated. result = result.lower() # Make sure it is all lowered if _("y") == result: # Set y, untranslated. result = True elif _("n") == result: # Set n, untranslated. result = False elif _("yes") in result: # This should be y. result = True elif _("no") in result: # This should be n. result = False else: # Unknown value... warn(_("Unknown value %s. Please re-try." % result)) result = self.question(text, default=default) # Finally return value return result
def entry(self, text, password=False, blank=False): """ Displays and entry prompt (normal or password) """ if password == True: choice = getpass.getpass(text + ": ") else: choice = raw_input(text + ": ") if not choice and blank == False: warn(_("You must insert something!")) return self.entry(text, password=password, blank=blank) else: return choice
def password_prompt(self, text): """ A simple password prompt """ passw1 = self.entry(text, password=True) if len(passw1) < int(self.settings["password_min_chars"]): warn(_("The password should be composed of at least %s charchters.") % self.settings["password_min_chars"]) return self.password_prompt(text) passw2 = self.entry(text + _(" (again)"), password=True) if not passw1 == passw2: # Wrong! warn(_("The passwords doesn't match! Please retry.")) return self.password_prompt(text) else: return passw1
def start(self): """ Start the frontend """ verbose("packages are: %s" % self.settings["packages"]) self.header(_("Installer Updates")) print(_("%(distroname)s's installer improves every day.") % {"distroname":self.moduleclass.main_settings["distro"]}) print(_("It is good measure to have the latest version before installing the distribution.") + "\n") result = self.question(_("Would you like to check for installer updates?"), default=True) if result: # Do checking. info(_("Updating APT cache...")) self.moduleclass.install.update() verbose("Opening the refreshed APT cache...") self.moduleclass.install.open() verbose("Checking if the packages have been updated...") res = self.moduleclass.install.check() if not res: info(_("No updates found.")) return info(_("Upgrading packages... this may take a while.")) try: self.moduleclass.install.upgrade() except: print warn(_("Something went wrong while updating packages.")) info(_("A reboot is recommended in order to start a safe linstaller version.\n")) result = self.question(_("Would you like to reboot now?"), default=True) if result: return "kthxbye" else: return # Everything should be cool now. self.header(_("Installer updated")) print(_("The installer packages have been updated successfully.") + "\n") result = self.entry(_("Press ENTER to start the updated installer"), blank=True) return "fullrestart"
def entry(self, text, password=False, blank=False, onlyint=False): """ Displays and entry prompt (normal or password) """ if password == True: choice = getpass.getpass(text + ": ") else: choice = raw_input(text + ": ") if onlyint: # We should check if it is an integer try: choice = int(choice) except: print "E: %s" % (_("You need to insert a number!")) if not choice and blank == False: warn(_("You must insert something!")) return self.entry(text, password=password, blank=blank) else: return choice
def on_next(self): """ Override for the on_next function. """ status = self.cbox.get_active() # Get status. if status: # Do checking info(_("Updating APT cache...")) self.moduleclass.install.update() verbose("Opening the refreshed APT cache...") self.moduleclass.install.open() verbose("Checking if the packages have been updated...") res = self.moduleclass.install.check() if not res: info(_("No updates found.")) return info("Upgrading packages... this may take a while.") try: self.moduleclass.install.upgrade() except: print warn("Something went wrong while updating packages.") info("A reboot is recommended in order to start a safe linstaller version.\n") result = self.question("Would you like to reboot now?", default=True) if result: return "kthxbye" else: return # Everything should be cool now. self.window.set_header("ok", _("Installer updated"), _("Everything went well")) print(_("The installer packages have been updated successfully.") + "\n") result = self.entry(_("Press ENTER to start the updated installer"), blank=True) return "fullrestart"
def append(self, leng, objs): """ Appends the object to the table. leng is the number of the objects to append objs is a tuple containing the objects. """ objs = tuple(objs) if objs == () or len(objs) != leng: warn("Unable to append objects to table. Check your arguments.") return self.item_n = 0 # Append items. for item in objs: self.table.attach(item, self.item_n, self.item_n + 1, self.rows_done, self.rows_done + 1) self.item_n += 1 self.rows_done += 1
def start(self): """ Start the frontend """ # Sets sets = self.moduleclass.modules_settings["mirrorselect"]["sets"].split(" ") check = self.moduleclass.modules_settings["mirrorselect"]["check"] # Get a progressbar progress = self.progressbar(_("Selecting mirrors:"), len(sets)) # Start progressbar progress.start() try: if check == None: return # Should not check if not self.moduleclass.install.prechecks(): return # We can't continue. num = 0 for set in sets: num += 1 if num == len(sets): # We are on the last set! isLast = True else: isLast = False self.moduleclass.install.select(set, isLast=isLast) progress.update(num) except: warn(_("Mirrorselect crashed. Please check sources.list(.d) later.")) finally: # Exit from chroot self.moduleclass.install.close() progress.finish()
def build_pages(self, single=None, replacepage=None, onsuccess=None, newlocale=None): """ Searches for support glade files and adds them to the pages object. If single is a string, only the module matching that string will be builded. If replacepage is an int, the single page will be positioned to the argument's value, removing the old page. If onsuccess is True (and in single mode), the supplied method will be called when the pages have been built. Note that the single mode does work ONLY on the supplied module, other modules are not touched.""" if newlocale: os.environ["LANG"] = newlocale os.environ["LC_ALL"]= newlocale import linstaller.core.changelocale as _cl _cl.change(newlocale) #locale.setlocale(locale.LC_ALL, newlocale) global _ _ = t9n.library.translation_init("linstaller") # Reset title GObject.idle_add(self.main.set_title, _("%s Installer") % self.main_settings["distro"]) if not replacepage and not single: self.modules_objects = {} self.inst_modules = [] if replacepage and not single: current_page = self.pages.get_current_page() counter = -1 # Get modules modules = self.main_settings["modules"] # Following the format introduced with linstaller 3.0 alpha 1, the modules are residing in directories (so welcome.front is welcome/front/ and not welcome/front.py) # Some modules may have not been converted to the new format, and we should handle them too. # GLADE FRONTEND WILL BE SEARCHED IN welcome/front/glade/ AND NOT in welcome/front/glade.py! for module in modules: if single and single != module: continue if module.split(".")[-1] == "inst": is_inst = True else: is_inst = False if module.startswith("!") or module.startswith("+"): # supermodule revert, skipping continue module_new = module.replace(".","/") module_new = os.path.join(MODULESDIR, module_new + "/glade/module.glade") if not os.path.exists(module_new) and not is_inst: warn(_("Module path %s does not exist! Skipping...") % module_new) continue objects_list = {"parent":self} if is_inst: # Inst module, skipping from now but adding to self.inst_modules... if not replacepage: self.modules_objects[module] = objects_list if os.path.exists(os.path.dirname(module_new)): self.inst_modules.append(module) continue # New builder objects_list["builder"] = Gtk.Builder() objects_list["builder"].set_translation_domain("linstaller") objects_list["builder"].add_from_file(module_new) # Get main object objects_list["main"] = objects_list["builder"].get_object("main") objects_list["main"].get_parent().remove(objects_list["main"]) objects_list["main"].show_all() # Add to pages if single and replacepage: # Due to some Gtk.Notebook wierdness, the calling module MUST destroy the old main container. self.pages.insert_page(objects_list["main"], None, replacepage) # Also enter into the new page self.pages.set_current_page(replacepage) elif replacepage: counter +=1 if counter > self.pages.get_current_page(): if module in self.modules_objects: self.modules_objects[module]["main"].destroy() self.pages.remove_page(counter) self.pages.insert_page(objects_list["main"], None, counter) else: continue else: self.pages.append_page(objects_list["main"], None) #self.pages.next_page() #self.pages.get_current_page() # Add to modules_objects self.modules_objects[module] = objects_list if single and onsuccess: onsuccess(objects_list) if not single and replacepage: self.pages.set_current_page(current_page)
def start(self, warning=False): """ Start the frontend """ self.header(_("Persistence partition")) if warning: warn(warning) print size = self.settings["size"] if size: # Size already selected, going ahead return # Calculate free space part = self.moduleclass.modules_settings["partdisks"]["root"] freespace = self.moduleclass.freespace(part) is_fat = self.moduleclass.is_fat(part) # Get the size of the things we will copy during install... if not self.settings["allfreespace"]: size = 0 size += os.path.getsize(self.moduleclass.modules_settings["echo"]["image"]) # Squashfs image size += os.path.getsize(self.moduleclass.modules_settings["echo"]["vmlinuz"]) # Kernel image size += os.path.getsize(self.moduleclass.modules_settings["echo"]["initrd"]) # Initrd image size += self.moduleclass.dirsize(self.moduleclass.modules_settings["echo"]["syslinux"]) # Syslinux directory # Then remove from freespace. freespace -= size # Convert to megabytes freespace = freespace / 1024 / 1024 # Round freespace freespace = int(round(freespace)) # Remove five megabytes from freespace, safe threshold to avoid problems when installing bootloader, etc. freespace -= 5 # If is fat, our threshold is 4045 MB. Let's set it to 4040. if is_fat and freespace > 4040: freespace = 4040 print(_("You need to specify the size of the persistence partition.")) print(_("The persistence partition will be stored as a file into the USB key and will contain all changes done to the stock system.")) print print(_("Usable freespace: %s MiB") % freespace) if is_fat: print(_("Partition uses a FAT partition, so there is a limit to a maximum of 4GiB per-file.")) print(_("You can insert the percentage of the partition (e.g: 50%) or the full size of the new partition, in megabytes.") + "\n") res = self.entry(_("Insert the value here")) if "%" in res and res != "100%": # This is a percentage, folks! res = res[:-1] # Drop last % try: res = float(res) except: # Not a number return self.start(warning=_("Wrong percentage specified!")) res = (res * freespace) / 100.0 elif res == "100%": res = freespace else: if float(res) == freespace: # Full partition. res = freespace else: try: res = float(res) except: # Not a number return self.start(warning=_("Wrong value specified!")) # Round res res = round(res) # Check if we can grow the partition at the given size... if freespace < res: # No! return self.start(warning=_("Not enough space!")) self.settings["size"] = str(int(res)) verbose("Selected size %s" % self.settings["size"])
def automatic(self, warning=False, information=False, jumpto=False, by="freespace"): """ Automatic partitioner. That's cool, babe! """ self.header(_("Automatic partitioner")) if warning: warn(warning + "\n") if information: info(information + "\n") # *RELOAD* original structure self._reload() if not jumpto: print(_("Available disks:")) res, choices = self.print_devices_partitions(interactive=True, only_disks=True, skip_notable=True) try: res = int(res) except ValueError: return self.edit_partitions(warning=_("You didn't entered a valid number.")) if not res in choices: # Number doesn't is in choices. return self.edit_partitions(warning=_("You didn't entered a valid number.")) obj = choices[res] if obj == "back": return self.edit_partitions() # Go back. self.header(_("Automatic partitioner") + " - %s" % obj.device.path) actions = {} actions[0] = (_("Use the free space"), "freespace") actions[1] = (_("Delete another system"), "delete") actions[2] = (_("Delete all partitions"), "deleteall") actions[3] = (_("Back"), "back") # Print actions for num, act in actions.iteritems(): print(" %d) %s") % (num, act[0]) print result = self.entry(_("Please insert your action here")) try: result = int(result) except: return self.edit_partitions(warning=_("You haven't entered a valid action.")) if not result in actions: return self.edit_partitions(warning=_("You haven't entered a valid action.")) by = actions[result][1] if by == "back": return self.edit_partitions() # Go back. if jumpto: obj = jumpto # We can continue. if by == "freespace": part, swap, swapcreated = lib.automatic_check(obj, by=by) if part == None: return self.automatic(information=_("Too little free space")) elif part == False: # Failed. return self.automatic(warning=_("Failed to add partition (AUTOMATIC)")) else: # Yey! self.header(_("Automatic partitioner choices")) if swap: # Get swap size. if int(swap.getSize("GB")) == 0: # GB is too big, use MB instead. _swap_unit = "MB" _swap_size = round(swap.getSize("MB")) else: # We can use GB. _swap_unit = "GB" _swap_size = round(swap.getSize("GB")) # Set-up touched... self.touched[part.path] = True if swap: self.touched[swap.path] = True print(" / - %s (%s - %s GB)" % (part.path, part.fileSystem.type, round(part.getSize("GB"), 2))) if swap: print(" swap - %s (%s %s)" % (swap.path, _swap_size, _swap_unit)) elif by == "delete": delete, swap = lib.automatic_check(obj, by=by) swapcreated = False print delete if not delete: # No distribution to delete. return self.automatic(warning=_("No distribution to delete!")) else: # Yey! self.header(_("Automatic partitioner choices")) if swap: # Get swap size. if int(swap.getSize("GB")) == 0: # GB is too big, use MB instead. _swap_unit = "MB" _swap_size = round(swap.getSize("MB")) else: # We can use GB. _swap_unit = "GB" _swap_size = round(swap.getSize("GB")) actions = {} num = 0 for part, distrib in delete: actions[num] = part print(" %s) (%s) / - %s (%s - %s GB)" % (num, bold(distrib), part.path, part.fileSystem.type, round(part.getSize("GB"), 2))) num += 1 print print(" %s) " % num + _("<- Back")) actions[num] = "back" print if swap: print(_("Whatever will be the selection, this swap partition will be used:") + "\n") print(" swap - %s (%s %s)" % (swap.path, _swap_size, _swap_unit)) print else: # Swap will be created - hopefully - by freespace. print(_("A swap partition, if all conditions are meet, will be created.")) print # Select action result = self.entry(_("Please insert your value here")) try: result = int(result) except: return self.automatic(warning=_("You didn't entered a valid value.")) if not result in actions: return self.automatic(warning=_("You didn't entered a valid value.")) if actions[result] == "back": # Go back. return self.automatic() # If we can continue, delete partition!! lib.delete_partition(actions[result]) # Now there is freespace ;-) # So use "freespace". return self.automatic(jumpto=obj, by="freespace") elif by == "deleteall": # The simplest ever! lib.delete_all(obj) # Now there is freespace ;-) # So use "freespace". return self.automatic(jumpto=obj, by="freespace") print res = self.question(_("Are you happy with this? Enter 'y' to write changes in memory"), default=True) # Cache part in self.changed if not part.path in self.changed: self.changed[part.path] = {"obj":part, "changes":{}} # Cache swap in self.changed if swap: if not swap.path in self.changed: self.changed[swap.path] = {"obj":swap, "changes":{}} if res: # Add useas. self.changed[part.path]["changes"] = {"useas":"/", "format_real":"ext4"} if swap: self.changed[swap.path]["changes"] = {"useas":"swap", "format_real":"linux-swap(v1)"} elif by == "freespace" and not jumpto: # We should deleted created partitions lib.delete_partition(part) if swapcreated: lib.delete_partition(swap) # We should delete swap if it was created. else: # We cannot undo, restore old structure self._reload() # Remove useas flags self.changed[part.path]["changes"] = {} if swap: self.changed[swap.path]["changes"] = {} return self.edit_partitions(information=_("Successfully added partitions."))
def edit_partitions(self, warning=None, information=None, device=False, device_changes=False): """ Partition editor. """ self.header(_("Edit Partition structure")) if warning: warn(warning + "\n") if information: info(information + "\n") res, choices = self.print_devices_partitions(interactive=True) try: res = int(res) except ValueError: return self.edit_partitions(warning=_("You didn't entered a valid number.")) if not res in choices: # Number doesn't is in choices. return self.edit_partitions(warning=_("You didn't entered a valid number.")) # We can continue. obj = choices[res] if obj == "back": return self.back() # We should go back. if obj == "write": return self.edit_partitions_write() # We should write to disk. if obj == "automatic": return self.automatic() # Automatic partitioning. if obj == "reload": return self._reload(interactive=True) # Reload. if obj == "commit": return self.commit(interactive=True) # Commit. self.header(_("Editing disk/partition")) print(_("You've selected:") + "\n") if type(obj) == lib.p.partition.Partition: if obj.fileSystem == None and not obj.number == -1 and not obj.type == 2: # If filesystem == None, skip. _fs = _("not formatted") elif obj.number == -1: _fs = _("free space") elif obj.type == 2: # Extended objition _fs = _("extended") else: _fs = obj.fileSystem.type if obj.name: _name = obj.name else: _name = "Untitled" if obj.path in self.distribs: # This partition contains a distribution! _moarspace = "%s: " % self.distribs[obj.path] else: _moarspace = "" if int(obj.getSize("GB")) > 0: # We can use GigaBytes to represent partition size. _size = round(obj.getSize("GB"), 2) _unit = "GB" elif int(obj.getSize("MB")) > 0: # Partition is too small to be represented with gigabytes. Use megabytes instead. _size = round(obj.getSize("MB"), 2) _unit = "MB" else: # Last try.. using kilobytes _size = round(obj.getSize("kB"), 2) _unit = "kB" print(bold(" %s%s (%s) - %s (%s %s)\n" % (_moarspace, _name, obj.path, _fs, _size, _unit))) actions = {} # Populate actions if obj.number == -1: actions[1] = (_("Add partition"), self.edit_partitions_add) num = 1 else: actions[1] = (_("Format partition"), self.edit_partitions_format) actions[2] = (_("Delete partition"), self.edit_partitions_delete) actions[3] = (_("Resize partition"), self.edit_partitions_resize) actions[4] = (_("Use as..."), self.edit_partitions_useas) actions[5] = (_("Unmark changes"), self.edit_partitions_unmark) num = 5 actions[num + 1] = (_("<- Back"), self.edit_partitions) elif type(obj) == lib.p.disk.Disk: # A disk. device = obj.device print(" %s - %s (%s GB)\n" % (device.path, device.model, round(device.getSize(unit="GB"), 2))) actions = {} # Populate actions actions[1] = (_("Delete all partitions on the disk"), self.edit_partitions_deleteall) actions[2] = (_("Unmark changes"), self.edit_partitions_unmark) actions[3] = (_("<- Back"), self.edit_partitions) else: # A device. device = obj print(" %s - %s (%s GB)\n" % (device.path, device.model, round(device.getSize(unit="GB"), 2))) actions = {} # Populate actions actions[1] = (_("Create MBR partition table"), self.edit_partitions_newmbr) actions[2] = (_("Create GPT partition table"), self.edit_partitions_newgpt) actions[3] = (_("<- Back"), self.edit_partitions) # Print actions for num, act in actions.iteritems(): print(" %d) %s") % (num, act[0]) print result = self.entry(_("Please insert your action here")) try: result = int(result) except: return self.edit_partitions(warning=_("You didn't entered a valid action.")) if not result in actions: return self.edit_partitions(warning=_("You didn't entered a valid action.")) # Generate a new device_changes, if any if type(obj) == lib.p.disk.Disk: # It is a Disk object, we should use Disk.device _path = obj.device.path else: _path = obj.path if not _path in self.changed: self.changed[_path] = {"obj":obj, "changes":{}} return actions[result][1](device=obj, device_changes=self.changed[_path]["changes"])
def partition_selection(self, warning=None, information=None): """ If root and swap aren't preseeded, prompts the user for a partition. """ self.header(_("Select distribution specific drives")) if warning: warn(warning + "\n") if information: info(information + "\n") self.print_devices_partitions() if not self.settings["root"]: # No root specified. Prompt for one. choice = self.entry(_("Select your root partition")) # Check if choice is into disk's partition try: _root_dev = self.disks[lib.return_device(choice).replace("/dev/","")] _root_par = _root_dev.getPartitionByPath(choice) if not _root_par: # Wrong disk return self.partition_selection(warning=_("Wrong partition selected!")) except: # Wrong disk return self.partition_selection(warning=_("Wrong partition selected!")) self.changed[choice] = {"obj":_root_par, "changes":{"useas":"/"}} self.settings["root"] = choice if not self.settings["root_filesystem"] and not self.settings["root_noformat"]: # No filesystem for root specified. # Prompt for one. return self.edit_partitions_format(_root_par, self.changed[choice]["changes"], _return="partsel") elif not self.settings["root_noformat"]: self.changed[choice]["changes"]["format"] = self.settings["root_filesystem"] self.changed[choice]["changes"]["format_real"] = self.settings["root_filesystem"] self.touched[lib.return_device(choice)] = True if self.settings["swap"] == False: swaps = lib.swap_available(deep=True) if swaps == []: # No swap available warn(_("No swap partition available. Continuing without.")) self.settings["swap"] = None else: # No swap specified. Prompt for one. choice = self.entry(_("Select your swap partition (press ENTER to not use swap)"), blank=True) if not choice: # Should not use swap. ok... self.settings["swap"] = None warn(_("No swap selected.")) else: # Check if choice is into disk's partition _swap_par = False for part in swaps: if choice == part.path: _swap_par = part if not _swap_par: # No swap :/ return self.partition_selection(warning=_("Wrong partition selected!")) self.changed[choice] = {"obj":_swap_par, "changes":{"useas":"swap"}} self.settings["swap"] = choice if not self.settings["swap_noformat"]: # Prompt for format. # Set format. self.changed[choice]["changes"]["format"] = "linux-swap(v1)" self.changed[choice]["changes"]["format_real"] = "linux-swap(v1)" self.touched[lib.return_device(self.settings["swap"])] = True if self.settings["root_noformat"]: # Do not alarm the user that we are going to format something -- as we will not format anything (if not swap) quest = _("Do you really want to continue?") else: quest = _("Do you really want to continue? This will destroy selected partitions.") res = self.question("\n" + quest, default=False) if res: # Write to memory lib.write_memory(self.changed) # Commit. self.commit() return else: return self.main()