diff --git a/src/salix-live-installer.py b/src/salix-live-installer.py index 73fe258..bc8ae45 100755 --- a/src/salix-live-installer.py +++ b/src/salix-live-installer.py @@ -1464,11 +1464,13 @@ def thread_install_salix(self): if not self.is_test: main_sizes = sltl.getSizes("/dev/{0}".format(self.main_partition)) main_size = main_sizes['size'] + main_block_size = getBlockSize("/dev/{0}".format(self.main_partition)) module_size = 0 for m in install_modules: - module_size += sltl.getUsedSize("/mnt/salt/mnt/{0}".format(m), blocksize = '4K')['size'] + module_size += sltl.getUsedSize("/mnt/salt/mnt/{0}".format(m), main_block_size, False)['size'] minimum_free_size = 50 * 1024 * 1024 # 50 M if module_size + minimum_free_size > main_size: + self.ProgressWindow.set_keep_above(False) error_dialog(_("Cannot install!\nNot enougth space on main partition ({size} needed)").format(size = getHumanSize(module_size + minimum_free_size))) self.installation = 'error' return @@ -1653,6 +1655,7 @@ def thread_install_completed(self): if self.installation == 'installing': self.InstallProgressBar.set_text(_("Installation process completed successfully...")) self.InstallProgressBar.set_fraction(1) + self.ProgressWindow.set_keep_above(False) if not self.is_test: if self.linux_partitions: rootmp = getMountPoint("/dev/{0}".format(self.main_partition)) diff --git a/src/salix_livetools_library/freesize.py b/src/salix_livetools_library/freesize.py index de1a592..4007551 100644 --- a/src/salix_livetools_library/freesize.py +++ b/src/salix_livetools_library/freesize.py @@ -5,6 +5,7 @@ Calculate some size and free size of folders and mount points. Functions: - getHumanSize + - getBlockSize - getSizes - getUsedSize """ @@ -40,7 +41,19 @@ def getHumanSize(size): sizeHuman = sizeHuman / 1024 return "{0:.1f}{1}".format(sizeHuman, units[unit]) -def getSizes(path): +def getBlockSize(path): + """ + Returns the block size of the underlying filesystem denoted by 'path'. + """ + if S_ISBLK(os.stat(path).st_mode): + diskDevice = re.sub(r'^.*/([^/]+?)[0-9]*$', r'\1', path) + blockSize = int(open('/sys/block/{0}/queue/logical_block_size'.format(diskDevice), 'r').read().strip()) + else: + st = os.statvfs(path) + blockSize = st.f_frsize + return blockSize + +def getSizes(path, withHuman = True): """ Computes the different sizes of the fileystem denoted by path (either a device or a file in filesystem). Return the following sizes (in a dictionary): @@ -75,15 +88,24 @@ def getSizes(path): uuFree = st.f_bavail * st.f_frsize # free size for unpriviliedge users used = size - free uuUsed = size - uuFree # used size appear differently for commun users than from root user - return { - 'size':size, 'sizeHuman':getHumanSize(size), - 'free':free, 'freeHuman':getHumanSize(free), - 'uuFree':uuFree, 'uuFreeHuman':getHumanSize(uuFree), - 'used':used, 'usedHuman':getHumanSize(used), - 'uuUsed':uuUsed, 'uuUsedHuman':getHumanSize(uuUsed) - } + if withHuman: + return { + 'size':size, 'sizeHuman':getHumanSize(size), + 'free':free, 'freeHuman':getHumanSize(free), + 'uuFree':uuFree, 'uuFreeHuman':getHumanSize(uuFree), + 'used':used, 'usedHuman':getHumanSize(used), + 'uuUsed':uuUsed, 'uuUsedHuman':getHumanSize(uuUsed) + } + else: + return { + 'size':size, 'sizeHuman':None, + 'free':free, 'freeHuman':None, + 'uuFree':uuFree, 'uuFreeHuman':None, + 'used':used, 'usedHuman':None, + 'uuUsed':uuUsed, 'uuUsedHuman':None + } -def getUsedSize(path, blocksize = None): +def getUsedSize(path, blocksize = None, withHuman = True): """ Returns the size of the space used by files and folders under 'path'. If 'blocksize' is specified, mimic the space that will be used if the blocksize of the underlying filesystem where the one specified. @@ -102,7 +124,10 @@ def getUsedSize(path, blocksize = None): size = int(size) if blocksize: size *= blocksize - return {'size':size, 'sizeHuman':getHumanSize(size)} + if withHuman: + return {'size':size, 'sizeHuman':getHumanSize(size)} + else: + return {'size':size, 'sizeHuman':None} # Unit test if __name__ == '__main__': diff --git a/src/salix_livetools_library/salt.py b/src/salix_livetools_library/salt.py index 9336e65..6b3d6ff 100644 --- a/src/salix_livetools_library/salt.py +++ b/src/salix_livetools_library/salt.py @@ -18,6 +18,9 @@ import glob import re from execute import execCall +from freesize import * +from threading import Thread +from time import sleep def getSaLTVersion(): """ @@ -125,14 +128,49 @@ def listSaLTModules(): moduledir = '{0}/{1}/{2}/modules'.format(getSaLTLiveMountPoint(), getSaLTBaseDir(), getSaLTRootDir()) return sorted(map(lambda(x): re.sub(r'.*/([^/]+).salt$', r'\1', x), glob.glob('{0}/*.salt'.format(moduledir)))) -def installSaLTModule(moduleName, targetMountPoint): +def getSaLTModulePath(moduleName): + """ + Get the module full path. + """ + return '/mnt/salt/mnt/{0}'.format(moduleName) + +def installSaLTModule(moduleName, targetMountPoint, callback, interval = 10, completeCallback = None): """ Install the module 'moduleName' from this Live session into the targetMountPoint. + The 'callback' function will be called each 'interval' seconds with the pourcentage (0 ≤ x ≤ 1) of progression (based on used size of target partition) as argument. + The 'completeCallback' function will be called after the completion of installation. """ _checkLive() - if not os.path.isdir('/mnt/salt/mnt/{0}'.format(moduleName)): + src = getSaLTModulePath(moduleName) + if not os.path.isdir(src): raise IOError("The module '{0}' does not exists".format(moduleName)) if not os.path.isdir(targetMountPoint): raise IOError("The target mount point '{0}' does not exists".format(targetMountPoint)) - # TODO Pythonic way ?? - execCall(['cp', '--preserve', '-r', '-f', '/mnt/salt/mnt/{0}/*'.format(moduleName), targetMountPoint], shell = False) + def get_used_size(p): + return getSizes(p, False)['used'] + class ExecCopyTask: + def _start(self, cmd): + self._stopped = False + execCall(cmd) + self.stop() + def start(self, cmd): + Thread(target=self._start, args=(cmd)).start() + def is_running(self): + return not self._stopped + def stop(self): + self._stopped = True + copy_size = getUsedSize(src, getBlockSize(targetMountPoint), False)['size'] # the source can use a different blocksize than the destination + init_size = get_used_size(targetMountPoint) + final_size = init_size + copy_size + actual_size = init_size + t = ExecCopyTask(callback, interval, completeCallback) + t.start(['cp', '--preserve', '-r', '-f', '{0}/*'.format(src), targetMountPoint]) + while t.is_running(): + sleep(interval) + actual_size = get_used_size(targetMountPoint) + p = float(actual_size) / final_size + if p > 1: + p = 1 + callback(p) + if completeCallback: + completeCallback()