#-*- coding: utf-8 -*- # Copyright 2010 Calculate Ltd. http://www.calculate-linux.org # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import re import sys from cl_install import cl_install, InstallError, __app__, __version__,\ get_install_errors from cl_vars_share import varsShare from cl_opt import opt from cl_share_cmd import share_cmd from cl_lang import lang lang().setLanguage(sys.modules[__name__]) OSSYSTEM_LIST=sorted(varsShare.dictNameSystem.keys()) DESCRIPTION = _("The Calculate Linux installation and configuration utility") CMD_OPTIONS = [{'shortOption':"d", 'longOption':"disk", 'optVal':"DISK[:[DIR:FILESYSTEM:OPTIONS]]", 'action':'append', 'help':_("the DISK for installation, which mounted to DIR") + ". " +_("DIR with value 'none' will cancels the mount point transfer") }, {'shortOption':"b", 'longOption':"bind", 'optVal':"SRC_DIR:DEST_DIR", 'action':'append', 'help':_("bind mount point for instalation") }, {'shortOption':"w", 'longOption':"swap", 'optVal':"SWAP_DISK", 'action':'append', 'help':_("swap disk for installation") }, {'longOption':"mbr", 'optVal':"DEVICE", 'help':_("boot disk for the installed system \ (to be recorded MBR), off - disable MBR writing") }, {'longOption':"type", 'optVal':"DISKTYPE", 'type':'choice', 'choices':['flash','hdd','usb-hdd'], 'help':_("device type for installed system") }, {'shortOption':"s", 'longOption':"os", 'optVal':"SYSTEM", 'type':'choice', 'choices_regignore': OSSYSTEM_LIST, 'help':_("select operation system") }, {'longOption':"march", 'optVal':"ARCH", 'type':'choice', 'choices':['i686','x86_64'], 'help':_("select processor architecture") }, {'longOption':"build", 'help':_("installation for assembling") }, {'shortOption':"l", 'longOption':"lang", 'optVal':"LANG", 'help':_("set language") }, {'shortOption':"u", 'longOption':"user", 'optVal':"USER", 'action':'append', 'help':_("add user to installed system") }, {'longOption':"hostname", 'optVal':"HOSTNAME", 'help':_("set short hostname of full hostname") }, {'longOption':"proxy", 'optVal':"PROXY", 'help':_("set proxy server for system") }, {'longOption':"ntp", 'optVal':"NTP", 'help':_("set ntp server for system") }, {'longOption':"nouuid", 'help':_("do not use UUID") }, {'longOption':'set'}, {'shortOption':"f", 'longOption':"force", 'help':_("no questions during the install process") }, {'longOption':"live", 'help':_("configure current system") }, {'longOption':"install", 'help':_("install package") }, {'longOption':"uninstall", 'help':_("uninstall package") }, {'longOption':"nospinner", 'help':_("disable spinner") }, {'shortOption':"P", 'help':_("use passwords for the users accounts \ (from standard input)") }] class install_cmd(share_cmd): """Class for work with cl_install by console""" def __init__(self): setpos = \ filter(lambda x:x[1].get('longOption')=="set", enumerate(CMD_OPTIONS))[0][0] CMD_OPTIONS[setpos] = opt.variable_set[0] self.optobj = opt(package=__app__, version=__version__, description=DESCRIPTION, option_list= CMD_OPTIONS + opt.variable_view + opt.color_control, check_values=self.checkOpts) self.logicObj = cl_install() # names incompatible options with --live self.optionsLiveIncompatible = ["type","d", "b", "mbr", "w", "f", "s","install","uninstall","build","u"] def _getNamesAllSetOptions(self): """Get list set options""" setOptDict = self.optobj.values.__dict__.items() defaultOptDict = self.optobj.get_default_values().__dict__.items() return reduce(lambda x,y: x+[y[0][0]], filter(lambda x:x[0][1] != x[1][1], zip(setOptDict,defaultOptDict)), []) def getStringIncompatibleOptions(self,listOpt): """Форматированная строка несовместимых опций разделенных ','""" return ", ".join(map(lambda x: len(x) == 1 and "'-%s'"%x or "'--%s'"%x, listOpt)) def checkIncompatibleLive(self): """Check incompatible options for option --live""" incompatible = list(set(self._getNamesAllSetOptions()) & set(self.optionsLiveIncompatible)) if incompatible: self.optobj.error(_("incompatible options")+":"+" %s"\ %self.getStringIncompatibleOptions(incompatible+["live"])) def checkIncompatibleInstallUninstall(self): """Check incompatible options for options --install and --uninstall""" opts = self._getNamesAllSetOptions() if len(opts)>1: self.optobj.error(_("incompatible options")+":"+" %s"\ %self.getStringIncompatibleOptions(opts)) def checkOpts(self, values, args): """Check values all specified options.""" if len(args) > 0: self.optobj.error(_("unrecognized option") + ": %s"% "".join(args)) if values.install or values.uninstall: self.checkIncompatibleInstallUninstall() if values.live: self.checkIncompatibleLive() if not values.v: if values.filter: errMsg = _("incorrect option") + ":" + " %s" %"--filter" +\ ": " + _("use with option '-v'") self.optobj.error(errMsg) return False if values.xml: errMsg = _("incorrect option") + ":" + " %s" %"--xml" +\ ": " + _("use with option '-v'") self.optobj.error(errMsg) return False if not (values.install or values.uninstall or values.live): if values.v is False and \ values.d is None and \ not self.logicObj.clVars.Get('os_install_dev_from'): self.optobj.error(_("need specify disk by '-d' option")) # check syntax DISK:DIR:FS:'Do I need to format the disk' if values.d: reTrueDisk = re.compile("^[^:]+(:[^:]*){0,3}$") wrongValue = filter(lambda x: not reTrueDisk.match(x),values.d) if wrongValue: self.optobj.error(_("option %s:") %"d" +\ " " + _("disk specifing error: '%s'")\ %", ".join(wrongValue)) # check syntax SRC_DIR:DEST_DIR if values.b: reTrueBind = re.compile("^[^:]+:[^:]+$") wrongValue = filter(lambda x: not reTrueBind.match(x),values.b) if wrongValue: self.optobj.error(_("option %s:") %"b" +\ " " + _("mount bind specifing error: '%s'")\ %", ".join(wrongValue)) # check syntax SWAP_DISK if values.w: reTrueBind = re.compile("^[^:]+$") wrongValue = filter(lambda x: not reTrueBind.match(x),values.w) if wrongValue: self.optobj.error(_("option %s:") %"w" +\ " " + _("mount bind specifing error: '%s'")\ %", ".join(wrongValue)) #check boot device if values.mbr: bootDisk = values.mbr reBootDisk = re.compile("^/dev/.+[^\d]|off$") if not reBootDisk.match(bootDisk): self.optobj.error(_("option %s:") %"mbr" + " " +\ _("disk specifing error: '%s'")%bootDisk) # check syntax --set self.optobj.checkVarSyntax(values) return (values, args) def setLang(self,lang): """Process set locales by lang""" if self.logicObj.setAllLocaleByLang(lang): return True else: self.printERROR(_("specified lang %s is unsupported")%lang) return False def setProxyNtpHostname(self,proxy,ntp,hostname): """Process set locales by lang""" if proxy: if not self.logicObj.clVars.SetWriteVar('os_install_proxy',proxy): self.printERROR(get_install_errors(),printBR=False) return False if ntp: if not self.logicObj.clVars.SetWriteVar('os_install_ntp',ntp): self.printERROR(get_install_errors(),printBR=False) return False if hostname: if "." in hostname: hostname, op, domain = hostname.partition('.') self.logicObj.clVars.Set('os_install_net_hostname', hostname,True) self.logicObj.clVars.Set('os_install_net_domain', domain,True) else: self.logicObj.clVars.Set('os_install_net_hostname', hostname,True) return True def setVars(self,options): """Process setting values for variables""" if options.set: for vals in options.set: for val in vals.split(','): k,o,v = val.partition('=') if self.logicObj.clVars.exists(k): if self.logicObj.clVars.SetWriteVar(k,v) == False: self.printERROR(get_install_errors(),printBR=False) return False else: self.printERROR(_('variable %s not found')%k) return False return True def setAction(self,live): """Set action by configuration or install system""" self.logicObj.clVars.Set('cl_action', "merge" if live else "system",True) def checkAndSetInstallOptions(self,diskOptions, swapOptions, bindOptions, usersOptions): """Check and set disk, swap and bind cmd options""" if self.optobj.values.s: self.logicObj.setLinuxName(self.optobj.values.s.upper()) if self.optobj.values.march: self.logicObj.clVars.Set('os_install_arch_machine', self.optobj.values.march,True) if self.optobj.values.nouuid: self.logicObj.clVars.Set('cl_uuid_set','off',True) if self.optobj.values.build: self.logicObj.clVars.Set('os_install_scratch',"on",True) else: self.logicObj.clVars.Set('os_install_scratch',"off",True) if self.optobj.values.type: self.logicObj.clVars.Set('os_install_root_type', self.optobj.values.type, True) listDiskOptions = [] listBindOptions = [] listSwapOptions = [] if diskOptions: listDiskOptions = self._parseOptDisk(diskOptions) if listDiskOptions is False: return False if bindOptions: listBindOptions = self._parseOptBind(bindOptions) if listBindOptions is False: return False if swapOptions: listSwapOptions = self._parseOptSwap(swapOptions) if listSwapOptions is False: return False if not self.logicObj.setInstallOptions(listDiskOptions, listBindOptions, listSwapOptions, usersOptions, self.optobj.values.mbr): return False return True def _parseOptSwap(self, listOpt): """Parse value cmd option --swap""" listNameOptions = ["dev"] lenOptions = len(listNameOptions) itemOptions = map(lambda x: (x,''), listNameOptions) rawListOpt = map(lambda x: filter(lambda y: y, x.split(':')), listOpt) sameLenListOpt = [] for listData in rawListOpt: lenListData = len(listData) if lenListData>1: errOpt = ":".join(filter(lambda x: x, listData)) self.printERROR(_("incorrect '%s'")%errOpt) return False dictOpt = {} dictOpt.update(zip(map(lambda x:x[0],itemOptions),listData)) sameLenListOpt.append(dictOpt) return sameLenListOpt def _parseOptBind(self, listOpt): """Parse value cmd option --bind""" listNameOptions = ["srcMountPoint", "destMountPoint"] lenOptions = len(listNameOptions) itemOptions = map(lambda x: (x,''), listNameOptions) rawListOpt = map(lambda x: filter(lambda y: y, x.split(':')), listOpt) sameLenListOpt = [] for listData in rawListOpt: lenListData = len(listData) if lenListData < lenOptions: listData += ['']*(lenOptions-lenListData) dictOpt = {} dictOpt.update(zip(map(lambda x: x[0], itemOptions),listData)) srcDir = dictOpt["srcMountPoint"] destDir = dictOpt["destMountPoint"] if not (srcDir and destDir): errOpt = ":".join(filter(lambda x: x, listData)) self.printERROR(_("incorrect '%s'")%errOpt) return False sameLenListOpt.append(dictOpt) return sameLenListOpt def _parseOptDisk(self, listOpt): """Parse value cmd option --disk""" listNameOptions = ["dev","mountPoint","fileSystem","options"] lenOptions = len(listNameOptions) itemOptions = map(lambda x: (x,''), listNameOptions) rawListOpt = map(lambda x: x.split(':'), listOpt) sameLenListOpt = [] for listData in rawListOpt: lenListData = len(listData) if lenListData < lenOptions: listData += ['']*(lenOptions-lenListData) dictOpt = {} dictOpt.update(zip(map(lambda x: x[0],itemOptions), listData)) options = [] strOptions = dictOpt["options"] if strOptions: options = filter(lambda x: x, strOptions.split(',')) dictOpt["options"] = options sameLenListOpt.append(dictOpt) return sameLenListOpt def templateSelect(self,template): """Process template appling""" if self.logicObj.applyTemplatesForSystem(): return True else: return False def installSystem(self, force=False, bootDisk=None, users=[], stdinReadPwd=False, builder=False, flagSpinner=True): """Run install system""" if self.logicObj.installSystem(force=force, bootDisk=bootDisk, stdinReadPwd=stdinReadPwd, builder=builder, flagSpinner=flagSpinner): self.defaultPrint("\n") self.defaultPrint(_("To apply changes you have to reboot")+".\n") return True else: return False def configureSystem(self): """Run configure system""" if self.logicObj.configureSystem(): return True else: return False def installPackage(self): """Run package installation""" if self.logicObj.installPackage(): return True else: return False def uninstallPackage(self): """Run package uninstallation""" if self.logicObj.uninstallPackage(): return True else: return False