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.
calculate-utils-2.2-assemble/pym/cl_assemble.py

1938 lines
82 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.28"
__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,cmpVersion, \
listDirectory, readFile, removeDir, getPkgInstalled, \
getTupleVersion, isPkgInstalled,reVerSplitToPV
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_overriding
import random
from shutil import copyfile
import time
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"""
# action list for update distributive
# step - step name
# args - variable get by clVars and paste to command
# command - executed command
# condition - check this package name merged in emerge.log
# message - Alternate message
# progname - check by 'which' existing this program
# hideout - hide stdout
# foraction - perform only for cl_action == value
DEFAULT_FORACTION = ('make','syncupdate','update')
ACTION_LIST = \
[
# emerge -e system first
{'command':'emerge -e system',
'message':_("First execute '%s'")%'emerge -e system',
'step':'firstsystem',
'foraction':('make',)},
# emerge -e system second
{'command':'emerge -e system',
'message':_("Second execute '%s'")%'emerge -e system',
'step':'secondsystem',
'foraction':('make',)},
# emerge world
{'command':'emerge -e world',
'step':'rebuildworld',
'foraction':('make',)},
{'step':'stagecomplete',
'foraction':('make',)},
# update prepareTemplates
{'command':"prepareTemplates()",
'foraction':('syncupdate','update','applytemplates'),
'hideout':True,
'message':_("Configuring with %s templates")% "assemble"
},
{'command':"_migratePortage()",
'foraction':('syncupdate',),
'step':"migrate",
'hideout':True,
'message':_("Checking portage repository")
},
{'command':'eix-sync',
'progname':'eix-sync',
'message':_("Updating portages"),
'hideout':True,
'step':"eixsync",
'foraction':('syncupdate',)},
# try install python
{'command':'emerge -u python',
'step':'updatepython',
'condition':'dev-lang/python',
'checkcommand':'emerge -uOp python'
},
# update python
{'command':'python-updater',
'step':'fixpython',
'condition':'dev-lang/python',
'progname':'python-updater'},
# try install perl
{'command':'emerge -u perl',
'step':'updateperl',
'condition':'dev-lang/perl',
'checkcommand':'emerge -uOp perl'
},
# update perl
{'command':'perl-cleaner all',
'step':'fixperl',
'condition':'dev-lang/perl',
'progname':'perl-cleaner'},
# install meta package
{'command':'emerge --noreplace calculate-meta',
'checkcommand':'find /var/db/pkg/app-misc -name "calculate-meta*"',
'condition':'^$',
'step':'meta'},
# update packages with fix newuse
#{'command':'emerge -D --newuse world',
# 'step':'newuse'},
# update world
{'command':'emerge -uDN --with-bdeps=y world',
'step':'update'},
# depclean
{'command':'emerge --depclean',
'step':'depclean'},
# module rebuild
{'command':'modulesRebuild()',
'step':'module',
'condition':'sys-kernel/.*source.*',
'message':_("Executing '%s'")%'module-rebuild -X rebuild',
'progname':'module-rebuild'},
# xorg module rebuild
{'command':'emerge @x11-module-rebuild',
'step':'x11module',
'condition':'x11-base/xorg-server*'},
# revdep-rebuild
{'command':'revdepRebuild()',
'step':'revdep',
'condition':'.',
'message':_("Executing '%s'")%'revdep-rebuild -i',
'progname':'revdep-rebuild'},
# emerge @preserved-rebuild
{'command':'emerge @preserved-rebuild',
'step':'presrebuild',
'condition':'.'
},
# prelink all packages
{'command':'prelink -afmR',
'step':'prelink',
'hideout':True,
'condition':'.',
'progname':'prelink'},
# get propreitary drivers
{'command':'fetchDrivers()',
'step':'fetchdrivers',
'message':_("Fetching %s")%'video drivers'},
# emerge all nvidia-drivers
#{'command':'makeNvidiaDrivers()',
# 'step':'nvidia',
# 'hideout':True,
# 'message':_("Assembling %s")%'nvidia-drivers'},
# binary cleaning
{'command':'binaryCleaning()',
'step':'binclean',
'message':_("Cleaning the binary repository"),
'hideout':True
},
# creating mask,unmask list
#{'command':'createMaskUnmaskList()',
# 'step':'maskunmask',
# 'message':_("Creating mask/unmask/use lists"),
# 'hideout':True
#},
# update eix base
{'command':'eix-update',
'step':'eixupdate',
'hideout':True,
'progname':'eix-update'},
{'command':'eselect news read new',
'step':'readnews',
'message':_("Reading news"),
'progname':'eselect'},
{'command':"checkDowngrades()",
'message':_("Checking downgrades"),
'step':'showdowngrade',
'progname':'eix'}]
reVerSplit = re.compile(r"^(.*?)-(([^-]+?)(?:-(r\d+))?)(?:.(tbz2))?$",re.S)
def __init__(self):
self.clVars = None
self.startMessage = ""
self.lenStartMessage = 0
self.clTempl = None
self.force = False
self.mainAction = None
self.assembleEnvFile = '/etc/calculate/assemble.env'
self.assemblePath = None
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 printSkip(self, string, offsetL=0, printBR=True):
"""print skip"""
self._printSysOut = sys.stdout
self.printLine((('', string),),
(('blueBr','['),
('yellowBr',' skipped '),
('blueBr',']'),
), offsetL, printBR)
def printOnlyNotOK(self, string, offsetL=0, printBR=True):
"""Print for error"""
self._printSysOut = sys.stdout
self.printLine((('', string),),
(('blueBr','['),
('redBr',' !! '),
('blueBr',']'),
), offsetL, printBR)
def printByResult(self,result=True,failMessage=None,skip=False):
if self.startMessage:
offset = 3
if skip:
self.printSkip(" ", self.lenStartMessage + offset)
elif 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 == "update":
self.clVars.Set("cl_action","update",True)
elif action == "syncupdate":
self.clVars.Set("cl_action","syncupdate",True)
elif action == "dependence":
self.clVars.Set("cl_action","dependence",True)
elif action == "applytemplates":
self.clVars.Set("cl_action","applytemplates",True)
else:
self.clVars.Set("cl_action","configure",True)
def __profileShortname(self,profilename):
return profilename.rpartition('/profiles/')[2]
def printInfo(self):
self.printSUCCESS(_("Preparing for assemble") + " Calculate Linux")
self.defaultPrint("%s\n"%_("System information"))
subname = self.clVars.Get('os_assemble_linux_subname')
subname = (" %s"%subname) if subname else ""
self.printSUCCESS(_("System profile")+": %s"%
self.__profileShortname(
self.clVars.Get('os_assemble_system_profile')))
self.printSUCCESS(_("System to be built")+": %s"%
self.clVars.Get('os_assemble_linux_name')+subname)
if self.clVars.Get('os_assemble_linux_ver'):
self.printSUCCESS(_("System version")+": %s"%
self.clVars.Get('os_assemble_linux_ver'))
self.printSUCCESS(_("Hardware type")+": %s"%
self.clVars.Get('os_assemble_arch_machine'))
if path.isdir(self.clVars.Get('os_assemble_root_dev')):
self.printSUCCESS(_("Directory for assembling: %s")%
self.clVars.Get('os_assemble_root_dev'))
else:
self.printSUCCESS(_("Partition for assemble: %s")%
self.clVars.Get('os_assemble_root_dev'))
self.printSUCCESS(_("File system: %s")%
self.clVars.Get('os_assemble_root_format'))
if self.clVars.Get('cl_assemble_sync'):
self.printSUCCESS(_("Portage mirror: %s")%
self.clVars.Get('cl_assemble_sync'))
self.printSUCCESS(_("Stage for assembling: %s")%
(self.clVars.Get('cl_assemble_image') or _("none")))
if self.clVars.Get('cl_assemble_image_type') == "stage" and \
self.clVars.Get('cl_assemble_branch') == '':
self.printSUCCESS(_("Portage snapshot for assemble: %s")%
(self.clVars.Get('cl_assemble_snapshot_portage') or _("none")))
self.defaultPrint("%s\n"%_("Checking up before assemble"))
self.defaultPrint("\n")
def printConfInfo(self):
self.defaultPrint("%s\n"%_("System information"))
subname = self.clVars.Get('os_assemble_linux_subname')
subname = (" %s"%subname) if subname else ""
self.printSUCCESS(_("System profile")+": %s"%
self.__profileShortname(
self.clVars.Get('os_assemble_system_profile')))
self.printSUCCESS(_("System to be built")+": %s"%
self.clVars.Get('os_assemble_linux_name')+subname)
if self.clVars.Get('os_assemble_linux_ver'):
self.printSUCCESS(_("System version")+": %s"%
self.clVars.Get('os_assemble_linux_ver'))
self.printSUCCESS(_("Hardware type")+": %s"%
self.clVars.Get('os_assemble_arch_machine'))
self.printSUCCESS(_("Partition for assemble: %s")%
self.clVars.Get('os_assemble_root_dev'))
self.printSUCCESS(_("The system is being assembled in: %s")%
self.clVars.Get('cl_assemble_path'))
self.defaultPrint("\n")
def _checkAlreadyAssembling(self,printERROR=True):
section = self.__sectionName()
if not section in self.clVars.Get('cl_assemble_distro'):
if printERROR:
self.printERROR(
_("System with '%s' profile not ready for assemble")%
self.__profileShortname(
self.clVars.Get('os_assemble_system_profile')))
self.printERROR(
_("Your system must be configured before you do this")+".")
self.printERROR(_("Execute with option")+' "--configure".')
if self.clVars.Get('cl_assemble_distro'):
self.defaultPrint("\n"+_("Systems prepared for assemble")+
":\n")
for system in self.clVars.Get('cl_assemble_distro'):
self.printSUCCESS(self.__profileShortname(system))
self.removeDistroInfo()
return False
return True
def preassembleCheckups(self):
rsyncServer = self.clVars.Get('cl_assemble_sync')
self.setSyncMirror(rsyncServer)
if re.match(r'^i.86$',self.clVars.Get('os_arch_machine'),re.S):
if self.clVars.Get('os_assemble_arch_machine') in ('x86_64','ia64'):
self.printERROR(
_("Unable to assemble the system %(what)s from %(from)s")%
{'what':self.clVars.Get('os_assemble_arch_machine'),
'from':self.clVars.Get('os_arch_machine')})
return False
dev = self.clVars.Get('os_assemble_root_dev')
mp = isFstabMount(dev)
if mp:
self.printERROR(
_("'%(dev)s' is used as '%(mp)s' on your current system")%
{'dev':dev,'mp':mp})
return False
if self._checkAlreadyAssembling(printERROR=False):
dev = self.readEnv('os_assemble_root_dev') or dev
mp = isMount(dev)
self.printERROR(
_("Distribution with profile %(profile)s is being assembled"
" in '%(dir)s' now")%
{'profile':self.__profileShortname(
self.clVars.Get('os_assemble_system_profile')),
'dir':mp})
return False
mp = isMount(dev)
if mp:
self.printERROR(_("'%(dev)s' already mounted to '%(mp)s'")%
{'dev':dev,'mp':mp})
return False
if not self.clVars.Get('cl_assemble_image'):
self.printERROR(_("Base stage not found. Try "
"to change '--source'."))
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 portages"))
if stageName:
portageSources = ArchiveDistributive(stageName)
portageTarget = DirectoryDistributive(
path.join(self.assemblePath,"usr"))
portageTarget.installFrom(portageSources)
self.printByResult(True)
else:
self.printByResult(skip=True)
def _formatAndUnpackStage(self):
"""Format partition for assemble and unpack stage"""
self.printMessageForTest(_("Formatting the partition"))
self.saveVars('os_assemble_root_dev')
self.targetDistr.performFormat()
self.printMessageForTest(_("Unpacking the stage image to 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',
'cl_assemble_sync',
'cl_assemble_branch',
'cl_assemble_buildpkg_set',
'cl_assemble_pkgdir')
def _getTarget(self):
rootPartdev = self.clVars.Get('os_assemble_root_dev')
formatId = PartitionDistributive.formatId
fileSystem = self.clVars.Get('os_assemble_root_format')
if rootPartdev.startswith('/dev'):
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')))
else:
return DirectoryDistributive(rootPartdev,
mdirectory=self.clVars.Get('cl_assemble_path'))
def _prepareMount(self):
"""Mount /proc,/sys, remote, /dev to chroot"""
mountResources = (("/dev",None,None),
("/dev/shm",None,None),
("/dev/pts",None,None),
(None,"-t proc","/proc"),
(None,"-t sysfs","/sys"),
("/var/calculate/remote",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(_("Failed to mount %(from)s to %(to)s")%
{'from':source,'to':target})
if self.targetDistr:
DirectoryDistributive(target,parent=self.targetDistr)
self.printByResult(True)
def _migratePortage(self):
if self.clVars.Get('cl_assemble_branch'):
if not isPkgInstalled('dev-vcs/git'):
self.printMessageForTest(_("Installing %s")%'dev-vcs/git')
self.runChroot("emerge -1 git")
portagePath = pathJoin(self.assemblePath,'usr/portage')
gitConfig = pathJoin(portagePath, '.git/config')
# check for repository contains .git and
# this git from cl_assemble_sync url
reUrl = re.compile('url\s*=\s*(.*)')
gitUrl = reUrl.search(readFile(gitConfig))
# need remove portage and reget from sync address
self.printMessageForTest(_("Fetching portages"))
if not gitUrl or \
gitUrl.group(1).strip() != self.clVars.Get('cl_assemble_sync'):
if path.exists(portagePath):
removeDir(portagePath)
getPortage = "git clone --depth 1 -n {gitrep} {portage}".format(
gitrep=self.clVars.Get('cl_assemble_sync'),
portage='/usr/portage')
self.runChroot(getPortage)
else:
getPortage = "cd {portage};git fetch".format(
gitrep=self.clVars.Get('cl_assemble_sync'),
portage='/usr/portage')
self.runChroot(getPortage)
updateBranch= "cd {portage};git checkout {branch}".format(
portage='/usr/portage',
branch=self.clVars.Get('cl_assemble_branch'))
self.runChroot(updateBranch)
portagePkg = getPkgInstalled('sys-apps/portage',
prefix=self.assemblePath)
portageMinVer = getTupleVersion('2.2.0_alpha72')
if portagePkg and \
getTupleVersion(portagePkg[0]['PVR']) < portageMinVer:
lastEbuild = \
sorted(
map(lambda x:(x['P'],
getTupleVersion(x['PVR'])),
map(lambda x:reVerSplitToPV(x),
filter(lambda x:x.endswith('ebuild'),
listDirectory(pathJoin(self.assemblePath,
'usr/portage/sys-apps/portage'))
))),key=lambda x:x[1])
if len(lastEbuild) > 1:
lastEbuild = lastEbuild[-2][0]
else:
return
self.printMessageForTest(_("Installing %s")%"portage")
emergePortage = \
'ebuild /usr/portage/sys-apps/portage/%s digest merge'% \
lastEbuild
self.runChroot(emergePortage)
restoreManifest = \
'cd /usr/portage;git checkout sys-apps'
self.runChroot(restoreManifest)
else:
portagePath = pathJoin(self.assemblePath,'usr/portage')
gitConfig = pathJoin(portagePath, '.git/config')
if path.exists(gitConfig):
removeDir(portagePath)
if self.clVars.Get('cl_assemble_branch') in ('master','update'):
pathOverlay = pathJoin(self.assemblePath,'var/lib/layman/calculate')
if path.exists(pathOverlay):
updateBranch= \
"cd {portage};git pull;git checkout {branch}".format(
portage='/var/lib/layman/calculate',
branch=self.clVars.Get('cl_assemble_branch'))
self.runChroot(updateBranch)
def _updatePackages(self):
"""Update portage and calculate overlay"""
self._migratePortage()
emergeSync = "emerge --sync"
self.printMessageForTest(_("Updating portages"))
self.runChroot(emergeSync)
emergeLayman = "USE='git' emerge layman"
self.printMessageForTest(_("Installing %s")%"layman")
self.runChroot(emergeLayman)
# stage3 contains python-2.7 without USE="xml" need for layman
emergePython = "USE='xml' emerge -1 python:2.7"
self.printMessageForTest(_("Installing %s")%"python:2.7")
self.runChroot(emergePython)
self.printMessageForTest(_("Set %s as default")%"python:2.7")
self.runChroot('eselect python set python2.7')
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")
if self.clVars.Get('cl_assemble_branch') in ('master','update'):
updateBranch= "cd {portage};git checkout {branch}".format(
portage='/var/lib/layman/calculate',
branch=self.clVars.Get('cl_assemble_branch'))
self.runChroot(updateBranch)
def _updateMan(self):
"""Remove man, install man-db"""
self.printMessageForTest(
_("Installing man-db"))
if "calculate" in self.clVars.Get('os_assemble_system_profile'):
removeMan = "CLEAN_DELAY=0 emerge -C --backtrack=0 " \
"sys-apps/man"
self.runChroot(removeMan)
self.runChroot("emerge sys-apps/man-db")
self.printByResult(True)
else:
self.printByResult(skip=True)
def _updateBaselayout(self):
"""Remove baselayout, update openrc"""
self.printMessageForTest(
_("Updating baselayout and installing openrc"))
if "calculate" in self.clVars.Get('os_assemble_system_profile'):
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=_("Cannot 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)
else:
self.printByResult(skip=True)
def prepareTemplates(self,message=False,changeAction=False):
"""Apply prepare templates"""
if changeAction:
self.clVars.Set('cl_action',"configure",True)
if message == True:
message = _("Configuring with %s templates")% "assemble/prepare"
self.applyConfigureTemplates(self.assemblePath,message)
if changeAction and self.mainAction:
self.clVars.Set('cl_action',self.mainAction,True)
self.printByResult(True)
def setupTemplates(self,message=False,changeAction=False):
"""Apply setup templates"""
if changeAction:
self.clVars.Set('cl_action',"setup",True)
if message == True:
message = _("Configuring with %s templates")% "assemble/setup"
self.applyConfigureTemplates(self.assemblePath,message)
if changeAction and self.mainAction:
self.clVars.Set('cl_action',self.mainAction,True)
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 system assemble")):
self.printERROR(_("Assemble interrupted"))
self.removeDistroInfo()
return False
self.writeVar('cl_assemble_make','configure')
# test /mnt
mntpath = '/mnt'
if not os.access(mntpath,os.W_OK):
raise AssembleError(
_("Unable to create the directory in '%s'")%mntpath)
# 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 not isinstance(self.sourceDistr,IsoDistributive) and \
self.clVars.Get('cl_assemble_branch') == '':
self._unpackPortage()
self._prepareMount()
self.prepareTemplates(True,changeAction=True)
if path.exists(pathAppMisc) and metaPackage and \
filter(lambda x:metaPackage in x, os.listdir(pathAppMisc)):
self.setupTemplates(True,changeAction=True)
self.writeVar('cl_assemble_make','')
return True
self._updatePackages()
self.setupTemplates(True,changeAction=True)
self.printMessageForTest(
_("Enabling calculate-install to configure packages"))
if "calculate" in self.clVars.Get('os_assemble_system_profile'):
# emerge sys-apps/iproute2, because calculate-install
# need emerge with USE="minimal", but emerging
# will install iproute2 with USE="minimal" also
self.runChroot("emerge -1 sys-apps/iproute2")
self.runChroot("USE='minimal -pxe' emerge "
'sys-apps/calculate-install')
self.runChroot("cl-install --install")
else:
self.printByResult(skip=True)
emergePortage = "emerge sys-apps/portage"
self.printMessageForTest(_("Installing %s")%"portage")
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(_("Installing %s")%"v86d")
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.setupTemplates(True,changeAction=True)
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)
self.writeVar('cl_assemble_make','')
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(
_("Failed to create the 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(_("Cannot remove '%s'")%rmFile)
else:
raise AssembleError(errormsg)
def _getCommand(self,commandlist):
def decodeCmd(x):
x = x.rpartition(";")[2]
if " " in x:
return '"%s"'%x
else:
return x
return " ".join(map(decodeCmd,commandlist))
def setSyncMirror(self,mirror):
"""Set sync mirror"""
reMirror = re.compile("^(rsync:|git:)?/?/?([^:]+)$",re.S)
res = reMirror.search(mirror)
if res:
if res.groups()[0] == "git:":
self.clVars.Set('cl_assemble_sync',"git://%s"%res.groups()[1],True)
else:
self.clVars.Set('cl_assemble_sync',"//%s"%res.groups()[1],True)
self.clVars.Set('cl_assemble_branch','',True)
return True
else:
return False
def runChroot(self,command,raiseError=True,showProcess=False,joinErr=False):
"""Run command in chroot specified by cl_assemble_path"""
try:
if showProcess:
IOval = None
else:
IOval = PIPE
if joinErr:
ERRval = STDOUT
else:
ERRval = IOval
envdict = {'CHROOT':"on"}
envdict.update(os.environ)
needAsk = self.clVars.Get('cl_assemble_ask_set') == "on"
if "emerge " in command:
command = "env-update &>/dev/null;" \
"source /etc/profile &>/dev/null;%s"%command
if showProcess and needAsk:
command = command.replace("emerge ","emerge -a ")
commandLine = ["chroot",self.clVars.Get('cl_assemble_path'),
"/bin/bash","-c",command]
curarch = self.clVars.Get('os_arch_machine')
buildarch = self.clVars.Get('os_assemble_arch_machine')
if curarch != buildarch:
if buildarch == "i686":
commandLine = ["linux32"] + commandLine
if showProcess and needAsk:
chrootCommand = process(*commandLine,stderr=ERRval,
stdin=None,stdout=IOval,envdict=envdict)
else:
chrootCommand = process(*commandLine,stderr=ERRval,
stdout=IOval,envdict=envdict)
DEBUG(self._getCommand(chrootCommand.command))
if raiseError and chrootCommand.failed():
raise AssembleError(
_("An error occurred when executing the command")+
":\n %s"%self._getCommand(chrootCommand.command))
except KeyboardInterrupt:
chrootCommand.kill()
self.defaultPrint("\b\b")
raise AssembleError(
_("Interrupted when executing the command")+
":\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 = \
_("Failed to prepare the system for assemble")
if not self._pidCheck():
return False
res = self.make(self.configureFunc,force,nounmount)
if res:
self.printSUCCESS(
_("System prepared for assemble in %s")%
self.clVars.Get('cl_assemble_path')+"!")
self.printSUCCESS(_("For furhter build, use the 'cl-make' command"))
return res
def breakFunc(self,force):
mp = self.clVars.Get('cl_assemble_path')
rootPartdev = self.clVars.Get('os_assemble_root_dev')
if not self._checkAlreadyAssembling():
return False
self.printSUCCESS(_("Assemble interrupted") + " Calculate Linux")
self.printConfInfo()
if not self._askUser(force, _("Interrupt system assemble")):
self.printERROR(_("Assemble resumed"))
return False
if mp:
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(_("Cannot unmount %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 not self._checkAlreadyAssembling():
return False
self.printSUCCESS(_("Checking dependencies of %s assemble")
% "Calculate Linux")
self.printConfInfo()
command = "emerge -puNv %s %s"%(self.clVars.Get('cl_assemble_meta'),
"world")
self.printSUCCESS(_("Checking dependencies")+ " ...")
if self.runChroot(command, showProcess=True,
raiseError=False).success():
self.printSUCCESS(_("Distribution with profile %(profile)s "
"is ready for compilation")%
{'profile':self.__profileShortname(
self.clVars.Get('os_assemble_system_profile'))}+"!")
return True
else:
self.printSUCCESS(_("Distribution with profile %(profile)s "
"has unresolved dependencies")%
{'profile':self.__profileShortname(
self.clVars.Get('os_assemble_system_profile'))})
return False
def breakAssembling(self,force):
self.msgOperationComplete = \
_("System assemble resumed")+"!"
self.msgOperationFailed = \
_("Failed to interrupt assemble correctly")
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(_("Already assembling")+" "+
self._getNameByAction() + " " +
_("of distribution with profile '%(profile)s'")%
{'profile':self.__profileShortname(
self.clVars.Get('os_assemble_system_profile'))})
return False
else:
self.saveVars('cl_assemble_pid')
return True
def makeSystem(self,force):
self.msgOperationComplete = \
_("System successfully assembled")+"!"
self.msgOperationFailed = \
_("System assemble failed")
if not self._pidCheck():
return False
return self.make(self.makeFunc,force,True,False)
def updateSystem(self,force,withsync=True):
if self.clVars.Get('cl_action') == "applytemplates":
self.msgOperationComplete = \
_("Templates successfully applied")+"!"
self.msgOperationFailed = \
_("Failed to apply templates")
else:
self.msgOperationComplete = \
_("System successfully assembled")+"!"
self.msgOperationFailed = \
_("System assemble failed")
if not self._pidCheck():
return False
stepWorld = filter(lambda x:x,
self.clVars.Get('cl_assemble_step_world').split(','))
imageType = self.clVars.Get('cl_assemble_image_type')
if imageType == 'stage' and \
not filter(lambda x:x in ("stagecomplete","finish"),stepWorld):
self.printERROR(
_("Unable to update the distribution: assemble not completed"))
self.printERROR(_("Use '%s' for assemble")%'cl-make -m')
return False
return self.make(self.makeFunc,force,False,withsync)
def _getNameByAction(self):
act = self.clVars.Get('cl_assemble_make')
if act == "configure":
return _("for configuration")
elif act == "break":
return _("for breaking the assemble")
elif act == "system":
return _("for compilation of system packages")
elif act != "":
return _("for package compilation")
else:
return ""
def makeFunc(self,force,forcesystem=False,makeSync=True):
rootPartdev = self.clVars.Get('os_assemble_root_dev')
mp = isMount(rootPartdev)
if not self._checkAlreadyAssembling():
return False
if forcesystem:
self.printSUCCESS(_("Compiling %s assemble") % "Calculate Linux")
else:
self.printSUCCESS(_("Updating %s assemble") % "Calculate Linux")
rsyncServer = self.clVars.Get('cl_assemble_sync')
self.setSyncMirror(rsyncServer)
self.printConfInfo()
self.defaultPrint("%s\n"%_("Checking up before compilation"))
if self.clVars.Get('cl_assemble_make') == 'configure':
self.printWARNING(_("WARNING") +": " +
_("assemble configuration was not completed"))
# if assembling completed (finish in cl_assemble_step_world)
if "finish" in self.clVars.Get('cl_assemble_step_world'):
# cancel if action make
if forcesystem:
return True
elif self.clVars.Get('cl_action') != "applytemplates":
# print warning and drop force option
self.printWARNING(_("WARNING") +": " +
_("assemble already finished"))
# if base stage is stage4(iso) display warning for make
if self.clVars.Get('cl_assemble_image_type') == 'iso' and \
forcesystem:
self.printERROR(_("WARNING") +": " +
_("system packages will be recompiled"))
self.defaultPrint("\n")
self._displayCompileAll(self.clVars.Get('cl_action'),
self.clVars.Get('cl_assemble_step_world'))
self.defaultPrint("\n")
if not self._askUser(force, _("Continue compiling system packages")):
self.printERROR(_("Compilation interrupted"))
return False
self.mainAction = self.clVars.Get('cl_action')
if self.mainAction in ('make','update','syncupdate'):
if not force:
self.clVars.Set('cl_assemble_ask_set', 'on', True)
self.assemblePath = self.clVars.Get('cl_assemble_path')
if "finish" in self.clVars.Get('cl_assemble_step_world'):
self.writeVar('cl_assemble_step_world','stagecomplete',True)
if self.clVars.Get('cl_assemble_make') == 'configure':
self.writeVar('cl_assemble_make','',True)
makeComplete = False
baseType = self.clVars.Get('cl_assemble_image_type')
getMake = lambda : self.clVars.Get('cl_assemble_make')
while not makeComplete:
if getMake() in ("world",""):
self._compileAll(self.mainAction)
self.writeVar('cl_assemble_make','')
makeComplete = True
else:
self.writeVar('cl_assemble_make','')
return True
def _printCheckExecute(self,command,checkBuild=False,msg=None,
hideOut=False):
if self.clVars.Get('cl_assemble_make') \
and command.startswith("emerge"):
origCommand = command
if self.clVars.Get('cl_assemble_skipfirst_set') == "on":
command = "emerge --resume --skipfirst"
else:
command = "emerge --resume"
msg = (_("Resuming '%(orig)s' by '%(exec)s'")%
{'orig':origCommand,
'exec':command})
else:
msg = msg or (_("Executing '%s'")%command)
self.writeVar('cl_assemble_make','world')
if checkBuild == False or (type(checkBuild) == str \
and not self.__isPackageBuilded(re.compile(checkBuild))):
self.printMessageForTest(msg)
self.printByResult(True,skip=True)
else:
if hideOut:
self.printMessageForTest(msg)
else:
self.printSUCCESS("-"*76)
self.printSUCCESS(msg + " ...")
self.printSUCCESS("-"*76)
if re.search(r"^\w+\(\)$",command,re.S):
getattr(self,command[:-2])()
else:
self.runChroot(command, showProcess=not hideOut)
self.printByResult(True)
self.writeVar('cl_assemble_make','')
def __isAnyPackageBuilded(self):
"""Any package was builded (detect by log)"""
logFile = pathJoin(self.clVars.Get('cl_assemble_path'),
'/var/log/emerge.log')
reEmerge = re.compile(r"^\d+:\s*>>>\s*emerge",re.S)
if not os.access(logFile,os.R_OK):
return False
return bool(filter(reEmerge.search,open(logFile,"r")))
def __isPackageBuilded(self,package):
"""'package' was builded (detect by log)"""
logFile = pathJoin(self.clVars.Get('cl_assemble_path'),
'/var/log/emerge.log')
reEmerge = re.compile(r"^\d+:\s*>>>\s*emerge[^/]+\s+(\S+/\S+)")
if not os.access(logFile,os.R_OK):
return False
packageWithVer = map(lambda x:x.groups()[0],
filter(lambda x:x,
map(reEmerge.search,
open(logFile,"r"))))
if type(package) == re._pattern_type:
return bool(filter(package.search,packageWithVer))
else:
return bool(filter(lambda x:package in x,packageWithVer))
def _checkChrootProgram(self,progname):
"""Check existing program by name"""
if self.runChroot("which %s"%progname,raiseError=False).failed():
return False
return True
def _compileAll(self,actionName):
dontRepeatCompleted = bool(actionName == "make")
"""World compiling"""
# try perform each action from action list
for action in self.ACTION_LIST:
# if specified "progname" check by which in chroot this prog
if "progname" in action:
if not self._checkChrootProgram(action["progname"]):
continue
if not actionName in action.get('foraction',self.DEFAULT_FORACTION):
continue
if "command" in action:
command = action["command"]
if "args" in action:
command = command % tuple(map(lambda x:self.clVars.Get(x),
action["args"]))
if dontRepeatCompleted and action["step"] in \
self.clVars.Get('cl_assemble_step_world'):
continue
checkBuild = action.get("condition",True)
if "checkcommand" in action:
process = \
self.runChroot(action["checkcommand"],raiseError=False)
checkBuild = bool(re.search(action.get("condition","."),
process.read(),re.S))
self._printCheckExecute(command,checkBuild=checkBuild,
msg=action.get("message",""),
hideOut=action.get("hideout",False))
if "step" in action:
self._appendToStep("world",action["step"])
self._appendToStep("world","finish")
def _displayCompileAll(self,actionName,stepWorld):
dontRepeatCompleted = bool(actionName == "make")
"""World compiling"""
# try perform each action from action list
self.defaultPrint(_("The following actions will be performed")+":\n")
showLegend=False
for action in self.ACTION_LIST:
if not "command" in action:
continue
# if specified "progname" check by which in chroot this prog
if not actionName in action.get('foraction',self.DEFAULT_FORACTION):
continue
command = action["command"]
if "args" in action:
command = command % tuple(map(lambda x:self.clVars.Get(x),
action["args"]))
suffix = ""
if "condition" in action:
suffix += "*"
showLegend = True
if dontRepeatCompleted and action["step"] in stepWorld:
suffix += " (%s)" % _("done")
self.printSUCCESS(action.get("message",
_("Executing '%s'")%command)+ suffix)
if showLegend:
self.defaultPrint(
_("Actions marked with '*' will be performed when needed")+
".\n")
def __sectionName(self):
"""Get section name of assemble.env by shortname and arch"""
return self.clVars.Get(
'os_assemble_system_profile').rpartition('/profiles/')[2]
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):
"""Clean env, remove empty section, remove empty file"""
# if file hasn't any section
if not assembleEnv.getAllSectionNames():
if not assembleEnv.getAllSectionNames():
if not assembleEnv.getAllSectionNames():
os.unlink(self.assembleEnvFile)
# if env has empty section, then remove it
elif self.__sectionName() in assembleEnv.getAllSectionNames() and \
not assembleEnv.getAreaVars(self.__sectionName()):
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 newaction in curval:
return curval
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(_("System assemble interrupted"))
error = _("System assemble manually interrupted")
try:
if self.clTempl:
self.clTempl.closeFiles()
if error or logicFunc == self.breakFunc:
self.printByResult(False)
if self.targetDistr:
self.removeDistroInfo()
if self.targetDistr.childs:
self.printMessageForTest(
_("Releasing the partition for assemble"))
assemblePath = self.clVars.Get('cl_assemble_path')
self.targetDistr.close()
if path.exists(assemblePath):
try:
os.rmdir(assemblePath)
except OSError,e:
pass
self.printByResult(True)
if self.sourceDistr and self.sourceDistr.childs:
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")
try:
if error:
self.printByResult(False)
if error:
map(self.printERROR,filter(lambda x: x,str(error).split('\n')))
self.printERROR(self.msgOperationFailed)
#self.removeVars('cl_assemble_pid')
return False
if self.msgOperationComplete:
self.printSUCCESS(self.msgOperationComplete)
#self.removeVars('cl_assemble_pid')
except KeyboardInterrupt,e:
return False
return True
def revdepRebuild(self):
"""Run revdep-rebuild and check result"""
cmd = self.runChroot("revdep-rebuild -i", showProcess=True)
if not self.assemblePath:
self.assemblePath = \
self.clVars.Get('cl_assemble_path')
statusFile = path.join(self.assemblePath,
"var/cache/revdep-rebuild/6_status.rr")
if path.exists(statusFile) and \
open(statusFile,'r').read().strip() != '0':
raise AssembleError(
_("An error occurred when executing the command")+
":\n %s"%self._getCommand(cmd.command))
def checkDowngrades(self):
"""Run check downgrades"""
cmd = self.runChroot("FORMAT='{downgrade}%{FORMAT_ALL}{}' eix -I",
raiseError=False,
showProcess=True)
return True
def modulesRebuild(self):
"""Run revdep-rebuild and check result"""
if not self.assemblePath:
self.assemblePath = \
self.clVars.Get('cl_assemble_path')
modulesFile = path.join(self.assemblePath,
"var/lib/module-rebuild/moduledb")
# if file exists and not empty
if path.exists(modulesFile) and open(modulesFile,'r').read().strip():
cmd = self.runChroot("module-rebuild -X rebuild", showProcess=True)
if cmd.failed():
raise AssembleError(
_("An error occurred when executing the command")+
":\n %s"%self._getCommand(cmd.command))
def setProfile(self,newprofile,isconfigure):
"""Set profile for assembling system"""
newprofile = newprofile or ""
# if $ at end of newprofile then it be at end of profile name
if newprofile.endswith("$"):
newprofile = newprofile[:-1]
reProfile = re.compile('(^|/)%s$'%
"/([^/]+/)*".join(newprofile.strip('/').split('/')),re.S|re.I)
else:
reProfile = re.compile('(^|/)%s(/|$)'%
"/([^/]+/)*".join(newprofile.strip('/').split('/')),re.S|re.I)
allProfile = self.clVars.Get('cl_assemble_distro')
if isconfigure:
allProfile = self.clVars.Get('cl_assemble_profile')
allProfile = list(set(allProfile))
likeProfile = filter(reProfile.search,allProfile)
if likeProfile > 2:
if newprofile in likeProfile:
likeProfile = [newprofile]
if len(likeProfile) != 1:
if isconfigure:
typeProfileList = _("profile symlink targets")
else:
typeProfileList = _("distributions for assemble")
if newprofile != 'list':
if not likeProfile:
self.printERROR(_("wrong value for '--profile'"))
self.printERROR(
_("specify '-p list' to print all available %s")%
typeProfileList )
return False
else:
self.printERROR(
_("The specified value of '--profile' is ambiguous. "
"Please specify the profile with more precision."))
self.defaultPrint(_("Select profile from")+":\n")
else:
likeProfile = allProfile
if likeProfile:
self.defaultPrint(
(_("Available %s")%typeProfileList)+":\n")
elif not isconfigure:
self.printERROR(_("No distribution to assemble"))
map(self.printSUCCESS,sorted(likeProfile))
return False
else:
newprofile = likeProfile[0]
newprofile = self._shortToLongProfileName(newprofile)
self.clVars.Set('os_assemble_system_profile',newprofile,True)
return True
def getValidSource(self):
"""Get valid sources"""
distRep = DistributiveRepository(
self.clVars.Get('cl_assemble_image_path'))
return distRep._getAvailableShortnames()
def setName(self,name):
"""Set name for assembling system"""
reRight = re.compile(
r"^([%(alnum)s]+)(?:/([%(alnum)s ]+)(?:/([%(alnum)s]*))?)?$"%
{'alnum':"A-Za-z0-9"})
res = reRight.search(name)
if res:
shortname,name,subname = res.groups()
if not shortname is None:
self.clVars.Set('os_assemble_linux_shortname',shortname,True)
if not name is None:
self.clVars.Set('os_assemble_linux_name',name,True)
if not subname is None:
self.clVars.Set('os_assemble_linux_subname',subname,True)
return True
return False
def _shortToLongProfileName(self,newprofile):
"""Convert short profile name to full name"""
if newprofile.startswith("calculate"):
return path.join("../var/lib/layman/calculate/profiles",
newprofile)
else:
return path.join("../usr/portage/profiles",
newprofile)
def checkVariables(self,printVars=None):
"""Check and fix variables values"""
def printVarError(varname):
self.printERROR(_("Wrong value in '%(var)s' variable: '%(val)s'")%
{'var':varname, 'val':self.clVars.Get(varname)})
discardEmpty = lambda x : filter(lambda y:y,x)
sync = self.clVars.Get('cl_assemble_sync')
if sync and not self.setSyncMirror(sync) and not printVars:
printVarError('cl_assemble_sync')
return False
profile = self.clVars.Get('os_assemble_system_profile')
profilesFullname = map(self._shortToLongProfileName,
self.clVars.Get('cl_assemble_profile'))
profilesFullname += map(lambda x:x[2:],profilesFullname)
if profile in profilesFullname:
if profile[0] == '/':
self.clVars.Set('os_assemble_system_profile',"..%s"%profile,
True)
elif not printVars and profile:
printVarError('os_assemble_system_profile')
return False
availableDev = self.clVars.Get('cl_assemble_available_dev').split(',')
availableDev = discardEmpty(availableDev)
osDiskDev = self.clVars.Get('os_disk_dev')
if availableDev:
badDevs = filter(lambda x:not x in osDiskDev,availableDev)
if badDevs:
printVarError('cl_assemble_available_dev')
self.printERROR(_("Device '%s' does not exist")%badDevs[0])
return False
return True
def tryUseAvailable(self):
"""Check free available device and set valut to os_assemble_root_dev"""
distros = self.clVars.Get('cl_assemble_distro')
assembleEnv = iniParser(self.assembleEnvFile)
discardEmpty = lambda x : filter(lambda y:y,x)
busyDevs = \
map(lambda x:x.encode('utf-8') if type(x) == unicode else x,
discardEmpty(
map(lambda x:assembleEnv.getVar(x,'os_assemble_root_dev'),
distros)))
discardBusy = lambda x : filter(lambda y:not (y in busyDevs
or isMount(y)),x)
availableDev = self.clVars.Get('cl_assemble_available_dev').split(',')
availableDev = discardEmpty(availableDev)
freeDev = discardBusy(availableDev)
if freeDev:
rootDev = random.choice(freeDev)
self.clVars.Set('os_assemble_root_dev',rootDev,True)
self.saveVars('os_assemble_root_dev')
return True
return False
def getCurrentNvidiaBinary(self):
"""Get versions already installed nvidia drivers"""
packagePath = \
path.join(self.clVars.Get('cl_assemble_path'),
'usr/portage/packages')
x11DriversPath = path.join(packagePath,'x11-drivers')
if not path.exists(x11DriversPath):
return []
return map(lambda x:x.groups()[1],
filter(lambda x:x,
map(self.reVerSplit.search,
os.listdir(x11DriversPath))))
def fetchDrivers(self):
"""Fetch propreitary drivers"""
if self.clVars.Get('cl_assemble_withvideo_set') == "on":
drivers = [
('nvidia-drivers',
'x11-drivers/nvidia-drivers'),
('nvidia-drivers',
'\\<x11-drivers/nvidia-drivers-174'),
('nvidia-drivers',
'\\<x11-drivers/nvidia-drivers-97'),
('ati-drivers',
'x11-drivers/ati-drivers')
]
else:
drivers = []
chrootPath = self.clVars.Get('cl_assemble_path')
distDir = '/usr/portage/distfiles'
pathDistDir = pathJoin(chrootPath,distDir)
if not path.exists(pathDistDir):
os.mkdir(pathDistDir)
os.chmod(pathDistDir,02775)
os.chown(pathDistDir,0,250)
if self.startMessage:
self.startMessage = ""
self.defaultPrint("\n")
needFiles = []
infoprocess = self.runChroot(
"emerge --info",raiseError=False,joinErr=True)
curDistdir = \
map(lambda x:x.strip().rpartition('=')[-1].strip('"\''),
filter(lambda x:x.startswith("DISTDIR"),
infoprocess))
if curDistdir:
curDistdir = curDistdir[0]
else:
curDistdir = '/var/calculate/remote/distfiles'
while drivers:
repeatDrivers = []
for verName,drvVer in drivers:
rePackage = re.compile("^\[ebuild[^\]]+]\s+(\S+)")
checkprocess = self.runChroot(
"emerge -pv %s"%
drvVer, raiseError=False,joinErr=True)
# get names of dep packages
installPkgList = \
map(lambda x:x.group(1),
filter(lambda x:x,
map(rePackage.search,
checkprocess)))
# get version from emerging nvidia-driver
nvidiaVersions = \
map(lambda x:x.groups()[1],
filter(lambda x:x,
map(self.reVerSplit.search,
map(lambda x:x.groups()[0],
filter(lambda x:x,
map(rePackage.search,
filter(lambda x:verName in x,
checkprocess.readlines())))))))
if nvidiaVersions:
nvidiaVersions = nvidiaVersions[0]
else:
nvidiaVersions = "0"
self.printSUCCESS(_("When installing '%s', the following "
"packages will be installed")
%"%s-%s"%(verName,nvidiaVersions)+":")
# print dep packages (error message for probably wrong packages)
nameRight = "/%s-"%verName.partition("-")[0]
for pkg in installPkgList:
if nameRight in pkg:
self.printSUCCESS(" %s"%pkg)
else:
self.printERROR(" %s"%pkg)
if installPkgList:
self.printSUCCESS("")
self.printMessageForTest(
_("Fetching %s")%"%s-%s"%(verName,nvidiaVersions))
# run verbose package emergin for get version
fetchprocess = self.runChroot(
"emerge -f --quiet-build=n %s"%
drvVer, raiseError=False,joinErr=True)
rePackage = re.compile(
"(?:^ \* (.*?) RMD160 SHA1|File.*is already locked)")
# get fetched files
fetchedFiles = \
map(lambda x:x.groups()[0],
filter(lambda x:x,
map(rePackage.search,
fetchprocess)))
if None in fetchedFiles:
repeatDrivers.append((verName,drvVer))
self.printByResult(skip=True)
else:
self.printByResult(fetchprocess.success())
needFiles += fetchedFiles
self.defaultPrint("\n")
drivers = repeatDrivers
if drivers:
self.printMessageForTest(" " +
_("Waiting for unlock %s")%drivers[0][0])
time.sleep(10)
self.printByResult(True)
needFiles = set(needFiles)
fetchedList = set(listDirectory(pathDistDir))
removedList = fetchedList - needFiles
self.printMessageForTest(" " +
_("Cleaning %s")%distDir)
map(lambda x:os.rmdir(x) if path.isdir(x) else os.unlink(x),
filter(lambda x:path.exists(x),
map(lambda x:pathJoin(chrootPath,distDir,x),
removedList)))
map(lambda x:copyfile(x[0],x[1]),
filter(lambda x:path.exists(x[0]) and not path.exists(x[1]),
map(lambda x:(pathJoin(chrootPath,curDistdir,x),
pathJoin(chrootPath,distDir,x)),
needFiles - fetchedList)))
self.printByResult(True)
def makeNvidiaDrivers(self):
"""Emerge all nvidia-drivers as binary"""
def removeNvidiaByVer(chrootPath,pkgDir,pkgName,versList):
map(lambda x:os.unlink(x),
filter(lambda x:path.exists(x),
map(lambda x:pathJoin(chrootPath,pkgDir,
pkgName+"-%s.tbz2"%x),
versList)))
verLt = lambda x,y: cmpVersion(x,y) < 0
verGe = lambda x,y: cmpVersion(x,y) >= 0
pkgCategory = "x11-drivers"
pkgName = "%s/nvidia-drivers"%pkgCategory
chrootPath = self.clVars.Get('cl_assemble_path')
varDbPath = path.join(chrootPath,'var/db/pkg')
x11DriversPath = path.join(varDbPath,'x11-drivers')
# if system has not nvidia-drivers then nvidia will not be updated
if not path.exists(x11DriversPath) or \
not filter(lambda x:x.startswith('nvidia-drivers'),
os.listdir(x11DriversPath)):
self.printByResult(skip=True)
return True
pkgDir = '/usr/portage/packages'
pathPackages = pathJoin(chrootPath,pkgDir,"Packages")
if self.startMessage:
self.startMessage = ""
self.defaultPrint("\n")
# get version list of installed binary nvidia-drivers
allInstalled = self.getCurrentNvidiaBinary()
if self.__isPackageBuilded(re.compile('sys-kernel/.*source.*')):
removeNvidiaByVer(chrootPath,pkgDir,pkgName,allInstalled)
allInstalled = []
drivers = (('96.XX.XX','97'),
('173.XX.XX','174'))
needRegenPackages = False
for verName,drvVer in drivers:
self.printMessageForTest(" " +
_("Assembling %s")%"nvidia-drivers-%s"%verName)
# run verbose package emergin for get version
checkprocess = self.runChroot(
"emerge -vp \<%s-%s"%
(pkgName,drvVer),raiseError=False,joinErr=True)
rePackage = re.compile("^\[ebuild[^\]]+]\s+(\S+)")
# get version from emerging nvidia-driver
nvidiaVersions = \
map(lambda x:x.groups()[1],
filter(lambda x:x,
map(self.reVerSplit.search,
map(lambda x:x.groups()[0],
filter(lambda x:x,
map(rePackage.search,
checkprocess))))))
# nvidia-driver for this version absent
if not nvidiaVersions:
self.printByResult(False)
continue
nvidiaVersion = nvidiaVersions[0]
# get version for this version range
verInstall = filter(lambda x:verLt(x,drvVer), allInstalled)
# discard this
allInstalled = filter(lambda x:verGe(x,drvVer), allInstalled)
# if package not newer
if verInstall:
if filter(lambda x:verGe(x,nvidiaVersion),verInstall):
self.printByResult(skip=True)
continue
# remove old version
else:
removeNvidiaByVer(chrootPath,pkgDir,pkgName,verInstall)
# remove package if it exists
needRegenPackages = True
# build binary
process = self.runChroot("PKGDIR='%s' emerge -B \<%s-%s"%
(pkgDir,pkgName,drvVer),raiseError=False)
self.printByResult(process.success())
if needRegenPackages:
self.regenPackages(chrootPath,pkgDir)
return True
def regenPackages(self,chrootPath,pkgDirPath):
"""Regenerate packages and clean SYNC param"""
def fixKeywords(s):
if s.startswith("KEYWORDS:"):
return "KEYWORDS: amd64 x86\n"
else:
return s
pathPackages = pathJoin(chrootPath,pkgDirPath,"Packages")
# remove Packages if it recreated
if path.exists(pathPackages):
os.unlink(pathPackages)
self.runChroot("PKGDIR='%s' emaint binhost"%pkgDirPath)
if path.exists(pathPackages):
# remove SYNC param
filtredPackages = \
map(fixKeywords,
filter(lambda x:not x.startswith("SYNC:"),
open(pathPackages,'r')))
open(pathPackages,'w').writelines(filtredPackages)
def binaryCleaning(self):
"""Clean binary repository"""
chrootPath = self.clVars.Get('cl_assemble_path')
pkgDir = pathJoin(chrootPath,
self.clVars.Get('cl_assemble_pkgdir'))
dbPkg = pathJoin(chrootPath, 'var/db/pkg')
try:
if not path.exists(dbPkg):
os.makedirs(dbPkg)
if not path.exists(pkgDir):
os.makedirs(pkgDir)
if path.exists(dbPkg) and path.exists(pkgDir):
# get pkg list from distro
pkgList = \
reduce(lambda x,y:x+y,
map(lambda x:map(lambda z:path.join(x,"%s.tbz2"%z),
os.listdir(path.join(dbPkg,x))),
os.listdir(dbPkg)),[])
# get binary packages
binList = \
reduce(lambda x,y:x+y,
map(lambda x:map(lambda z:path.join(x,z)[len(pkgDir)+1:],
os.listdir(path.join(x))),
filter(lambda x:path.isdir(x),
map(lambda x:path.join(pkgDir,x),
os.listdir(pkgDir)))),[])
# remove files which in binary and not in db/pkg
map(lambda x:os.unlink(x),
map(lambda x:pathJoin(pkgDir,x),
list(set(binList)-set(pkgList))))
# remove empty directories
map(lambda x:os.rmdir(x),
filter(lambda x:path.isdir(x) and not os.listdir(x),
map(lambda x:path.join(pkgDir,x),
os.listdir(pkgDir))))
#packagesDir = 'usr/portage/packages'
#x11_drivers = 'x11-drivers'
#nvidiaDir = pathJoin(chrootPath, packagesDir,x11_drivers)
#pkgDirX11Drivers = pathJoin(pkgDir,'x11-drivers')
#if not path.exists(pkgDirX11Drivers):
# os.makedirs(pkgDirX11Drivers,mode=0755)
#map(lambda x:copyfile(pathJoin(nvidiaDir,x),
# pathJoin(pkgDirX11Drivers,x)),
# listDirectory(nvidiaDir))
self.regenPackages(chrootPath,pkgDir[len(chrootPath):])
else:
self.printByResult(skip=True)
except OSError,e:
raise AssembleError(str(e))
return True
def createMaskList(self,chrootdir,filename):
"""Create package mask list by chrootdir"""
pkgdir = path.join(chrootdir,'var/db/pkg')
reVerSplit = re.compile(r"^(.*?)-(([^-]+?)(?:-(r\d+))?)$",re.S)
if not path.exists(chrootdir):
return False
try:
packageList= sorted(reduce(lambda x,y:x+map(lambda x:path.join(y,x),
os.listdir(path.join(pkgdir,y))), os.listdir(pkgdir),[]))
open(filename,'w').writelines(
map(lambda x:"%s\n"%x,
map(lambda x:x.groups()[0],
filter(lambda x:x,
map(reVerSplit.search,
packageList)))))
except (IOError,OSError),e:
return False
return True
def createUnmaskList(self,chrootdir,filename):
"""Create package unmask list by chrootdir"""
pkgdir = path.join(chrootdir,'var/db/pkg')
#x11_bindir = path.join(chrootdir,'usr/portage/packages/x11-drivers')
if not path.exists(chrootdir):
return False
try:
packageList= sorted(reduce(lambda x,y:x+map(lambda x:path.join(y,x),
os.listdir(path.join(pkgdir,y))), os.listdir(pkgdir),[]))
#packageList = \
# sorted(packageList+
# map(lambda x:path.join('x11-drivers',x[:-5]),
# filter(lambda x:x.endswith('.tbz2'),
# listDirectory(x11_bindir))))
open(filename,'w').writelines(map(lambda x:"=%s\n"%x,packageList))
except (IOError,OSError),e:
return False
return True
def createUseList(self,chrootdir,filename):
"""Create package uselist by chrootdir"""
pkgdir = path.join(chrootdir,'var/db/pkg')
def calcUseFlags(pkg):
iusePath = path.join(pkgdir,pkg,"IUSE")
usePath = path.join(pkgdir,pkg,"USE")
if path.exists(iusePath):
IUSE = set(
map(lambda x: x[1:] if x and x[0] in ("-","+") else x,
open(iusePath,"r").read().strip().split()))
else:
return ""
if path.exists(usePath):
USE = set(open(usePath,"r").read().strip().split())
else:
USE = set([])
plus = " ".join(sorted(IUSE & USE))
minus = " ".join(sorted(map(lambda x:"-%s"%x, IUSE - USE)))
if plus:
plus = " %s"%plus
if minus:
minus = " %s"%minus
return "=%s%s%s\n"%(pkg, plus, minus)
if not path.exists(chrootdir):
return False
try:
packageList= sorted(reduce(lambda x,y:x+map(lambda x:path.join(y,x),
os.listdir(path.join(pkgdir,y))), os.listdir(pkgdir),[]))
open(filename,'w').writelines(map(calcUseFlags,packageList))
except (IOError,OSError),e:
return False
return True
def createMaskUnmaskList(self):
"""Action create mask unmask list"""
baseDir = self.clVars.Get('cl_assemble_pkgdir')
name = "package"
if not path.exists(baseDir):
os.makedirs(baseDir,mode=0755)
maskName = pathJoin(baseDir,"%s.mask"%name)
unmaskName = pathJoin(baseDir,"%s.unmask"%name)
useName = pathJoin(baseDir,"%s.use"%name)
if self.createMaskList(self.clVars.Get('cl_assemble_path'),
maskName) and \
self.createUnmaskList(self.clVars.Get('cl_assemble_path'),
unmaskName) and \
self.createUseList(self.clVars.Get('cl_assemble_path'),
useName):
return True
return False