[pacman-dev] [PATCH 4/5] Add mtree code to test framework and basic unit tests for -Qkk.

Allan McRae allan at archlinux.org
Mon Dec 30 03:22:06 EST 2013


On 11/11/13 21:47, Jeremy Heiner wrote:
> The framework will now generate mtree data when the pmpkg.makemtree is
> set to True, but only for "local" packages. Since the mtree data is
> only used by -Qkk, and this change is sufficient to test that
> function, there seems to be no reason to generate mtree data for other
> packages. If that becomes a requirement in the future there are
> comments in the code that sketch out an implemention for that.
> 
> The two new unit tests are similar to the previous -Qkk tests (005 is
> like 002, and 006 is like 004), but with mtree data. So the filesystem
> is actually validated against the mtree (instead of merely checking for
> the warning about a lacking mtree).
> 
> Signed-off-by: Jeremy Heiner <ScalaProtractor at gmail.com>
> ---
>  test/pacman/pmdb.py                |  3 ++
>  test/pacman/pmpkg.py               | 18 ++++++++++++
>  test/pacman/tests/TESTS            |  2 ++
>  test/pacman/tests/querycheck005.py | 16 +++++++++++
>  test/pacman/tests/querycheck006.py | 20 +++++++++++++
>  test/pacman/util.py                | 57 ++++++++++++++++++++++++++++++++++++++
>  6 files changed, 116 insertions(+)
>  create mode 100644 test/pacman/tests/querycheck005.py
>  create mode 100644 test/pacman/tests/querycheck006.py
> 
> diff --git a/test/pacman/pmdb.py b/test/pacman/pmdb.py
> index 53de91e..088e284 100644
> --- a/test/pacman/pmdb.py
> +++ b/test/pacman/pmdb.py
> @@ -224,6 +224,9 @@ def db_write(self, pkg):
>              make_section(data, "BACKUP", pkg.local_backup_entries())
>              entry["files"] = "\n".join(data)
>  
> +            if pkg.mtreedata:
> +                entry["mtree"] = pkg.mtreedata
> +
>              if any(pkg.install.values()):
>                  entry["install"] = pkg.installfile()
>  
> diff --git a/test/pacman/pmpkg.py b/test/pacman/pmpkg.py
> index db97449..25e841a 100644
> --- a/test/pacman/pmpkg.py
> +++ b/test/pacman/pmpkg.py
> @@ -60,6 +60,8 @@ def __init__(self, name, version = "1.0-1"):
>          # files
>          self.files = []
>          self.backup = []
> +        self.makemtree = False # True => finalize generates mtreedata
> +        self.mtreedata = "" # you can set this, but makemtree is easier
>          # install
>          self.install = {
>              "pre_install": "",
> @@ -145,6 +147,19 @@ def makepkg(self, path):
>          if any(self.install.values()):
>              archive_files.append((".INSTALL", self.installfile()))
>  
> +        # .MTREE
> +        if self.mtreedata:
> +            raise NotImplementedError("attempt to put mtree into tar")
> +            # TODO: they work great in local dbs, but not in tar'd pkgs.
> +            # it seems unlikely that any test will ever need to, but:
> +            # easiest solution seems to be to hack the 'Generate package
> +            # file system' loop just below to copy the attributes from
> +            # the mtreedata over to the TarInfo fields. pulling the data
> +            # out with re.search shouldn't be too hard. put that code
> +            # over in util so it gets updated with the other mtree code.
> +            # then remove the raise and uncomment the following line:
> +            # archive_files.append((".MTREE", self.mtreedata))
> +
>          self.path = os.path.join(path, self.filename())
>          util.mkdir(os.path.dirname(self.path))
>  
> @@ -226,6 +241,9 @@ def finalize(self):
>                  name = os.path.dirname(name)
>          self.files.sort()
>  
> +        if self.makemtree:
> +            self.mtreedata = util.mtree(self.files)
> +
>          self.finalized = True
>  
>      def local_backup_entries(self):
> diff --git a/test/pacman/tests/TESTS b/test/pacman/tests/TESTS
> index f4e6caf..c460fe0 100644
> --- a/test/pacman/tests/TESTS
> +++ b/test/pacman/tests/TESTS
> @@ -92,6 +92,8 @@ TESTS += test/pacman/tests/querycheck001.py
>  TESTS += test/pacman/tests/querycheck002.py
>  TESTS += test/pacman/tests/querycheck003.py
>  TESTS += test/pacman/tests/querycheck004.py
> +TESTS += test/pacman/tests/querycheck005.py
> +TESTS += test/pacman/tests/querycheck006.py
>  TESTS += test/pacman/tests/reason001.py
>  TESTS += test/pacman/tests/remove001.py
>  TESTS += test/pacman/tests/remove002.py
> diff --git a/test/pacman/tests/querycheck005.py b/test/pacman/tests/querycheck005.py
> new file mode 100644
> index 0000000..95c776d
> --- /dev/null
> +++ b/test/pacman/tests/querycheck005.py
> @@ -0,0 +1,16 @@
> +self.description = "Query--check mtree, all there"
> +
> +pkg = pmpkg("dummy")
> +pkg.files = [
> +    "usr/lib/libdummy.so.0",
> +    "usr/lib/libdummy.so -> libdummy.so.0",
> +    "usr/share/dummy/C/",
> +    "usr/share/dummy/C/msgs",
> +    "usr/share/dummy/en -> C"]
> +pkg.makemtree = True
> +self.addpkg2db("local",pkg)
> +
> +self.args = "-Qkk"
> +
> +self.addrule("PACMAN_RETCODE=0")
> +self.addrule("!PACMAN_OUTPUT=dummy: no mtree file")
> diff --git a/test/pacman/tests/querycheck006.py b/test/pacman/tests/querycheck006.py
> new file mode 100644
> index 0000000..879fd00
> --- /dev/null
> +++ b/test/pacman/tests/querycheck006.py
> @@ -0,0 +1,20 @@
> +self.description = "Query--check mtree, missing"
> +
> +pkg = pmpkg("dummy")
> +pkg.files = [
> +    "usr/lib/libdummy.so.0",
> +    "usr/lib/libdummy.so -> libdummy.so.0",
> +    "usr/share/dummy/C/",
> +    "usr/share/dummy/C/msgs",
> +    "usr/share/dummy/en -> C"]
> +pkg.makemtree = True
> +pkg.install['post_install'] = "rm -r ../usr/share/dummy/*"
> +self.addpkg2db("local",pkg)
> +
> +self.args = "-Qkk"
> +
> +self.addrule("PACMAN_RETCODE=1")
> +self.addrule("PACMAN_OUTPUT=/usr/share/dummy/C .No such file")
> +self.addrule("PACMAN_OUTPUT=/usr/share/dummy/C/msgs .No such file")
> +self.addrule("PACMAN_OUTPUT=/usr/share/dummy/en .No such file")
> +self.addrule("PACMAN_OUTPUT=, 3 altered files")
> diff --git a/test/pacman/util.py b/test/pacman/util.py
> index beb7e3d..2158b80 100644
> --- a/test/pacman/util.py
> +++ b/test/pacman/util.py
> @@ -20,6 +20,8 @@
>  import os
>  import re
>  import hashlib
> +import subprocess
> +import sys
>  
>  import tap
>  
> @@ -93,6 +95,11 @@ def mkfile(base, name, data="", utime=False):
>  
>      if info["islink"]:
>          os.symlink(info["link"], path)
> +        if utime:
> +            if sys.hexversion < 0x03030000:
> +                subprocess.call(["touch","-ht","196912311905.55",path])
> +            else:
> +                os.utime(path, (355,355), follow_symlinks=False)
>      else:
>          writedata(path, data)
>          if utime:
> @@ -158,6 +165,56 @@ def mkmd5sum(data):
>  
>  
>  #
> +# mtree
> +# obviously not a full implementation of the spec (e.g. no
> +# quoting of paths), but just enough for a few tests.
> +# freebsd mtree(5) has a bit more detail than arch or openbsd.
> +# scripts/makepkg calls bsdtar to build mtrees at line 1890.

Comments referencing lines are awful because the line number will change.

Can we not just call bsdtar to generate these using the exact command
makepkg does?

> +#
> +
> +def mtree(files):
> +
> +    lines = ["#mtree"] # no version (ala bsdtar)
> +    for name in files:
> +        info = getfileinfo(name)
> +        filename = info["filename"]
> +
> +        if info["isdir"]:
> +            filename = filename.rstrip("/")
> +            mode = info["perms"] if info["hasperms"] else 0o755
> +            attrs = ("type=dir mode=%o"
> +                     % (mode))
> +
> +        elif info["islink"]:
> +            mode = info["perms"] if info["hasperms"] else 0o777
> +            attrs = ("type=link time=355.000000000"
> +                     " mode=%o link=%s"
> +                     % (mode, info["link"]))
> +
> +        else:
> +            mode = info["perms"] if info["hasperms"] else 0o644
> +            contents = name + "\n"
> +            md5 = hashlib.md5(contents).hexdigest()
> +            sha256 = hashlib.sha256(contents).hexdigest()
> +            attrs = ("type=file time=355.000000000"
> +                     " mode=%o size=%d md5digest=%s sha256digest=%s"
> +                     % (mode, len(contents), md5, sha256))
> +
> +        lines.append("./%s uid=0 gid=0 %s" % (filename, attrs))
> +                       
> +    mtree = "\n".join(lines)+"\n"
> +
> +    # scripts/makepkg compresses the mtree (via bsdtar using gzip).
> +    # python's gzip always opens a file (can't make it use StringIO).
> +    # gzip uses zlib, but if we zlib.compress(mtree) it causes libalpm
> +    # to reject the mtree with "Unrecognized archive format".
> +    # fortunately libalpm reads the uncompressed mtree files just fine,
> +    # so we don't have to jump through any hoops to get it compressed.
> +
> +    return mtree
> +
> +
> +#
>  # Miscellaneous
>  #
>  
> 



More information about the pacman-dev mailing list