[dpkg] 03/08: FIXME: cleanup

Mattia Rizzolo mattia at debian.org
Tue Sep 20 22:36:12 UTC 2016


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

mattia pushed a commit to branch pu/reproducible_builds
in repository dpkg.

commit 10fd6510c5768642fbb8bc958c535ae93e81ea17
Author: Guillem Jover <guillem at debian.org>
Date:   Sun Jul 17 21:21:13 2016 +0200

    FIXME: cleanup
---
 man/Makefile.am                    |   1 +
 man/deb-buildinfo.5                | 175 ++++++++++++++++
 man/dpkg-buildpackage.1            |  28 +--
 man/dpkg-genbuildinfo.1            |  31 ++-
 man/po/po4a.cfg                    |   3 +
 scripts/Dpkg/Control/FieldsCore.pm |  10 +-
 scripts/Dpkg/Control/Types.pm      |   2 +-
 scripts/Dpkg/Vendor/Default.pm     |  14 +-
 scripts/dpkg-buildpackage.pl       |  65 ++----
 scripts/dpkg-genbuildinfo.pl       | 419 ++++++++++++++++++++++---------------
 t/pod-spell.t                      |   2 +
 11 files changed, 488 insertions(+), 262 deletions(-)

diff --git a/man/Makefile.am b/man/Makefile.am
index 39a64a5..885091a 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -1,6 +1,7 @@
 ## Process this file with automake to produce Makefile.in
 
 dist_man_MANS = \
+	deb-buildinfo.5 \
 	deb-changelog.5 \
 	deb-changes.5 \
 	deb-conffiles.5 \
diff --git a/man/deb-buildinfo.5 b/man/deb-buildinfo.5
new file mode 100644
index 0000000..c07d63a
--- /dev/null
+++ b/man/deb-buildinfo.5
@@ -0,0 +1,175 @@
+.\" dpkg manual page - deb-buildinfo(5)
+.\"
+.\" Copyright © 1995-1996 Ian Jackson <ijackson at chiark.greenend.org.uk>
+.\" Copyright © 2010 Russ Allbery <rra at debian.org>
+.\" Copyright © 2015-2016 Guillem Jover <guillem at debian.org>
+.\"
+.\" This is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program.  If not, see <https://www.gnu.org/licenses/>.
+.
+.TH deb\-buildinfo 5 "2016-07-18" "Debian Project" "Debian"
+.SH NAME
+deb\-buildinfo \- Debian build information file format
+.
+.SH SYNOPSIS
+.IB filename .buildinfo
+.
+.SH DESCRIPTION
+Each Debian source package build can record the build information in
+a .buildinfo control file, which contains a number of fields.
+Each field begins with a tag, such as
+.B Source
+or
+.B Binary
+(case insensitive), followed by a colon, and the body of the field.
+Fields are delimited only by field tags.
+In other words, field text may be multiple lines in length, but the
+installation tools will generally join lines when processing the body
+of the field (except in case of the multiline fields
+.BR Binary\-Only\-Changes ", " Installed\-Build\-Depends ", " Environment ", "
+.BR \%Checksums\-Md5 ", " \%Checksums\-Sha1
+and
+.BR \%Checksums\-Sha256 ,
+see below).
+.PP
+The control data might be enclosed in an OpenPGP ASCII Armored signature,
+as specified in RFC4880.
+.PP
+XXX: Describe the filename format here.
+.
+.SH FIELDS
+.TP
+.BR Format: " \fIformat-version\fP (required)"
+The value of this field declares the format version of the file.
+The syntax of the field value is a version number with a major and minor
+component.
+Backward incompatible changes to the format will bump the major version,
+and backward compatible changes (such as field additions) will bump the
+minor version.
+The current format version is \fB0.1\fP.
+.TP
+.BR Source: " \fIsource-name\fP [\fB(\fP\fIsource-version\fP\fB)\fP] (required)"
+The name of the source package.
+If the source version differs from the binary version, then the
+\fIsource-name\fP will be followed by a \fIsource-version\fP in parenthesis.
+This can happen when the build is for a binary-only non-maintainer upload.
+.TP
+.BR Binary: " \fIbinary-package-list\fP (required)"
+This folded field is a space-separated list of binary packages built.
+.TP
+.BR Architecture: " \fIarch-list\fP (required)"
+This spare-separated field lists the architectures of the files currently
+being built..
+Common architectures are \fBamd64\fP, \fBarmel\fP, \fBi386\fP, etc.
+Note that the \fBall\fP value is meant for packages that are architecture
+independent.
+If the source for the package is also being built, the special entry
+\fBsource\fP is also present.
+Architecture wildcards must never be present in the list.
+.TP
+.BR Version: " \fIversion-string\fP (required)"
+Typically, this is the original package's version number in whatever form
+the program's author uses.
+It may also include a Debian revision number (for non-native packages).
+The exact format and sorting algorithm are described in
+.BR deb\-version (5).
+.TP
+.B Binary\-Only\-Changes:
+.TQ
+.I " changelog-entry"
+This multiline field contains the concatenated text of the changelog
+entry for a binary-only non-maintainer upload (binNMU) if that is the case.
+To make this a valid multiline field empty lines are replaced with a
+single full stop (\(oq.\(cq) and all lines are indented by one space
+character.
+The exact content depends on the changelog format.
+.TP
+.BR Checksums\-Md5: " (required)"
+.TQ
+.BR Checksums\-Sha1: " (required)"
+.TQ
+.BR Checksums\-Sha256: " (required)"
+.TQ
+.RI " " checksum " " size " " filename
+These multiline fields contain a list of files with a checksum and size
+for each one.
+These fields have the same syntax and differ only in the checksum algorithm
+used: MD5 for \fB\%Checksums\-Md5\fP, SHA-1 for \fB\%Checksums\-Sha1\fP and
+SHA-256 for \fB\%Checksums\-Sha256\fP.
+
+The first line of the field value (the part on the same line as the field
+name followed by a colon) is always empty.
+The content of the field is expressed as continuation lines, one line per file.
+Each line consists of space-separated entries describing the file:
+the checksum, the file size, and the file name.
+
+These fields list all files that make up the build.
+.TP
+.BR Build\-Architecture: " \fIarch\fP (required)"
+The Debian architecture for the installation the packages is being built in.
+Common architectures are \fBamd64\fP, \fBarmel\fP, \fBi386\fP, etc.
+.TP
+.BR Build\-Date: " \fIbuild-date\fP"
+(XXX Add to code ??)
+The date the package was built.
+It must be in the same format as the date in a \fBdeb\-changelog\fP(5)
+entry.
+
+The value of this field is the current date at the time of the build.
+.TP
+.BR Build\-Path: " \fIbuild-path\fP"
+The absolute build path, which correspond to the unpacked source tree.
+This field is only going to be present if the vendor has whitelisted it
+via some pattern match to avoid leaking possibly sensitive information.
+
+On Debian and derivaties only build paths starting with \fI/build/\fP
+will emit this field.
+.TP
+.BR Installed\-Build\-Depends: " (required)"
+.TQ
+.I " package-list"
+The list of installed and configured packages that might affect the package
+build process.
+
+The list consists of each package name, optionally arch-qualified for foreign
+architectures, with an exact version restriction, separated by commas.
+
+The list includes all essential packages, packages listed in
+\fBBuild\-Depends\fP, \fBBuild\-Depends\-Arch\fP, \fBBuild\-Depends\-Indep\fP
+source control fields, any vendor specific builtin dependencies, and all
+their recursive dependencies.
+On Debian and derivatives the dependency builtin is \fBbuild\-essential\fP.
+
+For dependencies coming from the source control fields, all dependency
+alternatives and all providers of virtual packages depended on will be
+included.
+.TP
+.BR Environment:
+.TQ
+.I " variable-list"
+The list of environment variables that are known to affect the package build
+process, with each environment variable followed by an equal sign (\(oq=\(cq)
+and the variable's quoted value, using double quotes (\(oq"\(cq), and
+backslashes escaped (\(oq\\\\\(cq).
+.
+.\" .SH EXAMPLE
+.\" .RS
+.\" .nf
+.\"
+.\" .fi
+.\" .RE
+.
+.SH SEE ALSO
+.BR deb\-changes (5),
+.BR deb\-version (5),
+.BR dpkg\-genbuildinfo (1).
diff --git a/man/dpkg-buildpackage.1 b/man/dpkg-buildpackage.1
index d444ac9..524e00d 100644
--- a/man/dpkg-buildpackage.1
+++ b/man/dpkg-buildpackage.1
@@ -62,8 +62,8 @@ build has been requested with \fB\-\-build\fP or equivalent options), or
 \fBbuild\-indep\fP and \fBbinary\-indep\fP (if an \fBall\fP and not \fBany\fP
 build has been requested with \fB\-\-build\fP or equivalent options).
 .IP \fB6.\fP 3
-Unless a source-only build has been requested, it runs the \fBbuildinfo\fP hook
-and calls \fBdpkg\-genbuildinfo\fP to generate a \fB.buildinfo\fP file.
+Unless a source-only build has been requested, it runs the \fBbuildinfo\fP
+hook and calls \fBdpkg\-genbuildinfo\fP to generate a \fB.buildinfo\fP file.
 Several \fBdpkg\-buildpackage\fP options are forwarded to
 \fBdpkg\-genbuildinfo\fP.
 .IP \fB7.\fP 3
@@ -362,15 +362,19 @@ The upstream version.
 .RE
 .TP
 .BI \-\-buildinfo-identifier= identifier
-Specify the identifier part of the \fB.buildinfo\fP file name (since dpkg
-1.18.5).
-By default, \fBdpkg\-buildpackage\fP will create an identifier using the
-current time and the first characters of the MD5 hash.
+Specify the identifier part of the \fB.buildinfo\fP file name
+(since dpkg 1.18.10).
+By default, \fBdpkg\-buildpackage\fP will create an identifier using
+the current time and the first characters of the MD5 hash.
 An arbitrary identifier can be specified as a replacement.
-The identifier has the same restriction as package names: they
-must consist only of lower case letters (a-z), digits (0-9), plus (+)
-and minus (\-) signs, and periods (.), be at least two characters long
-and must start with an alphanumeric character.
+The identifier has the same restriction as package names: they must consist
+only of lower case letters (a-z), digits (0-9), plus (+) and minus (\-)
+signs, and periods (.), be at least two characters long and must start
+with an alphanumeric character.
+.TP
+.BI \-\-buildinfo\-option= opt
+Pass option \fIopt\fP to \fBdpkg\-genbuildinfo\fP (since dpkg 1.18.10).
+Can be used multiple times.
 .TP
 .BR \-p ", " \-\-sign\-command= \fIsign-command\fP
 When \fBdpkg\-buildpackage\fP needs to execute GPG to sign a source
@@ -426,10 +430,6 @@ Passed unchanged to \fBdpkg\-source\fP. See its manual page.
 Pass option \fIopt\fP to \fBdpkg\-source\fP (since dpkg 1.15.6).
 Can be used multiple times.
 .TP
-.BI \-\-buildinfo\-option= opt
-Pass option \fIopt\fP to \fBdpkg\-genbuildinfo\fP (since dpkg 1.18.5).
-Can be used multiple times.
-.TP
 .BI \-\-changes\-option= opt
 Pass option \fIopt\fP to \fBdpkg\-genchanges\fP (since dpkg 1.15.6).
 Can be used multiple times.
diff --git a/man/dpkg-genbuildinfo.1 b/man/dpkg-genbuildinfo.1
index e4eba10..33fc700 100644
--- a/man/dpkg-genbuildinfo.1
+++ b/man/dpkg-genbuildinfo.1
@@ -32,14 +32,15 @@ dpkg\-genbuildinfo \- generate Debian .buildinfo files
 .B dpkg\-genbuildinfo
 reads information from an unpacked and built Debian source tree and
 from the files it has generated and generates a Debian control
-file describing the build environment and the build products
+file describing the build environment and the build artifacts
 .RB ( .buildinfo " file)."
+.P
+This command was introduced in dpkg 1.18.10.
 .
 .SH OPTIONS
 .TP
 .BI \-\-build= type
-Specifies the build \fItype\fP from a comma-separated list of components
-(since dpkg 1.18.5).
+Specifies the build \fItype\fP from a comma-separated list of components.
 
 The allowed values are:
 .RS
@@ -52,10 +53,10 @@ Generate build information including unqualified build dependencies
 .B all
 Generate build information including unqualified build dependencies
 (\fBBuild-Depends\fP) and architecture independent build dependencies
-(\fBBuild-Depends-Arch\fP).
+(\fBBuild-Depends-Indep\fP).
 .TP
 .B source
-Effectively ignored: generate build information with just the unqualified
+Effectively ignored; generate build information with just the unqualified
 build dependencies (\fBBuild-Depends\fP).
 .TP
 .B binary
@@ -64,16 +65,10 @@ This is an alias for \fBany,all\fP.
 .TP
 .B full
 Generate build information with all three types of build dependencies.
-This is an alias for \fBany,all,source\fP, and the same as the default case
-when no build option is specified.
+This is an alias for \fBany,all,source\fP, and the same as the default
+case when no build option is specified.
 .RE
 .TP
-.B -A
-Equivalent to \fB\-\-build=all\fP.
-.TP
-.B -B
-Equivalent to \fB\-\-build=any\fP.
-.TP
 .BI \-c controlfile
 Specifies the main source control file to read information from. The
 default is
@@ -98,11 +93,8 @@ Look for the files to be uploaded in
 .I upload-files-dir
 rather than
 .B ..
-.RB ( dpkg\-genbuildinfo
-needs to find these files so that it can include their sizes and
-checksums in the
-.B .buildinfo
-file).
+(\fBdpkg\-genbuildinfo\fP needs to find these files so that it can include
+their sizes and checksums in the \fB.buildinfo\fP file).
 .TP
 .BI \-\-admindir= dir
 Change the location of the \fBdpkg\fR database. The default location is
@@ -133,3 +125,6 @@ The list of generated files.
 reads the data here when producing a
 .B .buildinfo
 file.
+.
+.SH SEE ALSO
+.BR deb-buildinfo (5).
diff --git a/man/po/po4a.cfg b/man/po/po4a.cfg
index 8540edf..344b869 100644
--- a/man/po/po4a.cfg
+++ b/man/po/po4a.cfg
@@ -10,6 +10,9 @@
 [type:man] deb822.5 $lang:$lang/deb822.5 \
            add_$lang:po/$lang.add
 
+[type:man] deb-buildinfo.5 $lang:$lang/deb-buildinfo.5 \
+           add_$lang:po/$lang.add
+
 [type:man] deb-changelog.5 $lang:$lang/deb-changelog.5 \
            add_$lang:po/$lang.add
 
diff --git a/scripts/Dpkg/Control/FieldsCore.pm b/scripts/Dpkg/Control/FieldsCore.pm
index cae8d6b..068646f 100644
--- a/scripts/Dpkg/Control/FieldsCore.pm
+++ b/scripts/Dpkg/Control/FieldsCore.pm
@@ -160,7 +160,7 @@ our %FIELDS = (
         allowed => CTRL_REPO_RELEASE,
     },
     'Changes' => {
-        allowed => CTRL_FILE_BUILDINFO | ALL_CHANGES,
+        allowed => ALL_CHANGES,
     },
     'Classes' => {
         allowed => CTRL_TESTS,
@@ -223,6 +223,10 @@ our %FIELDS = (
         dependency => 'union',
         dep_order => 5,
     },
+    'Environment' => {
+        allowed => CTRL_FILE_BUILDINFO,
+        separator => FIELD_SEP_LINE,
+    },
     'Essential' => {
         allowed => ALL_PKG,
     },
@@ -462,10 +466,10 @@ our %FIELD_ORDER = (
         qw(Package-List), @checksum_fields, qw(Files)
     ],
     CTRL_FILE_BUILDINFO() => [
-        qw(Format Build-Architecture Source Binary Architecture Version
+        qw(Format Source Binary Architecture Version
         Binary-Only-Changes),
         @checksum_fields,
-        qw(Build-Path Installed-Build-Depends),
+        qw(Build-Architecture Build-Path Installed-Build-Depends Environment),
     ],
     CTRL_FILE_CHANGES() => [
         qw(Format Date Source Binary Binary-Only Built-For-Profiles Architecture
diff --git a/scripts/Dpkg/Control/Types.pm b/scripts/Dpkg/Control/Types.pm
index a6c6639..445079d 100644
--- a/scripts/Dpkg/Control/Types.pm
+++ b/scripts/Dpkg/Control/Types.pm
@@ -26,6 +26,7 @@ our @EXPORT = qw(
     CTRL_INDEX_PKG
     CTRL_PKG_SRC
     CTRL_PKG_DEB
+    CTRL_FILE_BUILDINFO
     CTRL_FILE_CHANGES
     CTRL_FILE_VENDOR
     CTRL_FILE_STATUS
@@ -34,7 +35,6 @@ our @EXPORT = qw(
     CTRL_COPYRIGHT_FILES
     CTRL_COPYRIGHT_LICENSE
     CTRL_TESTS
-    CTRL_FILE_BUILDINFO
 );
 
 use Exporter qw(import);
diff --git a/scripts/Dpkg/Vendor/Default.pm b/scripts/Dpkg/Vendor/Default.pm
index 9860a70..89627ae 100644
--- a/scripts/Dpkg/Vendor/Default.pm
+++ b/scripts/Dpkg/Vendor/Default.pm
@@ -118,13 +118,13 @@ Dpkg::BuildFlags object.
 
 =item builtin-system-build-paths ()
 
-The hook is called by dpkg-genbuildinfo to determine if the current
-path should be recorded in the Build-Path field. It takes no parameters,
-but returns a (possibly empty) list of root paths considered acceptable.
-As an example, if the list contains "/build/", a Build-Path field will
-be created if the current directory is "/build/dpkg-1.18.5". If the
-list contains "/", the path will always be recorded. If the list is
-empty, the current path will never be recorded.
+The hook is called by dpkg-genbuildinfo to determine if the current path
+should be recorded in the B<Build-Path> field. It takes no parameters, but
+returns a (possibly empty) list of root paths considered acceptable. As an
+example, if the list contains "/build/", a Build-Path field will be created
+if the current directory is "/build/dpkg-1.18.0". If the list contains "/",
+the path will always be recorded. If the list is empty, the current path
+will never be recorded.
 
 =back
 
diff --git a/scripts/dpkg-buildpackage.pl b/scripts/dpkg-buildpackage.pl
index 3f61768..acfee94 100755
--- a/scripts/dpkg-buildpackage.pl
+++ b/scripts/dpkg-buildpackage.pl
@@ -27,10 +27,9 @@ use Cwd;
 use File::Temp qw(tempdir);
 use File::Basename;
 use File::Copy;
-use POSIX qw(:sys_wait_h strftime);
+use POSIX qw(:sys_wait_h);
 
 use Dpkg ();
-use Dpkg::Control::Info;
 use Dpkg::Gettext;
 use Dpkg::ErrorHandling;
 use Dpkg::Build::Types;
@@ -96,8 +95,9 @@ sub usage {
       --hook-<name>=<command> set <command> as the hook <name>, known hooks:
                                 init preclean source build binary buildinfo
                                 changes postclean check sign done
-      --buildinfo-identifier=<identifier>
-                              set the identifier part of the .buildinfo filename.
+      --buildinfo-id=<id>     set the <id> part of the .buildinfo filename.
+      --buildinfo-option=<opt>
+                              pass option <opt> to dpkg-genbuildinfo.
   -p, --sign-command=<command>
                               command to sign .dsc and/or .changes files
                                 (default is gpg2 or gpg).
@@ -116,10 +116,6 @@ sub usage {
       --target-arch <arch>    set the target Debian architecture.
       --target-type <type>    set the target GNU system type.')
     . "\n\n" . g_(
-'Options passed to dpkg-genbuildinfo:
-      --buildinfo-option=<opt>
-                 pass option <opt> to dpkg-genbuildinfo.')
-    . "\n\n" . g_(
 'Options passed to dpkg-genchanges:
   -si                         source includes orig, if new upstream (default).
   -sa                         source includes orig, always.
@@ -176,7 +172,7 @@ my $since;
 my $maint;
 my $changedby;
 my $desc;
-my $buildinfo_identifier;
+my $buildinfo_id;
 my @buildinfo_opts;
 my @changes_opts;
 my @hook_names = qw(
@@ -239,8 +235,8 @@ while (@ARGV) {
 	usageerr(g_('missing hook %s command'), $hook_name)
 	    if not defined $hook_cmd;
 	$hook{$hook_name} = $hook_cmd;
-    } elsif (/^--buildinfo-identifier=(.*)$/) {
-	$buildinfo_identifier = $1;
+    } elsif (/^--buildinfo-id=(.*)$/) {
+	$buildinfo_id = $1;
     } elsif (/^(?:-p|--sign-command=)(.*)$/) {
 	$signcommand = $1;
     } elsif (/^(?:-k|--sign-key=)(.*)$/) {
@@ -403,10 +399,12 @@ if (defined $parallel) {
     $build_opts->export();
 }
 
-if (defined $buildinfo_identifier) {
-    # .buildinfo identifiers have the same restrictions as package names
-    my $err = pkg_name_is_illegal($buildinfo_identifier);
-    error(g_("illegal .buildinfo identifier '%s': %s"), $buildinfo_identifier, $err) if $err;
+if (defined $buildinfo_id) {
+    # The .buildinfo identifiers have the same restrictions as package names.
+    my $err = pkg_name_is_illegal($buildinfo_id);
+    if ($err) {
+        error(g_("illegal .buildinfo ID '%s': %s"), $buildinfo_id, $err);
+    }
 }
 
 set_build_profiles(@build_profiles) if @build_profiles;
@@ -556,39 +554,16 @@ if (build_has_any(BUILD_BINARY)) {
     withecho(@debian_rules, $buildtarget);
     run_hook('binary', 1);
     withecho(@rootcommand, @debian_rules, $binarytarget);
+}
 
-    run_hook('buildinfo', 1);
-
-    push @buildinfo_opts, "--build=$build_types" if build_has_none(BUILD_DEFAULT);
-    push @buildinfo_opts, "--admindir=$admindir" if $admindir;
-
-    open my $genbuildinfo_fh, '-|', 'dpkg-genbuildinfo', @buildinfo_opts
-        or subprocerr('dpkg-genbuildinfo');
-    my @buildinfo_content = <$genbuildinfo_fh>;
-    close $genbuildinfo_fh;
-
-    if (!defined $buildinfo_identifier) {
-        require Digest::MD5;
-
-        my $timestamp = strftime('%Y%m%dT%H%M%Sz', gmtime());
-        my $buildinfo_md5 = Digest::MD5::md5_hex(@buildinfo_content);
-        $buildinfo_identifier = "$timestamp-" . substr($buildinfo_md5, 0, 8);
-    }
-
-    my $buildinfo = "${pv}_${buildinfo_identifier}.buildinfo";
+run_hook('buildinfo', 1);
 
-    open my $buildinfo_fh, '>', "../$buildinfo"
-        or syserr(g_('cannot open %s', "../$buildinfo"));
-    print { $buildinfo_fh } @buildinfo_content;
-    close $buildinfo_fh;
+push @buildinfo_opts, "--build=$build_types" if build_has_none(BUILD_DEFAULT);
+push @buildinfo_opts, "--buildinfo-id=$buildinfo_id" if $buildinfo_id;
+push @buildinfo_opts, "-O$buildinfo";
+push @buildinfo_opts, "--admindir=$admindir" if $admindir;
 
-    my $control = Dpkg::Control::Info->new('debian/control');
-    my $sec = $control->get_source->{'Section'} // '-';
-    my $pri = $control->get_source->{'Priority'} // '-';
-    warning(g_('missing Section for source files')) if $sec eq '-';
-    warning(g_('missing Priority for source files')) if $pri eq '-';
-    withecho('dpkg-distaddfile', $buildinfo, $sec, $pri);
-}
+withecho('dpkg-genbuildinfo', @buildinfo_opts);
 
 run_hook('changes', 1);
 
diff --git a/scripts/dpkg-genbuildinfo.pl b/scripts/dpkg-genbuildinfo.pl
index 7183d94..1cce4e9 100755
--- a/scripts/dpkg-genbuildinfo.pl
+++ b/scripts/dpkg-genbuildinfo.pl
@@ -5,7 +5,7 @@
 # Copyright © 1996 Ian Jackson
 # Copyright © 2000,2001 Wichert Akkerman
 # Copyright © 2003-2013 Yann Dirson <dirson at debian.org>
-# Copyright © 2006-2014 Guillem Jover <guillem at debian.org>
+# Copyright © 2006-2016 Guillem Jover <guillem at debian.org>
 # Copyright © 2014 Niko Tyni <ntyni at debian.org>
 # Copyright © 2014-2015 Jérémy Bobbio <lunar at debian.org>
 #
@@ -25,8 +25,9 @@
 use strict;
 use warnings;
 
-use Carp;
 use Cwd;
+use File::Basename;
+use POSIX qw(:fcntl_h strftime);
 
 use Dpkg ();
 use Dpkg::Gettext;
@@ -43,6 +44,7 @@ use Dpkg::Changelog::Parse;
 use Dpkg::Deps;
 use Dpkg::Dist::Files;
 use Dpkg::Util qw(:list);
+use Dpkg::File;
 use Dpkg::Version;
 use Dpkg::Vendor qw(run_vendor_hook);
 
@@ -53,26 +55,29 @@ my $changelogfile = 'debian/changelog';
 my $changelogformat;
 my $fileslistfile = 'debian/files';
 my $uploadfilesdir = '..';
+my $outputfile;
 my $admindir = $Dpkg::ADMINDIR;
 my $always_include_path = 0;
 my @build_profiles = get_build_profiles();
-my $buildinfo_format = '1.0';
+my $buildinfo_format = '0.1';
+my $buildinfo_id;
+my $buildinfo;
 
 my $checksums = Dpkg::Checksums->new();
 my %archadded;
 my @archvalues;
 
-# There's almost the same function in dpkg-checkbuilddeps,
-# they probably should be factored out.
+# There is almost the same function in dpkg-checkbuilddeps, they probably
+# should be factored out.
 sub parse_status {
     my $status = shift;
 
     my $facts = Dpkg::Deps::KnownFacts->new();
     my %depends;
     my @essential_pkgs;
+
     local $/ = '';
-    open(my $status_fh, '<', $status)
-        or syserr(g_('cannot open %s'), $status);
+    open my $status_fh, '<', $status or syserr(g_('cannot open %s'), $status);
     while (<$status_fh>) {
         next unless /^Status: .*ok installed$/m;
 
@@ -80,8 +85,8 @@ sub parse_status {
         my ($version) = /^Version: (.*)$/m;
         my ($arch) = /^Architecture: (.*)$/m;
         my ($multiarch) = /^Multi-Arch: (.*)$/m;
-        $facts->add_installed_package($package, $version, $arch,
-                                      $multiarch);
+
+        $facts->add_installed_package($package, $version, $arch, $multiarch);
 
         if (/^Essential: yes$/m) {
             push @essential_pkgs, $package;
@@ -89,23 +94,21 @@ sub parse_status {
 
         if (/^Provides: (.*)$/m) {
             my $provides = deps_parse($1, reduce_arch => 1, union => 1);
+
             next if not defined $provides;
-            foreach (grep { $_->isa('Dpkg::Deps::Simple') }
-                                 $provides->get_deps())
-            {
-                $facts->add_provided_package($_->{package},
-                                    $_->{relation}, $_->{version},
-                                    $package);
-            }
+
+            deps_iterate($provides, sub {
+                my $dep = shift;
+                $facts->add_provided_package($dep->{package}, $dep->{relation},
+                                             $dep->{version}, $package);
+            });
         }
 
-        ## no critic (RegularExpressions::ProhibitUnusedCapture)
         if (/^(?:Pre-)?Depends: (.*)$/m) {
-            foreach (split(/,\s*/, $1)) {
+            foreach (split /,\s*/, $1) {
                 push @{$depends{"$package:$arch"}}, $_;
             }
         }
-        ## use critic
     }
     close $status_fh;
 
@@ -117,15 +120,156 @@ sub append_deps {
 
     foreach my $dep_str (@_) {
         next unless $dep_str;
+
         my $deps = deps_parse($dep_str, reduce_restrictions => 1,
-                              build_dep => 1, build_profiles => \@build_profiles);
-        # We add every sub-dependencies as we can't know which package in an OR
-        # dependency has been effectively used.
+                              build_dep => 1,
+                              build_profiles => \@build_profiles);
+
+        # We add every sub-dependencies as we cannot know which package in
+        # an OR dependency has been effectively used.
         deps_iterate($deps, sub {
             push @{$pkgs},
                 $_[0]->{package} . (defined $_[0]->{archqual} ? ':' . $_[0]->{archqual} : '');
-            1 });
+            1
+        });
+    }
+}
+
+sub collect_installed_builddeps {
+    my $control = shift;
+
+    my ($facts, $depends, $essential_pkgs) = parse_status("$admindir/status");
+    my %seen_pkgs;
+    my @unprocessed_pkgs;
+
+    # Parse essential packages list.
+    append_deps(\@unprocessed_pkgs,
+                @{$essential_pkgs},
+                run_vendor_hook('builtin-build-depends'),
+                $control->get_source->{'Build-Depends'});
+
+    if (build_has_any(BUILD_ARCH_DEP)) {
+        append_deps(\@unprocessed_pkgs,
+                    $control->get_source->{'Build-Depends-Arch'});
+    }
+
+    if (build_has_any(BUILD_ARCH_INDEP)) {
+        append_deps(\@unprocessed_pkgs,
+                    $control->get_source->{'Build-Depends-Indep'});
+    }
+
+    my $installed_deps = Dpkg::Deps::AND->new();
+
+    while (my $pkg_name = shift @unprocessed_pkgs) {
+        next if $seen_pkgs{$pkg_name};
+        $seen_pkgs{$pkg_name} = 1;
+
+        my $required_architecture;
+        if ($pkg_name =~ /\A(.*):(.*)\z/) {
+            $pkg_name = $1;
+            my $arch = $2;
+            $required_architecture = $arch if $arch !~ /\A(?:all|any|native)\Z/
+        }
+        my $pkg;
+        my $qualified_pkg_name;
+        foreach my $installed_pkg (@{$facts->{pkg}->{$pkg_name}}) {
+            if (!defined $required_architecture ||
+                $required_architecture eq $installed_pkg->{architecture}) {
+                $pkg = $installed_pkg;
+                $qualified_pkg_name = $pkg_name . ':' . $installed_pkg->{architecture};
+                last;
+            }
+        }
+        if (defined $pkg) {
+            my $version = $pkg->{version};
+            my $architecture = $pkg->{architecture};
+            my $new_deps_str = defined $depends->{$qualified_pkg_name} ? deps_concat(@{$depends->{$qualified_pkg_name}}) : '';
+            my $new_deps = deps_parse($new_deps_str);
+            if (!defined $required_architecture) {
+                $installed_deps->add(Dpkg::Deps::Simple->new("$pkg_name (= $version)"));
+            } else {
+                $installed_deps->add(Dpkg::Deps::Simple->new("$qualified_pkg_name (= $version)"));
+
+                # Dependencies of foreign packages are also foreign packages (or Arch:all)
+                # so we need to qualify them as well. We figure out if the package is actually
+                # foreign by searching for an installed package of the right architecture.
+                deps_iterate($new_deps, sub {
+                    my $dep = shift;
+                    $dep->{archqual} //= $architecture
+                        if any { $_[0]->{architecture} eq $architecture }, @{$facts->{pkg}->{$dep->{package}}};
+                    1;
+                });
+            }
+
+            # We add every sub-dependencies as we cannot know which package in
+            # an OR dependency has been effectively used.
+            deps_iterate($new_deps, sub {
+                push @unprocessed_pkgs,
+                     $_[0]->{package} . (defined $_[0]->{archqual} ? ':' . $_[0]->{archqual} : '');
+                1
+            });
+        } elsif (defined $facts->{virtualpkg}->{$pkg_name}) {
+            # virtual package: we cannot know for sure which implementation
+            # is the one that has been used, so let's add them all...
+            foreach my $provided (@{$facts->{virtualpkg}->{$pkg_name}}) {
+                my ($provided_by, $provided_rel, $provided_ver) = @{$provided};
+                push @unprocessed_pkgs, $provided_by;
+            }
+        }
+        # else: it is a package in an OR dependency that has been otherwise
+        # satisfied.
+    }
+    $installed_deps->sort();
+    $installed_deps = "\n" . $installed_deps->output();
+    $installed_deps =~ s/, /,\n/g;
+
+    return $installed_deps;
+}
+
+my @env_whitelist = (
+    qw(PATH),
+    # Toolchain.
+    qw(CC CPP CXX LD AR RANLIB MAKE AWK),
+    # Toolchain flags.
+    qw(CFLAGS CPPFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS GCJFLAGS FFLAGS
+       LDFLAGS ARFLAGS MAKEFLAGS),
+    # Dynamic linker, see ld(1).
+    qw(LD_LIBRARY_PATH),
+    # Locale, see locale(1).
+    qw(LANG LC_ALL LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY
+       LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
+       LC_IDENTIFICATION),
+    # Build flags, see dpkg-buildpackage(1).
+    qw(DEB_BUILD_OPTIONS DEB_BUILD_PROFILES),
+    # DEB_flag_{SET,STRIP,APPEND,PREPEND} will be recorded after being merged
+    # with system config and user config.
+    qw(DEB_VENDOR),           # See deb-vendor(1).
+    qw(DPKG_DATADIR),         # See dpkg-architecure(1).
+    qw(DPKG_ORIGINS_DIR),     # See Dpkg::Vendor(3).
+    # See <https://reproducible-builds.org/specs/source-date-epoch>.
+    qw(SOURCE_DATE_EPOCH),
+);
+
+sub cleansed_environment {
+    # Consider only whitelisted variables which are not supposed to leak
+    # local user information.
+    my %env = map { $_ => $ENV{$_} } grep { exists $ENV{$_} } @env_whitelist;
+
+    # Record flags from dpkg-buildflags.
+    my $bf = Dpkg::BuildFlags->new();
+    $bf->load_system_config();
+    $bf->load_user_config();
+    $bf->load_environment_config();
+    foreach my $flag ($bf->list()) {
+        next if $bf->get_origin($flag) eq 'vendor';
+
+        # We do not need to record *_{STRIP,APPEND,PREPEND} as they
+        # have been used already to compute the above value.
+        $env{"DEB_${flag}_SET"} = $bf->get($flag);
     }
+
+    return join "\n", map { $_ . '="' . ($env{$_} =~ s/"/\\"/gr) . '"' }
+                      sort keys %env;
 }
 
 sub version {
@@ -144,28 +288,24 @@ sub usage {
 "Options:
   --build=<type>[,...]     specify the build <type>: full, source, binary,
                              any, all (default is \'full\').
-  -B                       build of only arch-specific files.
-  -A                       build of only arch-indep files.
   -c<control-file>         get control info from this file.
   -l<changelog-file>       get per-version info from this file.
   -f<files-list-file>      get .deb files list from this file.
   -F<changelog-format>     force changelog format.
+  -O<buildinfo-file>       name of the buildinfo output file.
   -u<upload-files-dir>     directory with files (default is '..').
+  --buildinfo-id=<id>      specify the buildinfo id for the output file.
+  --always-include-path    always include Build-Path.
   --admindir=<directory>   change the administrative directory.
-  --always-include-path    always include Build-Path
   -?, --help               show this help message.
       --version            show the version.
 "), $Dpkg::PROGNAME;
 }
 
 while (@ARGV) {
-    $_ = shift(@ARGV);
+    $_ = shift @ARGV ;
     if (m/^--build=(.*)$/) {
         set_build_type_from_options($1, $_);
-    } elsif (m/^-B$/) {
-        set_build_type(BUILD_ARCH_DEP, $_);
-    } elsif (m/^-A$/) {
-        set_build_type(BUILD_ARCH_INDEP, $_);
     } elsif (m/^-c(.*)$/) {
         $controlfile = $1;
     } elsif (m/^-l(.*)$/) {
@@ -176,10 +316,14 @@ while (@ARGV) {
         $changelogformat = $1;
     } elsif (m/^-u(.*)$/) {
         $uploadfilesdir = $1;
-    } elsif (m/^--admindir=(.*)$/) {
-        $admindir = $1;
+    } elsif (m/^-O(.*)$/) {
+        $outputfile = $1;
+    } elsif (m/^--buildinfo-id=(.*)$/) {
+        $buildinfo_id = $1;
     } elsif (m/^--always-include-path$/) {
         $always_include_path = 1;
+    } elsif (m/^--admindir=(.*)$/) {
+        $admindir = $1;
     } elsif (m/^-(?:\?|-help)$/) {
         usage();
         exit(0);
@@ -187,7 +331,7 @@ while (@ARGV) {
         version();
         exit(0);
     } else {
-        usageerr(g_("unknown option \`%s'"), $_);
+        usageerr(g_("unknown option '%s'"), $_);
     }
 }
 
@@ -209,16 +353,21 @@ my $sourceversion = $changelog->{'Binary-Only'} ?
                     $prev_changelog->{'Version'} : $changelog->{'Version'};
 my $binaryversion = $changelog->{'Version'};
 
-# include .dsc if available
+# Include .dsc if available.
 my $spackage = $changelog->{'Source'};
 (my $sversion = $sourceversion) =~ s/^\d+://;
-my $dsc = "${spackage}_${sversion}.dsc";
-my $dsc_pathname = "$uploadfilesdir/$dsc";
-if ( -e $dsc_pathname) {
-    $checksums->add_from_file($dsc_pathname, key => $dsc);
-} else {
-    warning(g_('no .dsc file found: the resulting .buildinfo will not be ' .
-               'usable to verify the provenance of the binaries.'));
+
+if (build_has_any(BUILD_SOURCE)) {
+    my $dsc = "${spackage}_${sversion}.dsc";
+    my $dsc_pathname = "$uploadfilesdir/$dsc";
+
+    if (-e $dsc_pathname) {
+        $checksums->add_from_file($dsc_pathname, key => $dsc);
+        push @archvalues, 'source';
+    } else {
+        warning(g_('no .dsc file found: the resulting .buildinfo will not be ' .
+                   'usable to verify the provenance of the binaries.'));
+    }
 }
 
 my $dist_count = 0;
@@ -238,20 +387,8 @@ foreach my $file ($dist->get_files()) {
     }
 }
 
-my $build_arch = get_build_arch();
-
 $fields->{'Format'} = $buildinfo_format;
-$fields->{'Build-Architecture'} = $build_arch;
-
 $fields->{'Source'} = $spackage;
-if ($changelog->{'Binary-Only'}) {
-    $fields->{'Source'} .= ' (' . $sourceversion . ')';
-    $fields->{'Binary-Only-Changes'} =
-        $changelog->{'Changes'} . "\n\n"
-        . ' -- ' . $changelog->{'Maintainer'}
-        . '  ' . $changelog->{'Date'};
-}
-
 $fields->{'Binary'} = join(' ', map { $_->{'Package'} } $control->get_packages());
 # Avoid overly long line by splitting over multiple lines
 if (length($fields->{'Binary'}) > 980) {
@@ -261,6 +398,16 @@ if (length($fields->{'Binary'}) > 980) {
 $fields->{'Architecture'} = join ' ', sort @archvalues;
 $fields->{'Version'} = $binaryversion;
 
+if ($changelog->{'Binary-Only'}) {
+    $fields->{'Source'} .= ' (' . $sourceversion . ')';
+    $fields->{'Binary-Only-Changes'} =
+        $changelog->{'Changes'} . "\n\n"
+        . ' -- ' . $changelog->{'Maintainer'}
+        . '  ' . $changelog->{'Date'};
+}
+
+$fields->{'Build-Architecture'} = get_build_arch();
+
 my $cwd = cwd();
 if ($always_include_path) {
     $fields->{'Build-Path'} = $cwd;
@@ -276,132 +423,56 @@ if ($always_include_path) {
 
 $checksums->export_to_control($fields);
 
-my ($facts, $depends, $essential_pkgs) = parse_status("$admindir/status");
-my %seen_pkgs;
-my @unprocessed_pkgs;
-
-# parse essential list
+$fields->{'Installed-Build-Depends'} = collect_installed_builddeps($control);
 
-append_deps(\@unprocessed_pkgs,
-            @{$essential_pkgs},
-            run_vendor_hook('builtin-build-depends'),
-            $control->get_source->{'Build-Depends'});
+$fields->{'Environment'} = "\n" . cleansed_environment();
 
-if (build_has_any(BUILD_ARCH_DEP)) {
-    append_deps(\@unprocessed_pkgs, $control->get_source->{'Build-Depends-Arch'});
-}
+#
+# Write out the generated .buildinfo file.
+#
 
-if (build_has_any(BUILD_ARCH_INDEP)) {
-    append_deps(\@unprocessed_pkgs, $control->get_source->{'Build-Depends-Indep'});
-}
+if (defined $outputfile) {
+    $buildinfo = basename($outputfile);
+} else {
+    if (not defined $buildinfo_id) {
+        require Digest::MD5;
 
-my $installed_deps = Dpkg::Deps::AND->new();
-while (my $pkg_name = shift @unprocessed_pkgs) {
-    next if $seen_pkgs{$pkg_name};
-    $seen_pkgs{$pkg_name} = 1;
+        my $buildinfo_contents = $fields->output();
 
-    my $required_architecture;
-    if ($pkg_name =~ /\A(.*):(.*)\z/) {
-        $pkg_name = $1;
-        my $arch = $2;
-        $required_architecture = $arch if $arch !~ /\A(?:all|any|native)\Z/
-    }
-    my $pkg;
-    my $qualified_pkg_name;
-    foreach my $installed_pkg (@{$facts->{pkg}->{$pkg_name}}) {
-        if (!defined $required_architecture || $required_architecture eq $installed_pkg->{architecture}) {
-            $pkg = $installed_pkg;
-            $qualified_pkg_name = $pkg_name . ':' . $installed_pkg->{architecture};
-            last;
-        }
-    }
-    if (defined $pkg) {
-        my $version = $pkg->{version};
-        my $architecture = $pkg->{architecture};
-        my $new_deps_str = defined $depends->{$qualified_pkg_name} ? deps_concat(@{$depends->{$qualified_pkg_name}}) : '';
-        my $new_deps = deps_parse($new_deps_str);
-        if (!defined $required_architecture) {
-            $installed_deps->add(Dpkg::Deps::Simple->new("$pkg_name (= $version)"));
-        } else {
-            $installed_deps->add(Dpkg::Deps::Simple->new("$qualified_pkg_name (= $version)"));
-            # Dependencies of foreign packages are also foreign packages (or Arch:all)
-            # so we need to qualify them as well. We figure out if the package is actually
-            # foreign by searching for an installed package of the right architecture.
-            deps_iterate($new_deps, sub {
-                my $dep = shift;
-                $dep->{archqual} //= $architecture
-                    if any { $_[0]->{architecture} eq $architecture }, @{$facts->{pkg}->{$dep->{package}}};
-                1;
-            });
-        }
-        # We add every sub-dependencies as we can't know which package in an OR
-        # dependency has been effectively used.
-        deps_iterate($new_deps, sub {
-            push @unprocessed_pkgs,
-                $_[0]->{package} . (defined $_[0]->{archqual} ? ':' . $_[0]->{archqual} : '');
-            1 });
-    } elsif (defined $facts->{virtualpkg}->{$pkg_name}) {
-        # virtual package: we can't know for sure which implementation
-        # is the one that has been used, so let's add them all...
-        foreach my $provided (@{$facts->{virtualpkg}->{$pkg_name}}) {
-            my ($provided_by, $provided_rel, $provided_ver) = @{$provided};
-            push @unprocessed_pkgs, $provided_by;
-        }
-    }
-    # else: it's a package in an OR dependency that has been satisfied otherwise
-}
-$installed_deps->sort();
-$installed_deps = "\n" . $installed_deps->output();
-$installed_deps =~ s/, /,\n/g;
-$fields->{'Installed-Build-Depends'} = $installed_deps;
-
-my $toolchain =
-    qr{( CC | CPP | CXX
-       | LD | AR | RANLIB
-       | MAKE | AWK
-       )}x;
-my $toolchain_flags =
-    qr{( CFLAGS | CPPFLAGS | CXXFLAGS
-       | OBJCFLAGS | OBJCXXFLAGS
-       | GCJFLAGS | FFLAGS
-       | LDFLAGS | ARFLAGS | MAKEFLAGS
-       )}x;
-my $environment_whitelist =
-    qr{\A( PATH
-         | ${toolchain}
-         | ${toolchain_flags}
-         | LD_LIBRARY_PATH # see ld(1)
-         | LANG | LC_(CTYPE|NUMERIC|TIME|COLLATE|MONETARY|MESSAGES
-                     |PAPER|NAME|ADDRESS|TELEPHONE|MEASUREMENT
-                     |IDENTIFICATION|ALL) # documented in locale(1)
-         | DEB_BUILD_OPTIONS # documented in dpkg-buildpackage(1)
-         | DEB_BUILD_PROFILES # documented in dpkg-buildpackage(1)
-                              # env var will be set if -P is given
-         # DEB_flag_{SET,STRIP,APPEND,PREPEND} will be recorded after
-         # being merged with system config and user config
-         | DEB_VENDOR # documented in deb-vendor(1)
-         | DPKG_DATADIR # documented in dpkg-architecure(1)
-         | DPKG_ORIGINS_DIR # used by Dpkg::Vendor
-         | SOURCE_DATE_EPOCH # see https://reproducible-builds.org/specs/source-date-epoch
-         )\z}x;
-
-my %environment = map { $_ => $ENV{$_} } (grep { /$environment_whitelist/ } sort keys %ENV);
-
-# Record flags from dpkg-buildflags
-my $bf = Dpkg::BuildFlags->new();
-$bf->load_system_config();
-$bf->load_user_config();
-$bf->load_environment_config();
-foreach my $flag ($bf->list()) {
-    if ($bf->get_origin($flag) ne 'vendor') {
-        $environment{"DEB_${flag}_SET"} = $bf->get($flag);
-        # We don't need to record *_{STRIP,APPEND,PREPEND} as they
-        # have been used already to compute the above value
+        my $timestamp = strftime('%Y%m%dT%H%M%Sz', gmtime);
+        my $buildinfo_md5 = Digest::MD5::md5_hex($buildinfo_contents);
+        $buildinfo_id = "$timestamp-" . substr($buildinfo_md5, 0, 8);
     }
+
+    $buildinfo = "${spackage}_${sversion}_${buildinfo_id}.buildinfo";
+    $outputfile = "$uploadfilesdir/$buildinfo";
 }
+$fields->save($outputfile);
+
+# XXX: handle output to STDOUT.
+
+my $section = $control->get_source->{'Section'} || '-';
+my $priority = $control->get_source->{'Priority'} || '-';
+
+# Obtain a lock on debian/control to avoid simultaneous updates
+# of debian/files when parallel building is in use
+my $lockfh;
+my $lockfile = 'debian/control';
+$lockfile = $controlfile if not -e $lockfile;
+
+sysopen $lockfh, $lockfile, O_WRONLY
+    or syserr(g_('cannot write %s'), $lockfile);
+file_lock($lockfh, $lockfile);
+
+$dist = Dpkg::Dist::Files->new();
+$dist->load($fileslistfile) if -e $fileslistfile;
+$dist->add_file($buildinfo, $section, $priority);
+$dist->save("$fileslistfile.new");
+
+rename "$fileslistfile.new", $fileslistfile
+    or syserr(g_('install new files list file'));
 
-$fields->{'Environment'} = "\n" .
-    join "\n", map { $_ . '="' . ($environment{$_} =~ s/"/\\"/gr) . '"' }
-                   (sort keys %environment);
+# Release the lock
+close $lockfh or syserr(g_('cannot close %s'), $lockfile);
 
-$fields->output(\*STDOUT);
+1;
diff --git a/t/pod-spell.t b/t/pod-spell.t
index a70fc6f..3f00250 100644
--- a/t/pod-spell.t
+++ b/t/pod-spell.t
@@ -49,6 +49,7 @@ ORed
 OpenPGP
 XDG
 archqual
+buildinfo
 bzip2
 canonicalized
 checksum
@@ -62,6 +63,7 @@ dpkg
 dpkg-buildflags
 dpkg-checkbuilddeps
 dpkg-dev
+dpkg-genbuildinfo
 dpkg-gencontrol
 dpkg-parsechangelog
 dsc

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



More information about the Reproducible-commits mailing list