|
|
|
#-*- 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.
|
|
|
|
|
|
|
|
from os import path
|
|
|
|
from random import choice
|
|
|
|
import string
|
|
|
|
import os
|
|
|
|
import types
|
|
|
|
from time import sleep
|
|
|
|
import re
|
|
|
|
import sys
|
|
|
|
import operator
|
|
|
|
from cl_utils import runOsCommand,isMount,removeDir,typeFile,pathJoin, \
|
|
|
|
process,getRunCommands,getTupleVersion,cmpVersion, \
|
|
|
|
detectDeviceForPartition, getProgPath,listDirectory, \
|
|
|
|
checkUtils,STDOUT,getUdevDeviceInfo
|
|
|
|
from cl_vars_share import varsShare
|
|
|
|
from shutil import copyfile,copytree
|
|
|
|
from cl_template import _terms
|
|
|
|
from subprocess import Popen,PIPE,STDOUT
|
|
|
|
from cl_fill import fillVars
|
|
|
|
from cl_vars_share import varsShare
|
|
|
|
|
|
|
|
import threading
|
|
|
|
|
|
|
|
from cl_lang import lang
|
|
|
|
tr = lang()
|
|
|
|
tr.setLocalDomain('cl_install')
|
|
|
|
tr.setLanguage(sys.modules[__name__])
|
|
|
|
|
|
|
|
class SignalInterrupt:
|
|
|
|
__interruptProcessObjs = []
|
|
|
|
__sigint = False
|
|
|
|
|
|
|
|
def setSignalInterrupt(self):
|
|
|
|
"""Handler "SIGINT"""
|
|
|
|
if SignalInterrupt.__sigint is False:
|
|
|
|
sys.stdout.write("\b\b")
|
|
|
|
# killed processes
|
|
|
|
while (SignalInterrupt.__interruptProcessObjs):
|
|
|
|
process = SignalInterrupt.__interruptProcessObjs.pop()
|
|
|
|
if hasattr(process, "pipe") and hasattr(process.pipe,"kill"):
|
|
|
|
process.pipe.kill()
|
|
|
|
SignalInterrupt.__sigint = True
|
|
|
|
|
|
|
|
def getSignalInterrupt(self):
|
|
|
|
return SignalInterrupt.__sigint
|
|
|
|
|
|
|
|
def addInterruptProcess(self, process):
|
|
|
|
SignalInterrupt.__interruptProcessObjs.append(process)
|
|
|
|
|
|
|
|
|
|
|
|
class Spinner(threading.Thread):
|
|
|
|
stopSignal = threading.Event()
|
|
|
|
sequence= map(lambda x:x,iter("/-\\|"))
|
|
|
|
write = sys.stdout.write
|
|
|
|
selfthread = None
|
|
|
|
|
|
|
|
def setWriteFunc(self,writeFunc):
|
|
|
|
Spinner.write = writeFunc
|
|
|
|
|
|
|
|
def init(self,checkFunction=None,interval=0.1):
|
|
|
|
self.curpos = 0
|
|
|
|
self.checkFunction = checkFunction
|
|
|
|
self.interval = interval
|
|
|
|
Spinner.stopSignal.clear()
|
|
|
|
|
|
|
|
def stop(self):
|
|
|
|
Spinner.stopSignal.set()
|
|
|
|
if Spinner.selfthread:
|
|
|
|
Spinner.selfthread.join(2)
|
|
|
|
Spinner.selfthread = None
|
|
|
|
#Spinner().write('\n')
|
|
|
|
Spinner().write('\b')
|
|
|
|
|
|
|
|
def run(self):
|
|
|
|
self.write(self.sequence[-1])
|
|
|
|
Spinner.selfthread = self
|
|
|
|
while not Spinner.stopSignal.isSet():
|
|
|
|
if self.checkFunction and self.checkFunction():
|
|
|
|
self.write("\b%s"%self.sequence[self.curpos])
|
|
|
|
self.curpos += 1
|
|
|
|
if self.curpos >= len(self.sequence):
|
|
|
|
self.curpos = 0
|
|
|
|
sleep(self.interval)
|
|
|
|
|
|
|
|
class DistributiveError(Exception):
|
|
|
|
"""Error for distributive operations"""
|
|
|
|
pass
|
|
|
|
|
|
|
|
class DistributiveRepository:
|
|
|
|
varsShare = varsShare()
|
|
|
|
|
|
|
|
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 __init__(self,directories=[]):
|
|
|
|
self.dirs = directories
|
|
|
|
|
|
|
|
def ini_to_dict(self,filename):
|
|
|
|
"""Convert ini values to dict"""
|
|
|
|
if os.access(filename,os.R_OK):
|
|
|
|
return dict(map(lambda x: x.strip().rpartition('=')[0::2],
|
|
|
|
open(filename,'r')))
|
|
|
|
else:
|
|
|
|
return {}
|
|
|
|
|
|
|
|
def _getfromcontent(self,filename):
|
|
|
|
"""Get info from content"""
|
|
|
|
varsShare = self.varsShare
|
|
|
|
distr = None
|
|
|
|
# may be directory is isodir (directory which contains iso image)
|
|
|
|
extname = "isodir"
|
|
|
|
try:
|
|
|
|
if filename.startswith('/dev'):
|
|
|
|
distr = PartitionDistributive(filename)
|
|
|
|
else:
|
|
|
|
distr = IsoDistributive(filename)
|
|
|
|
filename = distr.convertToDirectory().directory
|
|
|
|
except Exception,e:
|
|
|
|
extname = "dir"
|
|
|
|
d = self.ini_to_dict(path.join(filename,
|
|
|
|
'etc/calculate/calculate.ini'))
|
|
|
|
if not d or not "march" in d:
|
|
|
|
if path.exists(path.join(filename,'lib64')):
|
|
|
|
d['march'] = 'x86_64'
|
|
|
|
else:
|
|
|
|
d['march']= 'i686'
|
|
|
|
if d:
|
|
|
|
d['ext'] = extname
|
|
|
|
d["name"] = varsShare.getShortnameByMakeprofile(filename) or \
|
|
|
|
varsShare.getShortnameByIni(filename) or \
|
|
|
|
varsShare.detectOtherShortname(filename) or \
|
|
|
|
"Linux"
|
|
|
|
d['ver'] = \
|
|
|
|
varsShare.getVersionFromMetapackage(filename,d["name"]) or \
|
|
|
|
varsShare.getVersionFromCalculateIni(filename) or "0"
|
|
|
|
reOsLinuxBuild = re.compile("^os_linux_build\s*=\s*(\S+)\s*$")
|
|
|
|
os_linux_build = \
|
|
|
|
map(lambda x:x.groups()[0],
|
|
|
|
filter(lambda x:x,
|
|
|
|
map(reOsLinuxBuild.search,
|
|
|
|
reduce(lambda x,y:x+y,
|
|
|
|
map(lambda x:open(x,"r").readlines(),
|
|
|
|
filter(path.exists,
|
|
|
|
[path.join(filename,"etc/calculate/calculate2.env")])),[]))))
|
|
|
|
if os_linux_build:
|
|
|
|
d['build'] = os_linux_build[-1]
|
|
|
|
else:
|
|
|
|
d['build'] = ""
|
|
|
|
if distr:
|
|
|
|
distr.close()
|
|
|
|
return d
|
|
|
|
|
|
|
|
def _getdistrinfo(self,filename):
|
|
|
|
"""Get information by distributive"""
|
|
|
|
varsShare = self.varsShare
|
|
|
|
# if filename is directory
|
|
|
|
if path.isdir(filename):
|
|
|
|
return self._getfromcontent(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 _getAvailableShortnames(self):
|
|
|
|
"""Get available distributives shortnames"""
|
|
|
|
distros = filter(lambda x:x,
|
|
|
|
map(self.reDistName.search,self._getAvailableDistributives()))
|
|
|
|
return sorted(list(set(map(lambda x:x.groupdict()['name'],distros))))
|
|
|
|
|
|
|
|
def _getAvailableDistributives(self,system=None,shortname=None,march=None,
|
|
|
|
version=None,op_compare=None):
|
|
|
|
"""Get all distributives by filter"""
|
|
|
|
if op_compare is None:
|
|
|
|
op_compare = operator.eq
|
|
|
|
if version:
|
|
|
|
version = getTupleVersion(version)
|
|
|
|
def distfilter(dist):
|
|
|
|
d = self._getdistrinfo(dist)
|
|
|
|
if not d:
|
|
|
|
return False
|
|
|
|
# check filter conditions
|
|
|
|
if system and self.system(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 op_compare(getTupleVersion(d['ver']), version):
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
|
|
def listdistr(pathname):
|
|
|
|
if path.exists(path.join(pathname,'etc/make.profile')):
|
|
|
|
return [pathname]
|
|
|
|
elif path.exists(path.join(pathname,'livecd')):
|
|
|
|
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)),
|
|
|
|
# discard not exists distrib directories
|
|
|
|
filter(lambda x: os.access(x,os.R_OK),
|
|
|
|
self.dirs))
|
|
|
|
# filter distributives
|
|
|
|
return filter(distfilter,
|
|
|
|
# join files lists to one list
|
|
|
|
reduce(lambda x,y: x + y,
|
|
|
|
allFiles, []))
|
|
|
|
|
|
|
|
def getDistributiveByFile(self,filename):
|
|
|
|
"""Get Distributive object by filename"""
|
|
|
|
# MAGIC_COMPRESS 0x000004 Check inside compressed files
|
|
|
|
tf = typeFile(magic=0x4)
|
|
|
|
ftype = tf.getMType(filename)
|
|
|
|
if "ISO 9660 CD-ROM" in ftype:
|
|
|
|
return IsoDistributive(filename)
|
|
|
|
elif "7-zip" in ftype or \
|
|
|
|
"POSIX tar archive" in ftype:
|
|
|
|
return ArchiveDistributive(filename)
|
|
|
|
elif "Squashfs filesystem" in ftype:
|
|
|
|
return SquashDistributive(filename)
|
|
|
|
elif path.isdir(filename):
|
|
|
|
if path.exists(path.join(filename,"livecd")):
|
|
|
|
return IsoDistributive(filename)
|
|
|
|
else:
|
|
|
|
return DirectoryDistributive(filename)
|
|
|
|
else:
|
|
|
|
raise DistributiveError(_("Wrong distributive") + " '%s':\n%s"\
|
|
|
|
%(filename,ftype))
|
|
|
|
|
|
|
|
def extcomparator(self,*exts):
|
|
|
|
avexts = ("iso","isodir","dir")
|
|
|
|
vals = []
|
|
|
|
for i in exts:
|
|
|
|
if i in avexts:
|
|
|
|
vals.append(avexts.index(i))
|
|
|
|
else:
|
|
|
|
vals.append(-1)
|
|
|
|
return cmp(vals[0],vals[1])
|
|
|
|
|
|
|
|
term = _terms()
|
|
|
|
|
|
|
|
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,build2 = self.term._convertVers(x[1].get('build',""),
|
|
|
|
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 getBestDistributive(self,system=None,shortname=None,march=None,
|
|
|
|
version=None,discardType=[], op_compare=None):
|
|
|
|
"""Get the actualest distributive"""
|
|
|
|
availDistrs = self._getAvailableDistributives(system,shortname,
|
|
|
|
march,version,
|
|
|
|
op_compare)
|
|
|
|
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))
|
|
|
|
availDistrs = sorted(availDistrs,self.sortdistrfunc,reverse=True)
|
|
|
|
|
|
|
|
if availDistrs:
|
|
|
|
return availDistrs[0][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,march=None):
|
|
|
|
"""Get latest stage by march"""
|
|
|
|
if march:
|
|
|
|
convert = {'x86_64':'amd64'}
|
|
|
|
march = convert.get(march,march)
|
|
|
|
reStage = re.compile(r'^.*/stage3-%s-(\d+)\.tar\.bz2$'%march,re.S)
|
|
|
|
else:
|
|
|
|
reStage = re.compile(r'^.*/stage3-[^-]+-(\d+)\.tar\.bz2$',re.S)
|
|
|
|
return self._findLatestFile(self.dirs,reStage,lambda x:x.groups()[0])
|
|
|
|
|
|
|
|
class Distributive(object, SignalInterrupt):
|
|
|
|
"""Distributive object. Parent object for all distributive."""
|
|
|
|
mountError = _("Cann't mount") + " %s:\n%s"
|
|
|
|
reLive = re.compile(r"^live[^.]*\.squashfs(\.(\d+))?$",re.S)
|
|
|
|
flagSpinner=True
|
|
|
|
|
|
|
|
def __init__(self, parent=None):
|
|
|
|
self.childs = []
|
|
|
|
# if specified parent
|
|
|
|
if parent:
|
|
|
|
# save parent type for correct resource release
|
|
|
|
self.parent = parent
|
|
|
|
# append this object as child to specified parent
|
|
|
|
parent.childs.append(self)
|
|
|
|
else:
|
|
|
|
self.parent = None
|
|
|
|
|
|
|
|
def detach(self):
|
|
|
|
"""Detach child distributive from parent.
|
|
|
|
|
|
|
|
At example: ArchiveDistributive create child DirectoryDistributive by
|
|
|
|
unpacking to temporary directory and at close method remove it. If the
|
|
|
|
removing directroy do not need, then need call detach in
|
|
|
|
DirectoryDistributive object
|
|
|
|
|
|
|
|
dist1 = ArchiveDistributive(file="/os.tar.bz2",mdirectory="/tmp/test")
|
|
|
|
dist2 = dist1.convertToDirectory()
|
|
|
|
dist2.detach()
|
|
|
|
dist1.close()
|
|
|
|
...
|
|
|
|
"""
|
|
|
|
self.parent = None
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
"""Release all child distributive and release himself.
|
|
|
|
|
|
|
|
Need call this method at end work with object for right releasing
|
|
|
|
resources.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
dist1 = PartitionDistributive(partition="/dev/sda2")
|
|
|
|
dist2 = dist1.convertToDirectory()
|
|
|
|
dist1.close()
|
|
|
|
"""
|
|
|
|
# close all child
|
|
|
|
if self.childs:
|
|
|
|
for child in reversed(self.childs):
|
|
|
|
# check detach
|
|
|
|
if child.parent:
|
|
|
|
child.close()
|
|
|
|
self.childs = []
|
|
|
|
# if has parent
|
|
|
|
if self.parent:
|
|
|
|
self.parent.releaseChild(self)
|
|
|
|
self.parent = None
|
|
|
|
|
|
|
|
def releaseChild(self,child):
|
|
|
|
"""Method of release child state of distributive
|
|
|
|
|
|
|
|
At example: PartitionDistributive may be DirectoryDistributive by
|
|
|
|
mounting it to directory. But at end this directory must be
|
|
|
|
unmounted."""
|
|
|
|
pass
|
|
|
|
|
|
|
|
def convertToDirectory(self):
|
|
|
|
"""Default c raise error about impossible convert object"""
|
|
|
|
raise DistributiveError(_("Cann't convert") + " '%s' "\
|
|
|
|
%self.__class__.__name__ + _("to") +\
|
|
|
|
" '%s'" %"DirectoryDistributive")
|
|
|
|
|
|
|
|
# def __del__(self):
|
|
|
|
# """Uncomment this method for automaticaly release all distributive
|
|
|
|
# instance"""
|
|
|
|
# self.close()
|
|
|
|
|
|
|
|
def runOsCommand(self, *argv, **kwarg):
|
|
|
|
res, mes = runOsCommand(*argv,**kwarg)
|
|
|
|
mes = "\n".join(map(lambda x: x.strip(), mes))
|
|
|
|
return res,mes
|
|
|
|
|
|
|
|
def getDirectory(self):
|
|
|
|
"""Get directory which contains distro"""
|
|
|
|
return self.convertToDirectory().directory
|
|
|
|
|
|
|
|
def getBootDirectory(self):
|
|
|
|
"""Get directory which contains boot"""
|
|
|
|
return path.join(self.getDirectory(),"boot")
|
|
|
|
|
|
|
|
def _makeDirectory(self,pathname):
|
|
|
|
"""Make directory and parent.
|
|
|
|
|
|
|
|
If directory exists then return False else True"""
|
|
|
|
try:
|
|
|
|
parent = path.split(path.normpath(pathname))[0]
|
|
|
|
if not path.exists(parent):
|
|
|
|
self._makeDirectory(parent)
|
|
|
|
else:
|
|
|
|
if path.exists(pathname):
|
|
|
|
return False
|
|
|
|
os.mkdir(pathname)
|
|
|
|
return True
|
|
|
|
except Exception, e:
|
|
|
|
raise DistributiveError(_("Cann't create directory") +" '%s':\n%s"
|
|
|
|
%(pathname,str(e)))
|
|
|
|
except KeyboardInterrupt, e:
|
|
|
|
self.setSignalInterrupt()
|
|
|
|
raise DistributiveError(_("Cann't create directory") +" '%s':\n%s"
|
|
|
|
%(pathname,str(e)))
|
|
|
|
|
|
|
|
def _removeDirectory(self,directory):
|
|
|
|
"""Remove directory and files contained in it"""
|
|
|
|
#print "removeDirectory:",directory
|
|
|
|
try:
|
|
|
|
removeDir(directory)
|
|
|
|
except Exception, e:
|
|
|
|
raise DistributiveError(_("Unable remove directory from") +\
|
|
|
|
" '%s':\n%s" %(directory,str(e)))
|
|
|
|
except KeyboardInterrupt, e:
|
|
|
|
self.setSignalInterrupt()
|
|
|
|
raise DistributiveError(_("Unable remove directory from") +\
|
|
|
|
" '%s':\n%s" %(directory,str(e)))
|
|
|
|
|
|
|
|
def _copyfile(self,infile,outfile):
|
|
|
|
try:
|
|
|
|
copyfile(infile,outfile)
|
|
|
|
except (Exception),e:
|
|
|
|
raise DistributiveError(_("Cann't copy") + " '%s' to '%s':\n%s"\
|
|
|
|
%(infile,outfile,str(e)))
|
|
|
|
|
|
|
|
def _copytree(self,indir,outdir):
|
|
|
|
try:
|
|
|
|
copytree(indir,outdir,symlinks=True)
|
|
|
|
except Exception ,e:
|
|
|
|
raise DistributiveError(_("Cann't copy") + " '%s' to '%s':\n%s"\
|
|
|
|
%(indir,outdir,str(e)))
|
|
|
|
except KeyboardInterrupt, e:
|
|
|
|
self.setSignalInterrupt()
|
|
|
|
raise DistributiveError(_("Cann't copy") + " '%s' to '%s':\n%s"\
|
|
|
|
%(indir,outdir,str(e)))
|
|
|
|
|
|
|
|
def rsync(self,fromdir,todir,hideSpin=False):
|
|
|
|
"""Copy files from 'fromdir' directory to 'todir' directory"""
|
|
|
|
if self.flagSpinner and not hideSpin:
|
|
|
|
def checkRsync():
|
|
|
|
try:
|
|
|
|
return len(filter(lambda x:"rsync\x00-a\x00-x" in x,
|
|
|
|
getRunCommands()))>2
|
|
|
|
except:
|
|
|
|
return False
|
|
|
|
spin = Spinner()
|
|
|
|
spin.init(checkFunction=checkRsync,interval=0.6)
|
|
|
|
spin.start()
|
|
|
|
rsyncCmd = varsShare().getProgPath('/usr/bin/rsync')
|
|
|
|
if not rsyncCmd:
|
|
|
|
raise DistributiveError(_("Can not find '%s' command")%"rsync")
|
|
|
|
try:
|
|
|
|
rsyncProcess = process(rsyncCmd, "-a", "-x",
|
|
|
|
"%s/"%fromdir,"%s/"%todir,stderr=STDOUT)
|
|
|
|
self.addInterruptProcess(rsyncProcess)
|
|
|
|
res = rsyncProcess.success()
|
|
|
|
errmes = rsyncProcess.read()
|
|
|
|
except Exception,e:
|
|
|
|
res = False
|
|
|
|
errmes = str(e)
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
self.setSignalInterrupt()
|
|
|
|
if self.flagSpinner:
|
|
|
|
spin.stop()
|
|
|
|
raise KeyboardInterrupt()
|
|
|
|
if self.flagSpinner and not hideSpin:
|
|
|
|
spin.stop()
|
|
|
|
if res is True:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
if "No space left on device" in errmes:
|
|
|
|
errmes = "No space left on device"
|
|
|
|
raise DistributiveError(_("Cann't copy files from") +\
|
|
|
|
" '%s' " %fromdir + _("to") +\
|
|
|
|
" '%s':\n%s" %(todir,errmes))
|
|
|
|
|
|
|
|
def _mountToBind(self,srcDirectory,destDirectory):
|
|
|
|
"""Mount srcDirectory to destDirectory"""
|
|
|
|
mount = process('/bin/mount',"-o","bind",srcDirectory,destDirectory,
|
|
|
|
stderr=STDOUT)
|
|
|
|
if mount.success():
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
os.rmdir(destDirectory)
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
raise DistributiveError(self.mountError%(srcDirectory,mount.read()))
|
|
|
|
|
|
|
|
def performFormat(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def formatPartition(self,format=""):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def rndString(self):
|
|
|
|
"""Get random string with len 8 char"""
|
|
|
|
return "".join([choice(string.ascii_letters+string.digits)
|
|
|
|
for i in xrange(0,8)])
|
|
|
|
|
|
|
|
def _getSquashNum(self,reMatch):
|
|
|
|
if reMatch.groups()[1] and reMatch.groups()[1].isdigit():
|
|
|
|
return int(reMatch.groups()[1])
|
|
|
|
else:
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def _getLastLive(self,directory):
|
|
|
|
"""Get last live squashfs image from directory"""
|
|
|
|
squashfiles = filter(lambda x:x,
|
|
|
|
map(self.reLive.search,
|
|
|
|
listDirectory(directory)))
|
|
|
|
if squashfiles:
|
|
|
|
return max(squashfiles, key=self._getSquashNum).group()
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def _mountToDirectory(self,file,directory,mountopts=""):
|
|
|
|
"""Mount squashfs to directory"""
|
|
|
|
if isMount(directory):
|
|
|
|
raise DistributiveError(_("Cann't mount to directory: %s\n")\
|
|
|
|
%directory+ _("Directory already mounted"))
|
|
|
|
mountopts = filter(lambda x:x,
|
|
|
|
mountopts.split(" "))
|
|
|
|
mountProcess = process('/bin/mount',file,directory,*mountopts,
|
|
|
|
stderr=STDOUT)
|
|
|
|
if mountProcess.success():
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
self._removeDirectory(directory)
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
raise DistributiveError(self.mountError%(file,mountProcess.read()))
|
|
|
|
|
|
|
|
def _umountDirectory(self,directory):
|
|
|
|
"""Umount directory"""
|
|
|
|
if isMount(directory):
|
|
|
|
for wait in [0,0.5,2,5]:
|
|
|
|
sleep(wait)
|
|
|
|
processUmount = process('/bin/umount',directory,stderr=STDOUT)
|
|
|
|
if processUmount.success():
|
|
|
|
return True
|
|
|
|
raise DistributiveError(_("Cann't umount") + " %s:\n%s"%
|
|
|
|
(directory,processUmount.read()))
|
|
|
|
else:
|
|
|
|
return True
|
|
|
|
|
|
|
|
def _getMntDirectory(self,directory):
|
|
|
|
"""Get directory name, which will use for mounting or unpacking
|
|
|
|
|
|
|
|
If queried name is not free then to name append random string
|
|
|
|
"""
|
|
|
|
newDirectoryName = directory
|
|
|
|
while path.exists(newDirectoryName):
|
|
|
|
newDirectoryName = "%s.%s"%(directory,self.rndString())
|
|
|
|
return newDirectoryName
|
|
|
|
|
|
|
|
class DirectoryDistributive(Distributive):
|
|
|
|
def __init__(self,directory,parent=None,mdirectory=None):
|
|
|
|
Distributive.__init__(self,parent=parent)
|
|
|
|
self.directory = directory
|
|
|
|
self.mdirectory = mdirectory
|
|
|
|
if not parent:
|
|
|
|
self._makeDirectory(self.directory)
|
|
|
|
|
|
|
|
def bindDirectory(self,mdirectory):
|
|
|
|
for child in self.childs:
|
|
|
|
if isinstance(child,DirectoryDistributive) and \
|
|
|
|
mdirectory in child.directory:
|
|
|
|
return child
|
|
|
|
mdirectory = self._getMntDirectory(mdirectory)
|
|
|
|
self._makeDirectory(mdirectory)
|
|
|
|
self._mountToBind(self.directory,mdirectory)
|
|
|
|
return DirectoryDistributive(mdirectory,parent=self)
|
|
|
|
|
|
|
|
def releaseChild(self,child):
|
|
|
|
"""Remove child Directory distributive"""
|
|
|
|
if isinstance(child,DirectoryDistributive):
|
|
|
|
self._umountDirectory(child.directory)
|
|
|
|
self._removeDirectory(child.directory)
|
|
|
|
child.directory = None
|
|
|
|
|
|
|
|
def convertToDirectory(self):
|
|
|
|
if self.mdirectory:
|
|
|
|
return self.bindDirectory(self.mdirectory)
|
|
|
|
else:
|
|
|
|
return self
|
|
|
|
|
|
|
|
def installFrom(self, source):
|
|
|
|
"""Install distributive to directory from source distributive"""
|
|
|
|
if isinstance(source,ArchiveDistributive):
|
|
|
|
source.unpackTo(self.directory)
|
|
|
|
else:
|
|
|
|
# get source distributive as directory distributive
|
|
|
|
dFrom = source.convertToDirectory()
|
|
|
|
# copy distributive from source to this
|
|
|
|
self.rsync(dFrom.directory,self.directory)
|
|
|
|
|
|
|
|
class DataPartition:
|
|
|
|
"""Data partition"""
|
|
|
|
dev = None
|
|
|
|
mountPoint = None
|
|
|
|
fileSystem = "reiserfs"
|
|
|
|
isFormat = False
|
|
|
|
systemId = None
|
|
|
|
partitionTable = None
|
|
|
|
|
|
|
|
class MultiPartitions:
|
|
|
|
"""Data partition list"""
|
|
|
|
listPartitions = []
|
|
|
|
|
|
|
|
def addPartition(self, **argv):
|
|
|
|
"""Add partition in data partition list"""
|
|
|
|
dictDataPart = reduce(lambda x,y:\
|
|
|
|
x.update({y:getattr(DataPartition,y)}) or x,
|
|
|
|
filter(lambda x: not x.startswith('_'),
|
|
|
|
DataPartition.__dict__),{})
|
|
|
|
updateAttrData = filter(lambda x: x[1]!=None, dictDataPart.items())
|
|
|
|
defaultAttr = []
|
|
|
|
for attrName, attrValue in updateAttrData:
|
|
|
|
if not attrName in argv.keys():
|
|
|
|
defaultAttr.append(attrName)
|
|
|
|
argv[attrName] = attrValue
|
|
|
|
if set(argv.keys()) != set(dictDataPart.keys()):
|
|
|
|
notFoundAttr = set(dictDataPart.keys()) - set(argv.keys())
|
|
|
|
if notFoundAttr:
|
|
|
|
raise DistributiveError(_("Were not specified attributes (%s)")\
|
|
|
|
%", ".join(map(lambda x:"DataPartition.%s"%x, notFoundAttr)))
|
|
|
|
unnecessaryAttr = (set(dictDataPart.keys()) ^ set(argv.keys())) -\
|
|
|
|
set(dictDataPart.keys())
|
|
|
|
if unnecessaryAttr:
|
|
|
|
raise DistributiveError(_("Not used attributes (%s)")\
|
|
|
|
%", ".join(map(lambda x:"DataPartition.%s"%x, unnecessaryAttr)))
|
|
|
|
else:
|
|
|
|
partObj = DataPartition()
|
|
|
|
for attr, value in argv.items():
|
|
|
|
if attr in defaultAttr:
|
|
|
|
continue
|
|
|
|
setattr(partObj,attr,value)
|
|
|
|
self.listPartitions.append(partObj)
|
|
|
|
|
|
|
|
def getSystemId(self):
|
|
|
|
"""Get systemID for change [None,82,...]"""
|
|
|
|
return map(lambda x: x.systemId, self.listPartitions)
|
|
|
|
|
|
|
|
def getPartitionTable(self):
|
|
|
|
"""Get systemID for change [dos,gpt,...]"""
|
|
|
|
return map(lambda x: x.partitionTable, self.listPartitions)
|
|
|
|
|
|
|
|
def getIsFormat(self):
|
|
|
|
"""Get list is format [True,...]"""
|
|
|
|
return map(lambda x: x.isFormat, self.listPartitions)
|
|
|
|
|
|
|
|
def getFileSystems(self):
|
|
|
|
"""Get list file systems ["reiserfs",...]"""
|
|
|
|
return map(lambda x: x.fileSystem, self.listPartitions)
|
|
|
|
|
|
|
|
def getPartitions(self):
|
|
|
|
"""Get list partition ["/dev/sda",...]"""
|
|
|
|
return map(lambda x: x.dev, self.listPartitions)
|
|
|
|
|
|
|
|
def getMountPoints(self):
|
|
|
|
"""Get list mount point ["/boot",...]"""
|
|
|
|
return map(lambda x: x.mountPoint, self.listPartitions)
|
|
|
|
|
|
|
|
|
|
|
|
class PartitionDistributive(Distributive):
|
|
|
|
formatUtilities = { 'ext2':'/sbin/mkfs.ext2 %s %s',
|
|
|
|
'ext3':'/sbin/mkfs.ext3 %s %s',
|
|
|
|
'ext4':'/sbin/mkfs.ext4 %s %s',
|
|
|
|
'jfs':'/sbin/mkfs.jfs %s -f %s',
|
|
|
|
'reiserfs':'/sbin/mkfs.reiserfs %s -f %s',
|
|
|
|
'xfs':'/sbin/mkfs.xfs %s -f %s',
|
|
|
|
'vfat':'/usr/sbin/mkfs.vfat %s -F 32 %s',
|
|
|
|
'ntfs-3g':'/usr/sbin/mkfs.ntfs %s -FQ %s',
|
|
|
|
'ntfs':'/usr/sbin/mkfs.ntfs %s -FQ %s',
|
|
|
|
'swap':'/sbin/mkswap %s'
|
|
|
|
}
|
|
|
|
labelForUtilities = { 'ext2':'-L %s',
|
|
|
|
'ext3':'-L %s',
|
|
|
|
'ext4':'-L %s',
|
|
|
|
'jfs':'-L %s',
|
|
|
|
'reiserfs':'-l %s',
|
|
|
|
'xfs':'-L %s',
|
|
|
|
'vfat':'-n %s',
|
|
|
|
'ntfs-3g':'-L %s',
|
|
|
|
'ntfs':'-L %s',
|
|
|
|
}
|
|
|
|
|
|
|
|
formatId = { 'ext2' : '83',
|
|
|
|
'ext3' : '83',
|
|
|
|
'ext4' : '83',
|
|
|
|
'reiserfs' : '83',
|
|
|
|
'jfs' : '83',
|
|
|
|
'xfs' : '83',
|
|
|
|
'vfat' : '0b',
|
|
|
|
'swap' : '82'
|
|
|
|
}
|
|
|
|
|
|
|
|
formatIdGpt = { 'ext2' : '0700',
|
|
|
|
'ext3' : '0700',
|
|
|
|
'ext4' : '0700',
|
|
|
|
'reiserfs' : '0700',
|
|
|
|
'jfs' : '0700',
|
|
|
|
'xfs' : '0700',
|
|
|
|
'vfat' : '0700',
|
|
|
|
'swap' : '8200'
|
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self,partition,parent=None,mdirectory="/mnt/calculate",
|
|
|
|
check=False,multipartition=None,flagRemoveDir=True,
|
|
|
|
fileSystem="reiserfs", isFormat=True,systemId=None,
|
|
|
|
rootLabel="Calculate", partitionTable=None):
|
|
|
|
"""Initialize partition distributive
|
|
|
|
|
|
|
|
mdirectory - directory for mount
|
|
|
|
check - check partition name and raise DistributiveError if partition
|
|
|
|
has bad name
|
|
|
|
"""
|
|
|
|
Distributive.__init__(self,parent=parent)
|
|
|
|
self.partition = partition
|
|
|
|
self.fileSystem = fileSystem
|
|
|
|
self.mdirectory = mdirectory
|
|
|
|
self.multipartition = multipartition
|
|
|
|
self.flagRemoveDir = flagRemoveDir
|
|
|
|
self.isFormat = isFormat
|
|
|
|
self.DirectoryObject = None
|
|
|
|
self.systemId = systemId
|
|
|
|
self.rootLabel = rootLabel
|
|
|
|
self.partitionTable = partitionTable
|
|
|
|
|
|
|
|
def _mountPartition(self,partition,directory,opts=""):
|
|
|
|
"""Mount partition to directory"""
|
|
|
|
self._makeDirectory(directory)
|
|
|
|
if "ntfs" in opts:
|
|
|
|
source_dir = isMount(partition)
|
|
|
|
if source_dir:
|
|
|
|
self._mountToBind(source_dir,directory)
|
|
|
|
return
|
|
|
|
self._mountToDirectory(partition,directory,opts)
|
|
|
|
|
|
|
|
def _umountPartition(self,directory):
|
|
|
|
"""Umount partition and remove directory"""
|
|
|
|
self._umountDirectory(directory)
|
|
|
|
if self.flagRemoveDir:
|
|
|
|
self._removeDirectory(directory)
|
|
|
|
|
|
|
|
def releaseChild(self,child):
|
|
|
|
"""Umount child Directory distributive"""
|
|
|
|
if isinstance(child,DirectoryDistributive):
|
|
|
|
self._umountPartition(child.directory)
|
|
|
|
child.directory = None
|
|
|
|
|
|
|
|
def _mountBind(self,srcDirectory,destDirectory):
|
|
|
|
"""Mount directory to directory"""
|
|
|
|
self._makeDirectory(destDirectory)
|
|
|
|
self._makeDirectory(srcDirectory)
|
|
|
|
self._mountToBind(srcDirectory,destDirectory)
|
|
|
|
|
|
|
|
def postinstallMountBind(self):
|
|
|
|
"""Mount bind mount point and create mount dirs"""
|
|
|
|
if self.multipartition and self.DirectoryObject:
|
|
|
|
mulipartDataBind = filter(lambda x: x[2]=="bind",
|
|
|
|
self.getMultipartData())
|
|
|
|
dirObj = self.DirectoryObject
|
|
|
|
mdirectory = dirObj.directory
|
|
|
|
for srcDir, destDir, fileSystem, isFormat, partTable \
|
|
|
|
in mulipartDataBind:
|
|
|
|
realDestDir = pathJoin(mdirectory, destDir)
|
|
|
|
realSrcDir = pathJoin(mdirectory, srcDir)
|
|
|
|
self._mountBind(realSrcDir, realDestDir)
|
|
|
|
isFormat = False
|
|
|
|
partObj = PartitionDistributive(realSrcDir, flagRemoveDir=False,
|
|
|
|
fileSystem=fileSystem,
|
|
|
|
isFormat=isFormat,
|
|
|
|
parent=dirObj)
|
|
|
|
DirectoryDistributive(realDestDir,parent=partObj)
|
|
|
|
|
|
|
|
def getMultipartData(self):
|
|
|
|
"""Get multipartition data"""
|
|
|
|
mulipartData = zip(self.multipartition.getPartitions(),
|
|
|
|
self.multipartition.getMountPoints(),
|
|
|
|
self.multipartition.getFileSystems(),
|
|
|
|
self.multipartition.getIsFormat(),
|
|
|
|
self.multipartition.getPartitionTable())
|
|
|
|
return mulipartData
|
|
|
|
|
|
|
|
def convertToDirectory(self):
|
|
|
|
"""Convert partition to directory by mounting"""
|
|
|
|
mdirectory = self.mdirectory
|
|
|
|
for child in self.childs:
|
|
|
|
if isinstance(child,DirectoryDistributive) and \
|
|
|
|
mdirectory in child.directory:
|
|
|
|
return child
|
|
|
|
mdirectory = self._getMntDirectory(mdirectory)
|
|
|
|
self._mountPartition(self.partition,mdirectory)
|
|
|
|
dirObj = DirectoryDistributive(mdirectory,parent=self)
|
|
|
|
if self.multipartition:
|
|
|
|
mulipartDataNotBind = filter(lambda x: x[2]!="bind",
|
|
|
|
self.getMultipartData())
|
|
|
|
for dev, mountPoint, fileSystem, isFormat, partTable\
|
|
|
|
in mulipartDataNotBind:
|
|
|
|
if fileSystem!="swap":
|
|
|
|
realMountPoint = pathJoin(mdirectory, mountPoint)
|
|
|
|
self._mountPartition(dev,realMountPoint,"-t %s"%fileSystem)
|
|
|
|
partObj = PartitionDistributive(dev, flagRemoveDir=False,
|
|
|
|
fileSystem=fileSystem,
|
|
|
|
isFormat=isFormat,
|
|
|
|
parent=dirObj)
|
|
|
|
if fileSystem!="swap":
|
|
|
|
DirectoryDistributive(realMountPoint,parent=partObj)
|
|
|
|
self.DirectoryObject = dirObj
|
|
|
|
return dirObj
|
|
|
|
|
|
|
|
def formatAllPartitions(self):
|
|
|
|
"""Format all partitions"""
|
|
|
|
FS,DEV,NEEDFORMAT,NEWID,PARTTABLE = 0,1,2,3,4
|
|
|
|
# get all information to matrix
|
|
|
|
dataPartitions = zip(self.multipartition.getFileSystems() +\
|
|
|
|
[self.fileSystem],
|
|
|
|
self.multipartition.getPartitions() + \
|
|
|
|
[self.partition],
|
|
|
|
self.multipartition.getIsFormat() + \
|
|
|
|
[self.isFormat],
|
|
|
|
self.multipartition.getSystemId() + \
|
|
|
|
[self.systemId],
|
|
|
|
self.multipartition.getPartitionTable() + \
|
|
|
|
[self.partitionTable])
|
|
|
|
# get partition which need format
|
|
|
|
formatPartitions = map(lambda x: (x[FS],x[DEV]),
|
|
|
|
filter(lambda x: x[NEEDFORMAT] and x[FS]!="bind",
|
|
|
|
dataPartitions))
|
|
|
|
# format all get partition
|
|
|
|
for fileSystem, dev in formatPartitions:
|
|
|
|
if fileSystem=="swap":
|
|
|
|
self.formatSwapPartition(dev)
|
|
|
|
else:
|
|
|
|
if dev == self.partition:
|
|
|
|
self.formatPartition(dev, format=fileSystem,
|
|
|
|
label=self.rootLabel)
|
|
|
|
else:
|
|
|
|
self.formatPartition(dev, format=fileSystem)
|
|
|
|
# change system id for partitions
|
|
|
|
changeidPartitions = map(lambda x: (x[NEWID],x[DEV],x[PARTTABLE]),
|
|
|
|
filter(lambda x: x[NEWID],
|
|
|
|
dataPartitions))
|
|
|
|
for systemid, dev, partTable in changeidPartitions:
|
|
|
|
self.changeSystemID(dev,systemid,partTable)
|
|
|
|
return True
|
|
|
|
|
|
|
|
def formatPartition(self, dev,format="reiserfs",label=""):
|
|
|
|
"""Format partition"""
|
|
|
|
if not format in self.formatUtilities:
|
|
|
|
raise DistributiveError(
|
|
|
|
_("Specified '%s' format is not supported")%format)
|
|
|
|
if dev in map(lambda y: y.split(" ")[0],
|
|
|
|
filter(lambda x: x.startswith("/"),
|
|
|
|
open("/proc/swaps"))):
|
|
|
|
raise DistributiveError(\
|
|
|
|
_("Cann't format partition %s, because it is used as swap")%
|
|
|
|
dev)
|
|
|
|
if isMount(dev):
|
|
|
|
raise DistributiveError(
|
|
|
|
_("Cann't format partition %s, because it is mounted")%dev)
|
|
|
|
if not os.access(dev,os.W_OK):
|
|
|
|
raise DistributiveError(_("Cann't format partition") + " %s:\n%s"%
|
|
|
|
(dev,_("Permission denied")))
|
|
|
|
if label:
|
|
|
|
labelStr = self.labelForUtilities.get(format,"")
|
|
|
|
if labelStr:
|
|
|
|
labelStr = labelStr%label
|
|
|
|
else:
|
|
|
|
labelStr = ""
|
|
|
|
execStr = self.formatUtilities[format]%(labelStr,dev)
|
|
|
|
res,errmes = self.runOsCommand(execStr)
|
|
|
|
if res == 0:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
raise DistributiveError(_("Cann't format partition") + " %s:\n%s"%
|
|
|
|
(dev,errmes))
|
|
|
|
|
|
|
|
def performFormat(self):
|
|
|
|
"""Perform format for all partition of this distributive"""
|
|
|
|
if self.multipartition:
|
|
|
|
self.formatAllPartitions()
|
|
|
|
elif self.isFormat:
|
|
|
|
self.formatPartition(self.partition,format=self.fileSystem,
|
|
|
|
label=self.rootLabel)
|
|
|
|
|
|
|
|
def changeSystemID(self,dev,systemid,parttable):
|
|
|
|
"""Change partition id, specified by systemid"""
|
|
|
|
deviceName = detectDeviceForPartition(dev)
|
|
|
|
if deviceName is None:
|
|
|
|
raise DistributiveError(
|
|
|
|
_("Can not determine parent device for %s")%dev)
|
|
|
|
# device hasn't any partition
|
|
|
|
elif deviceName == "":
|
|
|
|
return True
|
|
|
|
fdiskProg, gdiskProg = checkUtils('/sbin/fdisk','/usr/sbin/gdisk')
|
|
|
|
partitionNumber = getUdevDeviceInfo(dev).get('ID_PART_ENTRY_NUMBER','')
|
|
|
|
devicePartitionCount = countPartitions(deviceName)
|
|
|
|
if deviceName and not partitionNumber:
|
|
|
|
raise DistributiveError(
|
|
|
|
_("Can not determine partition number for %s")%dev)
|
|
|
|
if parttable == "dos":
|
|
|
|
fdisk = process(fdiskProg,deviceName,stderr=STDOUT)
|
|
|
|
pipe = Popen([fdiskProg,deviceName],
|
|
|
|
stdin=PIPE, stdout=PIPE,stderr=PIPE)
|
|
|
|
if devicePartitionCount > 1:
|
|
|
|
pipe.stdin.write("t\n%s\n%s\nw\n"%(partitionNumber,
|
|
|
|
systemid))
|
|
|
|
else:
|
|
|
|
pipe.stdin.write("t\n%s\nw\n"%systemid)
|
|
|
|
pipe.stdin.close()
|
|
|
|
pipe.wait()
|
|
|
|
elif parttable == "gpt":
|
|
|
|
pipe = Popen([gdiskProg,deviceName],
|
|
|
|
stdin=PIPE, stdout=PIPE,stderr=PIPE)
|
|
|
|
if devicePartitionCount > 1:
|
|
|
|
pipe.stdin.write("t\n%s\n%s\nw\ny\n"%(devicePartitionCount,
|
|
|
|
systemid))
|
|
|
|
else:
|
|
|
|
pipe.stdin.write("t\n%s\nw\ny\n"%systemid)
|
|
|
|
pipe.stdin.close()
|
|
|
|
pipe.wait()
|
|
|
|
return True
|
|
|
|
|
|
|
|
def formatSwapPartition(self, dev):
|
|
|
|
"""Format swap partition"""
|
|
|
|
if dev in map(lambda y: y.split(" ")[0],
|
|
|
|
filter(lambda x: x.startswith("/"),
|
|
|
|
open("/proc/swaps"))):
|
|
|
|
raise DistributiveError(\
|
|
|
|
_("Cann't 'mkswap %s', swap partition is used in the \
|
|
|
|
current system") %dev)
|
|
|
|
if isMount(dev):
|
|
|
|
raise DistributiveError(
|
|
|
|
_("Cann't format partition %s, because it is mounted") %dev)
|
|
|
|
execStr = self.formatUtilities["swap"]%dev
|
|
|
|
res,errmes = self.runOsCommand(execStr)
|
|
|
|
if res == 0:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
raise DistributiveError(_("Cann't execute '%s'")%execStr +\
|
|
|
|
"\n%s" %errmes)
|
|
|
|
|
|
|
|
def installFrom(self, source):
|
|
|
|
"""Install distributive to partition from source distributive"""
|
|
|
|
# get currect partition as directory
|
|
|
|
distrTo = self.convertToDirectory()
|
|
|
|
# install into directroy distributive from source
|
|
|
|
distrTo.installFrom(source)
|
|
|
|
|
|
|
|
class ArchiveDistributive(Distributive):
|
|
|
|
def __init__(self,file,parent=None,mdirectory="/var/calculate/tmp/stage"):
|
|
|
|
Distributive.__init__(self,parent=parent)
|
|
|
|
self.file = file
|
|
|
|
self.mdirectory = mdirectory
|
|
|
|
|
|
|
|
def _detectArchive(self,file):
|
|
|
|
"""Detect archive by "/usr/bin/file" command
|
|
|
|
|
|
|
|
Return bzip2,gzip,7z or None
|
|
|
|
"""
|
|
|
|
res,mes = self.runOsCommand("/usr/bin/file %s"%file)
|
|
|
|
if "bzip2 compressed data" in mes:
|
|
|
|
return "bzip2"
|
|
|
|
elif "gzip compressed data" in mes:
|
|
|
|
return "gzip"
|
|
|
|
elif "7-zip archive data" in mes:
|
|
|
|
return "7z"
|
|
|
|
elif file and file.endswith(".tar.lzma"):
|
|
|
|
if path.exists('/usr/bin/7za'):
|
|
|
|
return "7z"
|
|
|
|
else:
|
|
|
|
return "lzma"
|
|
|
|
return None
|
|
|
|
|
|
|
|
def _unpackArchive(self,archfile,directory):
|
|
|
|
"""Unpack archive"""
|
|
|
|
# archive is exists
|
|
|
|
if not path.exists(archfile):
|
|
|
|
raise DistributiveError(_("File '%s' not found")%archfile)
|
|
|
|
# detect type archive
|
|
|
|
archiveType = self._detectArchive(archfile)
|
|
|
|
# make directory if archive was detected normally
|
|
|
|
if archiveType:
|
|
|
|
self._makeDirectory(directory)
|
|
|
|
# unpack archive
|
|
|
|
if archiveType == "7z":
|
|
|
|
res,mes = self.runOsCommand("7za x -so %s | tar xf - -C %s/"%
|
|
|
|
(archfile,directory))
|
|
|
|
elif archiveType == "lzma":
|
|
|
|
res,mes = self.runOsCommand("lzma -dc %s | tar xf - -C %s/"%
|
|
|
|
(archfile,directory))
|
|
|
|
elif archiveType == "bzip2":
|
|
|
|
res,mes = self.runOsCommand("tar xjf %s -C %s/"%
|
|
|
|
(archfile,directory))
|
|
|
|
elif archiveType == "gzip":
|
|
|
|
res,mes = self.runOsCommand("tar xf %s -C %s/"%
|
|
|
|
(archfile,directory))
|
|
|
|
else:
|
|
|
|
raise DistributiveError(_("Unknown archive type by '%s'")%
|
|
|
|
archfile)
|
|
|
|
if res != 0:
|
|
|
|
raise DistributiveError(_("Error during unpacking\n%s")%mes)
|
|
|
|
|
|
|
|
def unpackTo(self,directory):
|
|
|
|
"""Unpack currect archive to directory"""
|
|
|
|
self._unpackArchive(self.file,directory)
|
|
|
|
|
|
|
|
def convertToDirectory(self):
|
|
|
|
"""Get archive as directory (unpack to directory)"""
|
|
|
|
# check may be the archive already unpacked
|
|
|
|
mdirectory = self.mdirectory
|
|
|
|
for child in self.childs:
|
|
|
|
if isinstance(child,DirectoryDistributive) and \
|
|
|
|
mdirectory in child.directory:
|
|
|
|
return child
|
|
|
|
# get temporary directory for unpacking
|
|
|
|
mdirectory = self._getMntDirectory(mdirectory)
|
|
|
|
dirdist = DirectoryDistributive(mdirectory,parent=self)
|
|
|
|
self._unpackArchive(self.file,mdirectory)
|
|
|
|
return dirdist
|
|
|
|
|
|
|
|
def releaseChild(self,child):
|
|
|
|
"""Remove child Directory distributive"""
|
|
|
|
if isinstance(child,DirectoryDistributive):
|
|
|
|
self._removeDirectory(child.directory)
|
|
|
|
child.directory = None
|
|
|
|
|
|
|
|
def packToArchive(self,directory,file):
|
|
|
|
res,errmes = self.runOsCommand("tar cf %s -C %s ."%(file,directory))
|
|
|
|
if res != 0:
|
|
|
|
raise DistributiveError(_("Cann't create archive") + " '%s':\n%s"%
|
|
|
|
(file,errmes))
|
|
|
|
|
|
|
|
def installFrom(self, source):
|
|
|
|
"""Install distributive to partition from source distributive"""
|
|
|
|
# get source distributive as directory distributive
|
|
|
|
dFrom = source.convertToDirectory()
|
|
|
|
# install into directroy distributive from source
|
|
|
|
self.packToArchive(dFrom.directory, self.file)
|
|
|
|
|
|
|
|
class SquashDistributive(Distributive):
|
|
|
|
def __init__(self,file,parent=None,mdirectory="/mnt/livecd",exclude=None,
|
|
|
|
compress=""):
|
|
|
|
Distributive.__init__(self,parent=parent)
|
|
|
|
self.file = file
|
|
|
|
self.mdirectory = mdirectory
|
|
|
|
self.exclude = [] if not exclude else exclude
|
|
|
|
self.compress = compress \
|
|
|
|
if compress and compress != "gzip" else \
|
|
|
|
""
|
|
|
|
|
|
|
|
def _mountSquash(self,file,directory):
|
|
|
|
"""Mount squashfs to directory"""
|
|
|
|
self._makeDirectory(directory)
|
|
|
|
self._mountToDirectory(file,directory,mountopts="-o loop -t squashfs")
|
|
|
|
|
|
|
|
def _umountSquash(self,directory):
|
|
|
|
self._umountDirectory(directory)
|
|
|
|
self._removeDirectory(directory)
|
|
|
|
|
|
|
|
def convertToDirectory(self):
|
|
|
|
mdirectory = self.mdirectory
|
|
|
|
for child in self.childs:
|
|
|
|
if isinstance(child,DirectoryDistributive) and \
|
|
|
|
mdirectory in child.directory:
|
|
|
|
return child
|
|
|
|
mdirectory = self._getMntDirectory(mdirectory)
|
|
|
|
self._mountSquash(self.file,mdirectory)
|
|
|
|
return DirectoryDistributive(mdirectory,parent=self)
|
|
|
|
|
|
|
|
def releaseChild(self,child):
|
|
|
|
"""Umount child Directory distributive"""
|
|
|
|
if isinstance(child,DirectoryDistributive):
|
|
|
|
self._umountSquash(child.directory)
|
|
|
|
child.directory = None
|
|
|
|
|
|
|
|
def packToSquash(self,directory,file):
|
|
|
|
mksquashfsUtil = '/usr/bin/mksquashfs'
|
|
|
|
if not path.exists(mksquashfsUtil):
|
|
|
|
raise DistributiveError(_("Cann't create squash") +
|
|
|
|
" : %s"%_("command '%s' not found")%mksquashfsUtil)
|
|
|
|
cmd = [mksquashfsUtil, "%s/"%directory,file, "-no-progress"]
|
|
|
|
if self.exclude:
|
|
|
|
cmd += ["-e"] + self.exclude
|
|
|
|
if self.compress:
|
|
|
|
cmd += ["-comp",self.compress]
|
|
|
|
processMkSquash = process(*cmd)
|
|
|
|
if processMkSquash.failed():
|
|
|
|
raise DistributiveError(_("Cann't create squashfs") + " '%s':\n%s"%
|
|
|
|
(file,processMkSquash.read()))
|
|
|
|
|
|
|
|
def installFrom(self, source):
|
|
|
|
"""Install distributive to partition from source distributive"""
|
|
|
|
# get source distributive as directory distributive
|
|
|
|
dFrom = source.convertToDirectory()
|
|
|
|
# install into directroy distributive from source
|
|
|
|
self.packToSquash(dFrom.directory, self.file)
|
|
|
|
|
|
|
|
class IsoDistributive(Distributive):
|
|
|
|
def __init__(self,file,parent=None,mdirectory="/mnt/cdrom",
|
|
|
|
bdirectory="/var/calculate/tmp/iso",exclude=None,
|
|
|
|
compress="gzip"):
|
|
|
|
Distributive.__init__(self,parent=parent)
|
|
|
|
self.file = file
|
|
|
|
if path.isdir(self.file):
|
|
|
|
self.mdirectory = self.file
|
|
|
|
else:
|
|
|
|
self.mdirectory = mdirectory
|
|
|
|
if file == bdirectory:
|
|
|
|
self.bdirectory = file
|
|
|
|
else:
|
|
|
|
self.bdirectory = self._getMntDirectory(bdirectory)
|
|
|
|
self.exclude = [] if not exclude else exclude
|
|
|
|
self.compress = compress
|
|
|
|
|
|
|
|
def _mountIso(self,file,directory):
|
|
|
|
if self.file != self.mdirectory:
|
|
|
|
self._makeDirectory(directory)
|
|
|
|
self._mountToDirectory(file,directory,mountopts="-o loop")
|
|
|
|
|
|
|
|
def _umountIso(self,directory):
|
|
|
|
if self.file != self.mdirectory:
|
|
|
|
self._umountDirectory(directory)
|
|
|
|
self._removeDirectory(directory)
|
|
|
|
|
|
|
|
def convertToSquash(self):
|
|
|
|
mdirectory = self.mdirectory
|
|
|
|
for child in self.childs:
|
|
|
|
if isinstance(child,SquashDistributive) and \
|
|
|
|
mdirectory in child.file:
|
|
|
|
return child
|
|
|
|
if self.mdirectory != self.file:
|
|
|
|
mdirectory = self._getMntDirectory(mdirectory)
|
|
|
|
self._mountIso(self.file,mdirectory)
|
|
|
|
fileLive = self._getLastLive(mdirectory)
|
|
|
|
if not fileLive:
|
|
|
|
self._umountIso(mdirectory)
|
|
|
|
raise DistributiveError(_("Iso %s doesn't contain live image") %
|
|
|
|
self.file)
|
|
|
|
return SquashDistributive(path.join(mdirectory,fileLive),
|
|
|
|
parent=self,exclude=self.exclude,
|
|
|
|
compress=self.compress)
|
|
|
|
|
|
|
|
def getIsoContentDirectory(self):
|
|
|
|
"""Return directory with content of iso image"""
|
|
|
|
squash = self.convertToSquash()
|
|
|
|
return path.dirname(squash.file)
|
|
|
|
|
|
|
|
def releaseChild(self,child):
|
|
|
|
"""Umount child Directory distributive"""
|
|
|
|
if isinstance(child,SquashDistributive):
|
|
|
|
self._umountIso(path.dirname(child.file))
|
|
|
|
child.directory = None
|
|
|
|
|
|
|
|
def convertToDirectory(self):
|
|
|
|
return self.convertToSquash().convertToDirectory()
|
|
|
|
|
|
|
|
def packToIso(self,directory,file):
|
|
|
|
# remove previous version of iso
|
|
|
|
try:
|
|
|
|
if path.exists(file):
|
|
|
|
os.unlink(file)
|
|
|
|
except Exception, e:
|
|
|
|
raise DistributiveError(_("Can not remove") +\
|
|
|
|
" %s:\n%s"%(file,str(e)))
|
|
|
|
except KeyboardInterrupt, e:
|
|
|
|
self.setSignalInterrupt()
|
|
|
|
raise DistributiveError(_("Can not remove") +\
|
|
|
|
" %s:\n%s"%(file,str(e)))
|
|
|
|
|
|
|
|
mkisoUtil = '/usr/bin/mkisofs'
|
|
|
|
if not path.exists(mkisoUtil):
|
|
|
|
raise DistributiveError(_("Cann't create iso image") +
|
|
|
|
" : %s"%_("command '%s' not found")%mkisoUtil)
|
|
|
|
res,errmes = self.runOsCommand(
|
|
|
|
"%(progname)s %(params)s -o %(target)s %(source)s/"%
|
|
|
|
{'progname':mkisoUtil,
|
|
|
|
'params':" ".join(["-b isolinux/isolinux.bin","-no-emul-boot",
|
|
|
|
"-boot-load-size 4","-boot-info-table","-iso-level 4",
|
|
|
|
"-hide boot.catalog"]),
|
|
|
|
'target':file,
|
|
|
|
'source':directory})
|
|
|
|
if res == 0:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
raise DistributiveError(_("Can not create iso image") + " %s:\n%s"%
|
|
|
|
(file,errmes))
|
|
|
|
|
|
|
|
def prepareIso(self):
|
|
|
|
raise DistributiveError(
|
|
|
|
_("Iso image can not be created without overriding prepareIso"))
|
|
|
|
|
|
|
|
def installFrom(self, source):
|
|
|
|
"""Install distributive to partition from source distributive"""
|
|
|
|
# make temporary directory for creating iso image
|
|
|
|
isoDirectory = self.bdirectory
|
|
|
|
self._makeDirectory(isoDirectory)
|
|
|
|
|
|
|
|
try:
|
|
|
|
# getting squash from source
|
|
|
|
liveimage = self._getLastLive(isoDirectory)
|
|
|
|
if liveimage:
|
|
|
|
curnum = self._getSquashNum(self.reLive.search(liveimage))
|
|
|
|
liveimage = "livecd.squashfs.%d"%(curnum+1)
|
|
|
|
else:
|
|
|
|
liveimage = "livecd.squashfs"
|
|
|
|
if isinstance(source,SquashDistributive):
|
|
|
|
self._copyfile(source.file,
|
|
|
|
path.join(isoDirectory,liveimage))
|
|
|
|
else:
|
|
|
|
distDirectory = source.convertToDirectory()
|
|
|
|
squashDistr = SquashDistributive(
|
|
|
|
path.join(isoDirectory,liveimage),
|
|
|
|
exclude=self.exclude,
|
|
|
|
compress=self.compress)
|
|
|
|
squashDistr.installFrom(distDirectory)
|
|
|
|
# prepare iso
|
|
|
|
self.prepareIso(isoDirectory)
|
|
|
|
# pack iso
|
|
|
|
if self.bdirectory != self.file:
|
|
|
|
self.packToIso(isoDirectory, self.file)
|
|
|
|
except DistributiveError,e:
|
|
|
|
raise e
|
|
|
|
except KeyboardInterrupt,e:
|
|
|
|
self.setSignalInterrupt()
|
|
|
|
raise DistributiveError(_("Keyboard interrupt"))
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
# close all child
|
|
|
|
Distributive.close(self)
|
|
|
|
# remove temporary directory
|
|
|
|
if path.lexists(self.bdirectory) and self.file != self.bdirectory:
|
|
|
|
self._removeDirectory(self.bdirectory)
|
|
|
|
|
|
|
|
class FlashDistributive(PartitionDistributive):
|
|
|
|
|
|
|
|
def installFrom(self, source):
|
|
|
|
"""Install distributive to partition from source distributive"""
|
|
|
|
# make temporary directory for creating iso image
|
|
|
|
distrTo = self.convertToDirectory()
|
|
|
|
# getting squash from source
|
|
|
|
if isinstance(source,IsoDistributive):
|
|
|
|
self.rsync(source.getIsoContentDirectory(),distrTo.directory)
|
|
|
|
else:
|
|
|
|
raise DistributiveError(
|
|
|
|
_("Installation to flash not support %s"%
|
|
|
|
source.__class__.__name__))
|
|
|
|
|
|
|
|
class ScratchDistributive(Distributive):
|
|
|
|
def __init__(self,directory,parent=None,mdirectory="/mnt/install",
|
|
|
|
check=False):
|
|
|
|
Distributive.__init__(self,parent=parent)
|
|
|
|
self.directory = directory
|
|
|
|
self.mdirectory = mdirectory
|
|
|
|
if check and not (path.exists(path.join(directory,"workspace")) and \
|
|
|
|
path.exists(path.join(directory,"delta")) and \
|
|
|
|
path.exists(path.join(directory,"calculate"))):
|
|
|
|
raise DistributiveError(
|
|
|
|
_("Wrong scratch distributive in '%s'")%directory)
|
|
|
|
|
|
|
|
def _mountLayers(self,source,target):
|
|
|
|
"""Mount squashfs to directory"""
|
|
|
|
self._makeDirectory(target)
|
|
|
|
self._mountToDirectory("none",target,
|
|
|
|
mountopts="-t aufs "+\
|
|
|
|
"-o udba=reval,br:%(work)s=rw:%(delta)s=ro+wh:%(static)s=ro" %\
|
|
|
|
{"work":path.join(source,"workspace"),
|
|
|
|
"delta":path.join(source,"delta"),
|
|
|
|
"static":path.join(source,"calculate")})
|
|
|
|
|
|
|
|
def _umountLayers(self,directory):
|
|
|
|
self._umountDirectory(directory)
|
|
|
|
self._removeDirectory(directory)
|
|
|
|
|
|
|
|
def _mountLiveImage(self,file,directory):
|
|
|
|
"""Mount squashfs to directory"""
|
|
|
|
self._makeDirectory(directory)
|
|
|
|
self._mountToDirectory(file,directory,mountopts="-o loop -t squashfs")
|
|
|
|
|
|
|
|
def _umountLiveImage(self,directory):
|
|
|
|
self._umountDirectory(directory)
|
|
|
|
|
|
|
|
def convertToDirectory(self):
|
|
|
|
"""Convert scrach directories to one directory"""
|
|
|
|
mdirectory = self.mdirectory
|
|
|
|
for child in self.childs:
|
|
|
|
if isinstance(child,DirectoryDistributive) and \
|
|
|
|
mdirectory in child.directory:
|
|
|
|
return child
|
|
|
|
mdirectory = self._getMntDirectory(mdirectory)
|
|
|
|
liveFile = self._getLastLive(self.directory)
|
|
|
|
self._mountLiveImage(path.join(self.directory,liveFile),
|
|
|
|
path.join(self.directory,"calculate"))
|
|
|
|
self._mountLayers(self.directory,mdirectory)
|
|
|
|
return DirectoryDistributive(mdirectory,parent=self)
|
|
|
|
|
|
|
|
def releaseChild(self,child):
|
|
|
|
"""Umount child Directory distributive"""
|
|
|
|
if isinstance(child,DirectoryDistributive):
|
|
|
|
self._umountLayers(child.directory)
|
|
|
|
self._umountLiveImage(path.join(self.directory,"calculate"))
|
|
|
|
child.directory = None
|
|
|
|
|
|
|
|
def installFrom(self, source):
|
|
|
|
"""Install distributive to partition from source distributive"""
|
|
|
|
# get source distributive as directory distributive
|
|
|
|
dFrom = source.convertToDirectory()
|
|
|
|
# install into directroy distributive from source
|
|
|
|
self.packToSquash(dFrom.directory, self.file)
|
|
|
|
|
|
|
|
class ScratchPartitionDistributive(PartitionDistributive):
|
|
|
|
|
|
|
|
def releaseChild(self,child):
|
|
|
|
"""Umount child Directory distributive"""
|
|
|
|
if isinstance(child,ScratchDistributive):
|
|
|
|
self._umountPartition(child.directory)
|
|
|
|
child.directory = None
|
|
|
|
|
|
|
|
def convertToDirectory(self):
|
|
|
|
"""Convert scratch partition to directory by scratch directory"""
|
|
|
|
return self.convertToScratch().convertToDirectory()
|
|
|
|
|
|
|
|
def convertToScratch(self):
|
|
|
|
mdirectory = self.mdirectory
|
|
|
|
for child in self.childs:
|
|
|
|
if isinstance(child,ScratchDistributive) and \
|
|
|
|
mdirectory in child.directory:
|
|
|
|
return child
|
|
|
|
mdirectory = self._getMntDirectory(mdirectory)
|
|
|
|
self._mountPartition(self.partition,mdirectory)
|
|
|
|
return ScratchDistributive(mdirectory,parent=self)
|
|
|
|
|
|
|
|
def prepareScratch(self,directory):
|
|
|
|
"""Create need scratch directories"""
|
|
|
|
for scrDirectory in ("calculate","delta","workspace"):
|
|
|
|
self._makeDirectory(path.join(directory,scrDirectory))
|
|
|
|
|
|
|
|
def getBootDirectory(self):
|
|
|
|
"""Get directory which contains boot"""
|
|
|
|
return path.join(self.convertToScratch().directory,"boot")
|
|
|
|
|
|
|
|
def postinstallMountBind(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def installFrom(self, source):
|
|
|
|
"""Install distributive to partition from source distributive"""
|
|
|
|
# get currect partition as directory
|
|
|
|
distrTo = self.convertToScratch()
|
|
|
|
scratchDirectory = distrTo.directory
|
|
|
|
|
|
|
|
try:
|
|
|
|
# getting squash from source
|
|
|
|
if isinstance(source,IsoDistributive):
|
|
|
|
source = source.convertToSquash()
|
|
|
|
if isinstance(source,SquashDistributive):
|
|
|
|
self._copyfile(source.file,
|
|
|
|
path.join(scratchDirectory,"livecd.squashfs"))
|
|
|
|
else:
|
|
|
|
distDirectory = source.convertToDirectory()
|
|
|
|
squashDistr = SquashDistributive(
|
|
|
|
path.join(scratchDirectory,"livecd.squashfs"))
|
|
|
|
squashDistr.installFrom(distDirectory)
|
|
|
|
|
|
|
|
# prepare scratch
|
|
|
|
self.prepareScratch(scratchDirectory)
|
|
|
|
except DistributiveError,e:
|
|
|
|
raise e
|
|
|
|
except KeyboardInterrupt,e:
|
|
|
|
self.setSignalInterrupt()
|
|
|
|
raise DistributiveError(_("Keyboard interrupt"))
|