diff options
-rw-r--r-- | debian/changelog | 7 | ||||
-rw-r--r-- | debian/dpkg-dev.install | 1 | ||||
-rw-r--r-- | debian/dpkg-dev.manpages | 2 | ||||
-rw-r--r-- | man/Makefile.am | 4 | ||||
-rw-r--r-- | man/deb-buildinfo.man | 178 | ||||
-rw-r--r-- | man/dpkg-buildpackage.man | 31 | ||||
-rw-r--r-- | man/dpkg-genbuildinfo.man | 153 | ||||
-rw-r--r-- | man/po/po4a.cfg | 6 | ||||
-rw-r--r-- | scripts/.gitignore | 1 | ||||
-rw-r--r-- | scripts/Dpkg/Control.pm | 13 | ||||
-rw-r--r-- | scripts/Dpkg/Control/FieldsCore.pm | 41 | ||||
-rw-r--r-- | scripts/Dpkg/Control/Types.pm | 3 | ||||
-rw-r--r-- | scripts/Dpkg/Vendor/Debian.pm | 2 | ||||
-rw-r--r-- | scripts/Dpkg/Vendor/Default.pm | 12 | ||||
-rw-r--r-- | scripts/Makefile.am | 2 | ||||
-rw-r--r-- | scripts/Test/Dpkg.pm | 1 | ||||
-rwxr-xr-x | scripts/dpkg-buildpackage.pl | 35 | ||||
-rwxr-xr-x | scripts/dpkg-genbuildinfo.pl | 491 | ||||
-rw-r--r-- | scripts/po/POTFILES.in | 1 | ||||
-rw-r--r-- | scripts/t/dpkg_buildpackage/test-source_0_all.changes | 3 | ||||
-rw-r--r-- | scripts/t/dpkg_buildpackage/test-source_0_any.changes | 3 | ||||
-rw-r--r-- | scripts/t/dpkg_buildpackage/test-source_0_binary.changes | 3 | ||||
-rw-r--r-- | scripts/t/dpkg_buildpackage/test-source_0_full.changes | 3 | ||||
-rw-r--r-- | t/pod-spell.t | 2 |
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 |