diff --git a/pisi/cli/commands.py b/pisi/cli/commands.py index 03f32995..1dd192a5 100644 --- a/pisi/cli/commands.py +++ b/pisi/cli/commands.py @@ -493,6 +493,55 @@ to be downloaded from a repository containing sources. pisi.api.build(x) self.finalize() +class Delta(Command): + """Creates delta PiSi packages + +Usage: delta oldpackage newpackage + +Delta command finds the changed files between the given packages by comparing the sha1sum of the files +and creates a delta pisi package with the changed files between two releases. + +""" + __metaclass__ = autocommand + + def __init__(self, args): + super(Delta, self).__init__(args) + + name = ("delta", "dt") + + def options(self): + + group = OptionGroup(self.parser, _("delta options")) + self.add_options(group) + self.parser.add_option_group(group) + + def add_options(self, group): + group.add_option("-O", "--output-dir", action="store", default=None, + help=_("Output directory for produced packages")) + + def run(self): + + from pisi.delta import create_delta_package + + self.init(database=False, write=False) + + if len(self.args) is not 2: + self.help() + return + + if ctx.get_option('output_dir'): + ctx.ui.info(_('Output directory: %s') % ctx.config.options.output_dir) + else: + ctx.ui.info(_('Outputting packages in the working directory.')) + ctx.config.options.output_dir = '.' + + oldpackage = self.args[0] + newpackage = self.args[1] + + create_delta_package(oldpackage, newpackage) + + self.finalize() + class Emerge(Build): """Build and install PiSi source packages from repository diff --git a/pisi/delta.py b/pisi/delta.py new file mode 100644 index 00000000..96112218 --- /dev/null +++ b/pisi/delta.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007, TUBITAK/UEKAE +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# Please read the COPYING file. + +import os +from sets import Set as set + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.context as ctx +from pisi.package import Package +import pisi.util as util +import pisi.archive as archive + +def create_delta_package(old_package, new_package): + + oldpkg = Package(old_package, "r") + newpkg = Package(new_package, "r") + + newmd = newpkg.get_metadata() + oldmd = oldpkg.get_metadata() + + oldfiles = oldpkg.get_files() + newfiles = newpkg.get_files() + + files_all = 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_all - files_old + + 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 + 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) + + tar = archive.ArchiveTar(util.join_path(newpkg_path, ctx.const.install_tar_lzma), 'tarlzma', False, False) + tar.unpack_dir(newpkg_path) + + # Create delta package + deltaname = "%s-%s-%s%s" % (oldmd.package.name, oldmd.package.release, newmd.package.release, ".delta.pisi") + + outdir = ctx.get_option('output_dir') + if outdir: + deltaname = util.join_path(outdir, deltaname) + + print deltaname + deltapkg = Package(deltaname, "w") + + c = os.getcwd() + os.chdir(newpkg_path) + + # add comar files to package + for pcomar in newmd.package.providesComar: + fname = util.join_path(ctx.const.comar_dir, pcomar.script) + deltapkg.add_to_package(fname) + + # add xmls and files + deltapkg.add_to_package(ctx.const.metadata_xml) + deltapkg.add_to_package(ctx.const.files_xml) + + 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) + tar.close() + + os.chdir(ctx.config.tmp_dir()) + deltapkg.add_to_package(ctx.const.install_tar_lzma) + deltapkg.close() + + os.unlink(util.join_path(ctx.config.tmp_dir(), ctx.const.install_tar_lzma)) + ctx.build_leftover = None + os.chdir(c) + + ctx.ui.info(_("Done.")) diff --git a/pisi/package.py b/pisi/package.py index 42807766..ef309d1e 100644 --- a/pisi/package.py +++ b/pisi/package.py @@ -98,6 +98,11 @@ class Package: this is the function used by the installer""" self.impl.unpack_dir_flat(dir, outdir) + def extract_to(self, outdir, clean_dir = False): + """Extracts contents of the archive to outdir. Before extracting if clean_dir + is set, outdir is deleted with its contents""" + self.impl.unpack(outdir, clean_dir) + def extract_pisi_files(self, outdir): """Extract PiSi control files: metadata.xml, files.xml, action scripts, etc."""