[reprotest] 04/04: Add "auto" presets and --testbed-init

Ximin Luo infinity0 at debian.org
Fri Nov 18 19:02:20 UTC 2016


This is an automated email from the git hooks/post-receive script.

infinity0 pushed a commit to branch master
in repository reprotest.

commit 6b29511c8d43ba08742e5d269cf52e145f553b77
Author: Ximin Luo <infinity0 at debian.org>
Date:   Fri Nov 18 20:01:58 2016 +0100

    Add "auto" presets and --testbed-init
    
    * Add a --testbed-init option to allow the user to install dependencies that
      are needed to make the variations in the first place.
    * Add an "auto" feature to the CLI, plus a presets module so it's easier to
      use, and other non-Debian systems can start populating this too.
---
 README.md             | 78 ++++++++++++++++++++++++++++-------------
 debian/changelog      |  4 +++
 reprotest/__init__.py | 26 +++++++++++---
 reprotest/presets.py  | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 176 insertions(+), 29 deletions(-)

diff --git a/README.md b/README.md
index f80b5f6..b165450 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,27 @@
 Command Line Interface
 ======================
 
-reprotest's CLI takes two mandatory arguments, the build command to
-run and the build artifact file/pattern to test after running the
-build. Here are some sample invocations for running reprotest on
-itself:
+The easiest way to run reprotest is via our presets:
+
+    # Build the current directory in a null server (/tmp)
+    reprotest auto . -- null -d
+
+    # Build the given Debian source package in an schroot
+    # See https://wiki.debian.org/sbuild for instructions on setting that up.
+    reprotest auto reprotest_0.3.3.dsc -- schroot unstable-amd64-sbuild
+
+Currently, we only support this for Debian packages, but are keen on adding
+more. If we don't have knowledge on how to build your file or directory, you
+can send a patch to us on adding this intelligence - see the reprotest.presets
+python module, and adapt the existing logic.
+
+Before that happens, you can use the more advanced CLI to build arbitrary
+things. This takes two mandatory arguments, the build command to run and the
+build artifact file/pattern to test after running the build. For example:
 
     reprotest 'python3 setup.py bdist' 'dist/*.tar.gz'
-    reprotest 'debuild -b -uc -us' '../*.deb' -- null -d
 
-When using reprotest from a shell:
+When using this from a shell:
 
 If the build command has spaces, you will need to quote them, e.g.
 `reprotest "debuild -b -uc -us" [..]`.
@@ -22,7 +34,10 @@ quote these twice, e.g. `'"a file with spaces.gz"'` for a single
 artifact or `'"dir 1"/* "dir 2"/*'` for multiple patterns.
 
 To get more help for the CLI, including documentation on optional
-arguments and what they do, run `reprotest --help`.
+arguments and what they do, run:
+
+    reprotest --help
+    reprotest --help schroot
 
 
 Running in a virtual server
@@ -38,24 +53,37 @@ full list. You run them like this:
 You can also run `reprotest --help <virtual_server_name>` for a full list of
 options for that particular virtual server.
 
-Unfortunately we currently don't set up build dependencies inside the virtual
-server so you will have to either do that yourself before running reprotest,
-or by giving the set-up command to reprotest manually. For example:
-
-    reprotest --dont-vary=fileordering,kernel \
-        'PATH=/sbin:/usr/sbin:$PATH apt-get install --no-install-recommends -y devscripts equivs;\
-         PATH=/sbin:/usr/sbin:$PATH mk-build-deps -t "apt-get --no-install-recommends -y" -ir;\
-         debuild -b -uc -us' '../*.deb' \
-         schroot unstable-amd64-sbuild
-
-TODO: fix this, e.g. by copying what sbuild does / running sbuild. In
-particular, the above example command installs devscripts and other unnecessary
-dependencies which might pollute the build, so it is not the ideal method.
-
-TODO: also the command is run *after* setting up the variations, which is why
-we need to disable the fileordering/kernel variations above - they use
-disorderfs and /usr/bin/linux64 (from util-linux) which aren't available even
-if we add "apt-get install disorderfs util-linux" into the build command.
+You will probably have to give extra commands to reprotest, in order to set up
+your build dependencies inside the virtual server. For example, to take you
+through what the "Debian directory" preset would look like, if we ran it via
+the advanced CLI:
+
+    reprotest auto . -- schroot unstable-amd64-sbuild
+    # equivalent to:
+    reprotest \
+        --testbed-init 'apt-get -y --no-install-recommends install \
+                        util-linux disorderfs 2>/dev/null; \
+                        test -c /dev/fuse || mknod -m 666 /dev/fuse c 10 229' \
+        'PATH=/sbin:/usr/sbin:$PATH apt-get -y --no-install-recommends build-dep ./; \
+         dpkg-buildpackage -uc -us -b' \
+        '../*.deb' \
+        -- \
+        schroot unstable-amd64-sbuild
+
+The `--testbed-init` argument is needed to set up basic tools, which reprotest
+needs in order to make the variations in the first place. This should be the
+same regardless of what package is being built, but might differ depending on
+what virtual_server is being used.
+
+Next, we have the build_command. For our Debian directory, we install
+build-dependencies using apt-get, then we run the actual build command itself
+using dpkg-buildpackage(1).
+
+Then, we have the artifact pattern. For reproducibility, we're only interested
+in the binary packages.
+
+Finally, we specify that this is to take place in the "schroot" virtual_server
+with arguments "unstable-amd64-sbuild".
 
 
 Config File
diff --git a/debian/changelog b/debian/changelog
index a09218c..d8a6f1f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -3,6 +3,10 @@ reprotest (0.3.3) UNRELEASED; urgency=medium
   * Document virtual servers and caveats better.
   * Add a --help [virtual server] option.
   * Add a --no-diffoscope option. (Closes: #844512)
+  * Add a --testbed-init option to allow the user to install dependencies that
+    are needed to make the variations in the first place.
+  * Add an "auto" feature to the CLI, plus a presets module so it's easier to
+    use, and other non-Debian systems can start populating this too.
 
  -- Ximin Luo <infinity0 at debian.org>  Fri, 18 Nov 2016 17:13:49 +0100
 
diff --git a/reprotest/__init__.py b/reprotest/__init__.py
index abb8841..4437a43 100644
--- a/reprotest/__init__.py
+++ b/reprotest/__init__.py
@@ -21,6 +21,7 @@ from reprotest.lib import adtlog
 from reprotest.lib import adt_testbed
 from reprotest import _contextlib
 from reprotest import _shell_ast
+from reprotest import presets
 
 
 adtlog.verbosity = 1
@@ -359,9 +360,6 @@ def check(build_command, artifact_pattern, virtual_server_args, source_root,
     with tempfile.TemporaryDirectory() as temp_dir, \
          start_testbed(virtual_server_args, temp_dir, no_clean_on_error) as testbed:
         script = Script(build_command)
-        if testbed_init:
-            script = script.append_setup(_shell_ast.SimpleCommand(
-                "sh", "-ec", _shell_ast.Quote(testbed_init)))
         script = Pair(script, script)
         env = Pair(types.MappingProxyType(os.environ.copy()),
                    types.MappingProxyType(os.environ.copy()))
@@ -378,13 +376,16 @@ def check(build_command, artifact_pattern, virtual_server_args, source_root,
             source_root = new_source_root
         testbed.command('copydown', (source_root + '/', tree.control))
         testbed.command('copydown', (source_root + '/', tree.experiment))
+        if testbed_init:
+            testbed.check_exec(["sh", "-ec", testbed_init])
         # print(source_root)
         try:
             with _contextlib.ExitStack() as stack:
                 for variation in variations:
                     # print('START')
                     # print(variation)
-                    script, env, tree = stack.enter_context(VARIATIONS[variation](script, env, tree, testbed))
+                    script, env, tree = stack.enter_context(
+                        VARIATIONS[variation](script, env, tree, testbed))
                     # print(script)
                     # print(env)
                     # print(tree)
@@ -456,6 +457,13 @@ COMMAND_LINE_OPTIONS = types.MappingProxyType(collections.OrderedDict([
         'default': None, 'metavar': 'COMMANDS',
         'help': 'Shell commands to run after starting the test bed, but before '
         'applying variations. Used to e.g. install disorderfs in a chroot.'})),
+    ('--auto-preset-expr', types.MappingProxyType({
+        'default': "_", 'metavar': 'PYTHON_EXPRESSION',
+        'help': 'This may be used to transform the presets returned by the '
+        'auto-detection feature. The value should be a python expression '
+        'that transforms the _ variable, which is a value of type '
+        'reprotest.presets.ReprotestPreset. See that class\'s documentation '
+        'for ways you can write this expression. Default: %(default)s'})),
     ('--diffoscope-arg', types.MappingProxyType({
         'default': [], 'action': 'append',
         'help': 'Give extra arguments to diffoscope when running it.'})),
@@ -592,6 +600,16 @@ def main():
     testbed_pre = command_line_options.get("testbed_pre")
     testbed_init = command_line_options.get("testbed_init")
 
+    if build_command == 'auto':
+        auto_preset_expr = command_line_options.get("auto_preset_expr")
+        values = presets.get_presets(artifact, virtual_server_args[0])
+        values = eval(auto_preset_expr, {'_':values}, {})
+        print(values)
+        build_command = values.build_command
+        artifact = values.artifact
+        testbed_pre = values.testbed_pre
+        testbed_init = values.testbed_init
+
     # print(build_command, artifact, virtual_server_args)
     sys.exit(check(build_command, artifact, virtual_server_args, source_root,
                    no_clean_on_error, variations, diffoscope_args,
diff --git a/reprotest/presets.py b/reprotest/presets.py
new file mode 100644
index 0000000..1cad6c3
--- /dev/null
+++ b/reprotest/presets.py
@@ -0,0 +1,97 @@
+# Licensed under the GPL: https://www.gnu.org/licenses/gpl-3.0.en.html
+# For details: reprotest/debian/copyright
+
+import collections
+import os
+
+
+class AttributeFunctor(collections.namedtuple('_AttributeFunctor', 'x f')):
+    def __getattr__(self, name):
+        return lambda *args: self.x._replace(**{
+            name: self.f(getattr(self.x, name), *args)
+        })
+
+
+class ReprotestPreset(collections.namedtuple('_ReprotestPreset',
+    'build_command artifact testbed_pre testbed_init')):
+    """Named-tuple representing a reprotest command preset.
+
+    You can manipulate it like this:
+
+    >>> ReprotestPreset(None, None, None, None)
+    ReprotestPreset(build_command=None, artifact=None, testbed_pre=None, testbed_init=None)
+
+    >>> _.set.build_command("etc")
+    ReprotestPreset(build_command='etc', artifact=None, testbed_pre=None, testbed_init=None)
+
+    >>> _.append.build_command("; etc2")
+    ReprotestPreset(build_command='etc; etc2', artifact=None, testbed_pre=None, testbed_init=None)
+
+    >>> _.prepend.build_command("setup; ")
+    ReprotestPreset(build_command='setup; etc; etc2', artifact=None, testbed_pre=None, testbed_init=None)
+
+    >>> _.set.build_command("dpkg-buildpackage -us -uc -b")
+    ReprotestPreset(build_command='dpkg-buildpackage -us -uc -b', artifact=None, testbed_pre=None, testbed_init=None)
+
+    >>> _.str_replace.build_command(
+    ...    "dpkg-buildpackage", "DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage -Pnocheck")
+    ReprotestPreset(build_command='DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage -Pnocheck -us -uc -b', artifact=None, testbed_pre=None, testbed_init=None)
+    """
+
+    @property
+    def set(self):
+        """Set the given attribute to the given value."""
+        return AttributeFunctor(self, lambda x, y: y)
+    @property
+    def str_replace(self):
+        """Do a substring-replace on the given attribute."""
+        return AttributeFunctor(self, str.replace)
+    @property
+    def prepend(self):
+        """Prepend the given value to the given attribute."""
+        return AttributeFunctor(self, lambda a, b: b + a)
+    @property
+    def append(self):
+        """Apppend the given value to the given attribute."""
+        return AttributeFunctor(self, lambda a, b: a + b)
+
+
+PRESET_DEB_DIR = ReprotestPreset(
+    build_command = 'dpkg-buildpackage -uc -us -b',
+    artifact = '../*.deb',
+    testbed_pre = None,
+    testbed_init = None
+)
+
+def preset_deb_schroot(preset):
+    return preset.prepend.build_command(
+        'PATH=/sbin:/usr/sbin:$PATH apt-get -y --no-install-recommends build-dep ./; '
+    ).set.testbed_init(
+        'apt-get -y --no-install-recommends install util-linux disorderfs 2>/dev/null; \
+        test -c /dev/fuse || mknod -m 666 /dev/fuse c 10 229'
+    )
+
+def preset_deb_dsc(fn):
+    return ReprotestPreset(
+        build_command = 'dpkg-source -x "%s" build && cd build && dpkg-buildpackage -uc -us -b' % fn,
+        artifact = '*.deb',
+        testbed_pre = None,
+        testbed_init = None
+    )
+
+def get_presets(buildfile, virtual_server):
+    fn = os.path.basename(buildfile)
+    parts = os.path.splitext(fn)
+    if os.path.isdir(buildfile):
+        if os.path.isdir(os.path.join(buildfile, "debian")):
+            if virtual_server == "null":
+                return PRESET_DEB_DIR
+            else:
+                return preset_deb_schroot(PRESET_DEB_DIR)
+    elif os.path.isfile(buildfile):
+        if parts[1] == '.dsc':
+            if virtual_server == "null":
+                return preset_deb_dsc(fn)
+            else:
+                return preset_deb_schroot(preset_deb_dsc(fn))
+    raise ValueError("unrecognised file type: %s" % buildfile)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/reproducible/reprotest.git



More information about the Reproducible-commits mailing list