support DEB_BUILD_PROFILES and -P for build profiles
authorDavid Kalnischkies <david@kalnischkies.de>
Tue, 25 Feb 2014 13:26:18 +0000 (14:26 +0100)
committerDavid Kalnischkies <david@kalnischkies.de>
Thu, 13 Mar 2014 12:58:44 +0000 (13:58 +0100)
Inspired by the rest of the patch in 661537, but abstract the
parsing of various ways of setting the build profiles more so it can
potentially be reused and all apt parts have the same behaviour.

Especially config options, cmdline options and environment will not be
combined as proposed as this isn't APTs usual behaviour and dpkg doesn't
do it either, so one overrides the other as it normally does.

apt-pkg/aptconfiguration.cc
apt-pkg/aptconfiguration.h
apt-pkg/deb/deblistparser.cc
apt-private/private-cmndline.cc
cmdline/apt-config.cc
cmdline/apt-get.cc
debian/control
doc/apt-get.8.xml
doc/apt.conf.5.xml
test/integration/framework
test/integration/test-bug-661537-build-profiles-support [new file with mode: 0755]

index f5c758e..3948854 100644 (file)
@@ -426,7 +426,7 @@ void Configuration::setDefaultConfigurationForCompressors() {
        }
 }
                                                                        /*}}}*/
-// getCompressors - Return Vector of usbale compressors                        /*{{{*/
+// getCompressors - Return Vector of usealbe compressors               /*{{{*/
 // ---------------------------------------------------------------------
 /* return a vector of compressors used by apt-ftparchive in the
    multicompress functionality or to detect data.tar files */
@@ -508,4 +508,28 @@ Configuration::Compressor::Compressor(char const *name, char const *extension,
                UncompressArgs.push_back(uncompressArg);
 }
                                                                        /*}}}*/
+// getBuildProfiles - return a vector of enabled build profiles                /*{{{*/
+std::vector<std::string> const Configuration::getBuildProfiles() {
+       // order is: override value (~= commandline), environment variable, list (~= config file)
+       std::string profiles_env = getenv("DEB_BUILD_PROFILES") == 0 ? "" : getenv("DEB_BUILD_PROFILES");
+       if (profiles_env.empty() == false) {
+               profiles_env = SubstVar(profiles_env, " ", ",");
+               std::string const bp = _config->Find("APT::Build-Profiles");
+               _config->Clear("APT::Build-Profiles");
+               if (bp.empty() == false)
+                       _config->Set("APT::Build-Profiles", bp);
+       }
+       return _config->FindVector("APT::Build-Profiles", profiles_env);
+}
+std::string const Configuration::getBuildProfilesString() {
+       std::vector<std::string> profiles = getBuildProfiles();
+       if (profiles.empty() == true)
+               return "";
+       std::vector<std::string>::const_iterator p = profiles.begin();
+       std::string list = *p;
+       for (; p != profiles.end(); ++p)
+          list.append(",").append(*p);
+       return list;
+}
+                                                                       /*}}}*/
 }
index bf7deae..026493c 100644 (file)
@@ -117,6 +117,11 @@ public:                                                                    /*{{{*/
 
        /** \brief Return a vector of extensions supported for data.tar's */
        std::vector<std::string> static const getCompressorExtensions();
+
+       /** \return Return a vector of enabled build profile specifications */
+       std::vector<std::string> static const getBuildProfiles();
+       /** \return Return a comma-separated list of enabled build profile specifications */
+       std::string static const getBuildProfilesString();
                                                                        /*}}}*/
        private:                                                        /*{{{*/
        void static setDefaultConfigurationForCompressors();
index a4795f1..89f3514 100644 (file)
@@ -625,7 +625,7 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop,
         if (unlikely(I == Stop))
            return 0;
 
-        std::vector<string> const profiles = _config->FindVector("APT::Build-Profiles");
+        std::vector<string> const profiles = APT::Configuration::getBuildProfiles();
 
         const char *End = I;
         bool Found = false;
index ef7d65f..b994432 100644 (file)
@@ -141,6 +141,7 @@ bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const * const
    {
       addArg('b', "compile", "APT::Get::Compile", 0);
       addArg('b', "build", "APT::Get::Compile", 0);
+      addArg('P', "build-profiles", "APT::Build-Profiles", CommandLine::HasArg);
       addArg(0, "diff-only", "APT::Get::Diff-Only", 0);
       addArg(0, "debian-only", "APT::Get::Diff-Only", 0);
       addArg(0, "tar-only", "APT::Get::Tar-Only", 0);
@@ -149,6 +150,7 @@ bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const * const
    else if (CmdMatches("build-dep"))
    {
       addArg('a', "host-architecture", "APT::Get::Host-Architecture", CommandLine::HasArg);
+      addArg('P', "build-profiles", "APT::Build-Profiles", CommandLine::HasArg);
       addArg(0, "purge", "APT::Get::Purge", 0);
       addArg(0, "solver", "APT::Solver", CommandLine::HasArg);
       // this has no effect *but* sbuild is using it (see LP: #1255806)
index 30c2a22..9f20b3c 100644 (file)
@@ -155,6 +155,11 @@ int main(int argc,const char *argv[])                                      /*{{{*/
         _config->Set(comp + "UncompressArg::", *a);
    }
 
+   std::vector<std::string> const profiles = APT::Configuration::getBuildProfiles();
+   _config->Clear("APT::Build-Profiles");
+   for (std::vector<std::string>::const_iterator p = profiles.begin(); p != profiles.end(); ++p)
+      _config->Set("APT::Build-Profiles::", *p);
+
    // Match the operation
    CmdL.DispatchArg(Cmds);
    
index 12e385b..f8de80a 100644 (file)
@@ -970,6 +970,12 @@ bool DoSource(CommandLine &CmdL)
            string buildopts = _config->Find("APT::Get::Host-Architecture");
            if (buildopts.empty() == false)
               buildopts = "-a" + buildopts + " ";
+
+           // get all active build profiles
+           std::string const profiles = APT::Configuration::getBuildProfilesString();
+           if (profiles.empty() == false)
+              buildopts.append(" -P").append(profiles).append(" ");
+
            buildopts.append(_config->Find("DPkg::Build-Options","-b -uc"));
 
            // Call dpkg-buildpackage
index 2d58d07..5ce6841 100644 (file)
@@ -21,7 +21,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${apt:keyring}, gnupg
 Replaces: manpages-pl (<< 20060617-3~), manpages-it (<< 2.80-4~)
 Breaks: manpages-pl (<< 20060617-3~), manpages-it (<< 2.80-4~)
 Conflicts: python-apt (<< 0.7.93.2~)
-Suggests: aptitude | synaptic | wajig, dpkg-dev, apt-doc, python-apt
+Suggests: aptitude | synaptic | wajig, dpkg-dev (>= 1.17.2), apt-doc, python-apt
 Description: commandline package manager
  This package provides commandline tools for searching and
  managing as well as querying information about packages
index 595ea87..1ed0890 100644 (file)
      by <command>apt-get source --compile</command> and how cross-builddependencies
      are satisfied. By default is it not set which means that the host architecture
      is the same as the build architecture (which is defined by <literal>APT::Architecture</literal>).
-     Configuration Item: <literal>APT::Get::Host-Architecture</literal>
+     Configuration Item: <literal>APT::Get::Host-Architecture</literal>.
+     </para></listitem>
+     </varlistentry>
+
+     <varlistentry><term><option>-P</option></term>
+                   <term><option>--build-profiles</option></term>
+     <listitem><para>This option controls the activated build profiles for which
+     a source package is built by <command>apt-get source --compile</command> and
+     how build dependencies are satisfied. By default no build profile is active.
+     More than one build profile can be activated at a time by concatenating them
+     with a comma.
+     Configuration Item: <literal>APT::Build-Profiles</literal>.
      </para></listitem>
      </varlistentry>
 
index bfc43ba..78f6a27 100644 (file)
@@ -177,6 +177,15 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";};
      </para></listitem>
      </varlistentry>
 
+     <varlistentry><term><option>Build-Profiles</option></term>
+     <listitem><para>
+     List of all build profiles enabled for build-dependency resolution,
+     without the "<literal>profile.</literal>" namespace prefix.
+     By default this list is empty. The <envar>DEB_BUILD_PROFILES</envar>
+     as used by &dpkg-buildpackage; overrides the list notation.
+     </para></listitem>
+     </varlistentry>
+
      <varlistentry><term><option>Default-Release</option></term>
      <listitem><para>Default release to install packages from if more than one
      version is available. Contains release name, codename or release version. Examples: 'stable', 'testing',
index 911a4d7..9c4ac87 100644 (file)
@@ -120,6 +120,9 @@ aptwebserver() {
 dpkg() {
        command dpkg --root=${TMPWORKINGDIRECTORY}/rootdir --force-not-root --force-bad-path --log=${TMPWORKINGDIRECTORY}/rootdir/var/log/dpkg.log "$@"
 }
+dpkgcheckbuilddeps() {
+       command dpkg-checkbuilddeps --admindir=${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg "$@"
+}
 aptitude() {
        if [ -f ./aptconfig.conf ]; then
                APT_CONFIG=aptconfig.conf LD_LIBRARY_PATH=${BUILDDIRECTORY}  command aptitude "$@"
@@ -240,6 +243,9 @@ setupenvironment() {
        # newer gpg versions are fine without it, but play it safe for now
        gpg --quiet --check-trustdb --secret-keyring $SECRETKEYRING --keyring $SECRETKEYRING >/dev/null 2>&1
 
+       # cleanup the environment a bit
+       unset GREP_OPTIONS DEB_BUILD_PROFILES
+
        msgdone "info"
 }
 
diff --git a/test/integration/test-bug-661537-build-profiles-support b/test/integration/test-bug-661537-build-profiles-support
new file mode 100755 (executable)
index 0000000..ae1403f
--- /dev/null
@@ -0,0 +1,147 @@
+#!/bin/sh
+set -e
+
+TESTDIR=$(readlink -f $(dirname $0))
+. $TESTDIR/framework
+setupenvironment
+configarchitecture 'amd64' 'i386' 'armel'
+
+insertinstalledpackage 'build-essential' 'all' '0' 'Multi-Arch: foreign'
+
+insertpackage 'unstable' 'foo' 'all' '1.0'
+insertpackage 'unstable' 'bar' 'all' '1.0'
+
+insertsource 'unstable' 'buildprofiles' 'any' '1' 'Build-Depends: foo (>= 1.0) [i386 arm] <!profile.stage1 !profile.cross>, bar'
+
+# table from https://wiki.debian.org/BuildProfileSpec
+insertsource 'unstable' 'spec-1' 'any' '1' 'Build-Depends: foo <!profile.stage1>'
+insertsource 'unstable' 'spec-2' 'any' '1' 'Build-Depends: foo <profile.stage1>'
+insertsource 'unstable' 'spec-3' 'any' '1' 'Build-Depends: foo <!profile.stage1 !profile.notest>'
+insertsource 'unstable' 'spec-4' 'any' '1' 'Build-Depends: foo <profile.stage1 profile.notest>'
+insertsource 'unstable' 'spec-5' 'any' '1' 'Build-Depends: foo <!profile.stage1 profile.notest>'
+insertsource 'unstable' 'spec-6' 'any' '1' 'Build-Depends: foo <profile.stage1 !profile.notest>'
+# multiple stanzas not supported: error out
+insertsource 'unstable' 'spec-7' 'any' '1' 'Build-Depends: foo <profile.stage1><!profile.notest>'
+insertsource 'unstable' 'spec-8' 'any' '1' 'Build-Depends: foo <profile.stage1> <!profile.notest>'
+
+setupaptarchive
+
+testequal 'Reading package lists...
+Building dependency tree...
+The following NEW packages will be installed:
+  bar
+0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
+Inst bar (1.0 unstable [all])
+Conf bar (1.0 unstable [all])' aptget build-dep buildprofiles -s
+
+testequal 'Reading package lists...
+Building dependency tree...
+The following NEW packages will be installed:
+  bar foo
+0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
+Inst bar (1.0 unstable [all])
+Inst foo (1.0 unstable [all])
+Conf bar (1.0 unstable [all])
+Conf foo (1.0 unstable [all])' aptget build-dep buildprofiles -s -o APT::Architecture=i386
+
+testequal 'Reading package lists...
+Building dependency tree...
+The following NEW packages will be installed:
+  bar
+0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
+Inst bar (1.0 unstable [all])
+Conf bar (1.0 unstable [all])' aptget build-dep buildprofiles -s -o APT::Architecture=armel
+
+testequal 'Reading package lists...
+Building dependency tree...
+The following NEW packages will be installed:
+  bar
+0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
+Inst bar (1.0 unstable [all])
+Conf bar (1.0 unstable [all])' aptget build-dep buildprofiles -s -o APT::Architecture=i386 -P stage1
+
+KEEP='Reading package lists...
+Building dependency tree...
+The following NEW packages will be installed:
+  foo
+0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
+Inst foo (1.0 unstable [all])
+Conf foo (1.0 unstable [all])'
+DROP='Reading package lists...
+Building dependency tree...
+0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.'
+
+msgtest 'Check if version of installed dpkg is high enough for' 'build profiles support'
+if dpkg --compare-versions "$(command dpkg-query --showformat='${Version}' --show dpkg)" 'ge' '1.17.2'; then
+       msgpass
+       testwithdpkg() {
+               msgtest "Test with" "dpkg-checkbuilddeps -d '$1' -P '$2'"
+               local OUTPUT="${TMPWORKINGDIRECTORY}/rootdir/tmp/testwithdpkg.output"
+               if dpkgcheckbuilddeps -d "$1" -P "$2" /dev/null >$OUTPUT 2>&1; then
+                       if [ "$3" = "$DROP" ]; then
+                               msgpass
+                       else
+                               cat $OUTPUT
+                               msgfail
+                       fi
+               else
+                       if [ "$3" = "$KEEP" ]; then
+                               msgpass
+                       else
+                               cat $OUTPUT
+                               msgfail
+                       fi
+               fi
+       }
+else
+       msgskip
+       testwithdpkg() {
+               msgtest "Test with" "dpkg-checkbuilddeps -d '$1' -P '$2'"
+               msgskip
+       }
+fi
+
+testprofile() {
+       if [ -n "$3" ]; then
+               testequal "$4" aptget build-dep "$1" -s -P "$3"
+               export DEB_BUILD_PROFILES="$(echo "$3" | tr ',' ' ')"
+               testequal "$4" aptget build-dep "$1" -s -o with::environment=1
+               unset DEB_BUILD_PROFILES
+       else
+               testequal "$4" aptget build-dep "$1" -s
+       fi
+       testwithdpkg "$2" "$3" "$4"
+}
+
+testprofile 'spec-1' 'foo <!profile.stage1>' '' "$KEEP"
+testprofile 'spec-1' 'foo <!profile.stage1>' 'stage1' "$DROP"
+testprofile 'spec-1' 'foo <!profile.stage1>' 'notest' "$KEEP"
+testprofile 'spec-1' 'foo <!profile.stage1>' 'stage1,notest' "$DROP"
+
+testprofile 'spec-2' 'foo <profile.stage1>' '' "$DROP"
+testprofile 'spec-2' 'foo <profile.stage1>' 'stage1' "$KEEP"
+testprofile 'spec-2' 'foo <profile.stage1>' 'notest' "$DROP"
+testprofile 'spec-2' 'foo <profile.stage1>' 'stage1,notest' "$KEEP"
+
+testprofile 'spec-3' 'foo <!profile.stage1 !profile.notest>' '' "$KEEP"
+testprofile 'spec-3' 'foo <!profile.stage1 !profile.notest>' 'stage1' "$DROP"
+testprofile 'spec-3' 'foo <!profile.stage1 !profile.notest>' 'notest' "$DROP"
+testprofile 'spec-3' 'foo <!profile.stage1 !profile.notest>' 'stage1,notest' "$DROP"
+
+testprofile 'spec-4' 'foo <profile.stage1 profile.notest>' '' "$DROP"
+testprofile 'spec-4' 'foo <profile.stage1 profile.notest>' 'stage1' "$KEEP"
+testprofile 'spec-4' 'foo <profile.stage1 profile.notest>' 'notest' "$KEEP"
+testprofile 'spec-4' 'foo <profile.stage1 profile.notest>' 'stage1,notest' "$KEEP"
+
+testprofile 'spec-5' 'foo <!profile.stage1 profile.notest>' '' "$KEEP"
+testprofile 'spec-5' 'foo <!profile.stage1 profile.notest>' 'stage1' "$DROP"
+testprofile 'spec-5' 'foo <!profile.stage1 profile.notest>' 'notest' "$KEEP"
+testprofile 'spec-5' 'foo <!profile.stage1 profile.notest>' 'stage1,notest' "$DROP"
+
+testprofile 'spec-6' 'foo <profile.stage1 !profile.notest>' '' "$KEEP"
+testprofile 'spec-6' 'foo <profile.stage1 !profile.notest>' 'stage1' "$KEEP"
+testprofile 'spec-6' 'foo <profile.stage1 !profile.notest>' 'notest' "$DROP"
+testprofile 'spec-6' 'foo <profile.stage1 !profile.notest>' 'stage1,notest' "$KEEP"
+
+testfailure aptget build-dep spec-7 -s
+testfailure aptget build-dep spec-8 -s