Example #1
0
        def test_set_content1(self):
                """ ASSERT: manifest string repr reflects its construction """

                self.m1.set_content(self.m1_contents)

                # It would be nice if we could just see if the string
                # representation of the manifest matched the input, but the
                # order of individual fields seems to change.  Instead we look
                # for useful substrings.

                # Index raises an exception if the substring isn't found;
                # if that were to happen, the test case would then fail.
                str(self.m1).index("fmri=pkg:/library/libc")
                str(self.m1).index("owner=sch")
                str(self.m1).index("group=staff")
                str(self.m1).index("isa=i386")

                # Verify set_content with a byte string with unicode data
                # works.
                bstr = "set name=pkg.summary:th value=\"ซอฟต์แวร์ \""
                m = manifest.Manifest()
                m.set_content(bstr)
                output = list(m.as_lines())[0].rstrip()
                self.assertEqual(bstr, output)
                self.assert_(isinstance(output, str))

                # Verify set_content with a Unicode string results in a
                # byte string (for now).
                m = manifest.Manifest()
                m.set_content(unicode(bstr, "utf-8"))
                output = list(m.as_lines())[0].rstrip()
                self.assertEqual(bstr, output)
                self.assert_(isinstance(output, str))
Example #2
0
    def test_validate(self):
        """Verifies that Manifest validation works as expected."""

        self.m2.set_content(self.m2_contents, signatures=True)
        self.m2.validate(signatures=self.m2_signatures)

        self.m2.set_content(self.diverse_contents, signatures=True)
        self.assertRaises(api_errors.BadManifestSignatures,
                          self.m2.validate,
                          signatures=self.m2_signatures)

        # Verify a manifest that has its content set using a byte string
        # has the same signature as that of one set with a Unicode
        # string when the content is the same.
        bstr = "set name=pkg.summary:th value=\"ซอฟต์แวร์ \""
        m1 = manifest.Manifest()
        m1.set_content(bstr, signatures=True)
        output1 = "".join(m1.as_lines())

        m2 = manifest.Manifest()
        if six.PY2:
            m2.set_content(six.text_type(bstr, "utf-8"), signatures=True)
        else:
            m2.set_content(bstr, signatures=True)
        output2 = "".join(m2.as_lines())
        self.assertEqualDiff(output1, output2)
        self.assertEqualDiff(m1.signatures, m2.signatures)
Example #3
0
    def setUp(self):
        pkg5unittest.Pkg5TestCase.setUp(self)

        self.m1 = manifest.Manifest()
        self.m1_contents = """\
set com.sun,test=true
depend type=require fmri=pkg:/library/libc
file fff555fff mode=0555 owner=sch group=staff path=/usr/bin/i386/sort isa=i386
"""
        self.m2 = manifest.Manifest()
        self.m2_contents = """\
set com.sun,test=false
set com.sun,data=true
depend type=require fmri=pkg:/library/libc
file fff555ff9 mode=0555 owner=sch group=staff \\
 path=/usr/bin/i386/sort isa=i386
file eeeaaaeee mode=0555 owner=sch group=staff path=/usr/bin/amd64/sort isa=amd64

file ff555fff mode=0555 owner=root group=bin path=/kernel/drv/foo isa=i386
file ff555ffe mode=0555 owner=root group=bin path=/kernel/drv/amd64/foo isa=amd64
file ff555ffd mode=0644 owner=root group=bin path=/kernel/drv/foo.conf
"""

        self.m2_signatures = {
            "sha-1": "7272cb2461a8a4ccf958b7a7f13f3ae20cbb0212"
        }

        #
        # Try to keep this up to date with one of
        # every action type.
        #
        self.diverse_contents = """\
set com.sun,test=false
set name=pkg.description value="The Z Shell (zsh) is a Bourne-like shell " \\
    "designed for interactive use, although it is also a powerful scripting " \\
    "language.  Many of the useful features of bash, ksh, and tcsh were " \\
    "incorporated into zsh, but many original features were added."
depend type=require fmri=pkg:/library/libc
file fff555ff9 mode=0555 owner=sch group=staff path=/usr/bin/i386/sort isa=i386
dir owner=root path=usr/bin group=bin mode=0755 variant.arch=i386 variant.arch=sparc
dir owner=root path="opt/dir with spaces in value" group=bin mode=0755
dir owner=root path="opt/dir with " \\
    "whitespaces        " \\
    "in value" group=bin mode=0755
link path=usr/lib/amd64/libjpeg.so \\
target=libjpeg.so.62.0.0
hardlink path=usr/bin/amd64/rksh93 target=ksh93 variant.opensolaris.zone=global
group groupname=testgroup gid=10
"""

        self.m4_contents = """\
set com.sun,test=false
set com.sun,data=true
depend type=require fmri=pkg:/library/libc
file fff555ff9 mode=0555 owner=sch group=staff path=/usr/bin/i386/sort \\
isa=i386
"""

        self.m5_contents = """\
Example #4
0
    def test_set_content1(self):
        """ ASSERT: manifest string repr reflects its construction """

        self.m1.set_content(self.m1_contents)

        # It would be nice if we could just see if the string
        # representation of the manifest matched the input, but the
        # order of individual fields seems to change.  Instead we look
        # for useful substrings.

        # Index raises an exception if the substring isn't found;
        # if that were to happen, the test case would then fail.
        mstr = str(self.m1)
        mstr.index("fmri=pkg:/library/libc")
        mstr.index("owner=sch")
        mstr.index("group=staff")
        mstr.index("isa=i386")

        # Verify set_content with a byte string with unicode data
        # works.
        bstr = "set name=pkg.summary:th value=\"ซอฟต์แวร์ \""
        m = manifest.Manifest()
        m.set_content(bstr)
        output = list(m.as_lines())[0].rstrip()
        self.assertEqual(bstr, output)
        self.assertTrue(isinstance(output, str))

        # Verify set_content with a Unicode string works.
        m = manifest.Manifest()
        if six.PY2:
            m.set_content(six.text_type(bstr, "utf-8"))
        else:
            m.set_content(bstr)
        output = list(m.as_lines())[0].rstrip()
        self.assertEqual(bstr, output)
        self.assertTrue(isinstance(output, str))

        # Verify Manifests using line continuation '\' are parsed as
        # expected.
        m = manifest.Manifest()
        m.set_content(self.diverse_contents)
        expected = sorted('''\
set name=com.sun,test value=false
set name=pkg.description value="The Z Shell (zsh) is a Bourne-like shell designed for interactive use, although it is also a powerful scripting language.  Many of the useful features of bash, ksh, and tcsh were incorporated into zsh, but many original features were added."
depend fmri=pkg:/library/libc type=require
group gid=10 groupname=testgroup
dir group=bin mode=0755 owner=root path="opt/dir with spaces in value"
dir group=bin mode=0755 owner=root path="opt/dir with whitespaces        in value"
dir group=bin mode=0755 owner=root path=usr/bin variant.arch=i386 variant.arch=sparc
file fff555ff9 group=staff isa=i386 mode=0555 owner=sch path=usr/bin/i386/sort
hardlink path=usr/bin/amd64/rksh93 target=ksh93 variant.opensolaris.zone=global
link path=usr/lib/amd64/libjpeg.so target=libjpeg.so.62.0.0
'''.splitlines())
        actual = sorted(l.strip() for l in m.as_lines())

        self.assertEqualDiff(expected, actual)
Example #5
0
        def setUp(self):
                pkg5unittest.Pkg5TestCase.setUp(self)

                self.m1 = manifest.Manifest()
                self.m1_contents = """\
set com.sun,test=true
depend type=require fmri=pkg:/library/libc
file fff555fff mode=0555 owner=sch group=staff path=/usr/bin/i386/sort isa=i386
"""
                self.m2 = manifest.Manifest()
                self.m2_contents = """\
set com.sun,test=false
set com.sun,data=true
depend type=require fmri=pkg:/library/libc
file fff555ff9 mode=0555 owner=sch group=staff \
 path=/usr/bin/i386/sort isa=i386
file eeeaaaeee mode=0555 owner=sch group=staff path=/usr/bin/amd64/sort isa=amd64

file ff555fff mode=0555 owner=root group=bin path=/kernel/drv/foo isa=i386
file ff555ffe mode=0555 owner=root group=bin path=/kernel/drv/amd64/foo isa=amd64
file ff555ffd mode=0644 owner=root group=bin path=/kernel/drv/foo.conf
"""

                self.m2_signatures = {
                    "sha-1": "e600f5e48a838b11ed73fd4afedfc35638ab0bbf"
                }

                #
                # Try to keep this up to date with on of
                # every action type.
                #
                self.diverse_contents = """\
set com.sun,test=false
depend type=require fmri=pkg:/library/libc
file fff555ff9 mode=0555 owner=sch group=staff path=/usr/bin/i386/sort isa=i386
dir owner=root path=usr/bin group=bin mode=0755 variant.arch=i386 variant.arch=sparc
dir owner=root path="opt/dir with spaces in value" group=bin mode=0755
dir owner=root path="opt/dir with whitespaces	in value" group=bin mode=0755
link path=usr/lib/amd64/libjpeg.so \
target=libjpeg.so.62.0.0
hardlink path=usr/bin/amd64/rksh93 target=ksh93 variant.opensolaris.zone=global
group groupname=testgroup gid=10
"""

                self.m4_contents = """\
set com.sun,test=false
set com.sun,data=true
depend type=require fmri=pkg:/library/libc
file fff555ff9 mode=0555 owner=sch group=staff path=/usr/bin/i386/sort \
isa=i386
"""

                self.m5_contents = """\
Example #6
0
        def __do_alter_only_verify(self, pfmri, verbose=False, quiet=False, exit=0,
            parsable=False, debug=""):
                # Alter the owner, group, mode of all files (and
                # directories) to something different than the package declares.
                m = manifest.Manifest()
                m.set_content(self.get_img_manifest(pfmri))
                for a in m.gen_actions():
                        if a.name not in ("file", "dir"):
                                # Only want file or dir actions.
                                continue

                        ubin = portable.get_user_by_name("bin", None, False)
                        groot = portable.get_group_by_name("root", None, False)

                        fname = a.attrs["path"]
                        fpath = os.path.join(self.get_img_path(), fname)
                        os.chown(fpath, ubin, groot)
                        os.chmod(fpath, misc.PKG_RO_FILE_MODE)

                verify_cmd = "verify"
                if verbose:
                        verify_cmd += " -v"
                if quiet:
                        verify_cmd += " -q"
                if parsable:
                        verify_cmd += " --parsable=0"

                self.pkg("{0}{1} {2}".format(debug, verify_cmd, pfmri),
                    exit=exit)
                if exit == 0:
                        self.assertTrue("OK" in self.output and "ERROR" not
                            in self.output)
                return exit
Example #7
0
    def __change_content_hash(self):
        """Change the content-hash attr in the manifest located at the
                target and expected repos."""

        mapping = {
            self.dpath2: self.published_targ,
            self.dpath3: self.published_exp
        }
        for repodir in (self.dpath2, self.dpath3):
            for s in mapping[repodir]:
                # Find elftest package
                if "elftest" in s:
                    break
            f = fmri.PkgFmri(s, None)
            repo = self.get_repo(repodir)
            mpath = repo.manifest(f)
            # load manifest, change content-hash attr and store back
            # to disk
            mani = manifest.Manifest()
            mani.set_content(pathname=mpath)
            for a in mani.gen_actions():
                if "bin/true" in str(a):
                    # change the signed version of hash of
                    # the ELF file
                    a.attrs["pkg.content-hash"][0] = "gelf:sha512t_256:foo"
            mani.store(mpath)
            # rebuild repo catalog since manifest digest changed
            repo.rebuild()
Example #8
0
def fetch_manifest(repouri, fmri):
    """Fetch the manifest for package-fmri 'fmri' from the server
        in 'server_url'... return as Manifest object."""

    mfst_str = xport.get_manifest(fmri, pub=repouri, content_only=True)
    m = manifest.Manifest(fmri)
    m.set_content(content=mfst_str)
    return m
Example #9
0
 def addmanifest(self, root, mfile, arch, modechecks, exceptions):
     """Treats the specified input file as a pkg(5) package
     manifest, and extends the ManifestTree dictionary with entries
     for the actions therein.
     """
     mfest = manifest.Manifest()
     try:
         mfest.set_content(open(os.path.join(root, mfile)).read())
     except IOError, exc:
         raise IOError("cannot read manifest: %s" % str(exc))
Example #10
0
def make_manifest(fp):
    """Given the file path, 'fp', return a Manifest for that path."""

    m = manifest.Manifest()
    try:
        fh = open(fp, "rb")
        lines = fh.read()
        fh.close()
    except EnvironmentError, e:
        raise
Example #11
0
def get_manifest(repouri, fmri):
        """Fetch the manifest for package-fmri 'fmri' from the source
        in 'repouri'... return as Manifest object."""

        # support null manifests to keep lists ordered for merge
        if not fmri:
                return null_manifest

        mfst_str = xport.get_manifest(fmri, pub=repouri, content_only=True)
        m = manifest.Manifest(fmri)
        m.set_content(content=mfst_str)
        return m
Example #12
0
def get_manifest(repo, pub, pfmri):
    """ Retrieve a manifest with FMRI 'pfmri' of publisher 'pub' from
        repository object 'repo'. """

    path = repo.manifest(pfmri, pub)
    mani = manifest.Manifest(pfmri)
    try:
        mani.set_content(pathname=path)
    except Exception as e:
        abort(err=_("Can not open manifest file {file}: {err}\n"
                    "Please run 'pkgrepo verify -s {rroot}' to check the "
                    "integrity of the repository.").format(
                        file=path, err=str(e), rroot=repo.root))
    return mani
Example #13
0
    def test_diffs4(self):
        """ ASSERT: Building m' from diff(m, null) should yield m """

        self.m2.set_content(self.m2_contents)
        diffs = self.m2.combined_difference(manifest.null)

        new_contents = ""
        for d in diffs:
            new_contents += str(d[1]) + "\n"

        mtmp = manifest.Manifest()
        #print(new_contents)
        mtmp.set_content(new_contents)

        diffs = self.m2.combined_difference(mtmp)
        self.assertEqual(len(diffs), 0)
def __make_manifest(fp, basedirs=None, load_data=True):
        """Given the file path, 'fp', return a Manifest for that path."""

        m = manifest.Manifest()
        fh = open(fp, "rb")
        acts = []
        missing_files = []
        accumulate = ""
        for l in fh:
                l = l.strip()
                if l.endswith("\\"):
                        accumulate += l[0:-1]
                        continue
                elif accumulate:
                        l = accumulate + l
                        accumulate = ""
                if not l or l[0] == '#':
                        continue
                try:
                        a, local_path, used_bd = actions.internalizestr(l,
                            basedirs=basedirs,
                            load_data=load_data)
                        if local_path:
                                assert portable.PD_LOCAL_PATH not in a.attrs
                                a.attrs[portable.PD_LOCAL_PATH] = local_path
                                a.attrs[portable.PD_PROTO_DIR] = used_bd
                                a.attrs[portable.PD_PROTO_DIR_LIST] = basedirs
                        acts.append(a)
                except actions.ActionDataError, e:
                        new_a, local_path, used_bd = actions.internalizestr(
                            l, basedirs=basedirs, load_data=False)
                        if new_a.name == "license":
                                acts.append(new_a)
                        else:
                                path = e.path
                                # If the path was not set, then parse the
                                # action, without trying to load the data and
                                # use the path defined in the action.
                                if not path:
                                        path = new_a.attrs["path"]
                                missing_files.append(base.MissingFile(path))
Example #15
0
def __merge_fmris(new_fmri, manifest_list, fmri_list, variant_list, variant):
        """Private merge implementation."""

        # Remove variant tags, package variant metadata, and signatures
        # from manifests since we're reassigning.  This allows merging
        # pre-tagged, already merged pkgs, or signed packages.

        blended_actions = []
        blend_names = set([variant, variant[8:]])

        for j, m in enumerate(manifest_list):
                deleted_count = 0
                vval = variant_list[j]
                for i, a in enumerate(m.actions[:]):
                        if a.name == "signature" or \
                            (a.name == "set" and a.attrs["name"] == "pkg.fmri"):
                                # signatures and pkg.fmri actions are no longer
                                # valid after merging
                                del m.actions[i - deleted_count]
                                deleted_count += 1
                                continue

                        if variant in a.attrs:
                                if a.attrs[variant] != vval:
                                        # we have an already merged
                                        # manifest; filter out actions
                                        # for other variants
                                        del m.actions[i - deleted_count]
                                        deleted_count += 1
                                        continue
                                else:
                                        del a.attrs[variant]

                        if a.name == "set" and a.attrs["name"] == variant:
                                if vval not in a.attrlist("value"):
                                        raise PkgmergeException(
                                            _("package {pkg} is tagged as "
                                            "not supporting {var_name} "
                                            "{var_value}").format(
                                            pkg=fmri_list[j],
                                            var_name=variant,
                                            var_value=vval))
                                del m.actions[i - deleted_count]
                                deleted_count += 1
                        # checking if we're supposed to blend this action
                        # for this variant.  Handle prepended "variant.".
                        if blend_names & set(a.attrlist("pkg.merge.blend")):
                                blended_actions.append((j, a))

        # add blended actions to other manifests
        for j, m in enumerate(manifest_list):
                for k, a in blended_actions:
                        if k != j:
                                m.actions.append(a)

        # Like the unix utility comm, except that this function
        # takes an arbitrary number of manifests and compares them,
        # returning a tuple consisting of each manifest's actions
        # that are not the same for all manifests, followed by a
        # list of actions that are the same in each manifest.
        try:
                action_lists = list(manifest.Manifest.comm(manifest_list))
        except manifest.ManifestError as e:
                raise PkgmergeException(
                    "Duplicate action(s) in package \"{0}\": \n{1}".format(
                    new_fmri.pkg_name, e))

        # Declare new package FMRI.
        action_lists[-1].insert(0,
            actions.fromstr("set name=pkg.fmri value={0}".format(new_fmri)))

        for a_list, v in zip(action_lists[:-1], variant_list):
                for a in a_list:
                        a.attrs[variant] = v
        # discard any blend tags for this variant from common list
        for a in action_lists[-1]:
                blend_attrs = set(a.attrlist("pkg.merge.blend"))
                match = blend_names & blend_attrs
                for m in list(match):
                        if len(blend_attrs) == 1:
                                del a.attrs["pkg.merge.blend"]
                        else:
                                a.attrlist("pkg.merge.blend").remove(m)
        # combine actions into single list
        allactions = reduce(lambda a, b: a + b, action_lists)

        # figure out which variants are actually there for this pkg
        actual_variant_list = [
            v
            for m, v in zip(manifest_list, variant_list)
        ]

        # add set action to document which variants are supported
        allactions.append(actions.fromstr("set name={0} {1}".format(variant,
            " ".join([
                "value={0}".format(a)
                for a in actual_variant_list
            ])
        )))

        allactions.sort()

        m = manifest.Manifest(pfmri=new_fmri)
        m.set_content(content=allactions)
        return m
Example #16
0
    def test_4_unsigned_option(self):

        self.__change_content_hash()

        # Copy target repo to tmp repo
        self.copy_repository(self.dpath2, self.dpath_tmp,
                             {"selachii": "selachii"})
        # The new repository won't have a catalog, so rebuild it.
        self.dcs[4].get_repo(auto_create=True).rebuild()

        # If '-u' is enabled, we just check the unsigned version of
        # hashes so that the target basic package is treated as no
        # content change and should be reversioned.
        elftest_exp = self.elftest_ref
        efldiff_exp = self.elfdiff_ref
        # Replace elftest package in the expected repo.
        for i, s in enumerate(self.published_exp):
            if "elftest" in s:
                self.published_exp[i] = self.pkgsend_bulk(
                    self.dpath3, (elftest_exp, ))[0]
            if "elfdiff" in s:
                self.published_exp[i] = self.pkgsend_bulk(
                    self.dpath3, (efldiff_exp, ))[0]

        # Check that '-u' option works and should not affect other
        # packages.
        self.pkgsurf("-s {0} -r {1} -u".format(self.dpath_tmp, self.dpath1))

        self.pkgrepo("-s {0} verify --disable dependency".format(
            self.dpath_tmp))

        # Create a target repo that just contains elfdiff and elfshare
        # package. Ultimately the file elftest.so.1 and elftest.so.2
        # should reside in the target repo.
        self.pkgsend_bulk(self.dpath5, [self.elfdiff_targ, self.elfshare_targ])
        self.pkgsurf("-s {0} -r {1} -u".format(self.dpath5, self.dpath1))
        self.pkgrepo("-s {0} verify --disable dependency".format(self.dpath5))

        # Test the HTTP-based reference repo case.
        self.pkgsend_bulk(self.dpath6, [self.elfdiff_targ, self.elfshare_targ])
        self.pkgsurf("-s {0} -r {1} -u".format(self.dpath6, self.durl1))
        self.pkgrepo("-s {0} verify --disable dependency".format(self.dpath6))

        ref_repo = self.get_repo(self.dpath1)
        targ_repo = self.get_repo(self.dpath_tmp)
        exp_repo = self.get_repo(self.dpath3)
        for s in self.published_exp:
            f = fmri.PkgFmri(s, None)
            targ = targ_repo.manifest(f)

            # Load target manifest
            targm = manifest.Manifest()
            targm.set_content(pathname=targ)

            # Load expected manifest
            exp = exp_repo.manifest(f)
            expm = manifest.Manifest()
            expm.set_content(pathname=exp)

            ta, ra, ca = manifest.Manifest.comm([targm, expm],
                                                cmp_policy=CMP_UNSIGNED)
            self.debug("{0}: {1:d} {2:d}".format(str(s), len(ta), len(ra)))

            self.assertEqual(
                0, len(ta), "{0} had unexpected actions:"
                " \n{1}".format(s, "\n".join([str(x) for x in ta])))
            self.assertEqual(
                0, len(ra), "{0} had missing actions: "
                "\n{1}".format(s, "\n".join([str(x) for x in ra])))
Example #17
0
        sys.exit(EXIT_OOPS)

class PkgmergeException(Exception):
        """An exception raised if something goes wrong during the merging
        process."""

        def __unicode__(self):
                # To workaround python issues 6108 and 2517, this provides a
                # a standard wrapper for this class' exceptions so that they
                # have a chance of being stringified correctly.
                return str(self)

catalog_dict   = {}    # hash table of catalogs by source uri
fmri_cache     = {}
manifest_cache = {}
null_manifest  = manifest.Manifest()
tmpdir         = None
dry_run        = False
xport          = None
dest_xport     = None
pubs           = set()
target_pub     = None

def cleanup():
        """To be called at program finish."""

        if tmpdir:
                shutil.rmtree(tmpdir, ignore_errors=True)

        if dry_run:
                return
Example #18
0
def main_func():
    gettext.install("pkg",
                    "/usr/share/locale",
                    codeset=locale.getpreferredencoding())

    ignoreattrs = []
    onlyattrs = []
    onlytypes = []
    varattrs = defaultdict(set)

    try:
        opts, pargs = getopt.getopt(sys.argv[1:], "i:o:t:v:?", ["help"])
        for opt, arg in opts:
            if opt == "-i":
                ignoreattrs.append(arg)
            elif opt == "-o":
                onlyattrs.append(arg)
            elif opt == "-t":
                onlytypes.extend(arg.split(","))
            elif opt == "-v":
                args = arg.split("=")
                if len(args) != 2:
                    usage(_("variant option incorrect {0}").format(arg))
                if not args[0].startswith("variant."):
                    args[0] = "variant." + args[0]
                varattrs[args[0]].add(args[1])
            elif opt in ("--help", "-?"):
                usage(exitcode=0)

    except getopt.GetoptError as e:
        usage(_("illegal global option -- {0}").format(e.opt))

    if len(pargs) != 2:
        usage(_("two manifest arguments are required"))

    if (pargs[0] == "-" and pargs[1] == "-"):
        usage(_("only one manifest argument can be stdin"))

    if ignoreattrs and onlyattrs:
        usage(_("-i and -o options may not be used at the same time."))

    for v in varattrs:
        if len(varattrs[v]) > 1:
            usage(_("For any variant, only one value may be " "specified."))
        varattrs[v] = varattrs[v].pop()

    ignoreattrs = set(ignoreattrs)
    onlyattrs = set(onlyattrs)
    onlytypes = set(onlytypes)

    utypes = set(t for t in onlytypes
                 if t == "generic" or t not in pkg.actions.types)

    if utypes:
        usage(
            _("unknown action types: {0}".format(apx.list_to_lang(
                list(utypes)))))

    manifest1 = manifest.Manifest()
    manifest2 = manifest.Manifest()
    try:
        # This assumes that both pargs are not '-'.
        for p, m in zip(pargs, (manifest1, manifest2)):
            if p == "-":
                m.set_content(content=sys.stdin.read())
            else:
                m.set_content(pathname=p)
    except (pkg.actions.ActionError, apx.InvalidPackageErrors) as e:
        error(_("Action error in file {p}: {e}").format(**locals()))
    except (EnvironmentError, apx.ApiException) as e:
        error(e)

    #
    # manifest filtering
    #

    # filter action type
    if onlytypes:
        for m in (manifest1, manifest2):
            # Must pass complete list of actions to set_content, not
            # a generator, to avoid clobbering manifest contents.
            m.set_content(content=list(m.gen_actions_by_types(onlytypes)))

    # filter variant
    v1 = manifest1.get_all_variants()
    v2 = manifest2.get_all_variants()
    for vname in varattrs:
        for _path, v, m in zip(pargs, (v1, v2), (manifest1, manifest2)):
            if vname not in v:
                continue
            filt = varattrs[vname]
            if filt not in v[vname]:
                usage(
                    _("Manifest {path} doesn't support "
                      "variant {vname}={filt}".format(**locals())))
            # remove the variant tag
            def rip(a):
                a.attrs.pop(vname, None)
                return a

            m.set_content([
                rip(a) for a in m.gen_actions(
                    excludes=[variant.Variants({
                        vname: filt
                    }).allow_action])
            ])
            m[vname] = filt

    if varattrs:
        # need to rebuild these if we're filtering variants
        v1 = manifest1.get_all_variants()
        v2 = manifest2.get_all_variants()

    # we need to be a little clever about variants, since
    # we can have multiple actions w/ the same key attributes
    # in each manifest in that case.  First, make sure any variants
    # of the same name have the same values defined.
    for k in set(v1.keys()) & set(v2.keys()):
        if v1[k] != v2[k]:
            error(
                _("Manifests support different variants "
                  "{v1} {v2}").format(v1=v1, v2=v2))

    # Now, get a list of all possible variant values, including None
    # across all variants and both manifests
    v_values = dict()

    for v in v1:
        v1[v].add(None)
        for a in v1[v]:
            v_values.setdefault(v, set()).add((v, a))

    for v in v2:
        v2[v].add(None)
        for a in v2[v]:
            v_values.setdefault(v, set()).add((v, a))

    diffs = []

    for tup in product(*v_values.values()):
        # build excludes closure to examine only actions exactly
        # matching current variant values... this is needed to
        # avoid confusing manifest difference code w/ multiple
        # actions w/ same key attribute values or getting dups
        # in output
        def allow(a, publisher=None):
            for k, v in tup:
                if v is not None:
                    if k not in a.attrs or a.attrs[k] != v:
                        return False
                elif k in a.attrs:
                    return False
            return True

        a, c, r = manifest2.difference(manifest1, [allow], [allow])
        diffs += a
        diffs += c
        diffs += r

    # License action still causes spurious diffs... check again for now.
    real_diffs = [(a, b) for a, b in diffs
                  if a is None or b is None or a.different(b)]

    if not real_diffs:
        return 0

    # define some ordering functions so that output is easily readable
    # First, a human version of action comparison that works across
    # variants and action changes...
    def compare(a, b):
        if hasattr(a, "key_attr") and hasattr(b, "key_attr") and \
            a.key_attr == b.key_attr:
            res = cmp(a.attrs[a.key_attr], b.attrs[b.key_attr])
            if res:
                return res
            # sort by variant
            res = cmp(sorted(list(a.get_variant_template())),
                      sorted(list(b.get_variant_template())))
            if res:
                return res
        else:
            res = cmp(a.ordinality, b.ordinality)
            if res:
                return res
        return cmp(str(a), str(b))

    # and something to pull the relevant action out of the old value, new
    # value tuples
    def tuple_key(a):
        if not a[0]:
            return a[1]
        return a[0]

    # sort and....
    diffs = sorted(diffs, key=tuple_key, cmp=compare)

    # handle list attributes
    def attrval(attrs, k, elide_iter=tuple()):
        def q(s):
            if " " in s or s == "":
                return '"{0}"'.format(s)
            else:
                return s

        v = attrs[k]
        if isinstance(v, list) or isinstance(v, set):
            out = " ".join([
                "{0}={1}".format(k, q(lmt)) for lmt in sorted(v)
                if lmt not in elide_iter
            ])
        elif " " in v or v == "":
            out = k + "=\"" + v + "\""
        else:
            out = k + "=" + v
        return out

    # figure out when to print diffs
    def conditional_print(s, a):
        if onlyattrs:
            if not set(a.attrs.keys()) & onlyattrs:
                return False
        elif ignoreattrs:
            if not set(a.attrs.keys()) - ignoreattrs:
                return False

        print("{0} {1}".format(s, a))
        return True

    different = False

    for old, new in diffs:
        if not new:
            different |= conditional_print("-", old)
        elif not old:
            different |= conditional_print("+", new)
        else:
            s = []

            if not onlyattrs:
                if (hasattr(old, "hash") and "hash" not in ignoreattrs):
                    if old.hash != new.hash:
                        s.append("  - {0}".format(old.hash))
                        s.append("  + {0}".format(new.hash))
                attrdiffs = (set(new.differences(old)) - ignoreattrs)
                attrsames = sorted(
                    list(
                        set(old.attrs.keys() + new.attrs.keys()) -
                        set(new.differences(old))))
            else:
                if hasattr(old, "hash") and "hash" in onlyattrs:
                    if old.hash != new.hash:
                        s.append("  - {0}".format(old.hash))
                        s.append("  + {0}".format(new.hash))
                attrdiffs = (set(new.differences(old)) & onlyattrs)
                attrsames = sorted(
                    list(
                        set(old.attrs.keys() + new.attrs.keys()) -
                        set(new.differences(old))))

            for a in sorted(attrdiffs):
                if a in old.attrs and a in new.attrs and \
                    isinstance(old.attrs[a], list) and \
                    isinstance(new.attrs[a], list):
                    elide_set = (set(old.attrs[a]) & set(new.attrs[a]))
                else:
                    elide_set = set()
                if a in old.attrs:
                    diff_str = attrval(old.attrs, a, elide_iter=elide_set)
                    if diff_str:
                        s.append("  - {0}".format(diff_str))
                if a in new.attrs:
                    diff_str = attrval(new.attrs, a, elide_iter=elide_set)
                    if diff_str:
                        s.append("  + {0}".format(diff_str))
            # print out part of action that is the same
            if s:
                different = True
                print("{0} {1} {2}".format(
                    old.name, attrval(old.attrs, old.key_attr), " ".join(
                        ("{0}".format(attrval(old.attrs, v)) for v in attrsames
                         if v != old.key_attr))))

                for l in s:
                    print(l)

    return int(different)
Example #19
0
        def info(self, fmri_strings, info_needed, excludes=misc.EmptyI):
                """Gathers information about fmris.  fmri_strings is a list
                of fmri_names for which information is desired. It
                returns a dictionary of lists.  The keys for the dictionary are
                the constants specified in the class definition.  The values are
                lists of PackageInfo objects or strings."""

                bad_opts = info_needed - PackageInfo.ALL_OPTIONS
                if bad_opts:
                        raise api_errors.UnrecognizedOptionsToInfo(bad_opts)

                fmris = []
                notfound = []
                illegals = []

                for pattern in fmri_strings:
                        try:
                                pfmri = None
                                pfmri = self.get_matching_pattern_fmris(pattern)
                        except pkg.fmri.IllegalFmri as e:
                                illegals.append(pattern)
                                continue
                        else:
                                fmris.extend(pfmri[0])
                                if not pfmri:
                                        notfound.append(pattern)

                repo_cat = self._depot.repo.get_catalog(self._pub)

                # Set of options that can use catalog data.
                cat_opts = frozenset([PackageInfo.SUMMARY,
                    PackageInfo.CATEGORIES, PackageInfo.DESCRIPTION,
                    PackageInfo.DEPENDENCIES])

                # Set of options that require manifest retrieval.
                act_opts = PackageInfo.ACTION_OPTIONS - \
                    frozenset([PackageInfo.DEPENDENCIES])

                pis = []
                for f in fmris:
                        pub = name = version = release = None
                        build_release = branch = packaging_date = None
                        if PackageInfo.IDENTITY in info_needed:
                                pub, name, version = f.tuple()
                                release = version.release
                                build_release = version.build_release
                                branch = version.branch
                                packaging_date = \
                                    version.get_timestamp().strftime("%c")

                        states = None

                        links = hardlinks = files = dirs = dependencies = None
                        summary = csize = size = licenses = cat_info = \
                            description = None

                        if cat_opts & info_needed:
                                summary, description, cat_info, dependencies = \
                                    _get_pkg_cat_data(repo_cat, info_needed,
                                        excludes=excludes, pfmri=f)
                                if cat_info is not None:
                                        cat_info = [
                                            PackageCategory(scheme, cat)
                                            for scheme, cat in cat_info
                                        ]

                        if (frozenset([PackageInfo.SIZE,
                            PackageInfo.LICENSES]) | act_opts) & info_needed:
                                mfst = manifest.Manifest(f)
                                try:
                                        mpath = self._depot.repo.manifest(f)
                                except srepo.RepositoryError as e:
                                        notfound.append(f)
                                        continue

                                if not os.path.exists(mpath):
                                        notfound.append(f)
                                        continue

                                mfst.set_content(pathname=mpath)

                                if PackageInfo.LICENSES in info_needed:
                                        licenses = self.__licenses(mfst)

                                if PackageInfo.SIZE in info_needed:
                                        size, csize = mfst.get_size(
                                            excludes=excludes)

                                if act_opts & info_needed:
                                        if PackageInfo.LINKS in info_needed:
                                                links = list(
                                                    mfst.gen_key_attribute_value_by_type(
                                                    "link", excludes))
                                        if PackageInfo.HARDLINKS in info_needed:
                                                hardlinks = list(
                                                    mfst.gen_key_attribute_value_by_type(
                                                    "hardlink", excludes))
                                        if PackageInfo.FILES in info_needed:
                                                files = list(
                                                    mfst.gen_key_attribute_value_by_type(
                                                    "file", excludes))
                                        if PackageInfo.DIRS in info_needed:
                                                dirs = list(
                                                    mfst.gen_key_attribute_value_by_type(
                                                    "dir", excludes))

                        pis.append(PackageInfo(pkg_stem=name, summary=summary,
                            category_info_list=cat_info, states=states,
                            publisher=pub, version=release,
                            build_release=build_release, branch=branch,
                            packaging_date=packaging_date, size=size,
                            csize=csize, pfmri=f, licenses=licenses,
                            links=links, hardlinks=hardlinks, files=files,
                            dirs=dirs, dependencies=dependencies,
                            description=description))
                return {
                    self.INFO_FOUND: pis,
                    self.INFO_MISSING: notfound,
                    self.INFO_ILLEGALS: illegals
                }
Example #20
0
def do_reversion(pub, ref_pub, target_repo, ref_xport, changes, ignores,
                 cmp_policy, ref_repo, ref, ref_xport_cfg):
    """Do the repo reversion.
        Return 'True' if repo got modified, 'False' otherwise."""

    global temp_root, tracker, dry_run, repo_finished, repo_modified

    target_cat = target_repo.get_catalog(pub=pub)
    ref_cat = fetch_catalog(ref_pub, ref_xport, temp_root)

    latest_pkgs = get_latest(target_cat)
    latest_ref_pkgs = get_latest(ref_cat)

    no_revs = get_matching_pkgs(target_cat, changes)

    # We use bulk prefetching for faster transport of the manifests.
    # Prefetch requires an intent which it sends to the server. Here
    # we just use operation=reversion for all FMRIs.
    intent = "operation=reversion;"
    # use list() to force the zip() to evaluate
    ref_pkgs = list(zip(latest_ref_pkgs.values(), repeat(intent)))

    # Retrieve reference manifests.
    # Try prefetching manifests in bulk first for faster, parallel
    # transport. Retryable errors during prefetch are ignored and
    # manifests are retrieved again during the "Reading" phase.
    ref_xport.prefetch_manifests(ref_pkgs, progtrack=tracker)

    # Need to change the output of mfst_fetch since otherwise we
    # would see "Download Manifests x/y" twice, once from the
    # prefetch and once from the actual manifest analysis.
    tracker.mfst_fetch = progress.GoalTrackerItem(_("Analyzing Manifests"))

    tracker.manifest_fetch_start(len(latest_pkgs))

    reversioned_pkgs = set()
    depend_changes = {}
    dups = 0  # target pkg has equal version to ref pkg
    new_p = 0  # target pkg not in ref
    sucs = 0  # ref pkg is successor to pkg in targ
    nrevs = 0  # pkgs requested to not be reversioned by user

    for p in latest_pkgs:
        # First check if the package is in the list of FMRIs the user
        # doesn't want to reversion.
        if p in no_revs:
            nrevs += 1
            tracker.manifest_fetch_progress(completion=True)
            continue

        # Check if the package is in the ref repo, if not: ignore.
        if not p in latest_ref_pkgs:
            new_p += 1
            tracker.manifest_fetch_progress(completion=True)
            continue

        pfmri = latest_pkgs[p]
        # Ignore if latest package is the same in targ and ref.
        if pfmri == latest_ref_pkgs[p]:
            dups += 1
            tracker.manifest_fetch_progress(completion=True)
            continue

        # Ignore packages where ref version is higher.
        if latest_ref_pkgs[p].is_successor(pfmri):
            sucs += 1
            tracker.manifest_fetch_progress(completion=True)
            continue

        # Pull the manifests for target and ref repo.
        dm = get_manifest(target_repo, pub, pfmri)
        rm = ref_xport.get_manifest(latest_ref_pkgs[p])
        tracker.manifest_fetch_progress(completion=True)

        tdeps = set()
        rdeps = set()

        # Diff target and ref manifest.
        # action only in targ, action only in ref, common action
        ta, ra, ca = manifest.Manifest.comm([dm, rm], cmp_policy=cmp_policy)

        # Check for manifest changes.
        if not all(use_ref(a, tdeps, ignores) for a in ta) \
            or not all(use_ref(a, rdeps, ignores) for a in ra):
            continue

        # Both dep lists should be equally long in case deps have just
        # changed. If not, it means a dep has been added or removed and
        # that means content change.
        if len(tdeps) != len(rdeps):
            continue

        # If len is not different we still have to make sure that
        # entries have the same pkg stem. The test above just saves time
        # in some cases.
        if not all(td in rdeps for td in tdeps):
            continue

        # Pkg only contains dependency change. Keep for further
        # analysis.
        if tdeps:
            depend_changes[pfmri.get_pkg_stem(anarchy=True)] = tdeps
            continue

        # Pkg passed all checks and can be reversioned.
        reversioned_pkgs.add(pfmri.get_pkg_stem(anarchy=True))

    tracker.manifest_fetch_done()

    def has_changed(pstem, seen=None, depth=0):
        """Determine if a package or any of its dependencies has
                changed.
                Function will check if a dependency had a content change. If it
                only had a dependency change, analyze its dependencies
                recursively. Only if the whole dependency chain didn't have any
                content change it is safe to reversion the package.

                Note about circular dependencies: The function keeps track of
                pkgs it already processed by stuffing them into the set 'seen'.
                However, 'seen' gets updated before the child dependencies of
                the current pkg are examined. This works if 'seen' is only used
                for one dependency chain since the function immediately comes
                back with a True result if a pkg has changed further down the
                tree. However, if 'seen' is re-used between runs, it will
                return prematurely, likely returning wrong results. """

        MAX_DEPTH = 100

        if not seen:
            seen = set()

        if pstem in seen:
            return False

        depth += 1
        if depth > MAX_DEPTH:
            # Let's make sure we don't run into any
            # recursion limits. If the dep chain is too deep
            # just treat as changed pkg.
            error(
                _("Dependency chain depth of >{md:d} detected for"
                  " {p}.").format(md=MAX_DEPTH, p=p))
            return True

        # Pkg has no change at all.
        if pstem in reversioned_pkgs:
            return False

        # Pkg must have content change, if it had no change it would be
        # in reversioned_pkgs, and if it had just a dep change it would
        # be in depend_changes.
        if pstem not in depend_changes:
            return True

        # We need to update 'seen' here, otherwise we won't find this
        # entry in case of a circular dependency.
        seen.add(pstem)

        return any(has_changed(d, seen, depth) for d in depend_changes[pstem])

    # Check if packages which just have a dep change can be reversioned by
    # checking if child dependencies also have no content change.
    dep_revs = 0
    for p in depend_changes:
        if not has_changed(p):
            dep_revs += 1
            reversioned_pkgs.add(p)

    status = []
    if cmp_policy == CMP_UNSIGNED:
        status.append((_("WARNING: Signature changes in file content "
                         "ignored in resurfacing")))
    status.append((_("Packages to process:"), str(len(latest_pkgs))))
    status.append((_("New packages:"), str(new_p)))
    status.append((_("Unmodified packages:"), str(dups)))
    if sucs:
        # This only happens if reference repo is ahead of target repo,
        # so only show if it actually happened.
        status.append((_("Packages with successors in "
                         "reference repo:"), str(sucs)))
    if nrevs:
        # This only happens if user specified pkgs to not revert,
        # so only show if it actually happened.
        status.append((_("Packages not to be reversioned by user "
                         "request:"), str(nrevs)))
    status.append((_("Packages with no content change:"),
                   str(len(reversioned_pkgs) - dep_revs)))
    status.append((_("Packages which only have dependency change:"),
                   str(len(depend_changes))))
    status.append(
        (_("Packages with unchanged dependency chain:"), str(dep_revs)))
    status.append(
        (_("Packages to be reversioned:"), str(len(reversioned_pkgs))))

    rjust_status = max(len(s[0]) for s in status)
    rjust_value = max(len(s[1]) for s in status)
    for s in status:
        msg("{0} {1}".format(s[0].rjust(rjust_status),
                             s[1].rjust(rjust_value)))

    if not reversioned_pkgs:
        msg(_("\nNo packages to reversion."))
        return False

    if dry_run:
        msg(_("\nReversioning packages (dry-run)."))
    else:
        msg(_("\nReversioning packages."))

    # Start the main pass. Reversion packages from reversioned_pkgs to the
    # version in the ref repo. For packages which don't get reversioned,
    # check if the dependency versions are still correct, fix if necessary.
    tracker.reversion_start(len(latest_pkgs), len(reversioned_pkgs))

    for p in latest_pkgs:
        tracker.reversion_add_progress(pfmri, pkgs=1)
        modified = False

        # Get the pkg fmri (pfmri) of the latest version based on if it
        # has been reversioned or not.
        stem = latest_pkgs[p].get_pkg_stem(anarchy=True)
        if stem in reversioned_pkgs:
            tracker.reversion_add_progress(pfmri, reversioned=1)
            if dry_run:
                continue
            pfmri = latest_ref_pkgs[p]
            # Retrieve manifest from ref repo and replace the one in
            # the target repo. We don't have to adjust depndencies
            # for these packages because they will not depend on
            # anything we'll reversion.
            rmani = ref_xport.get_manifest(pfmri)

            if cmp_policy == CMP_UNSIGNED:
                # Files with different signed content hash
                # values can have equivalent unsigned content
                # hash. CMP_UNSIGNED relaxes comparison
                # constraints and allows this case to compare
                # as equal. The reversioned manifest may
                # reference file data that is not present in
                # the target repository, so ensure that any
                # missing file data is added to the target
                # repository.
                add_missing_files(target_repo, pub, latest_pkgs[p], pfmri,
                                  rmani, ref, ref_repo, ref_xport,
                                  ref_xport_cfg, ref_pub)

            opath = target_repo.manifest(latest_pkgs[p], pub)
            os.remove(opath)
            path = target_repo.manifest(pfmri, pub)
            try:
                repo_modified = True
                repo_finished = False
                portable.rename(rmani.pathname, path)
            except OSError as e:
                abort(err=_("Could not reversion manifest "
                            "{path}: {err}").format(path=path, err=str(e)))
            continue

        # For packages we don't reversion we have to check if they
        # depend on a reversioned package.
        # Since the version of this dependency might be removed from the
        # repo, we have to adjust the dep version to the one of the
        # reversioned pkg.
        pfmri = latest_pkgs[p]
        omani = get_manifest(target_repo, pub, pfmri)
        mani = manifest.Manifest(pfmri)
        for act in omani.gen_actions():
            nact = adjust_dep_action(p, act, latest_ref_pkgs, reversioned_pkgs,
                                     ref_xport)
            if nact:
                mani.add_action(nact, misc.EmptyI)
                if nact is not act:
                    modified = True

        # Only touch manifest if something actually changed.
        if modified:
            tracker.reversion_add_progress(pfmri, adjusted=1)
            if not dry_run:
                path = target_repo.manifest(pfmri, pub)
                repo_modified = True
                repo_finished = False
                mani.store(path)
    tracker.reversion_done()

    return True
Example #21
0
    def test_1_basics(self):
        """Test basic resurfacing operation."""

        # Copy target repo to tmp repo
        self.copy_repository(self.dpath2, self.dpath_tmp,
                             {"selachii": "selachii"})
        # The new repository won't have a catalog, so rebuild it.
        self.dcs[4].get_repo(auto_create=True).rebuild()
        #self.assertTrue(False)

        # Check that empty repos get handled correctly
        tempdir = tempfile.mkdtemp(dir=self.test_root)
        # No repo at all
        self.pkgsurf("-s {0} -r {1}".format(tempdir, self.dpath1), exit=1)
        self.pkgsurf("-s {0} -r {1}".format(self.dpath1, tempdir), exit=1)

        # Repo empty
        self.pkgrepo("create -s {0}".format(tempdir))
        self.pkgsurf("-s {0} -r {1}".format(tempdir, self.dpath1), exit=1)
        self.pkgsurf("-s {0} -r {1}".format(self.dpath1, tempdir), exit=1)

        # No packages
        self.pkgrepo("add-publisher -s {0} selachii".format(tempdir))
        self.pkgsurf("-s {0} -r {1}".format(tempdir, self.dpath1))
        self.assertTrue("No packages to reversion." in self.output)
        self.pkgsurf("-s {0} -r {1}".format(self.dpath1, tempdir))
        self.assertTrue("No packages to reversion." in self.output)
        shutil.rmtree(tempdir)

        # Now check if it actually works.
        self.pkgsurf("-s {0} -r {1}".format(self.dpath_tmp, self.dpath1))

        ref_repo = self.get_repo(self.dpath1)
        targ_repo = self.get_repo(self.dpath_tmp)
        exp_repo = self.get_repo(self.dpath3)
        for s in self.published_exp:
            f = fmri.PkgFmri(s, None)
            targ = targ_repo.manifest(f)

            # Load target manifest
            targm = manifest.Manifest()
            targm.set_content(pathname=targ)

            # Load expected manifest
            exp = exp_repo.manifest(f)
            expm = manifest.Manifest()
            expm.set_content(pathname=exp)

            ta, ra, ca = manifest.Manifest.comm([targm, expm])
            self.debug("{0}: {1:d} {2:d}".format(str(s), len(ta), len(ra)))

            self.assertEqual(
                0, len(ta), "{0} had unexpected actions:"
                " \n{1}".format(s, "\n".join([str(x) for x in ta])))
            self.assertEqual(
                0, len(ra), "{0} had missing actions: "
                "\n{1}".format(s, "\n".join([str(x) for x in ra])))

        # Check that pkgsurf informed the user that there is a newer
        # version of a pkg in the ref repo.
        self.assertTrue("Packages with successors" in self.output)

        # Check that ignore option works.
        # Just run again and see if goblin pkg now gets reversioned.
        self.pkgsurf("-s {0} -r {1} -i info.home".format(
            self.dpath_tmp, self.dpath1))

        # Find goblin package
        for s in self.published_ref:
            if "goblin" in s:
                break
        f = fmri.PkgFmri(s, None)
        targ = targ_repo.manifest(f)
        ref = ref_repo.manifest(f)
        self.assertEqual(
            misc.get_data_digest(targ, hash_func=digest.DEFAULT_HASH_FUNC),
            misc.get_data_digest(ref, hash_func=digest.DEFAULT_HASH_FUNC))

        # Check that running the tool again doesn't find any pkgs
        # to reversion. Use http for accessing reference repo this time.
        self.pkgsurf("-s {0} -r {1}".format(self.dpath_tmp, self.durl1))
        self.assertTrue("No packages to reversion." in self.output)
Example #22
0
class CatalogInterface(_Interface):
        """This class presents an interface to server catalog objects that
        clients may use.
        """

        # Constants used to reference specific values that info can return.
        INFO_FOUND = 0
        INFO_MISSING = 1
        INFO_ILLEGALS = 3

        def fmris(self):
                """A generator function that produces FMRIs as it iterates
                over the contents of the server's catalog."""
                try:
                        c = self._depot.repo.catalog
                except srepo.RepositoryMirrorError:
                        return iter(())
                return self._depot.repo.catalog.fmris()

        def get_entry_all_variants(self, pfmri):
                """A generator function that yields tuples of the format
                (var_name, variants); where var_name is the name of the
                variant and variants is a list of the variants for that
                name."""
                try:
                        c = self._depot.repo.catalog
                except srepo.RepositoryMirrorError:
                        return iter(((), {}))
                return self._depot.repo.catalog.get_entry_all_variants(pfmri)

        def get_matching_pattern_fmris(self, patterns):
                """Returns a tuple of a sorted list of PkgFmri objects, newest
                versions first, for packages matching those found in the
                'patterns' list, and a dict of unmatched patterns indexed by
                match criteria.
                """
                try:
                        c = self._depot.repo.catalog
                except srepo.RepositoryMirrorError:
                        return tuple(), {}
                return pkg.catalog.extract_matching_fmris(c.fmris(),
                    patterns=patterns)

        def get_matching_version_fmris(self, versions):
                """Returns a tuple of a sorted list of PkgFmri objects, newest
                versions first, for packages matching those found in the
                'versions' list, and a dict of unmatched versions indexed by
                match criteria.

                'versions' should be a list of strings of the format:
                    release,build_release-branch:datetime

                ...with a value of '*' provided for any component to be ignored.
                '*' or '?' may be used within each component value and will act
                as wildcard characters ('*' for one or more characters, '?' for
                a single character).
                """
                try:
                        c = self._depot.repo.catalog
                except srepo.RepositoryMirrorError:
                        return tuple(), {}
                return pkg.catalog.extract_matching_fmris(c.fmris(),
                    versions=versions)

        def info(self, fmri_strings, info_needed, excludes=misc.EmptyI):
                """Gathers information about fmris.  fmri_strings is a list
                of fmri_names for which information is desired. It
                returns a dictionary of lists.  The keys for the dictionary are
                the constants specified in the class definition.  The values are
                lists of PackageInfo objects or strings."""

                bad_opts = info_needed - PackageInfo.ALL_OPTIONS
                if bad_opts:
                        raise api_errors.UnrecognizedOptionsToInfo(bad_opts)

                fmris = []
                notfound = []
                illegals = []

                for pattern in fmri_strings:
                        try:
                                pfmri = None
                                pfmri = self.get_matching_pattern_fmris(pattern)
                        except pkg.fmri.IllegalFmri, e:
                                illegals.append(pattern)
                                continue
                        else:
                                fmris.extend(pfmri[0])
                                if not pfmri:
                                        notfound.append(pattern)

                repo_cat = self._depot.repo.catalog
                
                # Set of options that can use catalog data.
                cat_opts = frozenset([PackageInfo.SUMMARY,
                    PackageInfo.CATEGORIES, PackageInfo.DESCRIPTION,
                    PackageInfo.DEPENDENCIES])

                # Set of options that require manifest retrieval.
                act_opts = PackageInfo.ACTION_OPTIONS - \
                    frozenset([PackageInfo.DEPENDENCIES])

                pis = []
                for f in fmris:
                        pub = name = version = release = None
                        build_release = branch = packaging_date = None
                        if PackageInfo.IDENTITY in info_needed:
                                pub, name, version = f.tuple()
                                pub = pkg.fmri.strip_pub_pfx(pub)
                                release = version.release
                                build_release = version.build_release
                                branch = version.branch
                                packaging_date = \
                                    version.get_timestamp().strftime("%c")

                        states = None

                        links = hardlinks = files = dirs = dependencies = None
                        summary = size = licenses = cat_info = description = \
                            None

                        if cat_opts & info_needed:
                                summary, description, cat_info, dependencies = \
                                    _get_pkg_cat_data(repo_cat, info_needed,
                                        excludes=excludes, pfmri=f)
                                if cat_info is not None:
                                        cat_info = [
                                            PackageCategory(scheme, cat)
                                            for scheme, cat in cat_info
                                        ]

                        if (frozenset([PackageInfo.SIZE,
                            PackageInfo.LICENSES]) | act_opts) & info_needed:
                                mfst = manifest.Manifest()
                                mfst.set_fmri(None, f)
                                try:
                                        mpath = os.path.join(
                                            self._depot.repo.manifest_root,
                                            f.get_dir_path())
                                except pkg.fmri.FmriError, e:
                                        notfound.append(f)
                                        continue

                                if not os.path.exists(mpath):
                                        notfound.append(f)
                                        continue

                                mfst.set_content(file(mpath).read())
                                
                                if PackageInfo.LICENSES in info_needed:
                                        licenses = self.__licenses(mfst)

                                if PackageInfo.SIZE in info_needed:
                                        size = mfst.get_size(excludes=excludes)

                                if act_opts & info_needed:
                                        if PackageInfo.LINKS in info_needed:
                                                links = list(
                                                    mfst.gen_key_attribute_value_by_type(
                                                    "link", excludes))
                                        if PackageInfo.HARDLINKS in info_needed:
                                                hardlinks = list(
                                                    mfst.gen_key_attribute_value_by_type(
                                                    "hardlink", excludes))
                                        if PackageInfo.FILES in info_needed:
                                                files = list(
                                                    mfst.gen_key_attribute_value_by_type(
                                                    "file", excludes))
                                        if PackageInfo.DIRS in info_needed:
                                                dirs = list(
                                                    mfst.gen_key_attribute_value_by_type(
                                                    "dir", excludes))

                        pis.append(PackageInfo(pkg_stem=name, summary=summary,
                            category_info_list=cat_info, states=states,
                            publisher=pub, version=release,
                            build_release=build_release, branch=branch,
                            packaging_date=packaging_date, size=size,
                            pfmri=str(f), licenses=licenses, links=links,
                            hardlinks=hardlinks, files=files, dirs=dirs,
                            dependencies=dependencies, description=description))
Example #23
0
def main_func():
        global_settings.client_name = "pkgsign"

        try:
                opts, pargs = getopt.getopt(sys.argv[1:], "a:c:i:k:ns:D:",
                    ["help", "no-index", "no-catalog"])
        except getopt.GetoptError as e:
                usage(_("illegal global option -- {0}").format(e.opt))

        show_usage = False
        sig_alg = "rsa-sha256"
        cert_path = None
        key_path = None
        chain_certs = []
        add_to_catalog = True
        set_alg = False
        dry_run = False

        repo_uri = os.getenv("PKG_REPO", None)
        for opt, arg in opts:
                if opt == "-a":
                        sig_alg = arg
                        set_alg = True
                elif opt == "-c":
                        cert_path = os.path.abspath(arg)
                        if not os.path.isfile(cert_path):
                                usage(_("{0} was expected to be a certificate "
                                    "but isn't a file.").format(cert_path))
                elif opt == "-i":
                        p = os.path.abspath(arg)
                        if not os.path.isfile(p):
                                usage(_("{0} was expected to be a certificate "
                                    "but isn't a file.").format(p))
                        chain_certs.append(p)
                elif opt == "-k":
                        key_path = os.path.abspath(arg)
                        if not os.path.isfile(key_path):
                                usage(_("{0} was expected to be a key file "
                                    "but isn't a file.").format(key_path))
                elif opt == "-n":
                        dry_run = True
                elif opt == "-s":
                        repo_uri = misc.parse_uri(arg)
                elif opt == "--help":
                        show_usage = True
                elif opt == "--no-catalog":
                        add_to_catalog = False
                elif opt == "-D":
                        try:
                                key, value = arg.split("=", 1)
                                DebugValues.set_value(key, value)
                        except (AttributeError, ValueError):
                                error(_("{opt} takes argument of form "
                                    "name=value, not {arg}").format(
                                    opt=opt, arg=arg))
        if show_usage:
                usage(retcode=EXIT_OK)

        if not repo_uri:
                usage(_("a repository must be provided"))

        if key_path and not cert_path:
                usage(_("If a key is given to sign with, its associated "
                    "certificate must be given."))

        if cert_path and not key_path:
                usage(_("If a certificate is given, its associated key must be "
                    "given."))

        if chain_certs and not cert_path:
                usage(_("Intermediate certificates are only valid if a key "
                    "and certificate are also provided."))

        if not pargs:
                usage(_("At least one fmri or pattern must be provided to "
                    "sign."))

        if not set_alg and not key_path:
                sig_alg = "sha256"

        s, h = actions.signature.SignatureAction.decompose_sig_alg(sig_alg)
        if h is None:
                usage(_("{0} is not a recognized signature algorithm.").format(
                    sig_alg))
        if s and not key_path:
                usage(_("Using {0} as the signature algorithm requires that a "
                    "key and certificate pair be presented using the -k and -c "
                    "options.").format(sig_alg))
        if not s and key_path:
                usage(_("The {0} hash algorithm does not use a key or "
                    "certificate.  Do not use the -k or -c options with this "
                    "algorithm.").format(sig_alg))

        if DebugValues:
                reload(digest)

        errors = []

        t = misc.config_temp_root()
        temp_root = tempfile.mkdtemp(dir=t)
        del t

        cache_dir = tempfile.mkdtemp(dir=temp_root)
        incoming_dir = tempfile.mkdtemp(dir=temp_root)
        chash_dir = tempfile.mkdtemp(dir=temp_root)
        cert_dir = tempfile.mkdtemp(dir=temp_root)

        try:
                chain_certs = [
                    __make_tmp_cert(cert_dir, c) for c in chain_certs
                ]
                if cert_path is not None:
                        cert_path = __make_tmp_cert(cert_dir, cert_path)

                xport, xport_cfg = transport.setup_transport()
                xport_cfg.add_cache(cache_dir, readonly=False)
                xport_cfg.incoming_root = incoming_dir

                # Configure publisher(s)
                transport.setup_publisher(repo_uri, "source", xport,
                    xport_cfg, remote_prefix=True)
                pats = pargs
                successful_publish = False

                concrete_fmris = []
                unmatched_pats = set(pats)
                all_pats = frozenset(pats)
                get_all_pubs = False
                pub_prefs = set()
                # Gather the publishers whose catalogs will be needed.
                for pat in pats:
                        try:
                                p_obj = fmri.MatchingPkgFmri(pat)
                        except fmri.IllegalMatchingFmri as e:
                                errors.append(e)
                                continue
                        pub_prefix = p_obj.get_publisher()
                        if pub_prefix:
                                pub_prefs.add(pub_prefix)
                        else:
                                get_all_pubs = True
                # Check each publisher for matches to our patterns.
                for p in xport_cfg.gen_publishers():
                        if not get_all_pubs and p.prefix not in pub_prefs:
                                continue
                        cat = fetch_catalog(p, xport, temp_root)
                        ms, tmp1, u = cat.get_matching_fmris(pats)
                        # Find which patterns matched.
                        matched_pats = all_pats - u
                        # Remove those patterns from the unmatched set.
                        unmatched_pats -= matched_pats
                        for v_list in ms.values():
                                concrete_fmris.extend([(v, p) for v in v_list])
                if unmatched_pats:
                        raise api_errors.PackageMatchErrors(
                            unmatched_fmris=unmatched_pats)

                for pfmri, src_pub in sorted(set(concrete_fmris)):
                        try:
                                # Get the existing manifest for the package to
                                # be signed.
                                m_str = xport.get_manifest(pfmri,
                                    content_only=True, pub=src_pub)
                                m = manifest.Manifest()
                                m.set_content(content=m_str)

                                # Construct the base signature action.
                                attrs = { "algorithm": sig_alg }
                                a = actions.signature.SignatureAction(cert_path,
                                    **attrs)
                                a.hash = cert_path

                                # Add the action to the manifest to be signed
                                # since the action signs itself.
                                m.add_action(a, misc.EmptyI)

                                # Set the signature value and certificate
                                # information for the signature action.
                                a.set_signature(m.gen_actions(),
                                    key_path=key_path, chain_paths=chain_certs,
                                    chash_dir=chash_dir)

                                # The hash of 'a' is currently a path, we need
                                # to find the hash of that file to allow
                                # comparison to existing signatures.
                                hsh = None
                                if cert_path:
                                        # Action identity still uses the 'hash'
                                        # member of the action, so we need to
                                        # stay with the sha1 hash.
                                        hsh, _dummy = \
                                            misc.get_data_digest(cert_path,
                                            hash_func=hashlib.sha1)

                                # Check whether the signature about to be added
                                # is identical, or almost identical, to existing
                                # signatures on the package.  Because 'a' has
                                # already been added to the manifest, it is
                                # generated by gen_actions_by_type, so the cnt
                                # must be 2 or higher to be an issue.
                                cnt = 0
                                almost_identical = False
                                for a2 in m.gen_actions_by_type("signature"):
                                        try:
                                                if a.identical(a2, hsh):
                                                        cnt += 1
                                        except api_errors.AlmostIdentical as e:
                                                e.pkg = pfmri
                                                errors.append(e)
                                                almost_identical = True
                                if almost_identical:
                                        continue
                                if cnt == 2:
                                        continue
                                elif cnt > 2:
                                        raise api_errors.DuplicateSignaturesAlreadyExist(pfmri)
                                assert cnt == 1, "Cnt was:{0}".format(cnt)

                                if not dry_run:
                                        # Append the finished signature action
                                        # to the published manifest.
                                        t = trans.Transaction(repo_uri,
                                            pkg_name=str(pfmri), xport=xport,
                                            pub=src_pub)
                                        try:
                                                t.append()
                                                t.add(a)
                                                for c in chain_certs:
                                                        t.add_file(c)
                                                t.close(add_to_catalog=
                                                    add_to_catalog)
                                        except:
                                                if t.trans_id:
                                                        t.close(abandon=True)
                                                raise
                                msg(_("Signed {0}").format(pfmri.get_fmri(
                                    include_build=False)))
                                successful_publish = True
                        except (api_errors.ApiException, fmri.FmriError,
                            trans.TransactionError) as e:
                                errors.append(e)
                if errors:
                        error("\n".join([str(e) for e in errors]))
                        if successful_publish:
                                return EXIT_PARTIAL
                        else:
                                return EXIT_OOPS
                return EXIT_OK
        except api_errors.ApiException as e:
                error(e)
                return EXIT_OOPS
        finally:
                shutil.rmtree(temp_root)
Example #24
0
    def __do_alter_verify(self,
                          pfmri,
                          verbose=False,
                          quiet=False,
                          exit=0,
                          parsable=False):
        # Alter the owner, group, mode, and timestamp of all files (and
        # directories) to something different than the package declares.
        m = manifest.Manifest()
        m.set_content(self.get_img_manifest(pfmri))
        ctime = time.time() - 1000
        for a in m.gen_actions():
            if a.name not in ("file", "dir"):
                # Only want file or dir actions.
                continue

            ubin = portable.get_user_by_name("bin", None, False)
            groot = portable.get_group_by_name("root", None, False)

            fname = a.attrs["path"]
            fpath = os.path.join(self.get_img_path(), fname)
            os.chown(fpath, ubin, groot)
            os.chmod(fpath, misc.PKG_RO_FILE_MODE)
            os.utime(fpath, (ctime, ctime))

        # Call pkg fix to fix them.
        fix_cmd = "fix"
        if verbose:
            fix_cmd += " -v"
        if quiet:
            fix_cmd += " -q"
        if parsable:
            fix_cmd += " --parsable=0"

        self.pkg("{0} {1}".format(fix_cmd, pfmri), exit=exit)
        if exit != 0:
            return exit

        editables = []
        # Now verify that fix actually fixed them.
        for a in m.gen_actions():
            if a.name not in ("file", "dir"):
                # Only want file or dir actions.
                continue

            # Validate standard attributes.
            self.validate_fsobj_attrs(a)

            # Now validate attributes that require special handling.
            fname = a.attrs["path"]
            fpath = os.path.join(self.get_img_path(), fname)
            lstat = os.lstat(fpath)

            # Verify that preserved files don't get renamed, and
            # the new ones are not installed if the file wasn't
            # missing already.
            preserve = a.attrs.get("preserve")
            if preserve == "renamenew":
                self.assert_(not os.path.exists(fpath + ".new"))
            elif preserve == "renameold":
                self.assert_(not os.path.exists(fpath + ".old"))

            if preserve:
                editables.append("{0}".format(a.attrs["path"]))

            # Verify timestamp (if applicable).
            ts = a.attrs.get("timestamp")
            if ts:
                expected = misc.timestamp_to_time(ts)
                actual = lstat.st_mtime
                if preserve:
                    self.assertNotEqual(
                        expected, actual, "timestamp expected {expected} == "
                        "actual {actual} for "
                        "{fname}".format(expected=expected,
                                         actual=actual,
                                         fname=fname))
                else:
                    self.assertEqual(
                        expected, actual, "timestamp expected {expected} != "
                        "actual {actual} for "
                        "{fname}".format(expected=expected,
                                         actual=actual,
                                         fname=fname))

        # Verify the parsable output (if applicable).
        if parsable:
            if editables:
                self.assertEqualParsable(
                    self.output,
                    affect_packages=["{0}".format(pfmri)],
                    change_editables=[["updated", editables]])
            else:
                self.assertEqualParsable(self.output,
                                         affect_packages=["{0}".format(pfmri)])
Example #25
0
    def addmanifest(self, root, mfile, arch, modechecks, exceptions):
        """Treats the specified input file as a pkg(7) package
        manifest, and extends the ManifestTree dictionary with entries
        for the actions therein.
        """
        mfest = manifest.Manifest()
        try:
            mfest.set_content(open(os.path.join(root, mfile)).read())
        except IOError as exc:
            raise IOError("cannot read manifest: %s" % str(exc))
        except actions.ActionError as exc:
            raise ManifestParsingError(mfile, str(exc))

        #
        # Make sure the manifest is applicable to the user-specified
        # architecture.  Assumption: if variant.arch is not an
        # attribute of the manifest, then the package should be
        # installed on all architectures.
        #
        if arch not in mfest.attributes.get("variant.arch", (arch, )):
            return

        modewarnings = set()
        for action in mfest.gen_actions():
            if "path" not in action.attrs or \
                not ActionInfo.supported(action.name):
                continue

            #
            # The dir action is currently fully specified, in that it
            # lists owner, group, and mode attributes.  If that
            # changes in pkg(7) code, we'll need to revisit either this
            # code or the ActionInfo() constructor.  It's possible
            # that the pkg(7) system could be extended to provide a
            # mechanism for specifying directory permissions outside
            # of the individual manifests that deliver files into
            # those directories.  Doing so at time of manifest
            # processing would mean that validate_pkg continues to work,
            # but doing so at time of publication would require updates.
            #

            #
            # See pkgsend(1) for the use of NOHASH for objects with
            # datastreams.  Currently, that means "files," but this
            # should work for any other such actions.
            #
            if getattr(action, "hash", "NOHASH") != "NOHASH":
                path = action.hash
            else:
                path = action.attrs["path"]

            #
            # This is the wrong tool in which to enforce consistency
            # on a set of manifests.  So instead of comparing the
            # different actions with the same "path" attribute, we
            # use the first one.
            #
            if path in self:
                continue

            #
            # As with the manifest itself, if an action has specified
            # variant.arch, we look for the target architecture
            # therein.
            #
            var = None

            #
            # The name of this method changed in pkg(7) build 150, we need to
            # work with both sets.
            #
            if hasattr(action, 'get_variants'):
                var = action.get_variants()
            else:
                var = action.get_variant_template()
            if "variant.arch" in var and arch not in var["variant.arch"]:
                return

            self[path] = ActionInfo(action)
            if modechecks is not None and path not in exceptions:
                modewarnings.update(self[path].checkmodes(modechecks))

        if len(modewarnings) > 0:
            print("warning: unsafe permissions in %s" % mfile)
            for w in sorted(modewarnings):
                print(w)
            print("")
Example #26
0
def merge_fmris(server_list, fmri_list, variant_list, variant, basedir,
                basename, get_files):

    manifest_list = [
        get_manifest(s, f) for s, f in zip(server_list, fmri_list)
    ]

    # remove variant tags and package variant metadata
    # from manifests since we're reassigning...
    # this allows merging pre-tagged packages
    for m in manifest_list:
        for i, a in enumerate(m.actions[:]):
            if variant in a.attrs:
                del a.attrs[variant]
            if a.name == "set" and a.attrs["name"] == variant:
                del m.actions[i]

    action_lists = manifest.Manifest.comm(*tuple(manifest_list))

    # set fmri actions require special merge logic.
    set_fmris = []
    for l in action_lists:
        for i, a in enumerate(l):
            if not (a.name == "set" and a.attrs["name"] == "pkg.fmri"):
                continue

            set_fmris.append(a)
            del l[i]

    # If set fmris are present, then only the most recent one
    # and add it back to the last action list.
    if set_fmris:

        def order(a, b):
            f1 = pkg.fmri.PkgFmri(a.attrs["value"], "5.11")
            f2 = pkg.fmri.PkgFmri(b.attrs["value"], "5.11")
            return cmp(f1, f2)

        set_fmris.sort(cmp=order)
        action_lists[-1].insert(0, set_fmris[-1])

    for a_list, v in zip(action_lists[0:-1], variant_list):
        for a in a_list:
            a.attrs[variant] = v

    # combine actions into single list
    allactions = reduce(lambda a, b: a + b, action_lists)

    # figure out which variants are actually there for this pkg
    actual_variant_list = [
        v for m, v in zip(manifest_list, variant_list) if m != null_manifest
    ]
    print "Merging %s for %s" % (basename, actual_variant_list)

    # add set action to document which variants are supported
    allactions.append(
        actions.fromstr(
            "set name=%s %s" %
            (variant, " ".join(["value=%s" % a
                                for a in actual_variant_list]))))

    allactions.sort()

    m = manifest.Manifest()
    m.set_content(content=allactions)

    # urlquote to avoid problems w/ fmris w/ '/' character in name
    basedir = os.path.join(basedir, urllib.quote(basename, ""))
    if not os.path.exists(basedir):
        os.makedirs(basedir)

    m_path = os.path.join(basedir, "manifest")
    m.store(m_path)

    for f in fmri_list:
        if f:
            fmri = str(f).rsplit(":", 1)[0]
            break
    f_file = file(os.path.join(basedir, "fmri"), "w")
    f_file.write(fmri)
    f_file.close()

    if get_files:
        # generate list of hashes for each server; last is commom
        already_seen = {}

        def repeated(a, d):
            if a in d:
                return True
            d[a] = 1
            return False

        action_sets = [
                set(
                        [
                         a
                         for a in action_list
                         if hasattr(a, "hash") and not \
                         repeated(a.hash, already_seen)
                        ]
                        )
                for action_list in action_lists
                ]
        # remove duplicate files (save time)

        for server, action_set in zip(server_list + [server_list[0]],
                                      action_sets):
            if len(action_set) > 0:
                fetch_files_byaction(server, action_set, basedir)

    return 0
Example #27
0
    def test_info(self):
        """Testing information showed in /info/0."""

        depot_url = self.dc.get_depot_url()
        plist = self.pkgsend_bulk(depot_url, self.info20)

        openurl = urlparse.urljoin(depot_url, "info/0/{0}".format(plist[0]))
        content = urllib2.urlopen(openurl).read()
        # Get text from content.
        lines = content.splitlines()
        info_dic = {}
        attr_list = [
            'Name', 'Summary', 'Publisher', 'Version', 'Build Release',
            'Branch', 'Packaging Date', 'Size', 'Compressed Size', 'FMRI'
        ]

        for line in lines:
            fields = line.split(":", 1)
            attr = fields[0].strip()
            if attr == "License":
                break
            if attr in attr_list:
                if len(fields) == 2:
                    info_dic[attr] = fields[1].strip()
                else:
                    info_dic[attr] = ""

        # Read manifest.
        openurl = urlparse.urljoin(depot_url,
                                   "manifest/0/{0}".format(plist[0]))
        content = urllib2.urlopen(openurl).read()
        manifest = man.Manifest()
        manifest.set_content(content=content)
        fmri_content = manifest.get("pkg.fmri", "")

        # Check if FMRI is empty.
        self.assert_(fmri_content)
        pfmri = fmri.PkgFmri(fmri_content, None)
        pub, name, ver = pfmri.tuple()
        size, csize = manifest.get_size()

        # Human version.
        version = info_dic['Version']
        hum_ver = ""
        if '(' in version:
            start = version.find('(')
            end = version.rfind(')')
            hum_ver = version[start + 1:end - len(version)]
            version = version[:start - len(version)]
            info_dic['Version'] = version.strip()

        # Compare each attribute.
        self.assertEqual(
            info_dic["Summary"],
            manifest.get("pkg.summary", manifest.get("description", "")))
        self.assertEqual(info_dic["Version"], str(ver.release))
        self.assertEqual(hum_ver, manifest.get("pkg.human-version", ""))
        self.assertEqual(info_dic["Name"], name)
        self.assertEqual(info_dic["Publisher"], pub)
        self.assertEqual(info_dic["Build Release"], str(ver.build_release))
        timestamp = datetime.datetime.strptime(info_dic["Packaging Date"],
                                               "%a %b %d %H:%M:%S %Y")
        self.assertEqual(timestamp, ver.get_timestamp())
        self.assertEqual(info_dic["Size"], misc.bytes_to_str(size))
        self.assertEqual(info_dic["Compressed Size"], misc.bytes_to_str(csize))
        self.assertEqual(info_dic["FMRI"], fmri_content)