You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
884 lines
36 KiB
884 lines
36 KiB
#-*- 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.
|
|
|
|
__version__ = "2.2.0.1"
|
|
__app__ = "calculate-assemble"
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
import traceback
|
|
from os import path
|
|
from cl_template import template,iniParser
|
|
from cl_utils import process,pathJoin,getRunCommands,getTupleVersion,isMount,\
|
|
isFstabMount,childMounts,_toUNICODE
|
|
from subprocess import STDOUT,PIPE
|
|
from cl_print import color_print
|
|
from cl_datavars import DataVars
|
|
from cl_distr import IsoDistributive, DirectoryDistributive, \
|
|
DistributiveError, PartitionDistributive, \
|
|
DistributiveRepository, ArchiveDistributive
|
|
from cl_vars_share import varsShare
|
|
|
|
from cl_lang import lang
|
|
lang().setLanguage(sys.modules[__name__])
|
|
from server.utils import dialogYesNo
|
|
import cl_install
|
|
import cl_overriding
|
|
|
|
def DEBUG(msg):
|
|
if "DEBUG" in os.environ:
|
|
sys.stderr.write("%s\n"%msg)
|
|
sys.stderr.flush()
|
|
|
|
class printNoColor:
|
|
def colorPrint(self,attr,fg,bg,string):
|
|
sys.stdout.write(string)
|
|
|
|
class AssembleError(Exception):
|
|
"""Installation Error"""
|
|
assemble_errors = ""
|
|
|
|
def installExit(self,*args,**kwars):
|
|
raise AssembleError(self.__class__.assemble_errors)
|
|
|
|
def overprintERROR(self,error):
|
|
self.__class__.assemble_errors += str(error) + "\n"
|
|
|
|
def getAssembleErrors(self):
|
|
return self.__class__.assemble_errors
|
|
|
|
def popAssembleErrors(self):
|
|
res = self.__class__.assemble_errors
|
|
self.__class__.assemble_errors = ""
|
|
return res
|
|
|
|
def getOverrideMethods(self):
|
|
return self.installExit, self.overprintERROR
|
|
|
|
cl_overriding.exit, cl_overriding.printERROR = \
|
|
AssembleError().getOverrideMethods()
|
|
|
|
class DataVarsAssemble(DataVars):
|
|
"""Variable class for assemble"""
|
|
|
|
def importAssemble(self, **args):
|
|
'''Get variables for assemble'''
|
|
# section name in calculate.env
|
|
envSection = "assemble"
|
|
# import assemble variables
|
|
self.importData(envSection, ('cl_vars_assemble','cl_fill_assemble'))
|
|
|
|
class cl_assemble(color_print):
|
|
"""Primary class for assemble actions"""
|
|
|
|
def __init__(self):
|
|
self.clVars = None
|
|
self.startMessage = ""
|
|
self.lenStartMessage = 0
|
|
self.clTempl = None
|
|
self.force = False
|
|
self.assembleEnvFile = '/etc/calculate/assemble.env'
|
|
|
|
def setNoColor(self):
|
|
self.color = False
|
|
|
|
def initVars(self):
|
|
"""Primary initialization of variables"""
|
|
self.clVars = DataVarsAssemble()
|
|
self.clVars.importAssemble()
|
|
self.clVars.flIniFile()
|
|
|
|
def applyConfigureTemplates(self,directory,message=None):
|
|
"""Apply templates for root of system."""
|
|
if message:
|
|
self.printMessageForTest(message)
|
|
self.clVars.Set("cl_chroot_path",directory, True)
|
|
self.clTempl = template(self.clVars)
|
|
dirsFiles = self.clTempl.applyTemplates()
|
|
self.clTempl.closeFiles()
|
|
if self.clTempl.getError():
|
|
raise AssembleError(self.clTempl.getError())
|
|
else:
|
|
return dirsFiles
|
|
|
|
def printMessageForTest(self, message, lenMsg=False):
|
|
"""Print waiting message and OK or Error by func result"""
|
|
self.printByResult(True)
|
|
message = "%s ..." % message
|
|
self.printSUCCESS(message,printBR=False)
|
|
self.startMessage = message
|
|
if lenMsg:
|
|
self.lenStartMessage = lenMsg
|
|
else:
|
|
self.lenStartMessage = self.lenString(self.startMessage)
|
|
|
|
def printOnlyNotOK(self, string, offsetL=0, printBR=True):
|
|
"""Вывод на печать в случае сбоя"""
|
|
self._printSysOut = sys.stdout
|
|
self.printLine((('', string),),
|
|
(('blueBr','['),
|
|
('redBr',' !! '),
|
|
('blueBr',']'),
|
|
), offsetL, printBR)
|
|
|
|
def printByResult(self,result,failMessage=None):
|
|
if self.startMessage:
|
|
offset = 3
|
|
if result:
|
|
self.printOnlyOK(" ", self.lenStartMessage + offset)
|
|
else:
|
|
self.printOnlyNotOK(" ", self.lenStartMessage + offset)
|
|
if failMessage:
|
|
self.printERROR(failMessage)
|
|
self.startMessage = ""
|
|
self.lenStartMessage = 0
|
|
|
|
def setAction(self,action):
|
|
if action == "break":
|
|
self.clVars.Set("cl_action","break",True)
|
|
elif action == "make":
|
|
self.clVars.Set("cl_action","make",True)
|
|
elif action == "dependence":
|
|
self.clVars.Set("cl_action","dependence",True)
|
|
else:
|
|
self.clVars.Set("cl_action","configure",True)
|
|
|
|
def printInfo(self):
|
|
self.printSUCCESS(_("Preparing for assembling of") + " Calculate Linux")
|
|
self.defaultPrint("%s\n"%_("System information"))
|
|
subname = self.clVars.Get('os_assemble_linux_subname')
|
|
subname = (" %s"%subname) if subname else ""
|
|
self.printSUCCESS(_("Assembling system")+": %s"%
|
|
self.clVars.Get('os_assemble_linux_name')+subname)
|
|
self.printSUCCESS(_("System version")+": %s"%
|
|
self.clVars.Get('os_assemble_linux_ver'))
|
|
self.printSUCCESS(_("Machine hardware name")+": %s"%
|
|
self.clVars.Get('os_assemble_arch_machine'))
|
|
self.printSUCCESS(_("Partition for assembling: %s")%
|
|
self.clVars.Get('os_assemble_root_dev'))
|
|
self.printSUCCESS(_("File system: %s")%
|
|
self.clVars.Get('os_assemble_root_format'))
|
|
self.printSUCCESS(_("Stage for assembling: %s")%
|
|
self.clVars.Get('cl_assemble_image'))
|
|
if self.clVars.Get('cl_assemble_image_type') == "stage":
|
|
self.printSUCCESS(_("Portage snapshot for assembling: %s")%
|
|
self.clVars.Get('cl_assemble_snapshot_portage'))
|
|
self.defaultPrint("%s\n"%_("Perform pre-assemble checkups"))
|
|
|
|
self.defaultPrint("\n")
|
|
if not self.clVars.Get('cl_assemble_image'):
|
|
self.printWARNING("No path for image creating.")
|
|
|
|
def printConfInfo(self):
|
|
self.printSUCCESS(_("Breaking assembling of") + " Calculate Linux")
|
|
self.defaultPrint("%s\n"%_("System information"))
|
|
subname = self.clVars.Get('os_assemble_linux_subname')
|
|
subname = (" %s"%subname) if subname else ""
|
|
self.printSUCCESS(_("Assembling system")+": %s"%
|
|
self.clVars.Get('os_assemble_linux_name')+subname)
|
|
self.printSUCCESS(_("System version")+": %s"%
|
|
self.clVars.Get('os_assemble_linux_ver'))
|
|
self.printSUCCESS(_("Machine hardware name")+": %s"%
|
|
self.clVars.Get('os_assemble_arch_machine'))
|
|
self.printSUCCESS(_("Partition for assembling: %s")%
|
|
self.clVars.Get('os_assemble_root_dev'))
|
|
self.printSUCCESS(_("System is assembled into directory: %s")%
|
|
self.clVars.Get('cl_assemble_path'))
|
|
|
|
self.defaultPrint("\n")
|
|
|
|
def _checkAlreadyAssembling(self):
|
|
section = ",".join(self.__sectionName())
|
|
if section in self.clVars.Get('cl_assemble_distro'):
|
|
return False
|
|
return True
|
|
|
|
def preassembleCheckups(self):
|
|
dev = self.clVars.Get('os_assemble_root_dev')
|
|
mp = isFstabMount(dev)
|
|
if mp:
|
|
self.printERROR(
|
|
_("'%(dev)s' is used as '%(mp)s' in current system")%
|
|
{'dev':dev,'mp':mp})
|
|
return False
|
|
if not self._checkAlreadyAssembling():
|
|
dev = self.readEnv('os_assemble_root_dev') or dev
|
|
mp = isMount(dev)
|
|
self.printERROR(_("%(system)s %(arch)s is assembling in"
|
|
" '%(dir)s' now")%
|
|
{'system':self.clVars.Get('os_assemble_linux_shortname'),
|
|
'arch':self.clVars.Get('os_assemble_arch_machine'),
|
|
'dir':mp})
|
|
return False
|
|
mp = isMount(dev)
|
|
if mp:
|
|
self.printERROR(_("'%(dev)s' already mounted to '%(mp)s'")%
|
|
{'dev':dev,'mp':mp})
|
|
return False
|
|
return True
|
|
|
|
def _askUser(self,force,question,):
|
|
"""Ask user about continue"""
|
|
if not force:
|
|
dialogMessage = question + " (yes/no)"
|
|
try:
|
|
dialogRes = dialogYesNo(dialogMessage)
|
|
except KeyboardInterrupt:
|
|
self.defaultPrint("\n")
|
|
raise KeyboardInterrupt
|
|
if dialogRes in (None,False):
|
|
return False
|
|
return True
|
|
|
|
# configure helper functions
|
|
def _unpackPortage(self):
|
|
"""Unpack portage"""
|
|
stageName = self.clVars.Get('cl_assemble_snapshot_portage')
|
|
self.printMessageForTest(_("Unpacking portage"))
|
|
portageSources = ArchiveDistributive(stageName)
|
|
portageTarget = DirectoryDistributive(
|
|
path.join(self.assemblePath,"usr"))
|
|
portageTarget.installFrom(portageSources)
|
|
|
|
def _formatAndUnpackStage(self):
|
|
"""Format partition for assemble and unpack stage"""
|
|
self.printMessageForTest(_("Formating partition"))
|
|
self.targetDistr.performFormat()
|
|
|
|
self.printMessageForTest(_("Unpacking stage image into target"))
|
|
self.saveVars('os_assemble_root_dev')
|
|
self.targetDistr.installFrom(self.sourceDistr)
|
|
self.assemblePath = \
|
|
self.targetDistr.convertToDirectory().getDirectory()
|
|
self.clVars.Set('cl_assemble_path', self.assemblePath, True)
|
|
self.saveVars('os_assemble_linux_shortname',
|
|
'os_assemble_linux_ver',
|
|
'os_assemble_arch_machine',
|
|
'cl_assemble_image',
|
|
'os_assemble_root_dev',
|
|
'cl_assemble_path')
|
|
|
|
def _getTarget(self):
|
|
rootPartdev = self.clVars.Get('os_assemble_root_dev')
|
|
formatId = PartitionDistributive.formatId
|
|
fileSystem = self.clVars.Get('os_assemble_root_format')
|
|
return PartitionDistributive(rootPartdev,
|
|
mdirectory=self.clVars.Get('cl_assemble_path'),
|
|
check=True, fileSystem=fileSystem, isFormat=True,
|
|
systemId=formatId.get(fileSystem,"83"),
|
|
flagRemoveDir=False,
|
|
rootLabel="%s-%s"%
|
|
(self.clVars.Get('os_assemble_linux_shortname'),
|
|
self.clVars.Get('os_assemble_linux_ver')))
|
|
|
|
def _prepareMount(self):
|
|
"""Mount /proc,/sys, remote, /dev to chroot"""
|
|
mountResources = ((None,"-t proc","/proc"),
|
|
(None,"-t sysfs","/sys"),
|
|
("/var/calculate/remote",None,None),
|
|
("/dev",None,None),
|
|
("/dev/shm",None,None),
|
|
("/dev/pts",None,None))
|
|
for source,opts,target in mountResources:
|
|
opts = opts or "-o bind"
|
|
target = target or source
|
|
self.printMessageForTest(_("Mounting %s")%(source or target))
|
|
target = pathJoin(self.assemblePath,target)
|
|
if not path.exists(target):
|
|
os.makedirs(target,mode=0755)
|
|
if source == isMount(target):
|
|
continue
|
|
args = ["mount"]+opts.split()+[str(source).lower(),target]
|
|
mountProcess = process(*args)
|
|
if mountProcess.failed():
|
|
raise AssembleError(_("Can not mount %(from)s to %(to)s")%
|
|
{'from':source,'to':target})
|
|
if self.targetDistr:
|
|
DirectoryDistributive(target,parent=self.targetDistr)
|
|
self.printByResult(True)
|
|
|
|
def _updatePackages(self):
|
|
"""Update portage and calculate overlay"""
|
|
emergeSync = "emerge --sync"
|
|
self.printMessageForTest(_("Executing '%s'")%emergeSync)
|
|
self.runChroot(emergeSync)
|
|
|
|
emergeLayman = 'USE="git" emerge layman'
|
|
self.printMessageForTest(_("Executing '%s'")%emergeLayman)
|
|
self.runChroot(emergeLayman)
|
|
|
|
self.printMessageForTest(_("Loading calculate overlay"))
|
|
if filter(lambda x:"calculate" in x,self.runChroot("layman -l")):
|
|
self.runChroot("layman -s calculate")
|
|
else:
|
|
self.runChroot("layman -L")
|
|
self.runChroot("layman -a calculate")
|
|
|
|
def _updateMan(self):
|
|
"""Remove man, install man-db"""
|
|
self.printMessageForTest(
|
|
_("Updating man program"))
|
|
removeMan = "CLEAN_DELAY=0 emerge -C --backtrack=0 " \
|
|
"sys-apps/man"
|
|
self.runChroot(removeMan)
|
|
self.runChroot("emerge sys-apps/man-db")
|
|
self.printByResult(True)
|
|
|
|
def _updateBaselayout(self):
|
|
"""Remove baselayout, update openrc"""
|
|
self.printMessageForTest(
|
|
_("Updating baselayout and compiling openrc"))
|
|
removeBaselayout = "CLEAN_DELAY=0 emerge -C --backtrack=0 " \
|
|
"sys-apps/baselayout sys-apps/sysvinit"
|
|
self.runChroot(removeBaselayout)
|
|
self._removeFiles("/etc/init.d/depscan.sh","/etc/init.d/functions.sh",
|
|
"/etc/init.d/runscript.sh",
|
|
prefix=self.assemblePath,
|
|
errormsg=_("Can not remove files from baselayout"))
|
|
self.runChroot("emerge sys-apps/openrc sys-apps/sysvinit "
|
|
"sys-fs/udev sys-fs/e2fsprogs")
|
|
self._removeFiles("/etc/runlevels/boot/network",
|
|
prefix=self.assemblePath)
|
|
self.printByResult(True)
|
|
|
|
def configureFunc(self,force=False,nounmount=False):
|
|
"""Function of configure partition for assembling by make"""
|
|
# print info
|
|
self.printInfo()
|
|
if not self.preassembleCheckups():
|
|
return False
|
|
self.targetDistr = self._getTarget()
|
|
distName = self.clVars.Get('cl_assemble_image')
|
|
if distName and self.targetDistr:
|
|
distRep = DistributiveRepository()
|
|
self.sourceDistr = distRep.getDistributiveByFile(distName)
|
|
if not self._askUser(force, _("Continue with the assembling"
|
|
" of the system")):
|
|
self.printERROR(_("Interrupting the assembling"))
|
|
return False
|
|
self.writeVar('cl_assemble_make','configure')
|
|
# format partion
|
|
self._formatAndUnpackStage()
|
|
if nounmount:
|
|
self.targetDistr = None
|
|
|
|
pathAppMisc = pathJoin(self.assemblePath,'/var/db/pkg/app-misc')
|
|
metaPackage = self.clVars.Get('cl_assemble_meta').rpartition('/')[2]
|
|
|
|
if path.exists(pathAppMisc) and \
|
|
filter(lambda x:metaPackage in x, os.listdir(pathAppMisc)):
|
|
self._prepareMount()
|
|
self.writeVar('cl_assemble_step_system','2')
|
|
return True
|
|
if not isinstance(self.sourceDistr,IsoDistributive):
|
|
self._unpackPortage()
|
|
self.applyConfigureTemplates(self.assemblePath,
|
|
_("Configurate assembling system"))
|
|
self._prepareMount()
|
|
self._updatePackages()
|
|
self.clVars.Set('cl_action',"setup",True)
|
|
self.applyConfigureTemplates(self.assemblePath,
|
|
_("Update configuration of assembling system"))
|
|
|
|
self.printMessageForTest(
|
|
_("Linking calculate-install to package configuration"))
|
|
self.runChroot('USE="minimal" emerge sys-apps/calculate-install')
|
|
self.runChroot("cl-install --install")
|
|
|
|
emergePortage = "emerge sys-apps/portage"
|
|
self.printMessageForTest(_("Executing '%s'")%emergePortage)
|
|
self.runChroot(emergePortage)
|
|
|
|
if not isinstance(self.sourceDistr,IsoDistributive):
|
|
self.printMessageForTest(_("Receiving kernel sources"))
|
|
self.runChroot("USE='-vmlinuz' emerge "
|
|
"sys-kernel/calculate-sources")
|
|
|
|
if not isinstance(self.sourceDistr,IsoDistributive):
|
|
emergeV86d = "emerge sys-apps/v86d"
|
|
self.printMessageForTest(_("Executing '%s'")%emergeV86d)
|
|
self.runChroot(emergeV86d)
|
|
|
|
if not isinstance(self.sourceDistr,IsoDistributive):
|
|
self._updateBaselayout()
|
|
if self.clVars.Get('os_assemble_linux_system') == "server" or \
|
|
self.clVars.Get('os_assemble_linux_shortname') != "CLS":
|
|
self._removeFiles("/etc/init.d/net.eth0",
|
|
prefix=self.assemblePath)
|
|
if not isinstance(self.sourceDistr,IsoDistributive):
|
|
self._updateMan()
|
|
|
|
self.printMessageForTest(_("Executing '%s'")%"etc-update")
|
|
self.runChroot("OVERWRITE_ALL='yes' etc-update")
|
|
|
|
if not isinstance(self.sourceDistr,IsoDistributive):
|
|
if self.clVars.Get('os_assemble_linux_system')=='desktop':
|
|
self.groupAdd(35,"games")
|
|
self.groupAdd(440,"plugdev")
|
|
self.groupAdd(441,"scanner")
|
|
if self.clVars.Get('os_assemble_linux_shortname')=='CDS':
|
|
self.userAdd(100,"p2p",mode=0700,chown=(100,0),
|
|
home="/home/p2p",groups=["100","wheel"],
|
|
comment="added by Calculate for p2p",
|
|
shell="/bin/bash",prefix=self.assemblePath)
|
|
|
|
if isinstance(self.sourceDistr,IsoDistributive):
|
|
self.writeVar('cl_assemble_step_system','0')
|
|
return True
|
|
return False
|
|
|
|
def userAdd(self,userid,username,mode=0755,chown=(0,0),home=None,
|
|
groups=[],comment="",shell="/bin/bash",prefix="/"):
|
|
"""Check exists user and create new"""
|
|
if self.runChroot("id %s"%username,raiseError=False).failed():
|
|
self.printMessageForTest(
|
|
_("Creating %(user)s(%(id)d) user")%
|
|
{'user':username,'id':userid})
|
|
command = "useradd -u %d %s"%(userid,username)
|
|
if groups:
|
|
command += " -g %s"%groups[0]
|
|
if len(groups)>1:
|
|
command += " -G %s"%",".join(groups[1:])
|
|
if comment:
|
|
command += " -c '%s'"%comment
|
|
if shell:
|
|
command += " -s %s"%shell
|
|
self.runChroot(command)
|
|
try:
|
|
os.makedirs(pathJoin(prefix,home),mode=mode)
|
|
os.chown(pathJoin(prefix,home),chown[0],chown[1])
|
|
except (OSError,IOError),e:
|
|
raise AssembleError(
|
|
_("Can not create home directory for %s")%username)
|
|
|
|
def groupAdd(self,groupid,groupname):
|
|
"""Check exists group and create new"""
|
|
if self.runChroot("groupmems -l -g %s"
|
|
%groupname,raiseError=False).failed():
|
|
self.printMessageForTest(
|
|
_("Creating %(name)s(%(id)d) group")%
|
|
{'name':groupname,'id':groupid})
|
|
self.runChroot("groupadd -g %d %s"%(groupid,groupname))
|
|
self.printByResult(True)
|
|
|
|
def _removeFiles(self,*files,**kwarg):
|
|
"""Remove files specified by files list"""
|
|
prefix = kwarg.get("prefix","/")
|
|
errormsg = kwarg.get("errormsg",None)
|
|
try:
|
|
rmFile = ""
|
|
for fileName in files:
|
|
rmFile = pathJoin(prefix,fileName)
|
|
if path.lexists(rmFile):
|
|
os.unlink(rmFile)
|
|
except (OSError,IOError),e:
|
|
if errormsg is None:
|
|
raise AssembleError(_("Can not remove '%s'")%rmFile)
|
|
else:
|
|
raise AssembleError(errormsg)
|
|
|
|
def _getCommand(self,commandlist):
|
|
return " ".join(map(lambda x:'"%s"'%x if " " in x else x,commandlist))
|
|
|
|
def runChroot(self,command,raiseError=True,showProcess=False):
|
|
"""Run command in chroot specified by cl_assemble_path"""
|
|
try:
|
|
if showProcess:
|
|
IOval = None
|
|
else:
|
|
IOval = PIPE
|
|
chrootCommand = process("chroot",
|
|
self.clVars.Get('cl_assemble_path'),
|
|
"/bin/bash","-c",command,stderr=IOval,
|
|
stdout=IOval,env_dict={'CHROOT':"on"})
|
|
DEBUG(self._getCommand(chrootCommand.command))
|
|
if raiseError and chrootCommand.failed():
|
|
raise AssembleError(
|
|
_("An error occurred during the command executing")+
|
|
":\n %s"%self._getCommand(chrootCommand.command))
|
|
except KeyboardInterrupt:
|
|
chrootCommand.kill()
|
|
self.defaultPrint("\b\b")
|
|
raise AssembleError(
|
|
_("An interrupt occurred during the command executing")+
|
|
":\n %s"%self._getCommand(chrootCommand.command))
|
|
return chrootCommand
|
|
|
|
def configureSystem(self,force,nounmount):
|
|
"""Unpack stage or cls|css and prepare for assemble"""
|
|
self.msgOperationComplete = ""
|
|
self.msgOperationFailed = \
|
|
_("Preparing for assembling failed")
|
|
if not self._pidCheck():
|
|
return False
|
|
res = self.make(self.configureFunc,force,nounmount)
|
|
if res:
|
|
self.printSUCCESS(
|
|
_("System was have prepared for assembling successfully in %s")%
|
|
self.clVars.Get('cl_assemble_path'))
|
|
return res
|
|
|
|
def breakFunc(self,force):
|
|
rootPartdev = self.clVars.Get('os_assemble_root_dev')
|
|
mp = isMount(rootPartdev)
|
|
if self._checkAlreadyAssembling() or not mp:
|
|
self.printERROR(_("For performance of operation it is "
|
|
"necessary to configure system")+".")
|
|
self.printERROR(_('Execute with parameter')+' "--configure".')
|
|
self.removeDistroInfo()
|
|
return False
|
|
|
|
self.printConfInfo()
|
|
if not self._askUser(force, _("Continue breaking assembling"
|
|
" of the system")):
|
|
self.printERROR(_("Interrupting the breaking"))
|
|
return False
|
|
mps = filter(lambda x:x!=mp,map(lambda x:x[1],childMounts(mp)))
|
|
for target in sorted(mps, reverse=True):
|
|
self.printMessageForTest(_("Unmounting %s")%(target[len(mp):]))
|
|
umountProcess = process("umount",target)
|
|
if umountProcess.failed():
|
|
raise AssembleError(_("Can not umount %s")%target)
|
|
self.printByResult(True)
|
|
self.targetDistr = PartitionDistributive(rootPartdev,
|
|
mdirectory='/mnt/builder',flagRemoveDir=False)
|
|
dd = DirectoryDistributive(mp,parent=self.targetDistr)
|
|
return True
|
|
|
|
def checkDependence(self):
|
|
rootPartdev = self.clVars.Get('os_assemble_root_dev')
|
|
mp = isMount(rootPartdev)
|
|
if self._checkAlreadyAssembling() or not mp:
|
|
self.printERROR(_("For performance of operation it is "
|
|
"necessary to configure system")+".")
|
|
self.printERROR(_('Execute with parameter')+' "--configure".')
|
|
return False
|
|
self.printConfInfo()
|
|
|
|
command = "emerge -pv %s"%self.clVars.Get('cl_assemble_meta')
|
|
self.printSUCCESS(_("Executing '%s'")% command + " ...")
|
|
if self.runChroot(command, showProcess=True,
|
|
raiseError=False).success():
|
|
self.printSUCCESS(_("%(system)s %(arch)s ready for compile")%
|
|
{'system':self.clVars.Get('os_assemble_linux_shortname'),
|
|
'arch':self.clVars.Get('os_assemble_arch_machine')})
|
|
return True
|
|
else:
|
|
self.printSUCCESS(_("%(system)s %(arch)s have wrong dependence")%
|
|
{'system':self.clVars.Get('os_assemble_linux_shortname'),
|
|
'arch':self.clVars.Get('os_assemble_arch_machine')})
|
|
return False
|
|
|
|
def breakAssembling(self,force):
|
|
self.msgOperationComplete = \
|
|
_("Break of system assembling is successfully")
|
|
self.msgOperationFailed = \
|
|
_("Breaking of system assembling failed")
|
|
if not self._pidCheck():
|
|
return False
|
|
return self.make(self.breakFunc,force)
|
|
|
|
def _pidCheck(self):
|
|
"""Check pid for run"""
|
|
if str(os.getpid()) != self.clVars.Get('cl_assemble_pid'):
|
|
self.printERROR(_("cl-assemble already run")+" "+
|
|
self._getNameByAction() +
|
|
_(" of distributive %(system)s %(arch)s")%
|
|
{'system':self.clVars.Get('os_assemble_linux_shortname'),
|
|
'arch':self.clVars.Get('os_assemble_arch_machine')})
|
|
return False
|
|
else:
|
|
self.saveVars('cl_assemble_pid')
|
|
return True
|
|
|
|
def makeSystem(self,force):
|
|
self.msgOperationComplete = \
|
|
_("System assembled is successfully")
|
|
self.msgOperationFailed = \
|
|
_("System compiling failed")
|
|
if not self._pidCheck():
|
|
return False
|
|
return self.make(self.makeFunc,force,True)
|
|
|
|
def updateSystem(self,force):
|
|
self.msgOperationComplete = \
|
|
_("System assembled is successfully")
|
|
self.msgOperationFailed = \
|
|
_("System compiling failed")
|
|
if not self._pidCheck():
|
|
return False
|
|
if self.clVars.Get('cl_assemble_image_type') == 'stage':
|
|
self.printERROR(_("Impossible to update the distributive "
|
|
"which assembled by stage"))
|
|
return False
|
|
return self.make(self.makeFunc,force)
|
|
|
|
def _getNameByAction(self):
|
|
act = self.clVars.Get('cl_assemble_make')
|
|
if act == "configure":
|
|
return _("for configuration")
|
|
elif act == "break":
|
|
return _("for breaking assemblinig")
|
|
elif act == "system":
|
|
return _("for system packages compiling")
|
|
elif act != "":
|
|
return _("for package compiling")
|
|
else:
|
|
return ""
|
|
|
|
def makeFunc(self,force,forcesystem=False):
|
|
rootPartdev = self.clVars.Get('os_assemble_root_dev')
|
|
mp = isMount(rootPartdev)
|
|
if self._checkAlreadyAssembling() or not mp:
|
|
self.printERROR(_("For performance of operation it is "
|
|
"necessary to configure system")+".")
|
|
self.printERROR(_('Execute with parameter')+' "--configure".')
|
|
return False
|
|
self.printConfInfo()
|
|
self.defaultPrint("%s\n"%_("Perform pre-compile checkups"))
|
|
|
|
if self.clVars.Get('cl_assemble_step_system') == '':
|
|
self.printWARNING(_("WARNING") +": " +
|
|
_("assemble configuration was not completed"))
|
|
force = False
|
|
if self.clVars.Get('cl_assemble_image_type') == 'iso' and \
|
|
forcesystem:
|
|
self.printERROR(_("WARNING") +": " +
|
|
_("will be recompiled system packages"))
|
|
return False
|
|
self.defaultPrint("\n")
|
|
|
|
if not self._askUser(force, _("Continue package compilation"
|
|
" of the system")):
|
|
self.printERROR(_("Interrupting the compilation"))
|
|
return False
|
|
makeComplete = False
|
|
baseType = self.clVars.Get('cl_assemble_image_type')
|
|
getMake = lambda : self.clVars.Get('cl_assemble_make')
|
|
getStepCount = self._getStepCount
|
|
while not makeComplete:
|
|
if (baseType != "iso" or forcesystem) and \
|
|
getMake() in ("newuse","") and getStepCount('system') < 2:
|
|
self._resumeCompile() or self._compileSystem()
|
|
self._incStepClearMake('system')
|
|
elif baseType == "iso" and \
|
|
getMake() in ("newuse","") and getStepCount('newuse')<1:
|
|
self._resumeCompile() or self._compileNewuse()
|
|
self._incStepClearMake('newuse')
|
|
elif baseType == "iso" and \
|
|
getMake() in ("update","") and getStepCount('update')< 1:
|
|
self._resumeCompile() or self._compileUpdate()
|
|
self._incStepClearMake('update')
|
|
elif getMake() in ("world",""):
|
|
self._compileWorld()
|
|
self.writeVar('cl_assemble_make','')
|
|
makeComplete = True
|
|
return True
|
|
|
|
def _printCheckExecute(self,command,action,step="world"):
|
|
if not action in self.clVars.Get('cl_assemble_step_%s'%step):
|
|
self.printSUCCESS(_("Executing '%s'")% command + " ...")
|
|
self.runChroot(command, showProcess=True)
|
|
self._appendToStep(step,action)
|
|
|
|
def _compileWorld(self):
|
|
"""World compiling"""
|
|
self.writeVar('cl_assemble_make','world')
|
|
self._printCheckExecute("emerge --noreplace %s"% \
|
|
self.clVars.Get('cl_assemble_meta'),"meta")
|
|
self._printCheckExecute("emerge -D --newuse world","newuse")
|
|
self._printCheckExecute("python-updater","python")
|
|
if path.exists(pathJoin(self.clVars.Get('cl_assemble_path'),
|
|
"/usr/bin/perl-cleaner")):
|
|
self._printCheckExecute("perl-cleaner all","perl")
|
|
if path.exists(pathJoin(self.clVars.Get('cl_assemble_path'),
|
|
"/usr/sbin/module-rebuild")):
|
|
self._printCheckExecute("module-rebuild -X rebuild","modules")
|
|
self._printCheckExecute("emerge -uD world","update")
|
|
self._printCheckExecute("emerge --depclean","depclean")
|
|
if path.exists(pathJoin(self.clVars.Get('cl_assemble_path'),
|
|
"/usr/bin/revdep-rebuild")):
|
|
self._printCheckExecute("revdep-rebuild","revdep")
|
|
self._appendToStep("world","finish")
|
|
|
|
def _compileNewuse(self):
|
|
"""New use compiling"""
|
|
self.writeVar('cl_assemble_make','newuse')
|
|
emergeCommand = "emerge -D --newuse world"
|
|
self.printSUCCESS(_("Executing '%s'")% emergeCommand + " ...")
|
|
self.runChroot(emergeCommand, showProcess=True)
|
|
|
|
def _compileUpdate(self):
|
|
"""Update compiling"""
|
|
self.writeVar('cl_assemble_make','update')
|
|
emergeCommand = "emerge -uD world"
|
|
self.printSUCCESS(_("Executing '%s'")% emergeCommand + " ...")
|
|
self.runChroot(emergeCommand, showProcess=True)
|
|
|
|
def _compileSystem(self):
|
|
"""System compiling"""
|
|
self.writeVar('cl_assemble_make','system')
|
|
emergeCommand = "emerge -e system"
|
|
self.printSUCCESS(_("Executing '%s'")% emergeCommand + " ...")
|
|
self.runChroot(emergeCommand, showProcess=True)
|
|
|
|
def _resumeCompile(self):
|
|
if self.clVars.Get('cl_assemble_make'):
|
|
if self.clVars.Get('cl_assemble_skipfirst') == "yes":
|
|
emergeCommand = "emerge --resume --skipfirst"
|
|
else:
|
|
emergeCommand = "emerge --resume"
|
|
self.printSUCCESS(_("Executing '%s'")% emergeCommand + " ...")
|
|
self.runChroot(emergeCommand, showProcess=True)
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def __sectionName(self):
|
|
"""Get section name of assemble.env by shortname and arch"""
|
|
return (self.clVars.Get('os_assemble_linux_shortname'),
|
|
self.clVars.Get('os_assemble_arch_machine'))
|
|
|
|
def writeVar(self,varname,varvalue,setvar=True):
|
|
"""Write variable to assemble env file"""
|
|
assembleEnv = iniParser(self.assembleEnvFile)
|
|
if setvar:
|
|
self.clVars.Set(varname,varvalue,True)
|
|
return assembleEnv.setVar(self.__sectionName(),{varname:varvalue})
|
|
|
|
def readEnv(self,varname):
|
|
"""Read variable from assemble env file"""
|
|
assembleEnv = iniParser(self.assembleEnvFile)
|
|
return _toUNICODE(assembleEnv.getVar(self.__sectionName(),
|
|
varname)).encode('utf-8')
|
|
|
|
def saveVars(self,*varsname):
|
|
"""Save vars with it current values"""
|
|
assembleEnv = iniParser(self.assembleEnvFile)
|
|
return assembleEnv.setVar(self.__sectionName(),
|
|
dict(map(lambda x:(x,self.clVars.Get(x)),varsname)))
|
|
|
|
def _cleanEnv(self,assembleEnv):
|
|
if not assembleEnv.getAllSectionNames():
|
|
os.unlink(self.assembleEnvFile)
|
|
elif not ",".join(self.__sectionName()) in \
|
|
assembleEnv.getAllSectionNames():
|
|
assembleEnv.delArea(self.__sectionName())
|
|
|
|
def removeDistroInfo(self):
|
|
assembleEnv = iniParser(self.assembleEnvFile)
|
|
assembleEnv.delArea(self.__sectionName())
|
|
self._cleanEnv(assembleEnv)
|
|
|
|
def removeVars(self,*varsname):
|
|
"""Remove vars specified by varsname"""
|
|
res = True
|
|
assembleEnv = iniParser(self.assembleEnvFile)
|
|
for var in varsname:
|
|
res = res and assembleEnv.delVar(self.__sectionName(),var)
|
|
self._cleanEnv(assembleEnv)
|
|
return bool(res)
|
|
|
|
def _getStepCount(self,stepname):
|
|
"""Get value of variable as number"""
|
|
val = self.clVars.Get("cl_assemble_step_%s"%stepname)
|
|
if val.isdigit():
|
|
return int(val)
|
|
else:
|
|
return 0
|
|
|
|
def _appendToStep(self,stepname,newaction):
|
|
"""Append action to step"""
|
|
curval = self.clVars.Get('cl_assemble_step_%s'%stepname)
|
|
curval = filter(lambda x:x,map(lambda x:x.strip(),curval.split(',')))
|
|
if curval:
|
|
curval.append(newaction)
|
|
else:
|
|
curval = [newaction]
|
|
return self.writeVar("cl_assemble_step_%s"%stepname,",".join(curval))
|
|
|
|
def _incStepClearMake(self,stepname):
|
|
"""Increase make step, specified by stepname, and clear make"""
|
|
self.writeVar('cl_assemble_make','')
|
|
return self.writeVar("cl_assemble_step_%s"%stepname,
|
|
str(self._getStepCount(stepname) + 1))
|
|
|
|
def make(self,logicFunc,*argv):
|
|
"""Make iso image by variables"""
|
|
self.sourceDistr = None
|
|
self.targetDistr = None
|
|
error = None
|
|
try:
|
|
try:
|
|
if not logicFunc(*argv):
|
|
return False
|
|
except KeyboardInterrupt:
|
|
raise KeyboardInterrupt
|
|
except (EOFError), e:
|
|
error = e
|
|
except (AssembleError,DistributiveError),e:
|
|
error = e
|
|
except (Exception),e:
|
|
error = ""
|
|
for i in apply(traceback.format_exception, sys.exc_info()):
|
|
error += i
|
|
except KeyboardInterrupt,e:
|
|
self.defaultPrint("\b\b")
|
|
self.printByResult(False)
|
|
self.printWARNING(_("Interrupting the system assembling"))
|
|
error = _("System assembling manually interrupt")
|
|
try:
|
|
if self.clTempl:
|
|
self.clTempl.closeFiles()
|
|
if error or logicFunc == self.breakFunc:
|
|
self.printByResult(False)
|
|
if self.targetDistr:
|
|
self.removeDistroInfo()
|
|
self.printMessageForTest(
|
|
_("Releasing partition for assembling"))
|
|
assemblePath = \
|
|
self.targetDistr.convertToDirectory().getDirectory()
|
|
self.targetDistr.close()
|
|
if assemblePath.startswith('/mnt/builder'):
|
|
if path.exists(assemblePath):
|
|
os.rmdir(assemblePath)
|
|
self.printByResult(True)
|
|
if self.sourceDistr:
|
|
self.printMessageForTest(_("Releasing source data"))
|
|
self.sourceDistr.close()
|
|
self.printByResult(True)
|
|
except (AssembleError,DistributiveError),e:
|
|
if error:
|
|
error = "%s\n%s" % (str(error),_("Unmounting error"))
|
|
else:
|
|
error = _("Unmounting error")
|
|
except KeyboardInterrupt,e:
|
|
self.defaultPrint("\b\b")
|
|
error = _("Unmounting error")
|
|
if error:
|
|
self.printByResult(False)
|
|
if error:
|
|
for line in filter(lambda x: x,str(error).split('\n')):
|
|
self.printERROR(line)
|
|
self.printERROR(self.msgOperationFailed)
|
|
self.removeVars('cl_assemble_pid')
|
|
return False
|
|
if self.msgOperationComplete:
|
|
self.printSUCCESS(self.msgOperationComplete)
|
|
self.removeVars('cl_assemble_pid')
|
|
return True
|