From c13f9aacf49ecb8360541cd965e762d45ec351c8 Mon Sep 17 00:00:00 2001 From: Faik Uygur Date: Mon, 5 Feb 2007 14:51:05 +0000 Subject: [PATCH] * delta creation and delta package installation. The good part of this relocation implementation is that the relocation info is calculated on-the-fly with no performance impact during the installation, so we do not need to find some somewhere to keep these. --- pisi/atomicoperations.py | 20 ++++++++++++++++ pisi/delta.py | 49 ++++++++++++++++++++++++++++++++++------ 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/pisi/atomicoperations.py b/pisi/atomicoperations.py index 616a4cb9..3a1344ba 100644 --- a/pisi/atomicoperations.py +++ b/pisi/atomicoperations.py @@ -286,6 +286,23 @@ class Install(AtomicOperation): os.rename(path, newconfig) os.rename(oldconfig, path) + # Delta package does not contain the files that have the same hash as in + # the old package's. Because it means the file has not changed. But some + # of these files may be relocated to some other directory in the new package. + # We handle these cases here. + def relocate_files(): + from shutil import move + from pisi.delta import find_relocations + + relocations = find_relocations(self.old_files, self.files) + + for old_file, new_file in relocations: + path = "/%s" % os.path.dirname(new_file.path) + if not os.path.exists(path): + os.makedirs(path) + + move("/%s" % old_file.path, "/%s" % new_file.path) + # remove left over files from the old package. def clean_leftovers(): new = set(map(lambda x: str(x.path), self.files.list)) @@ -322,6 +339,9 @@ class Install(AtomicOperation): if config_changed: rename_configs() + if self.package_fname.endswith(ctx.const.package_suffix): + relocate_files() + if self.reinstall: clean_leftovers() diff --git a/pisi/delta.py b/pisi/delta.py index 2e02c046..fff7732d 100644 --- a/pisi/delta.py +++ b/pisi/delta.py @@ -32,17 +32,16 @@ def create_delta_package(old_package, new_package): oldfiles = oldpkg.get_files() newfiles = newpkg.get_files() - files_new = set(map(lambda x:(x.path, x.hash), newfiles.list)) - files_old = set(map(lambda x:(x.path, x.hash), oldfiles.list)) - files_delta = files_new - files_old + files_delta = find_delta(oldfiles, newfiles) + # FIXME: handle only metadata changed cases if not files_delta: ctx.ui.info(_("Nothing has changed between builds, not creating a delta")) return ctx.ui.info(_("Creating delta PiSi package between %s %s") % (old_package, new_package)) - # Unpack new package to temp + # Unpack new package to temp newpkg_name = util.package_name(newmd.package.name, newmd.package.version, newmd.package.release, newmd.package.build, False) newpkg_path = util.join_path(ctx.config.tmp_dir(), newpkg_name) newpkg.extract_to(newpkg_path, True) @@ -57,7 +56,6 @@ def create_delta_package(old_package, new_package): if outdir: deltaname = util.join_path(outdir, deltaname) - print deltaname deltapkg = Package(deltaname, "w") c = os.getcwd() @@ -75,8 +73,8 @@ def create_delta_package(old_package, new_package): ctx.build_leftover = util.join_path(ctx.config.tmp_dir(), ctx.const.install_tar_lzma) tar = archive.ArchiveTar(util.join_path(ctx.config.tmp_dir(), ctx.const.install_tar_lzma), "tarlzma") - for path, hash in files_delta: - tar.add_to_archive(path) + for file in files_delta: + tar.add_to_archive(file.path) tar.close() os.chdir(ctx.config.tmp_dir()) @@ -88,3 +86,40 @@ def create_delta_package(old_package, new_package): os.chdir(c) ctx.ui.info(_("Done.")) + +# Hash not equals (these are the deltas) +# Hash equal but path different ones (these are the relocations) +# Hash and also path equal ones (do nothing) + +def find_delta(oldfiles, newfiles): + + hashto_files = {} + for file in newfiles.list: + hashto_files[file.hash] = file + + files_new = set(map(lambda x:x.hash, newfiles.list)) + files_old = set(map(lambda x:x.hash, oldfiles.list)) + files_delta = files_new - files_old + + return map(lambda x:hashto_files[x], files_delta) + +def find_relocations(oldfiles, newfiles): + +# FIXME: A minor issue: Hash files may collide in any package (same file in different +# places in the same package.. ex. COPYING). Handle this case if check fails while installing. +# Because of that we do not use sets here but lists to append those files. + + files_new = {} + for file in newfiles.list: + files_new.setdefault(file.hash, []).append(file) + + files_old = {} + for file in oldfiles.list: + files_old.setdefault(file.hash, []).append(file) + + relocations = [] + for hash in files_new.keys(): + if hash in files_old and files_new[hash][0].path != files_old[hash][0].path: + relocations.append((files_old[hash][0], files_new[hash][0])) + + return relocations