def set_left(self, left):
        if left is None:
            self.left_version = None
            self.left_distro = None
            self.left_suite = None
            self.left_component = None
            self.left_pool_dir = None
            self.left_files = []
        else:
            self.source_package = left.package.name
            self.left_distro = left.package.distro.name
            self.left_suite = left.package.dist
            self.left_component = left.package.component
            self.left_version = left.version
            self.left_pool_dir = left.package.poolPath
            self.left_files = [f[2] for f in files(left.getDscContents())]
            self.left_files.append(left.dscFilename)

            if isinstance(left.package.distro, OBSDistro):
                self.obs_project = left.package.distro.obsProject(
                    left.package.dist, left.package.component)

                # this requires a just-in-time-populated cache of stuff from
                # OBS, so it isn't 100% reliable yet
                try:
                    self.obs_package = left.package.obsName
                except Exception:
                    logger.exception('ignoring error getting obsName for %s:',
                                     left.package)
    def set_left(self, left):
        if left is None:
            self.left_version = None
            self.left_distro = None
            self.left_suite = None
            self.left_component = None
            self.left_pool_dir = None
            self.left_files = []
        else:
            self.source_package = left.package.name
            self.left_distro = left.package.distro.name
            self.left_suite = left.package.dist
            self.left_component = left.package.component
            self.left_version = left.version
            self.left_pool_dir = left.package.poolDirectory().path
            self.left_files = [f[2] for f in files(left.getSources())]

            if isinstance(left.package.distro, OBSDistro):
                self.obs_project = left.package.distro.obsProject(
                        left.package.dist,
                        left.package.component)

                # this requires a just-in-time-populated cache of stuff from
                # OBS, so it isn't 100% reliable yet
                try:
                    self.obs_package = left.package.obsName
                except Exception:
                    logger.exception('ignoring error getting obsName for %s:',
                            left.package)
    def setUp(self):
        # Create a single package (not in any repo) and then set up json files
        # and directory structure in a way that matches snapshot.debian.org
        assert (update_sources.SNAPSHOT_BASE.startswith('file://'))
        self.debsnap_base = update_sources.SNAPSHOT_BASE[7:]

        filedir = os.path.join(self.debsnap_base, 'file')
        os.makedirs(os.path.join(filedir))

        data = {
            '_comment': "foo",
            'version': "1.2-1",
            'fileinfo': {},
        }

        foo = th.TestPackage(name='foo', version='1.2-1')
        foo.build()
        dsc_path = foo.dsc_path
        dsc_data = ControlFile(dsc_path, multi_para=False, signed=True).para

        with open(dsc_path, 'r') as fd:
            sha1 = hashlib.sha1(fd.read()).hexdigest()
            data['fileinfo'][sha1] = [{
                'name': os.path.basename(dsc_path),
                'archive_name': 'debian',
                'path': '/pool/main/f/foo',
                'size': os.path.getsize(dsc_path),
            }]
        shutil.copyfile(dsc_path, os.path.join(filedir, sha1))

        for dsc_hash, size, filename in files(dsc_data):
            path = os.path.join(foo.base_path, filename)
            with open(path, 'r') as fd:
                sha1 = hashlib.sha1(fd.read()).hexdigest()

            data['fileinfo'][sha1] = [{
                'name': filename,
                'archive_name': 'debian',
                'path': '/pool/main/f/foo',
                'size': size,
            }]
            shutil.copyfile(path, os.path.join(filedir, sha1))

        path = os.path.join(self.debsnap_base, 'mr/package/foo/1.2-1')
        os.makedirs(path)
        with open(os.path.join(path, 'srcfiles?fileinfo=1'), 'w') as fd:
            json.dump(data, fd)

        self.output_dir = mkdtemp(prefix='momtest.ustest.')
Exemple #4
0
 def set_right(self, right):
     if right is None:
         self.right_version = None
         self.right_distro = None
         self.right_suite = None
         self.right_component = None
         self.right_pool_dir = None
         self.right_files = []
     else:
         self.source_package = right.package.name
         self.right_distro = right.package.distro.name
         self.right_suite = right.package.dist
         self.right_component = right.package.component
         self.right_version = right.version
         self.right_pool_dir = right.package.poolPath
         self.right_files = [f[2] for f in files(right.getDscContents())]
Exemple #5
0
 def set_base(self, base):
     if base is None:
         self.base_version = None
         self.base_distro = None
         self.base_suite = None
         self.base_component = None
         self.base_pool_dir = None
         self.base_files = []
     else:
         self.source_package = base.package.name
         self.base_version = base.version
         self.base_distro = base.package.distro.name
         self.base_suite = base.package.dist
         self.base_component = base.package.component
         self.base_pool_dir = base.package.poolPath
         self.base_files = [f[2] for f in files(base.getDscContents())]
 def set_right(self, right):
     if right is None:
         self.right_version = None
         self.right_distro = None
         self.right_suite = None
         self.right_component = None
         self.right_pool_dir = None
         self.right_files = []
     else:
         self.source_package = right.package.name
         self.right_distro = right.package.distro.name
         self.right_suite = right.package.dist
         self.right_component = right.package.component
         self.right_version = right.version
         self.right_pool_dir = right.package.poolDirectory().path
         self.right_files = [f[2] for f in files(right.getSources())]
 def set_base(self, base):
     if base is None:
         self.base_version = None
         self.base_distro = None
         self.base_suite = None
         self.base_component = None
         self.base_pool_dir = None
         self.base_files = []
     else:
         self.source_package = base.package.name
         self.base_version = base.version
         self.base_distro = base.package.distro.name
         self.base_suite = base.package.dist
         self.base_component = base.package.component
         self.base_pool_dir = base.package.poolDirectory().path
         self.base_files = [f[2] for f in files(base.getSources())]
def write_text_report(left, left_patch, base, tried_bases, right, right_patch,
                      merged_version, conflicts, src_file, patch_file,
                      output_dir, merged_dir, merged_is_right,
                      build_metadata_changed):
    """Write the merge report."""

    package = left.package.name
    assert package == right.package.name, (package, right.package.name)

    assert isinstance(left, PackageVersion)
    left_distro = left.package.distro.name

    assert isinstance(right, PackageVersion)
    right_distro = right.package.distro.name

    filename = "%s/REPORT" % output_dir
    tree.ensure(filename)
    with open(filename, "w") as report:
        # Package and time
        print >> report, "%s" % package
        print >> report, "%s" % time.ctime()
        print >> report

        # General rambling
        print >> report, fill(
            "Below now follows the report of the automated "
            "merge of the %s changes to the %s source "
            "package against the new %s version." %
            (left_distro.title(), package, right_distro.title()))
        print >> report
        print >> report, fill(
            "This file is designed to be both human readable "
            "and machine-parseable.  Any line beginning with "
            "four spaces is a file that should be downloaded "
            "for the complete merge set.")
        print >> report
        print >> report

        print >> report, fill(
            "Here are the particulars of the three versions "
            "of %s that were chosen for the merge.  The base "
            "is the newest version that is a common ancestor "
            "of both the %s and %s packages.  It may be of "
            "a different upstream version, but that's not "
            "usually a problem." %
            (package, left_distro.title(), right_distro.title()))
        print >> report
        print >> report, fill(
            "The files are the source package itself, and "
            "the patch from the common base to that version.")
        print >> report

        # Base version and files
        if tried_bases:
            # We print this even if base is not None: we want to
            # record the better base versions we tried and failed to find
            print >> report, "missing base version(s):"
            for v in tried_bases:
                print >> report, " %s" % v

        if base is not None:
            print >> report, "base: %s" % base.version
            for md5sum, size, name in files(base.getDscContents()):
                print >> report, "    %s" % name
        print >> report

        # Left version and files
        print >> report, "our distro (%s): %s" % (left_distro, left.version)
        for md5sum, size, name in files(left.getDscContents()):
            print >> report, "    %s" % name
        print >> report
        if left_patch is not None:
            print >> report, "base -> %s" % left_distro
            print >> report, "    %s" % left_patch
            print >> report

        # Right version and files
        print >> report, "source distro (%s): %s" % (right_distro,
                                                     right.version)
        for md5sum, size, name in files(right.getDscContents()):
            print >> report, "    %s" % name
        print >> report
        if right_patch is not None:
            print >> report, "base -> %s" % right_distro
            print >> report, "    %s" % right_patch
            print >> report

        # Generated section
        print >> report
        print >> report, "Generated Result"
        print >> report, "================"
        print >> report
        if base is None:
            print >> report, fill(
                "Failed to merge because the base version "
                "required for a 3-way diff is missing from "
                "%s pool. Uou will need to either merge "
                "manually; or add the missing base version "
                "sources to '%s/%s/*/%s/' and run "
                "update_sources.py." %
                (right_distro, config.get('ROOT'), right_distro, package))
            print >> report
        elif merged_is_right:
            print >> report, fill("The %s version supercedes the %s version "
                                  "and can be added to %s with no changes." %
                                  (right_distro.title(), left_distro.title(),
                                   left_distro.title()))
            print >> report
            print >> report, "Merged without changes: YES"
            print >> report
            if build_metadata_changed:
                print >> report, "Build-time metadata changed: NO"
                print >> report
        else:
            if src_file.endswith(".dsc"):
                print >> report, fill(
                    "No problems were encountered during the "
                    "merge, so a source package has been "
                    "produced along with a patch containing "
                    "the differences from the %s version to "
                    "the new version." % right_distro.title())
                print >> report
                print >> report, fill(
                    "You should compare the generated patch "
                    "against the patch for the %s version "
                    "given above and ensure that there are "
                    "no unexpected changes.  You should also "
                    "sanity check the source package." % left_distro.title())
                print >> report

                print >> report, "generated: %s" % merged_version

                # Files from the dsc
                dsc = ControlFile("%s/%s" % (output_dir, src_file),
                                  multi_para=False,
                                  signed=True).para
                print >> report, "    %s" % src_file
                for md5sum, size, name in files(dsc):
                    print >> report, "    %s" % name
                print >> report
                if patch_file is not None:
                    print >> report, "%s -> generated" % right_distro
                    print >> report, "    %s" % patch_file
                    print >> report
                if build_metadata_changed:
                    print >> report, "Build-time metadata changed: NO"
                    print >> report
            else:
                print >> report, fill("Due to conflict or error, it was not "
                                      "possible to automatically create a "
                                      "source package.  Instead the result of "
                                      "the mergehas been placed into the "
                                      "following tar file which you will need "
                                      "to turn into a source package once the "
                                      "problems have been resolved.")
                print >> report
                print >> report, "    %s" % src_file
                print >> report

            if len(conflicts):
                print >> report
                print >> report, "Conflicts"
                print >> report, "========="
                print >> report
                print >> report, fill(
                    "In one or more cases, there were "
                    "different changes made in both %s and "
                    "%s to the same file; these are known as "
                    "conflicts." % (left_distro.title(), right_distro.title()))
                print >> report
                print >> report, fill("It is not possible for these to be "
                                      "automatically resolved, so this source "
                                      "needs human attention.")
                print >> report
                print >> report, fill(
                    "Those files marked with 'C ' contain "
                    "diff3 conflict markers, which can be "
                    "resolved using the text editor of your "
                    "choice. Those marked with 'C*' could "
                    "not be merged that way, so you will "
                    "find .%s and .%s files instead and "
                    "should chose one of them or a "
                    "combination of both, moving it to the "
                    "real filename and deleting the other." %
                    (left_distro.upper(), right_distro.upper()))
                print >> report

                conflicts.sort()
                for name in conflicts:
                    if os.path.isfile("%s/%s" % (merged_dir, name)):
                        print >> report, "  C  %s" % name
                    else:
                        print >> report, "  C* %s" % name
                print >> report

            if merged_version.revision is not None \
                    and left.version.upstream != merged_version.upstream:
                sa_arg = " -sa"
            else:
                sa_arg = ""

            print >> report
            print >> report, fill(
                "Once you have a source package you are "
                "happy to upload, you should make sure you "
                "include the orig.tar.gz if appropriate and "
                "information about all the versions included "
                "in the merge.")
            print >> report
            print >> report, fill("Use the following command to generate a "
                                  "correct .changes file:")
            print >> report
            print >> report, "  $ dpkg-genchanges -S -v%s%s" % (left.version,
                                                                sa_arg)
def write_text_report(left, left_patch,
                 base, tried_bases,
                 right, right_patch,
                 merged_version, conflicts, src_file, patch_file, output_dir,
                 merged_dir, merged_is_right, build_metadata_changed):
    """Write the merge report."""

    package = left.package.name
    assert package == right.package.name, (package, right.package.name)

    assert isinstance(left, PackageVersion)
    left_source = left.getSources()
    left_distro = left.package.distro.name

    if base is None:
        base_source = None
    else:
        assert isinstance(base, PackageVersion)
        base_source = base.getSources()

    assert isinstance(right, PackageVersion)
    right_source = right.getSources()
    right_distro = right.package.distro.name

    filename = "%s/REPORT" % output_dir
    tree.ensure(filename)
    with open(filename, "w") as report:
        # Package and time
        print >>report, "%s" % package
        print >>report, "%s" % time.ctime()
        print >>report

        # General rambling
        print >>report, fill("Below now follows the report of the automated "
                             "merge of the %s changes to the %s source "
                             "package against the new %s version."
                             % (left_distro.title(), package,
                                right_distro.title()))
        print >>report
        print >>report, fill("This file is designed to be both human readable "
                             "and machine-parseable.  Any line beginning with "
                             "four spaces is a file that should be downloaded "
                             "for the complete merge set.")
        print >>report
        print >>report

        print >>report, fill("Here are the particulars of the three versions "
                             "of %s that were chosen for the merge.  The base "
                             "is the newest version that is a common ancestor "
                             "of both the %s and %s packages.  It may be of "
                             "a different upstream version, but that's not "
                             "usually a problem."
                             % (package, left_distro.title(),
                                right_distro.title()))
        print >>report
        print >>report, fill("The files are the source package itself, and "
                             "the patch from the common base to that version.")
        print >>report

        # Base version and files
        if tried_bases:
            # We print this even if base_source is not None: we want to
            # record the better base versions we tried and failed to find
            print >>report, "missing base version(s):"
            for v in tried_bases:
                print >>report, " %s" % v

        if base_source is not None:
            print >>report, "base: %s" % base_source["Version"]
            for md5sum, size, name in files(base_source):
                print >>report, "    %s" % name
        print >>report

        # Left version and files
        print >>report, "our distro (%s): %s" % (left_distro, left_source["Version"])
        for md5sum, size, name in files(left_source):
            print >>report, "    %s" % name
        print >>report
        if left_patch is not None:
            print >>report, "base -> %s" % left_distro
            print >>report, "    %s" % left_patch
            print >>report

        # Right version and files
        print >>report, "source distro (%s): %s" % (right_distro, right_source["Version"])
        for md5sum, size, name in files(right_source):
            print >>report, "    %s" % name
        print >>report
        if right_patch is not None:
            print >>report, "base -> %s" % right_distro
            print >>report, "    %s" % right_patch
            print >>report

        # Generated section
        print >>report
        print >>report, "Generated Result"
        print >>report, "================"
        print >>report
        if base_source is None:
            print >>report, fill("Failed to merge because the base version "
                                 "required for a 3-way diff is missing from %s pool. "
                                 "You will need to either merge manually; or add the "
                                 "missing base version sources to '%s/%s/*/%s/' and run "
                                 "update_sources.py."
                                 % (right_distro, config.get('ROOT'), right_distro, package))
            print >>report
        elif merged_is_right:
            print >>report, fill("The %s version supercedes the %s version "
                                 "and can be added to %s with no changes." %
                                 (right_distro.title(), left_distro.title(),
                                  left_distro.title()))
            print >>report
            print >>report, "Merged without changes: YES"
            print >>report
            if build_metadata_changed:
                print >>report, "Build-time metadata changed: NO"
                print >>report
        else:
            if src_file.endswith(".dsc"):
                print >>report, fill("No problems were encountered during the "
                                    "merge, so a source package has been "
                                    "produced along with a patch containing "
                                    "the differences from the %s version to the "
                                    "new version." % right_distro.title())
                print >>report
                print >>report, fill("You should compare the generated patch "
                                    "against the patch for the %s version "
                                    "given above and ensure that there are no "
                                    "unexpected changes.  You should also "
                                    "sanity check the source package."
                                    % left_distro.title())
                print >>report

                print >>report, "generated: %s" % merged_version

                # Files from the dsc
                dsc = ControlFile("%s/%s" % (output_dir, src_file),
                                multi_para=False, signed=True).para
                print >>report, "    %s" % src_file
                for md5sum, size, name in files(dsc):
                    print >>report, "    %s" % name
                print >>report
                if patch_file is not None:
                    print >>report, "%s -> generated" % right_distro
                    print >>report, "    %s" % patch_file
                    print >>report
                if build_metadata_changed:
                    print >>report, "Build-time metadata changed: NO"
                    print >>report
            else:
                print >>report, fill("Due to conflict or error, it was not "
                                    "possible to automatically create a source "
                                    "package.  Instead the result of the merge "
                                    "has been placed into the following tar file "
                                    "which you will need to turn into a source "
                                    "package once the problems have been "
                                    "resolved.")
                print >>report
                print >>report, "    %s" % src_file
                print >>report

            if len(conflicts):
                print >>report
                print >>report, "Conflicts"
                print >>report, "========="
                print >>report
                print >>report, fill("In one or more cases, there were different "
                                    "changes made in both %s and %s to the same "
                                    "file; these are known as conflicts."
                                    % (left_distro.title(), right_distro.title()))
                print >>report
                print >>report, fill("It is not possible for these to be "
                                    "automatically resolved, so this source "
                                    "needs human attention.")
                print >>report
                print >>report, fill("Those files marked with 'C ' contain diff3 "
                                    "conflict markers, which can be resolved "
                                    "using the text editor of your choice.  "
                                    "Those marked with 'C*' could not be merged "
                                    "that way, so you will find .%s and .%s "
                                    "files instead and should chose one of them "
                                    "or a combination of both, moving it to the "
                                    "real filename and deleting the other."
                                    % (left_distro.upper(), right_distro.upper()))
                print >>report

                conflicts.sort()
                for name in conflicts:
                    if os.path.isfile("%s/%s" % (merged_dir, name)):
                        print >>report, "  C  %s" % name
                    else:
                        print >>report, "  C* %s" % name
                print >>report

            if merged_version.revision is not None \
                and Version(left_source["Version"]).upstream != merged_version.upstream:
                sa_arg = " -sa"
            else:
                sa_arg = ""

            print >>report
            print >>report, fill("Once you have a source package you are happy "
                                "to upload, you should make sure you include "
                                "the orig.tar.gz if appropriate and information "
                                "about all the versions included in the merge.")
            print >>report
            print >>report, fill("Use the following command to generate a "
                                "correct .changes file:")
            print >>report
            print >>report, "  $ dpkg-genchanges -S -v%s%s" \
                % (left_source["Version"], sa_arg)