summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/changelog7
-rw-r--r--debian/dpkg-dev.install1
-rw-r--r--debian/dpkg-dev.manpages2
-rw-r--r--man/Makefile.am4
-rw-r--r--man/deb-buildinfo.man178
-rw-r--r--man/dpkg-buildpackage.man31
-rw-r--r--man/dpkg-genbuildinfo.man153
-rw-r--r--man/po/po4a.cfg6
-rw-r--r--scripts/.gitignore1
-rw-r--r--scripts/Dpkg/Control.pm13
-rw-r--r--scripts/Dpkg/Control/FieldsCore.pm41
-rw-r--r--scripts/Dpkg/Control/Types.pm3
-rw-r--r--scripts/Dpkg/Vendor/Debian.pm2
-rw-r--r--scripts/Dpkg/Vendor/Default.pm12
-rw-r--r--scripts/Makefile.am2
-rw-r--r--scripts/Test/Dpkg.pm1
-rwxr-xr-xscripts/dpkg-buildpackage.pl35
-rwxr-xr-xscripts/dpkg-genbuildinfo.pl491
-rw-r--r--scripts/po/POTFILES.in1
-rw-r--r--scripts/t/dpkg_buildpackage/test-source_0_all.changes3
-rw-r--r--scripts/t/dpkg_buildpackage/test-source_0_any.changes3
-rw-r--r--scripts/t/dpkg_buildpackage/test-source_0_binary.changes3
-rw-r--r--scripts/t/dpkg_buildpackage/test-source_0_full.changes3
-rw-r--r--t/pod-spell.t2
24 files changed, 982 insertions, 16 deletions
diff --git a/debian/changelog b/debian/changelog
index 1143bd9ce..e924ff751 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -62,6 +62,10 @@ dpkg (1.18.11) UNRELEASED; urgency=medium
when printing to STDOUT (via -O).
* Do not add architectures to .changes Architecture field for artifacts
that are not a .deb or .udeb in dpkg-genchanges.
+ * Add support for .buildinfo files:
+ - Add new dpkg-genbuildinfo command.
+ - Hook it into the dpkg-buildpackage machinery.
+ Based on a patch by Jérémy Bobbio <lunar@debian.org>. Closes: #138409
* Architecture support:
- Add support for AIX operating system.
- Add a version pseudo-field to the arch tables.
@@ -113,6 +117,9 @@ dpkg (1.18.11) UNRELEASED; urgency=medium
instead of FileHandle.
- Add new Dpkg::PROGTAR variable to store GNU tar command name.
- Add new Dpkg::PROGMAKE variable to store GNU make command name.
+ - Add new CTRL_FILE_BUILDINFO type to Dpkg::Control.
+ - Add new .buildinfo fields to Dpkg::Control::Fields.
+ - Add new builtin-system-build-paths Dpkg::Vendor hook.
* Packaging:
- Add liblocale-gettext-perl to libdpkg-perl Recommends.
- Wrap and document dependency relationships.
diff --git a/debian/dpkg-dev.install b/debian/dpkg-dev.install
index 5cec6fe4d..2ed6d6525 100644
--- a/debian/dpkg-dev.install
+++ b/debian/dpkg-dev.install
@@ -6,6 +6,7 @@ usr/bin/dpkg-buildflags
usr/bin/dpkg-buildpackage
usr/bin/dpkg-checkbuilddeps
usr/bin/dpkg-distaddfile
+usr/bin/dpkg-genbuildinfo
usr/bin/dpkg-genchanges
usr/bin/dpkg-gencontrol
usr/bin/dpkg-gensymbols
diff --git a/debian/dpkg-dev.manpages b/debian/dpkg-dev.manpages
index e53918393..0169b6a32 100644
--- a/debian/dpkg-dev.manpages
+++ b/debian/dpkg-dev.manpages
@@ -1,3 +1,4 @@
+debian/tmp/usr/share/man/*/deb-buildinfo.5
debian/tmp/usr/share/man/*/deb-changelog.5
debian/tmp/usr/share/man/*/deb-changes.5
debian/tmp/usr/share/man/*/deb-control.5
@@ -25,6 +26,7 @@ debian/tmp/usr/share/man/*/dpkg-buildflags.1
debian/tmp/usr/share/man/*/dpkg-buildpackage.1
debian/tmp/usr/share/man/*/dpkg-checkbuilddeps.1
debian/tmp/usr/share/man/*/dpkg-distaddfile.1
+debian/tmp/usr/share/man/*/dpkg-genbuildinfo.1
debian/tmp/usr/share/man/*/dpkg-genchanges.1
debian/tmp/usr/share/man/*/dpkg-gencontrol.1
debian/tmp/usr/share/man/*/dpkg-gensymbols.1
diff --git a/man/Makefile.am b/man/Makefile.am
index bf468a250..e5f3c54a8 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -1,6 +1,7 @@
## Process this file with automake to produce Makefile.in
man_MANS = \
+ deb-buildinfo.5 \
deb-changelog.5 \
deb-changes.5 \
deb-conffiles.5 \
@@ -30,6 +31,7 @@ man_MANS = \
dpkg-deb.1 \
dpkg-distaddfile.1 \
dpkg-divert.1 \
+ dpkg-genbuildinfo.1 \
dpkg-genchanges.1 \
dpkg-gencontrol.1 \
dpkg-gensymbols.1 \
@@ -70,6 +72,7 @@ endif
CLEANFILES = $(man_MANS)
EXTRA_DIST = \
+ deb-buildinfo.man \
deb-changelog.man \
deb-changes.man \
deb-conffiles.man \
@@ -99,6 +102,7 @@ EXTRA_DIST = \
dpkg-deb.man \
dpkg-distaddfile.man \
dpkg-divert.man \
+ dpkg-genbuildinfo.man \
dpkg-genchanges.man \
dpkg-gencontrol.man \
dpkg-gensymbols.man \
diff --git a/man/deb-buildinfo.man b/man/deb-buildinfo.man
new file mode 100644
index 000000000..b5e4c5baf
--- /dev/null
+++ b/man/deb-buildinfo.man
@@ -0,0 +1,178 @@
+.\" dpkg manual page - deb-buildinfo(5)
+.\"
+.\" Copyright © 1995-1996 Ian Jackson <ijackson@chiark.greenend.org.uk>
+.\" Copyright © 2010 Russ Allbery <rra@debian.org>
+.\" Copyright © 2015-2016 Guillem Jover <guillem@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 "%RELEASE_DATE%" "%VERSION%" "Debian"
+.nh
+.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 \fB.buildinfo\fP 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
+The \fB.buildinfo\fP filename by default has the following form:
+
+\fIsource-name\fP\fB_\fP\fIsource-version\fP\fB_\fP\fIbuildinfo-id\fP\fB.buildinfo\fP
+
+where \fIbuildinfo-id\fP is composed of the build time formatted as
+\fBstrftime\fP(2) «%Y%m%dT%H%M%Sz», followed by a minus ‘\-’ and the
+eight left-most characters from the \fB.buildinfo\fP's file contents MD5
+digest.
+.
+.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 (‘.’) 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 \fBChecksums\-Md5\fP, SHA-1 for \fBChecksums\-Sha1\fP and
+SHA-256 for \fBChecksums\-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\-Origin: " \fIname\fP"
+The name of the distribution this package is originating from.
+.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\-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 (‘=’)
+and the variable's quoted value, using double quotes (‘"’), and
+backslashes escaped (‘\\\\’).
+.
+.\" .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.man b/man/dpkg-buildpackage.man
index 923e10ce7..599ff1e80 100644
--- a/man/dpkg-buildpackage.man
+++ b/man/dpkg-buildpackage.man
@@ -63,6 +63,11 @@ 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.
+Several \fBdpkg\-buildpackage\fP options are forwarded to
+\fBdpkg\-genbuildinfo\fP.
+.IP \fB7.\fP 3
It runs the \fBchanges\fP hook and calls \fBdpkg\-genchanges\fP to
generate a \fB.changes\fP file.
The name of the \fB.changes\fP file will depend on the type of build and
@@ -75,22 +80,22 @@ or otherwise for a build that includes \fBsource\fP the name will be
\fIsource-name\fP\fB_\fP\fIsource-version\fP\fB_\fP\fBsource.changes\fP.
Many \fBdpkg\-buildpackage\fP options are forwarded to
\fBdpkg\-genchanges\fP.
-.IP \fB7.\fP 3
+.IP \fB8.\fP 3
It runs the \fBpostclean\fP hook and if \fB\-tc\fP or \fB\-\-post\-clean\fP
is specified, it will call \fBfakeroot debian/rules clean\fP again.
-.IP \fB8.\fP 3
-It calls \fBdpkg\-source \-\-after\-build\fP.
.IP \fB9.\fP 3
+It calls \fBdpkg\-source \-\-after\-build\fP.
+.IP \fB10.\fP 3
It runs the \fBcheck\fP hook and calls a package checker for the
\fB.changes\fP file (if a command is specified in \fBDEB_CHECK_COMMAND\fP or
with \fB\-\-check\-command\fP).
-.IP \fB10.\fP 3
+.IP \fB11.\fP 3
It runs the \fBsign\fP hook and calls \fBgpg2\fP or \fBgpg\fP to sign
the \fB.dsc\fP file (if any, unless \fB\-us\fP or \fB\-\-unsigned\-source\fP
is specified or on UNRELEASED builds), and the \fB.changes\fP file
(unless \fB\-uc\fP or \fB\-\-unsigned\-changes\fP is specified or on
UNRELEASED builds).
-.IP \fB11.\fP 3
+.IP \fB12.\fP 3
It runs the \fBdone\fP hook.
.
.SH OPTIONS
@@ -365,6 +370,21 @@ The source package version (without the epoch).
The upstream version.
.RE
.TP
+.BI \-\-buildinfo-id= identifier
+Specify the identifier part of the \fB.buildinfo\fP file name
+(since dpkg 1.18.11).
+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: it 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.11).
+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
control (\fB.dsc\fP) file or a \fB.changes\fP file it will run
@@ -519,6 +539,7 @@ and initial arguments for
.BR dpkg\-source (1),
.BR dpkg\-architecture (1),
.BR dpkg\-buildflags (1),
+.BR dpkg\-genbuildinfo (1),
.BR dpkg\-genchanges (1),
.BR fakeroot (1),
.BR lintian (1),
diff --git a/man/dpkg-genbuildinfo.man b/man/dpkg-genbuildinfo.man
new file mode 100644
index 000000000..5cac25565
--- /dev/null
+++ b/man/dpkg-genbuildinfo.man
@@ -0,0 +1,153 @@
+.\" dpkg manual page - dpkg-genbuildinfo(1)
+.\"
+.\" Copyright © 1995-1996 Ian Jackson <ian@chiark.chu.cam.ac.uk>
+.\" Copyright © 2000 Wichert Akkerman <wakkerma@debian.org>
+.\" Copyright © 2008-2010 Raphaël Hertzog <hertzog@debian.org>
+.\" Copyright © 2006-2016 Guillem Jover <guillem@debian.org>
+.\" Copyright © 2015 Jérémy Bobbio <lunar@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 dpkg\-genbuildinfo 1 "%RELEASE_DATE%" "%VERSION%" "dpkg utilities"
+.nh
+.SH NAME
+dpkg\-genbuildinfo \- generate Debian .buildinfo files
+.
+.SH SYNOPSIS
+.B dpkg\-genbuildinfo
+.RI [ option ...]
+.br
+.
+.SH DESCRIPTION
+.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 artifacts
+.RB ( .buildinfo " file)."
+.P
+This command was introduced in dpkg 1.18.11.
+.
+.SH OPTIONS
+.TP
+.BI \-\-build= type
+Specifies the build \fItype\fP from a comma-separated list of components.
+
+The allowed values are:
+.RS
+.TP
+.B any
+Generate build information including unqualified build dependencies
+(\fBBuild-Depends\fP) and architecture specific build dependencies
+(\fBBuild-Depends-Arch\fP).
+.TP
+.B all
+Generate build information including unqualified build dependencies
+(\fBBuild-Depends\fP) and architecture independent build dependencies
+(\fBBuild-Depends-Indep\fP).
+.TP
+.B source
+Effectively ignored; generate build information with just the unqualified
+build dependencies (\fBBuild-Depends\fP).
+.TP
+.B binary
+Generate build information with all three types of build dependencies.
+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.
+.RE
+.TP
+.BI \-c controlfile
+Specifies the main source control file to read information from. The
+default is
+.BR debian/control .
+.TP
+.BI \-l changelog-file
+Specifies the changelog file to read information from. The
+default is
+.BR debian/changelog .
+.TP
+.BI \-f files-list-file
+Specifies where is the list of files that have been produced by the build,
+rather than using
+.BR debian/files .
+.TP
+.BI \-F changelog-format
+Specifies the format of the changelog. See \fBdpkg\-parsechangelog\fP(1)
+for information about alternative formats.
+.TP
+.BR \-O [\fIfilename\fP]
+Print the buildinfo file to standard output (or \fIfilename\fP if specified)
+rather than to
+.IB dir / source-name _ source-version _ buildinfo-id .buildinfo
+(where \fIdir\fP is \fB..\fP by default or \fIupload-files-dir\fP
+if \fB\-u\fP was used).
+.TP
+.BI \-u upload-files-dir
+Look for the files to be uploaded in
+.I upload-files-dir
+rather than
+.B ..
+(\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 \-\-buildinfo-id= identifier
+Specify the identifier part of the \fB.buildinfo\fP file name.
+By default, \fBdpkg\-genbuildinfo\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: it 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 \-\-always\-include\-path
+By default, the \fBBuild\-Path\fR field will only be written if the current
+directory starts with a whitelisted pattern.
+
+On Debian and derivatives the pattern matches on \fB/build/\fR at the start
+of the pathname.
+
+Specify this option to always write a \fBBuild\-Path\fR field when generating
+the \fB.buildinfo\fR.
+.TP
+.BI \-\-admindir= dir
+Change the location of the \fBdpkg\fR database. The default location is
+\fI/var/lib/dpkg\fP.
+.TP
+.B \-q
+.B dpkg\-genbuildinfo
+might produce informative messages on standard error.
+.B \-q
+suppresses these messages.
+.TP
+.BR \-? ", " \-\-help
+Show the usage message and exit.
+.TP
+.BR \-\-version
+Show the version and exit.
+.
+.SH FILES
+.TP
+.B debian/files
+The list of generated files.
+.B dpkg\-genbuildinfo
+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 418435455..3aeb93c02 100644
--- a/man/po/po4a.cfg
+++ b/man/po/po4a.cfg
@@ -10,6 +10,9 @@
[type:man] deb822.man $lang:$lang/deb822.man \
add_$lang:po/$lang.add
+[type:man] deb-buildinfo.man $lang:$lang/deb-buildinfo.man \
+ add_$lang:po/$lang.add
+
[type:man] deb-changelog.man $lang:$lang/deb-changelog.man \
add_$lang:po/$lang.add
@@ -88,6 +91,9 @@
[type:man] dpkg-buildpackage.man $lang:$lang/dpkg-buildpackage.man \
add_$lang:po/$lang.add
+[type:man] dpkg-genbuildinfo.man $lang:$lang/dpkg-genbuildinfo.man \
+ add_$lang:po/$lang.add
+
[type:man] dpkg-checkbuilddeps.man $lang:$lang/dpkg-checkbuilddeps.man \
add_$lang:po/$lang.add
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 380ad9182..0d1f29ac9 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -3,6 +3,7 @@ dpkg-buildflags
dpkg-buildpackage
dpkg-checkbuilddeps
dpkg-distaddfile
+dpkg-genbuildinfo
dpkg-genchanges
dpkg-gencontrol
dpkg-gensymbols
diff --git a/scripts/Dpkg/Control.pm b/scripts/Dpkg/Control.pm
index e65891f3a..f41f250d5 100644
--- a/scripts/Dpkg/Control.pm
+++ b/scripts/Dpkg/Control.pm
@@ -18,7 +18,7 @@ package Dpkg::Control;
use strict;
use warnings;
-our $VERSION = '1.02';
+our $VERSION = '1.03';
our @EXPORT = qw(
CTRL_UNKNOWN
CTRL_INFO_SRC
@@ -28,6 +28,7 @@ our @EXPORT = qw(
CTRL_REPO_RELEASE
CTRL_PKG_SRC
CTRL_PKG_DEB
+ CTRL_FILE_BUILDINFO
CTRL_FILE_CHANGES
CTRL_FILE_VENDOR
CTRL_FILE_STATUS
@@ -104,6 +105,10 @@ Corresponds to a .dsc file of a Debian source package.
Corresponds to the F<control> file generated by dpkg-gencontrol
(F<DEBIAN/control>) and to the same file inside .deb packages.
+=item CTRL_FILE_BUILDINFO
+
+Corresponds to a .buildinfo file.
+
=item CTRL_FILE_CHANGES
Corresponds to a .changes file.
@@ -210,6 +215,8 @@ sub set_options {
$$self->{name} = sprintf(g_('%s file'), '.dsc');
} elsif ($t == CTRL_PKG_DEB) {
$$self->{name} = g_('control info of a .deb package');
+ } elsif ($t == CTRL_FILE_BUILDINFO) {
+ $$self->{name} = g_('build information file');
} elsif ($t == CTRL_FILE_CHANGES) {
$$self->{name} = sprintf(g_('%s file'), '.changes');
} elsif ($t == CTRL_FILE_VENDOR) {
@@ -240,6 +247,10 @@ sub get_type {
=head1 CHANGES
+=head2 Version 1.03 (dpkg 1.18.11)
+
+New type: CTRL_FILE_BUILDINFO.
+
=head2 Version 1.02 (dpkg 1.18.8)
New type: CTRL_TESTS.
diff --git a/scripts/Dpkg/Control/FieldsCore.pm b/scripts/Dpkg/Control/FieldsCore.pm
index bbc19aa83..4c0ae50c8 100644
--- a/scripts/Dpkg/Control/FieldsCore.pm
+++ b/scripts/Dpkg/Control/FieldsCore.pm
@@ -66,7 +66,7 @@ use constant {
# Deprecated fields of dpkg's status file are also not listed
our %FIELDS = (
'Architecture' => {
- allowed => (ALL_PKG | ALL_SRC | CTRL_FILE_CHANGES) & (~CTRL_INFO_SRC),
+ allowed => (ALL_PKG | ALL_SRC | CTRL_FILE_BUILDINFO | CTRL_FILE_CHANGES) & (~CTRL_INFO_SRC),
separator => FIELD_SEP_SPACE,
},
'Architectures' => {
@@ -74,7 +74,7 @@ our %FIELDS = (
separator => FIELD_SEP_SPACE,
},
'Binary' => {
- allowed => CTRL_PKG_SRC | CTRL_FILE_CHANGES,
+ allowed => CTRL_PKG_SRC | CTRL_FILE_BUILDINFO | CTRL_FILE_CHANGES,
# XXX: This field values are separated either by space or comma
# depending on the context.
separator => FIELD_SEP_SPACE | FIELD_SEP_COMMA,
@@ -82,6 +82,9 @@ our %FIELDS = (
'Binary-Only' => {
allowed => ALL_CHANGES,
},
+ 'Binary-Only-Changes' => {
+ allowed => CTRL_FILE_BUILDINFO,
+ },
'Breaks' => {
allowed => ALL_PKG,
separator => FIELD_SEP_COMMA,
@@ -91,6 +94,9 @@ our %FIELDS = (
'Bugs' => {
allowed => (ALL_PKG | CTRL_INFO_SRC | CTRL_FILE_VENDOR) & (~CTRL_INFO_PKG),
},
+ 'Build-Architecture' => {
+ allowed => CTRL_FILE_BUILDINFO,
+ },
'Build-Conflicts' => {
allowed => ALL_SRC,
separator => FIELD_SEP_COMMA,
@@ -130,6 +136,12 @@ our %FIELDS = (
'Build-Essential' => {
allowed => ALL_PKG,
},
+ 'Build-Origin' => {
+ allowed => CTRL_FILE_BUILDINFO,
+ },
+ 'Build-Path' => {
+ allowed => CTRL_FILE_BUILDINFO,
+ },
'Build-Profiles' => {
allowed => CTRL_INFO_PKG,
separator => FIELD_SEP_SPACE,
@@ -214,6 +226,10 @@ our %FIELDS = (
dependency => 'union',
dep_order => 5,
},
+ 'Environment' => {
+ allowed => CTRL_FILE_BUILDINFO,
+ separator => FIELD_SEP_LINE,
+ },
'Essential' => {
allowed => ALL_PKG,
},
@@ -230,11 +246,17 @@ our %FIELDS = (
separator => FIELD_SEP_LINE | FIELD_SEP_SPACE,
},
'Format' => {
- allowed => CTRL_PKG_SRC | CTRL_FILE_CHANGES | CTRL_COPYRIGHT_HEADER,
+ allowed => CTRL_PKG_SRC | CTRL_FILE_CHANGES | CTRL_COPYRIGHT_HEADER | CTRL_FILE_BUILDINFO,
},
'Homepage' => {
allowed => ALL_SRC | ALL_PKG,
},
+ 'Installed-Build-Depends' => {
+ allowed => CTRL_FILE_BUILDINFO,
+ separator => FIELD_SEP_COMMA,
+ dependency => 'union',
+ dep_order => 11,
+ },
'Installed-Size' => {
allowed => ALL_PKG & ~CTRL_INFO_PKG,
},
@@ -311,7 +333,7 @@ our %FIELDS = (
separator => FIELD_SEP_LINE | FIELD_SEP_SPACE,
},
'Source' => {
- allowed => (ALL_PKG | ALL_SRC | ALL_CHANGES | CTRL_COPYRIGHT_HEADER) &
+ allowed => (ALL_PKG | ALL_SRC | ALL_CHANGES | CTRL_COPYRIGHT_HEADER | CTRL_FILE_BUILDINFO) &
(~(CTRL_INDEX_SRC | CTRL_INFO_PKG)),
},
'Standards-Version' => {
@@ -419,7 +441,7 @@ our %FIELDS = (
allowed => CTRL_FILE_VENDOR,
},
'Version' => {
- allowed => (ALL_PKG | ALL_SRC | ALL_CHANGES) &
+ allowed => (ALL_PKG | ALL_SRC | CTRL_FILE_BUILDINFO | ALL_CHANGES) &
(~(CTRL_INFO_SRC | CTRL_INFO_PKG)),
},
);
@@ -427,7 +449,7 @@ our %FIELDS = (
my @checksum_fields = map { &field_capitalize("Checksums-$_") } checksums_get_list();
my @sum_fields = map { $_ eq 'md5' ? 'MD5sum' : &field_capitalize($_) }
checksums_get_list();
-&field_register($_, CTRL_PKG_SRC | CTRL_FILE_CHANGES) foreach @checksum_fields;
+&field_register($_, CTRL_PKG_SRC | CTRL_FILE_CHANGES | CTRL_FILE_BUILDINFO) foreach @checksum_fields;
&field_register($_, CTRL_INDEX_PKG | CTRL_REPO_RELEASE,
separator => FIELD_SEP_LINE | FIELD_SEP_SPACE) foreach @sum_fields;
@@ -446,6 +468,13 @@ our %FIELD_ORDER = (
Vcs-Svn Testsuite Testsuite-Triggers), &field_list_src_dep(),
qw(Package-List), @checksum_fields, qw(Files)
],
+ CTRL_FILE_BUILDINFO() => [
+ qw(Format Source Binary Architecture Version
+ Binary-Only-Changes),
+ @checksum_fields,
+ qw(Build-Origin Build-Architecture Build-Path
+ Installed-Build-Depends Environment),
+ ],
CTRL_FILE_CHANGES() => [
qw(Format Date Source Binary Binary-Only Built-For-Profiles Architecture
Version Distribution Urgency Maintainer Changed-By Description
diff --git a/scripts/Dpkg/Control/Types.pm b/scripts/Dpkg/Control/Types.pm
index 1bb3e0ae4..445079d41 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
@@ -86,6 +87,8 @@ use constant {
CTRL_COPYRIGHT_LICENSE => 8192,
# Package test suite control file in debian/tests/control.
CTRL_TESTS => 16384,
+ # .buildinfo file
+ CTRL_FILE_BUILDINFO => 32768,
};
=head1 CHANGES
diff --git a/scripts/Dpkg/Vendor/Debian.pm b/scripts/Dpkg/Vendor/Debian.pm
index 560db2de8..bbba00d52 100644
--- a/scripts/Dpkg/Vendor/Debian.pm
+++ b/scripts/Dpkg/Vendor/Debian.pm
@@ -83,6 +83,8 @@ sub run_hook {
$self->_add_reproducible_flags(@params);
$self->_add_sanitize_flags(@params);
$self->_add_hardening_flags(@params);
+ } elsif ($hook eq 'builtin-system-build-paths') {
+ return qw(/build/);
} else {
return $self->SUPER::run_hook($hook, @params);
}
diff --git a/scripts/Dpkg/Vendor/Default.pm b/scripts/Dpkg/Vendor/Default.pm
index 9d53097f9..40815efde 100644
--- a/scripts/Dpkg/Vendor/Default.pm
+++ b/scripts/Dpkg/Vendor/Default.pm
@@ -130,6 +130,16 @@ The hook is called in Dpkg::BuildFlags to allow the vendor to override
the default values set for the various build flags. $flags is a
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 B<Build-Path> field (since dpkg 1.18.11). 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
=cut
@@ -160,6 +170,8 @@ sub run_hook {
my ($textref, $ch_info) = @params;
} elsif ($hook eq 'update-buildflags') {
my $flags = shift @params;
+ } elsif ($hook eq 'builtin-system-build-paths') {
+ return ();
}
# Default return value for unknown/unimplemented hooks
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index dba3d7777..417e3b3e4 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -8,6 +8,7 @@ bin_SCRIPTS = \
dpkg-buildpackage \
dpkg-checkbuilddeps \
dpkg-distaddfile \
+ dpkg-genbuildinfo \
dpkg-genchanges \
dpkg-gencontrol \
dpkg-gensymbols \
@@ -27,6 +28,7 @@ EXTRA_DIST = \
dpkg-buildpackage.pl \
dpkg-checkbuilddeps.pl \
dpkg-distaddfile.pl \
+ dpkg-genbuildinfo.pl \
dpkg-genchanges.pl \
dpkg-gencontrol.pl \
dpkg-gensymbols.pl \
diff --git a/scripts/Test/Dpkg.pm b/scripts/Test/Dpkg.pm
index e0395dec6..5dc8732c0 100644
--- a/scripts/Test/Dpkg.pm
+++ b/scripts/Test/Dpkg.pm
@@ -111,6 +111,7 @@ sub test_neutralize_checksums
open my $fh, '<', $filename or die;
while (<$fh>) {
s/^ ([0-9a-f]{32,}) [1-9][0-9]* /q{ } . $1 =~ tr{0-9a-f}{0}r . q{ 0 }/e;
+ s/^( 0{32,} 0(?: [\w]* [\w]*)? [^_]*_[^_]*)_[^.]*\.(buildinfo)$/$1_20160101T123000z-00000000.$2/;
print { $fhnew } $_;
}
close $fh or die;
diff --git a/scripts/dpkg-buildpackage.pl b/scripts/dpkg-buildpackage.pl
index 52aec0495..2a1b78266 100755
--- a/scripts/dpkg-buildpackage.pl
+++ b/scripts/dpkg-buildpackage.pl
@@ -38,6 +38,7 @@ use Dpkg::BuildProfiles qw(set_build_profiles);
use Dpkg::Conf;
use Dpkg::Compression;
use Dpkg::Checksums;
+use Dpkg::Package;
use Dpkg::Version;
use Dpkg::Control;
use Dpkg::Control::Info;
@@ -92,8 +93,11 @@ sub usage {
command to check the .changes file (no default).
--check-option=<opt> pass <opt> to check <command>.
--hook-<name>=<command> set <command> as the hook <name>, known hooks:
- init preclean source build binary changes
- postclean check sign done
+ init preclean source build binary buildinfo
+ changes postclean check sign done
+ --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).
@@ -168,9 +172,11 @@ my $since;
my $maint;
my $changedby;
my $desc;
+my $buildinfo_id;
+my @buildinfo_opts;
my @changes_opts;
my @hook_names = qw(
- init preclean source build binary changes postclean check sign done
+ init preclean source build binary buildinfo changes postclean check sign done
);
my %hook;
$hook{$_} = undef foreach @hook_names;
@@ -205,6 +211,8 @@ while (@ARGV) {
$admindir = $1;
} elsif (/^--source-option=(.*)$/) {
push @source_opts, $1;
+ } elsif (/^--buildinfo-option=(.*)$/) {
+ push @buildinfo_opts, $1;
} elsif (/^--changes-option=(.*)$/) {
push @changes_opts, $1;
} elsif (/^(?:-j|--jobs=)(\d*|auto)$/) {
@@ -227,6 +235,8 @@ while (@ARGV) {
usageerr(g_('missing hook %s command'), $hook_name)
if not defined $hook_cmd;
$hook{$hook_name} = $hook_cmd;
+ } elsif (/^--buildinfo-id=(.*)$/) {
+ $buildinfo_id = $1;
} elsif (/^(?:-p|--sign-command=)(.*)$/) {
$signcommand = $1;
} elsif (/^(?:-k|--sign-key=)(.*)$/) {
@@ -389,6 +399,14 @@ if (defined $parallel) {
$build_opts->export();
}
+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;
my $cwd = cwd();
@@ -530,15 +548,24 @@ run_hook('build', build_has_any(BUILD_BINARY));
# This is a temporary measure to not break too many packages on a flag day.
build_target_fallback();
+my $build_types = get_build_options_from_type();
+
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, "--buildinfo-id=$buildinfo_id" if $buildinfo_id;
+push @buildinfo_opts, "--admindir=$admindir" if $admindir;
+
+withecho('dpkg-genbuildinfo', @buildinfo_opts);
+
run_hook('changes', 1);
-my $build_types = get_build_options_from_type();
push @changes_opts, "--build=$build_types" if build_has_none(BUILD_DEFAULT);
push @changes_opts, "-m$maint" if defined $maint;
push @changes_opts, "-e$changedby" if defined $changedby;
diff --git a/scripts/dpkg-genbuildinfo.pl b/scripts/dpkg-genbuildinfo.pl
new file mode 100755
index 000000000..cbb052327
--- /dev/null
+++ b/scripts/dpkg-genbuildinfo.pl
@@ -0,0 +1,491 @@
+#!/usr/bin/perl
+#
+# dpkg-genbuildinfo
+#
+# Copyright © 1996 Ian Jackson
+# Copyright © 2000,2001 Wichert Akkerman
+# Copyright © 2003-2013 Yann Dirson <dirson@debian.org>
+# Copyright © 2006-2016 Guillem Jover <guillem@debian.org>
+# Copyright © 2014 Niko Tyni <ntyni@debian.org>
+# Copyright © 2014-2015 Jérémy Bobbio <lunar@debian.org>
+#
+# This program 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 program 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/>.
+
+use strict;
+use warnings;
+
+use Cwd;
+use File::Basename;
+use POSIX qw(:fcntl_h strftime);
+
+use Dpkg ();
+use Dpkg::Gettext;
+use Dpkg::Checksums;
+use Dpkg::ErrorHandling;
+use Dpkg::Arch qw(get_build_arch);
+use Dpkg::Build::Types;
+use Dpkg::BuildFlags;
+use Dpkg::BuildProfiles qw(get_build_profiles);
+use Dpkg::Control::Info;
+use Dpkg::Control::Fields;
+use Dpkg::Control;
+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(get_current_vendor run_vendor_hook);
+
+textdomain('dpkg-dev');
+
+my $controlfile = 'debian/control';
+my $changelogfile = 'debian/changelog';
+my $changelogformat;
+my $fileslistfile = 'debian/files';
+my $uploadfilesdir = '..';
+my $outputfile;
+my $stdout = 0;
+my $admindir = $Dpkg::ADMINDIR;
+my $always_include_path = 0;
+my @build_profiles = get_build_profiles();
+my $buildinfo_format = '0.1';
+my $buildinfo_id;
+my $buildinfo;
+
+my $checksums = Dpkg::Checksums->new();
+my %archadded;
+my @archvalues;
+
+# 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);
+ while (<$status_fh>) {
+ next unless /^Status: .*ok installed$/m;
+
+ my ($package) = /^Package: (.*)$/m;
+ my ($version) = /^Version: (.*)$/m;
+ my ($arch) = /^Architecture: (.*)$/m;
+ my ($multiarch) = /^Multi-Arch: (.*)$/m;
+
+ $facts->add_installed_package($package, $version, $arch, $multiarch);
+
+ if (/^Essential: yes$/m) {
+ push @essential_pkgs, $package;
+ }
+
+ if (/^Provides: (.*)$/m) {
+ my $provides = deps_parse($1, reduce_arch => 1, union => 1);
+
+ next if not defined $provides;
+
+ deps_iterate($provides, sub {
+ my $dep = shift;
+ $facts->add_provided_package($dep->{package}, $dep->{relation},
+ $dep->{version}, $package);
+ });
+ }
+
+ if (/^(?:Pre-)?Depends: (.*)$/m) {
+ foreach (split /,\s*/, $1) {
+ push @{$depends{"$package:$arch"}}, $_;
+ }
+ }
+ }
+ close $status_fh;
+
+ return ($facts, \%depends, \@essential_pkgs);
+}
+
+sub append_deps {
+ my $pkgs = shift;
+
+ 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 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
+ });
+ }
+}
+
+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->simplify_deps(Dpkg::Deps::KnownFacts->new());
+ $installed_deps->sort();
+ $installed_deps = "\n" . $installed_deps->output();
+ $installed_deps =~ s/, /,\n/g;
+
+ return $installed_deps;
+}
+
+my @env_whitelist = (
+ # Toolchain.
+ qw(CC CPP CXX OBJC OBJCXX PC FC M2C AS LD AR RANLIB MAKE AWK LEX YACC),
+ # 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_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 {
+ printf g_("Debian %s version %s.\n"), $Dpkg::PROGNAME, $Dpkg::PROGVERSION;
+
+ printf g_('
+This is free software; see the GNU General Public License version 2 or
+later for copying conditions. There is NO warranty.
+');
+}
+
+sub usage {
+ printf g_(
+'Usage: %s [<option>...]')
+ . "\n\n" . g_(
+"Options:
+ --build=<type>[,...] specify the build <type>: full, source, binary,
+ any, all (default is \'full\').
+ -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>] write to stdout (or <buildinfo-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.
+ -?, --help show this help message.
+ --version show the version.
+"), $Dpkg::PROGNAME;
+}
+
+while (@ARGV) {
+ $_ = shift @ARGV ;
+ if (m/^--build=(.*)$/) {
+ set_build_type_from_options($1, $_);
+ } elsif (m/^-c(.*)$/) {
+ $controlfile = $1;
+ } elsif (m/^-l(.*)$/) {
+ $changelogfile = $1;
+ } elsif (m/^-f(.*)$/) {
+ $fileslistfile = $1;
+ } elsif (m/^-F([0-9a-z]+)$/) {
+ $changelogformat = $1;
+ } elsif (m/^-u(.*)$/) {
+ $uploadfilesdir = $1;
+ } elsif (m/^-O$/) {
+ $stdout = 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);
+ } elsif (m/^--version$/) {
+ version();
+ exit(0);
+ } else {
+ usageerr(g_("unknown option '%s'"), $_);
+ }
+}
+
+my $control = Dpkg::Control::Info->new($controlfile);
+my $fields = Dpkg::Control->new(type => CTRL_FILE_BUILDINFO);
+my $dist = Dpkg::Dist::Files->new();
+
+# Retrieve info from the current changelog entry.
+my %options = (file => $changelogfile);
+$options{changelogformat} = $changelogformat if $changelogformat;
+my $changelog = changelog_parse(%options);
+
+# Retrieve info from the former changelog entry to handle binNMUs.
+$options{count} = 1;
+$options{offset} = 1;
+my $prev_changelog = changelog_parse(%options);
+
+my $sourceversion = $changelog->{'Binary-Only'} ?
+ $prev_changelog->{'Version'} : $changelog->{'Version'};
+my $binaryversion = $changelog->{'Version'};
+
+# Include .dsc if available.
+my $spackage = $changelog->{'Source'};
+(my $sversion = $sourceversion) =~ s/^\d+://;
+
+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;
+
+$dist_count = $dist->load($fileslistfile) if -e $fileslistfile;
+
+warning(g_('binary build with no binary artifacts found; .buildinfo will be meaningless'))
+ if $dist_count == 0;
+
+foreach my $file ($dist->get_files()) {
+ my $path = "$uploadfilesdir/$file->{filename}";
+ $checksums->add_from_file($path, key => $file->{filename});
+
+ if (defined $file->{package_type} and $file->{package_type} =~ m/^u?deb$/) {
+ push @archvalues, $file->{arch}
+ if defined $file->{arch} and not $archadded{$file->{arch}}++;
+ }
+}
+
+$fields->{'Format'} = $buildinfo_format;
+$fields->{'Source'} = $spackage;
+$fields->{'Binary'} = join(' ', map { $_->{'Package'} } $control->get_packages());
+# Avoid overly long line by splitting over multiple lines.
+if (length($fields->{'Binary'}) > 980) {
+ $fields->{'Binary'} =~ s/(.{0,980}) /$1\n/g;
+}
+
+$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-Origin'} = get_current_vendor();
+
+$fields->{'Build-Architecture'} = get_build_arch();
+
+my $cwd = cwd();
+if ($always_include_path) {
+ $fields->{'Build-Path'} = $cwd;
+} else {
+ # Only include the build path if its root path is considered acceptable
+ # by the vendor.
+ foreach my $root_path (run_vendor_hook('builtin-system-build-paths')) {
+ if (index($cwd, $root_path) == 0) {
+ $fields->{'Build-Path'} = $cwd;
+ last;
+ }
+ }
+}
+
+$checksums->export_to_control($fields);
+
+$fields->{'Installed-Build-Depends'} = collect_installed_builddeps($control);
+
+$fields->{'Environment'} = "\n" . cleansed_environment();
+
+# Generate the buildinfo filename.
+if ($stdout) {
+ # Nothing to do.
+} elsif (defined $outputfile) {
+ $buildinfo = basename($outputfile);
+} else {
+ if (not defined $buildinfo_id) {
+ require Digest::MD5;
+
+ my $buildinfo_contents = $fields->output();
+
+ 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";
+}
+
+# Write out the generated .buildinfo file.
+
+if ($stdout) {
+ $fields->output(\*STDOUT);
+} else {
+ 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'));
+
+ # Release the lock
+ close $lockfh or syserr(g_('cannot close %s'), $lockfile);
+
+ $fields->save("$outputfile.new");
+
+ rename "$outputfile.new", $outputfile
+ or syserr(g_("cannot install output buildinfo file '%s'"), $outputfile);
+}
+
+1;
diff --git a/scripts/po/POTFILES.in b/scripts/po/POTFILES.in
index ab99f47e9..2ba1705d7 100644
--- a/scripts/po/POTFILES.in
+++ b/scripts/po/POTFILES.in
@@ -5,6 +5,7 @@ scripts/dpkg-buildflags.pl
scripts/dpkg-buildpackage.pl
scripts/dpkg-checkbuilddeps.pl
scripts/dpkg-distaddfile.pl
+scripts/dpkg-genbuildinfo.pl
scripts/dpkg-genchanges.pl
scripts/dpkg-gencontrol.pl
scripts/dpkg-gensymbols.pl
diff --git a/scripts/t/dpkg_buildpackage/test-source_0_all.changes b/scripts/t/dpkg_buildpackage/test-source_0_all.changes
index 7e57baf8b..9c4bdb4b0 100644
--- a/scripts/t/dpkg_buildpackage/test-source_0_all.changes
+++ b/scripts/t/dpkg_buildpackage/test-source_0_all.changes
@@ -18,7 +18,10 @@ Changes:
* Entry. Closes: #12345
Checksums-Sha1:
0000000000000000000000000000000000000000 0 test-binary-all_0_all.deb
+ 0000000000000000000000000000000000000000 0 test-source_0_20160101T123000z-00000000.buildinfo
Checksums-Sha256:
0000000000000000000000000000000000000000000000000000000000000000 0 test-binary-all_0_all.deb
+ 0000000000000000000000000000000000000000000000000000000000000000 0 test-source_0_20160101T123000z-00000000.buildinfo
Files:
00000000000000000000000000000000 0 test optional test-binary-all_0_all.deb
+ 00000000000000000000000000000000 0 test optional test-source_0_20160101T123000z-00000000.buildinfo
diff --git a/scripts/t/dpkg_buildpackage/test-source_0_any.changes b/scripts/t/dpkg_buildpackage/test-source_0_any.changes
index 4ccaf69bf..6b2c29715 100644
--- a/scripts/t/dpkg_buildpackage/test-source_0_any.changes
+++ b/scripts/t/dpkg_buildpackage/test-source_0_any.changes
@@ -18,7 +18,10 @@ Changes:
* Entry. Closes: #12345
Checksums-Sha1:
0000000000000000000000000000000000000000 0 test-binary-any_0_amd64.deb
+ 0000000000000000000000000000000000000000 0 test-source_0_20160101T123000z-00000000.buildinfo
Checksums-Sha256:
0000000000000000000000000000000000000000000000000000000000000000 0 test-binary-any_0_amd64.deb
+ 0000000000000000000000000000000000000000000000000000000000000000 0 test-source_0_20160101T123000z-00000000.buildinfo
Files:
00000000000000000000000000000000 0 test optional test-binary-any_0_amd64.deb
+ 00000000000000000000000000000000 0 test optional test-source_0_20160101T123000z-00000000.buildinfo
diff --git a/scripts/t/dpkg_buildpackage/test-source_0_binary.changes b/scripts/t/dpkg_buildpackage/test-source_0_binary.changes
index 15d23784c..cd57b7f94 100644
--- a/scripts/t/dpkg_buildpackage/test-source_0_binary.changes
+++ b/scripts/t/dpkg_buildpackage/test-source_0_binary.changes
@@ -19,9 +19,12 @@ Changes:
Checksums-Sha1:
0000000000000000000000000000000000000000 0 test-binary-all_0_all.deb
0000000000000000000000000000000000000000 0 test-binary-any_0_amd64.deb
+ 0000000000000000000000000000000000000000 0 test-source_0_20160101T123000z-00000000.buildinfo
Checksums-Sha256:
0000000000000000000000000000000000000000000000000000000000000000 0 test-binary-all_0_all.deb
0000000000000000000000000000000000000000000000000000000000000000 0 test-binary-any_0_amd64.deb
+ 0000000000000000000000000000000000000000000000000000000000000000 0 test-source_0_20160101T123000z-00000000.buildinfo
Files:
00000000000000000000000000000000 0 test optional test-binary-all_0_all.deb
00000000000000000000000000000000 0 test optional test-binary-any_0_amd64.deb
+ 00000000000000000000000000000000 0 test optional test-source_0_20160101T123000z-00000000.buildinfo
diff --git a/scripts/t/dpkg_buildpackage/test-source_0_full.changes b/scripts/t/dpkg_buildpackage/test-source_0_full.changes
index 77cb41244..6eec5523a 100644
--- a/scripts/t/dpkg_buildpackage/test-source_0_full.changes
+++ b/scripts/t/dpkg_buildpackage/test-source_0_full.changes
@@ -21,13 +21,16 @@ Checksums-Sha1:
0000000000000000000000000000000000000000 0 test-source_0.tar.xz
0000000000000000000000000000000000000000 0 test-binary-all_0_all.deb
0000000000000000000000000000000000000000 0 test-binary-any_0_amd64.deb
+ 0000000000000000000000000000000000000000 0 test-source_0_20160101T123000z-00000000.buildinfo
Checksums-Sha256:
0000000000000000000000000000000000000000000000000000000000000000 0 test-source_0.dsc
0000000000000000000000000000000000000000000000000000000000000000 0 test-source_0.tar.xz
0000000000000000000000000000000000000000000000000000000000000000 0 test-binary-all_0_all.deb
0000000000000000000000000000000000000000000000000000000000000000 0 test-binary-any_0_amd64.deb
+ 0000000000000000000000000000000000000000000000000000000000000000 0 test-source_0_20160101T123000z-00000000.buildinfo
Files:
00000000000000000000000000000000 0 test optional test-source_0.dsc
00000000000000000000000000000000 0 test optional test-source_0.tar.xz
00000000000000000000000000000000 0 test optional test-binary-all_0_all.deb
00000000000000000000000000000000 0 test optional test-binary-any_0_amd64.deb
+ 00000000000000000000000000000000 0 test optional test-source_0_20160101T123000z-00000000.buildinfo
diff --git a/t/pod-spell.t b/t/pod-spell.t
index 2b903cba6..e2a7190f6 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