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-3-install/install/variables/distr.py

467 lines
18 KiB

#-*- coding: utf-8 -*-
# Copyright 2008-2012 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
from os import path
import re
import operator
from calculate.lib.datavars import Variable,VariableError,ReadonlyVariable
from calculate.lib.utils.common import getSupportArch,getTupleVersion
from calculate.lib.utils.files import readLinesFile, listDirectory
from calculate.lib.variables.linux import Linux
from calculate.install.cl_distr import (Distributive,PartitionDistributive,
ScratchPartitionDistributive,DistributiveError,FlashDistributive,
MultiPartitions)
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_install',sys.modules[__name__])
class DistroRepository(Linux):
contentCache = {}
marches = ['i686','x86_64']
extensiton = ['iso','tar.bz2','tar.gz','tar.7z','tar.lzma']
reDistName = re.compile("""
^.*/(?P<name>%(name)s)
-(?P<ver>%(ver)s)
-(?P<march>%(march)s)
.(?P<ext>%(ext)s)$""" %
{'name':"[a-z0-9]+",
'ver':r"(\d+\.)*\d+",
'march':"|".join(marches),
'ext':"|".join(extensiton)
}, re.X)
def _getDistrInfo(self,filename):
"""Get information by distributive"""
# if filename is directory
if not path.isfile(filename):
return Distributive().getInfo(filename)
else:
match = self.reDistName.match(filename)
if not match:
return {}
distdic = match.groupdict()
distdic["build"] = ""
if "ver" in distdic:
if re.match("^\d{8}$", distdic["ver"]):
distdic["build"] = distdic["ver"]
distdic["ver"] = ""
return distdic
def getImage(self,scratch,rootType,imagePath,march=None,
shortName=None,linuxVer=None,linuxBuild=None):
"""Get image by parameters"""
# exclude directory distributive for flash and scratch install
if scratch == "on" or rootType == "flash":
discardType = ["dir"]
else:
discardType = []
return self.getBestDistributive(imagePath,
march=march,
shortname=shortName,
discardType=discardType,
version=linuxVer,
build=linuxBuild)
def _getAvailableShortnames(self,dirs):
"""Get available distributives shortnames"""
distros = filter(lambda x:x,
map(self.reDistName.search,self._getAvailableDistributives(dirs)))
return sorted(list(set(map(lambda x:x.groupdict()['name'],distros))))
def opcompareByString(self,buf):
if buf:
reOp = re.compile("^(!=|=|==|<=|>=|>|<)?(\d+.*)$")
res = reOp.search(buf)
if res:
return ({'!=':operator.ne,
'=':operator.eq,
'==':operator.eq,
'>=':operator.ge,
'<=':operator.le,
'<':operator.lt,
'>':operator.gt}.get(res.group(1),operator.eq),
res.group(2))
else:
return operator.eq,buf
return None,None
def _getAvailableDistributives(self,dirs,system=None,shortname=None,march=None,
version=None,build=None):
"""Get all distributives by filter"""
def systemByName(name):
return self.dictNameSystem.get(name.upper(),"")
verCmp, version = self.opcompareByString(version)
if version:
version = getTupleVersion(version)
buildCmp, build = self.opcompareByString(build)
if build and build.isdigit():
build = int(build)
def distfilter(dist):
d = self._getDistrInfo(dist)
if not d:
return False
# check filter conditions
if system and systemByName(d['name']) != system:
return False
if not "name" in d or not "ver" in d:
return False
if shortname and d['name'].lower() != shortname.lower():
return False
if march and d['march'] != march:
return False
if version and not verCmp(getTupleVersion(d['ver']), version):
return False
if build and "build" in d and (not d['build'].isdigit() or
not buildCmp(int(d['build']),build)):
return False
return True
def listdistr(pathname):
if path.exists(path.join(pathname,'etc/make.profile')) or \
path.exists(path.join(pathname,'livecd')) or \
pathname.startswith('/dev/'):
return [pathname]
else:
# discard inner directories
return filter(lambda x:not path.isdir( path.join(pathname,x)),
listDirectory(pathname))
# get lists files in directories
allFiles = map(lambda x: map(lambda y: path.join(x,y),
listdistr(x)),
dirs)
# filter distributives
return filter(distfilter,
# join files lists to one list
reduce(lambda x,y: x + y,
allFiles, []))
def extcomparator(self,*exts):
"""Compare extensions"""
mapExts = {'iso':0,
'flash':-1,
'isodir':-2,
'partdir':-3,
'dir':-4}
return cmp(mapExts.get(exts[0],-4),mapExts.get(exts[1],-4))
def sortdistrfunc(self,x,y):
"""Func of comparing two distributive"""
ver1, ver2 = x[1].get('ver',""), y[1].get('ver',"")
if ver1 and ver2 and ver1 != "0" and ver2 != "0" and ver1 != ver2:
return cmpVersion(ver1,ver2)
build1 = getTupleVersion(x[1].get('build',""))
build2 = getTupleVersion(y[1].get('build',""))
if build1 != build2:
return cmp(build1,build2)
else:
ext1 = x[1].get('ext',"")
ext2 = y[1].get('ext',"")
return self.extcomparator(ext1,ext2)
def getAvailableDristibutives(self,dirs,system=None,shortname=None,
march=None, version=None, build=None,discardType=[]):
"""Get list available distributives"""
if shortname:
shortname = shortname.lower()
availDistrs = self._getAvailableDistributives(dirs,system,shortname,
march,version,
build)
availDistrs = filter(lambda x:x[1] and "ext" in x[1] and
not x[1]["ext"] in discardType,
map(lambda x:(x,self._getDistrInfo(x)),
availDistrs))
return map(lambda x:x[0],
sorted(availDistrs,self.sortdistrfunc,reverse=True))
def getBestDistributive(self,dirs,system=None,shortname=None,march=None,
version=None, build=None,discardType=[]):
"""Get the actualest distributive"""
availDistrs = self.getAvailableDristibutives(dirs,system,shortname,
march,version,build,discardType)
if availDistrs:
return availDistrs[0]
else:
return None
def _findLatestFile(self,dirs,reMatch,keyfunc):
"""Find latest file in dirs, which match by reMatch,
comparable part get by keyfunc"""
existsdirs = filter(path.exists,dirs)
listimgs = reduce(lambda x,y:x + \
map(lambda x:reMatch.search(path.join(y,x)),
listDirectory(y)),
existsdirs,[])
listimgs = filter(lambda x:x, listimgs)
if listimgs:
return max(listimgs,key=keyfunc).group()
return ""
def getBestStage(self,dirs,march=None,hardened=None):
"""Get latest stage by march"""
if march:
march = {'x86_64':'amd64'}.get(march,march)
else:
march = "[^-]+"
if hardened is None:
hardened = "(?:-hardened)?"
elif hardened == True:
hardened = "-hardened"
elif hardened == False:
hardened = ""
reStage = re.compile(r'^.*/stage3-%s%s-(\d+)\.tar\.bz2$'%
(march,hardened),re.S)
return self._findLatestFile(dirs,reStage,lambda x:x.groups()[0])
class VariableClImage(ReadonlyVariable):
"""
System image for installation
"""
type = "object"
def get(self):
"""Get image file from distributive repository"""
if self.Get('cl_action') != 'system':
return Distributive.fromFile('/')
filename = self.Get('cl_image_filename')
try:
if filename:
filename = Distributive.fromFile(filename)
except DistributiveError as e:
return ""
return filename
def humanReadable(self):
filename = self.Get('cl_image')
if filename:
return filename.getType()
return filename
class VariableClImageFilename(Variable,DistroRepository):
"""
Distributive image filename
"""
type = 'file'
element = 'file'
opt = ['--iso']
def init(self):
self.label = _("Installation image")
self.help = _("ISO image for installation")
def get(self):
if self.Get('cl_action') != 'system':
return ""
arch = self.Get('cl_image_arch_machine') or self.Get('os_arch_machine')
shortname = self.Get('cl_image_linux_shortname') or \
self.Get('os_linux_shortname')
ver = self.Get('cl_image_linux_ver') or None
build = self.Get('cl_image_linux_build') or None
return self.getImage(self.Get('os_install_scratch'),
self.Get('os_install_root_type'),
self.Get('cl_image_path'),
arch,shortname,ver,build)
def check(self,isoimage):
"""Set image file"""
imageData = Distributive().getInfo(isoimage)
if not("name" in imageData and imageData.get('build','') and \
"march" in imageData):
raise VariableError(_("Wrong image file"))
def humanImageName(self,distroinfo,filepath):
distroinfo['name'] = distroinfo['name'].upper()
return "{name} {march} {build} ({filepath})".format(
filepath=filepath,**distroinfo)
def choice(self):
scratch = self.Get('os_install_scratch')
rootType = self.Get('os_install_root_type')
imagePath = self.Get('cl_image_path')
if scratch == "on" or rootType == "flash" or \
self.Get('cl_install_type') == 'flash':
discardType = ["dir"]
else:
discardType = []
distros = self.getAvailableDristibutives(imagePath,
discardType=discardType)
return map(lambda x:(x,self.humanImageName(self._getDistrInfo(x),x)),
distros)
class VariableClImageArchMachine(Variable,DistroRepository):
"""
Filter by architecture
"""
type = 'choice'
opt = ['--march']
available_arch = ["i686","x86_64"]
def init(self):
self.label = _("Preferred processor architecture")
self.help = _("select the processor architecture")
def set(self,march):
if march == "auto":
march = getSupportArch()[-1]
return march
def choice(self):
return self.available_arch + ["auto"]
class VariableClImageLinuxShortname(Variable,Linux,DistroRepository):
"""
Filter by shortname
"""
type = 'choice'
opt = ['--os','-s']
def init(self):
self.label = _("Distributive")
self.help = _("select the operation system")
def choice(self):
return self.dictLinuxName.keys()
class VariableClImageLinuxVer(Variable,DistroRepository):
"""
Filter by version
"""
value = ""
def init(self):
self.label = _("Version")
self.help = _("select the operation system by version")
class VariableClImageLinuxBuild(Variable,DistroRepository):
"""
Filter by build
"""
value = ""
def init(self):
self.label = _("Build")
self.help = _("select the operation system by build")
class VariableClImagePath(ReadonlyVariable):
"""
Image search path
"""
type = "list"
def get(self):
# if current distributive is live
if self.Get('os_root_type') == "livecd":
# if builder from flash then this source path '/mnt/flash'
# may be this path will be '/mnt/builder' for install
# modified system
if self.Get('os_scratch') == "on" and path.exists('/mnt/flash'):
livedistr = ['/mnt/flash']
# if system boot with kernel param 'docache'
elif path.exists('/mnt/squash'):
livedistr = ['/mnt/livecd']
# standard livecd
else:
livedistr = ['/mnt/cdrom']
else:
livedistr = []
# search all partition for source installation distributive
rootDev = self.Get('os_install_root_dev')
livedistr += \
map(lambda x:x[0],
filter(lambda x:" live" in x[1] and x[0] != rootDev,
zip(self.Get('os_disk_dev'),
self.Get('os_disk_content'))))
# add to standard path
return filter(path.exists,
['/var/calculate/remote/linux',
'/var/calculate/linux'] + livedistr)
class VariableClTarget(ReadonlyVariable):
"""
Target distributive
"""
type = "object"
def get(self):
listVars = ['os_install_disk_dev', 'os_install_disk_mount',
'os_install_disk_format', 'os_install_disk_perform_format',
'os_install_disk_part', 'os_install_disk_id']
rootLabel = "{short}-{ver}".format(
short=self.Get('os_install_linux_shortname'),
ver=self.Get('os_install_linux_ver'))
osInstallScratch = self.isTrue(self.Get('os_install_scratch'))
mapDevId = dict(self.ZipVars('os_disk_dev','os_disk_id'))
disk, mount, fileSystem, isFormat, partTable,systemId = \
self.Select(listVars,
where='os_install_disk_mount',
eq='/',limit=1)
if not systemId or mapDevId.get(disk,'') == systemId:
systemId = None
if osInstallScratch:
return ScratchPartitionDistributive(disk,mdirectory='/mnt/install',
check=True,fileSystem=fileSystem,
isFormat=self.isTrue(isFormat),
systemId=systemId,
partitionTable=partTable)
elif self.Get('os_install_root_type')=="flash":
return FlashDistributive(disk,mdirectory="/mnt/install",
check=True, fileSystem=fileSystem,
isFormat=isFormat, systemId=systemId,
partitionTable=partTable)
else:
target = PartitionDistributive(disk,mdirectory='/mnt/install',
check=True,fileSystem=fileSystem,
rootLabel=rootLabel,
isFormat=self.isTrue(isFormat),
systemId=systemId,
partitionTable=partTable)
multiPartition = None
diskData = self.Select(listVars,
where='os_install_disk_mount',
ne='/')
bindData = self.Select(['os_install_bind_path',
'os_install_bind_mountpoint'],
where='os_install_bind_mountpoint',
ne='')
if diskData or bindData:
multiPartition = MultiPartitions()
target.multipartition = multiPartition
for disk,mount,fileSystem,isFormat,partTable,systemId in diskData:
if not systemId or mapDevId.get(disk,'') == systemId:
systemId = None
multiPartition.addPartition(dev=disk,
mountPoint=mount,
fileSystem=fileSystem,
isFormat=self.isTrue(isFormat),
systemId=systemId,
partitionTable=partTable)
for source,dest in bindData:
multiPartition.addPartition(dev=source,
mountPoint=dest,
fileSystem='bind',
isFormat=False,
systemId=None,
partitionTable='')
return target