|
|
|
#-*- 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
|