Guillem Jover: > Oh and had completely forgotten, could you please also add a new > deb-buildinfo(5) man page describing the format of the file? I really > want all file formats supported by dpkg to be documented here for > external parties to refer to.
I think the manpage is the only remaining task that I had on my lists after your comments. I'd rather make sure we all agree on the fields before getting to it. An updated patch is attached. A breakdown of the change since the last submitted patch is available for easier review: https://anonscm.debian.org/cgit/reproducible/dpkg.git/log/?h=pu/buildinfo 931b291 dpkg-genbuildinfo: add missing escapes to manpage 7fb4335 dpkg-buildpackage: Use a more privacy-preserving default buildinfo identifier ecda68c dpkg-buildpackage: Use the same restrictions for buildinfo identifiers as package names df785bb dpkg-genbuildinfo: Use g_() instead of deprecated _g() e6efefb dpkg-buildpackage: reword description of --buildinfo-identifier in manpage c9d96ef dpkg-genbuildinfo: Use vendor hook instead of hardcoding build-essential 414eda9 dpkg-genbuildinfo: implement allowed Build-Paths as a vendor hook bf6b372 dpkg-genbuildinfo: Improve handling of parse_status return values 73cf850 dpkg-genbuildinfo: Rename Changes in Binary-Only-Changes 83d85ce dpkg-buildpackage: always create a .buildinfo file b02b2bf dpkg-genbuildinfo: Use parenthesis for non-built-ins functions fa122f5 dpkg-genbuildinfo: replace tabs with spaces 53aecbb dpkg-genbuildinfo: Improve computation of dependencies fcedf2e dpkg-genbuildinfo: Add support for build profiles 413bf9e dpkg-genbuildinfo: Rewrite Build-Environment generator 8040903 dpkg-genbuildinfo: Rename Build-Environment to Installed-Build-Depends 9be50d7 dpkg-genbuildinfo: Record some environment variables -- Lunar .''`. lu...@debian.org : :Ⓐ : # apt-get install anarchism `. `'` `-
diff --git a/debian/dpkg-dev.install b/debian/dpkg-dev.install index 5cec6fe..2ed6d65 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 0a08ac6..30a00e6 100644 --- a/debian/dpkg-dev.manpages +++ b/debian/dpkg-dev.manpages @@ -20,6 +20,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 f656b6b..5d65dab 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -24,6 +24,7 @@ dist_man_MANS = \ dpkg-deb.1 \ dpkg-distaddfile.1 \ dpkg-divert.1 \ + dpkg-genbuildinfo.1 \ dpkg-genchanges.1 \ dpkg-gencontrol.1 \ dpkg-gensymbols.1 \ diff --git a/man/dpkg-buildpackage.1 b/man/dpkg-buildpackage.1 index 13770ba..2199885 100644 --- a/man/dpkg-buildpackage.1 +++ b/man/dpkg-buildpackage.1 @@ -58,25 +58,30 @@ or \fBbuild\-arch\fP and \fBbinary\-arch\fP (if \fB\-B\fP or \fB\-G\fP are specified), or \fBbuild\-indep\fP and \fBbinary\-indep\fP (if \fB\-A\fP or \fB\-g\fP are specified). .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. 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 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 is specified or on UNRELEASED builds), and the \fB.changes\fP file (unless \fB\-uc\fP is specified or on UNRELEASED builds). -.IP \fB11.\fP 3 +.IP \fB12.\fP 3 It runs the \fBdone\fP hook. . .SH OPTIONS @@ -317,6 +322,17 @@ The source package version (without the epoch). The upstream version. .RE .TP +.BI \-\-buildinfo-identifier= identifier +Specify the identifier part of the \fB.buildinfo\fP file name (since dpkg +1.18.5). +By default, \fBdpkg\-buildpackage\fP will create an identifier using the +current time and the first characters of the MD5 hash. +An arbitrary identifier can be specified as a replacement. +The identifier has the same restriction as package names: they +must consist only of lower case letters (a-z), digits (0-9), plus (+) +and minus (\-) signs, and periods (.), be at least two characters long +and must start with an alphanumeric character. +.TP .BI \-p sign-command 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 @@ -351,6 +367,10 @@ Passed unchanged to \fBdpkg\-source\fP. See its manual page. Pass option \fIopt\fP to \fBdpkg\-source\fP (since dpkg 1.15.6). Can be used multiple times. .TP +.BI \-\-buildinfo\-option= opt +Pass option \fIopt\fP to \fBdpkg\-genbuildinfo\fP (since dpkg 1.18.5). +Can be used multiple times. +.TP .BI \-\-changes\-option= opt Pass option \fIopt\fP to \fBdpkg\-genchanges\fP (since dpkg 1.15.6). Can be used multiple times. @@ -422,6 +442,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.1 b/man/dpkg-genbuildinfo.1 new file mode 100644 index 0000000..1745f24 --- /dev/null +++ b/man/dpkg-genbuildinfo.1 @@ -0,0 +1,98 @@ +.\" dpkg manual page - dpkg-genbuildinfo(1) +.\" +.\" Copyright © 1995-1996 Ian Jackson <i...@chiark.chu.cam.ac.uk> +.\" Copyright © 2000 Wichert Akkerman <wakke...@debian.org> +.\" Copyright © 2008-2010 Raphaël Hertzog <hert...@debian.org> +.\" Copyright © 2006-2014 Guillem Jover <guil...@debian.org> +.\" Copyright © 2015 Jérémy Bobbio <lu...@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 "2015-01-01" "Debian Project" "dpkg utilities" +.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 products +.RB ( .buildinfo " file)." +. +.SH OPTIONS +.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 +.BI \-u upload-files-dir +Look for the files to be uploaded in +.I upload-files-dir +rather than +.B .. +.RB ( dpkg\-genbuildinfo +needs to find these files so that it can include their sizes and +checksums in the +.B .buildinfo +file). +.TP +.BI \-\-admindir= dir +Change the location of the \fBdpkg\fR database. The default location is +\fI/var/lib/dpkg\fP. +.TP +.BI \-\-always\-include\-path +By default, the \fBBuild\-Path\fR field will only be written if the current +directory starts with \fB/build/\fR. Specify this option to always write +a \fBBuild\-Path\fR field when generating the \fB.buildinfo\fR. +.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. diff --git a/man/po/po4a.cfg b/man/po/po4a.cfg index 64d00ae..21d2bf8 100644 --- a/man/po/po4a.cfg +++ b/man/po/po4a.cfg @@ -93,6 +93,9 @@ [type:man] dpkg-divert.1 $lang:$lang/dpkg-divert.1 \ add_$lang:po/$lang.add +[type:man] dpkg-genbuildinfo.1 $lang:$lang/dpkg-genbuildinfo.1 \ + add_$lang:po/$lang.add + [type:man] dpkg-genchanges.1 $lang:$lang/dpkg-genchanges.1 \ add_$lang:po/$lang.add diff --git a/scripts/.gitignore b/scripts/.gitignore index 380ad91..0d1f29a 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 b3d4e71..45c460f 100644 --- a/scripts/Dpkg/Control.pm +++ b/scripts/Dpkg/Control.pm @@ -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 @@ -103,6 +104,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. diff --git a/scripts/Dpkg/Control/FieldsCore.pm b/scripts/Dpkg/Control/FieldsCore.pm index 3af6fa7..bc9b6de 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,9 @@ our %FIELDS = ( 'Build-Essential' => { allowed => ALL_PKG, }, + 'Build-Path' => { + allowed => CTRL_FILE_BUILDINFO, + }, 'Build-Profiles' => { allowed => CTRL_INFO_PKG, separator => FIELD_SEP_SPACE, @@ -151,7 +160,7 @@ our %FIELDS = ( allowed => CTRL_REPO_RELEASE, }, 'Changes' => { - allowed => ALL_CHANGES, + allowed => CTRL_FILE_BUILDINFO | ALL_CHANGES, }, 'Closes' => { allowed => ALL_CHANGES, @@ -222,11 +231,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, }, @@ -299,7 +314,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' => { @@ -390,7 +405,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)), }, ); @@ -398,7 +413,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; @@ -417,6 +432,12 @@ our %FIELD_ORDER = ( Vcs-Svn Testsuite), &field_list_src_dep(), qw(Package-List), @checksum_fields, qw(Files) ], + CTRL_FILE_BUILDINFO() => [ + qw(Format Build-Architecture Source Binary Architecture Version + Binary-Only-Changes), + @checksum_fields, + qw(Build-Path Installed-Build-Depends), + ], 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 938659b..e401019 100644 --- a/scripts/Dpkg/Control/Types.pm +++ b/scripts/Dpkg/Control/Types.pm @@ -33,6 +33,7 @@ our @EXPORT = qw( CTRL_COPYRIGHT_HEADER CTRL_COPYRIGHT_FILES CTRL_COPYRIGHT_LICENSE + CTRL_FILE_BUILDINFO ); use Exporter qw(import); @@ -83,6 +84,8 @@ use constant { CTRL_COPYRIGHT_FILES => 4096, # License control block in debian/copyright. CTRL_COPYRIGHT_LICENSE => 8192, + # .buildinfo file + CTRL_FILE_BUILDINFO => 16384, }; =head1 CHANGES diff --git a/scripts/Dpkg/Vendor/Debian.pm b/scripts/Dpkg/Vendor/Debian.pm index db40b2c..b981cc4 100644 --- a/scripts/Dpkg/Vendor/Debian.pm +++ b/scripts/Dpkg/Vendor/Debian.pm @@ -76,6 +76,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 3685001..e44a277 100644 --- a/scripts/Dpkg/Vendor/Default.pm +++ b/scripts/Dpkg/Vendor/Default.pm @@ -116,6 +116,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 Build-Path field. It takes no parameters, +but returns a (possibly empty) list of root paths considered acceptable. +As an example, if the list contains "/build/", a Build-Path field will +be created if the current directory is "/build/dpkg-1.18.5". If the +list contains "/", the path will always be recorded. If the list is +empty, the current path will never be recorded. + =back =cut @@ -139,6 +149,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 54cfad9..9056a7c 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 \ @@ -31,6 +32,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/dpkg-buildpackage.pl b/scripts/dpkg-buildpackage.pl index 17ada97..ddffd52 100755 --- a/scripts/dpkg-buildpackage.pl +++ b/scripts/dpkg-buildpackage.pl @@ -28,9 +28,10 @@ use Cwd; use File::Temp qw(tempdir); use File::Basename; use File::Copy; -use POSIX qw(:sys_wait_h); +use POSIX qw(:sys_wait_h strftime); use Dpkg (); +use Dpkg::Control::Info; use Dpkg::Gettext; use Dpkg::ErrorHandling; use Dpkg::BuildOptions; @@ -84,8 +85,10 @@ sub usage { pass <opt> to <check-command>. --hook-<hook-name>=<hook-command> set <hook-command> as the hook <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-identifier=<identifier> + set the identifier part of the .buildinfo filename. -p<sign-command> command to sign .dsc and/or .changes files (default is gpg2 or gpg). @@ -106,6 +109,10 @@ sub usage { --target-arch <arch> set the target Debian architecture. --target-type <type> set the target GNU system type.') . "\n\n" . g_( +'Options passed to dpkg-genbuildinfo: + --buildinfo-option=<opt> + pass option <opt> to dpkg-genbuildinfo.') + . "\n\n" . g_( 'Options passed to dpkg-genchanges: -si source includes orig, if new upstream (default). -sa source includes orig, always. @@ -161,9 +168,11 @@ my $since; my $maint; my $changedby; my $desc; +my $buildinfo_identifier; +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; @@ -232,6 +241,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(\d*|auto)$/) { @@ -254,6 +265,8 @@ while (@ARGV) { usageerr(g_('missing hook %s command'), $hook_name) if not defined $hook_cmd; $hook{$hook_name} = $hook_cmd; + } elsif (/^--buildinfo-identifier=(.*)$/) { + $buildinfo_identifier = $1; } elsif (/^-p(.*)$/) { $signcommand = $1; } elsif (/^-k(.*)$/) { @@ -312,9 +325,11 @@ while (@ARGV) { } elsif (/^-B$/) { set_build_type(BUILD_ARCH_DEP, $_); push @changes_opts, '-B'; + push @buildinfo_opts, '-B'; } elsif (/^-A$/) { set_build_type(BUILD_ARCH_INDEP, $_); push @changes_opts, '-A'; + push @buildinfo_opts, '-A'; } elsif (/^-S$/) { set_build_type(BUILD_SOURCE, $_); push @changes_opts, '-S'; @@ -412,6 +427,12 @@ if (defined $parallel) { $build_opts->export(); } +if (defined $buildinfo_identifier) { + # .buildinfo identifiers have the same restrictions as package names + my $err = pkg_name_is_illegal($buildinfo_identifier); + error(g_("illegal .buildinfo identifier '%s': %s"), $buildinfo_identifier, $err) if $err; +} + set_build_profiles(@build_profiles) if @build_profiles; my $cwd = cwd(); @@ -569,6 +590,37 @@ if ($include & BUILD_BINARY) { withecho(@debian_rules, $buildtarget); run_hook('binary', 1); withecho(@rootcommand, @debian_rules, $binarytarget); + + run_hook('buildinfo', 1); + + push @buildinfo_opts, "--admindir=$admindir" if $admindir; + + open my $genbuildinfo_fh, '-|', 'dpkg-genbuildinfo', @buildinfo_opts + or subprocerr('dpkg-genbuildinfo'); + my @buildinfo_content = <$genbuildinfo_fh>; + close $genbuildinfo_fh; + + if (!defined $buildinfo_identifier) { + require Digest::MD5; + + my $timestamp = strftime('%Y%m%dT%H%M%Sz', gmtime()); + my $buildinfo_md5 = Digest::MD5::md5_hex(@buildinfo_content); + $buildinfo_identifier = "$timestamp-" . substr($buildinfo_md5, 0, 8); + } + + my $buildinfo = "${pv}_${buildinfo_identifier}.buildinfo"; + + open my $buildinfo_fh, ">../$buildinfo" + or syserr(g_('cannot open %s', "../$buildinfo")); + print $buildinfo_fh, @buildinfo_content; + close $buildinfo_fh; + + my $control = Dpkg::Control::Info->new('debian/control'); + my $sec = $control->get_source->{'Section'} // '-'; + my $pri = $control->get_source->{'Priority'} // '-'; + warning(g_('missing Section for source files')) if $sec eq '-'; + warning(g_('missing Priority for source files')) if $pri eq '-'; + withecho('dpkg-distaddfile', $buildinfo, $sec, $pri); } run_hook('changes', 1); diff --git a/scripts/dpkg-genbuildinfo.pl b/scripts/dpkg-genbuildinfo.pl new file mode 100755 index 0000000..8062434 --- /dev/null +++ b/scripts/dpkg-genbuildinfo.pl @@ -0,0 +1,424 @@ +#!/usr/bin/perl +# +# dpkg-genbuildinfo +# +# Copyright © 1996 Ian Jackson +# Copyright © 2000,2001 Wichert Akkerman +# Copyright © 2003-2013 Yann Dirson <dir...@debian.org> +# Copyright © 2006-2014 Guillem Jover <guil...@debian.org> +# Copyright © 2014 Niko Tyni <nt...@debian.org> +# Copyright © 2014-2015 Jérémy Bobbio <lu...@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 Carp; +use Cwd; + +use Dpkg (); +use Dpkg::Gettext; +use Dpkg::Checksums; +use Dpkg::ErrorHandling; +use Dpkg::Arch qw(get_build_arch); +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::Version; +use Dpkg::Vendor qw(run_vendor_hook); + +textdomain('dpkg-dev'); + +my $controlfile = 'debian/control'; +my $changelogfile = 'debian/changelog'; +my $changelogformat; +my $fileslistfile = 'debian/files'; +my $uploadfilesdir = '..'; +my $admindir = $Dpkg::ADMINDIR; +my $always_include_path = 0; +my @build_profiles = get_build_profiles(); +my $buildinfo_format = '1.0'; + +my $checksums = Dpkg::Checksums->new(); +my %archadded; +my @archvalues; + +use constant BUILD_ARCH_DEP => 1; +use constant BUILD_ARCH_INDEP => 2; +use constant BUILD_ALL => BUILD_ARCH_DEP | BUILD_ARCH_INDEP; +my $include = BUILD_ALL; + +sub build_is_default() { return ($include & BUILD_ALL) == BUILD_ALL; } +sub build_opt { + if ($include == BUILD_ARCH_DEP) { + return '-B'; + } elsif ($include == BUILD_ARCH_INDEP) { + return '-A'; + } else { + croak "build_opt called with include=$include"; + } +} + +sub set_build_type +{ + my ($build_type, $build_option) = @_; + + usageerr(g_('cannot combine %s and %s'), build_opt(), $build_option) + if not build_is_default and $include != $build_type; + $include = $build_type; +} + +# There's 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; + foreach (grep { $_->isa('Dpkg::Deps::Simple') } + $provides->get_deps()) + { + $facts->add_provided_package($_->{package}, + $_->{relation}, $_->{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 can't 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 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: + -B build of only arch-specific files. + -A build of only arch-indep files. + -c<control-file> get control info from this file. + -l<changelog-file> get per-version info from this file. + -f<files-list-file> get .deb files list from this file. + -F<changelog-format> force changelog format. + -u<upload-files-dir> directory with files (default is '..'). + --admindir=<directory> change the administrative directory. + --always-include-path always include Build-Path + -?, --help show this help message. + --version show the version. +"), $Dpkg::PROGNAME; +} + +while (@ARGV) { + $_ = shift(@ARGV); + if (m/^-B$/) { + set_build_type(BUILD_ARCH_DEP, $_); + } elsif (m/^-A$/) { + set_build_type(BUILD_ARCH_INDEP, $_); + } elsif (m/^-c(.*)$/) { + $controlfile = $1; + } elsif (m/^-l(.*)$/) { + $changelogfile = $1; + } elsif (m/^-f(.*)$/) { + $fileslistfile = $1; + } elsif (m/^-F([0-9a-z]+)$/) { + $changelogformat = $1; + } elsif (m/^-u(.*)$/) { + $uploadfilesdir = $1; + } elsif (m/^--admindir=(.*)$/) { + $admindir = $1; + } elsif (m/^--always-include-path$/) { + $always_include_path = 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+://; +my $dsc = "${spackage}_${sversion}.dsc"; +my $dsc_pathname = "$uploadfilesdir/$dsc"; +if ( -e $dsc_pathname) { + $checksums->add_from_file($dsc_pathname, key => $dsc); +} else { + warning(g_('no .dsc file found: the resulting .buildinfo will not be ' . + 'usable to verify the provenance of the binaries.')); +} + +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->{arch}) { + push @archvalues, $file->{arch} + if $file->{arch} and not $archadded{$file->{arch}}++; + } +} + +my $build_arch = get_build_arch(); + +$fields->{'Format'} = $buildinfo_format; +$fields->{'Build-Architecture'} = $build_arch; + +$fields->{'Source'} = $spackage; +if ($changelog->{'Binary-Only'}) { + $fields->{'Source'} .= ' (' . $sourceversion . ')'; + $fields->{'Binary-Only-Changes'} = + $changelog->{'Changes'} . "\n\n" + . ' -- ' . $changelog->{'Maintainer'} + . ' ' . $changelog->{'Date'}; +} + +$fields->{'Binary'} = join(' ', map { $_->{'Package'} } $control->get_packages()); +# Avoid overly long line by splitting over multiple lines +if (length($fields->{'Binary'}) > 980) { + $fields->{'Binary'} =~ s/(.{0,980}) /$1\n/g; +} + +$fields->{'Architecture'} = join ' ', sort @archvalues; +$fields->{'Version'} = $binaryversion; + +my $cwd = cwd(); +if ($always_include_path) { + $fields->{'Build-Path'} = $cwd; +} else { + # Only include build path if its root path is considered acceptable by the vendor + foreach my $root_path (run_vendor_hook('builtin-system-build-path')) { + if (index($cwd, $root_path) == 0) { + $fields->{'Build-Path'} = $cwd; + last; + } + } +} + +$checksums->export_to_control($fields); + +my ($facts, $depends, $essential_pkgs) = parse_status("$admindir/status"); +my %seen_pkgs; +my @unprocessed_pkgs; + +# parse essential list + +append_deps(\@unprocessed_pkgs, + @{$essential_pkgs}, + run_vendor_hook('builtin-build-depends'), + $control->get_source->{'Build-Depends'}); + +if ($include & BUILD_ARCH_DEP) { + append_deps(\@unprocessed_pkgs, $control->get_source->{'Build-Depends-Arch'}); +} + +if ($include & 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 grep sub { $_[0]->{architecture} eq $architecture }, @{$facts->{pkg}->{$dep->{package}}}; + 1; + }); + } + # We add every sub-dependencies as we can't know which package in an OR + # dependency has been effectively used. + deps_iterate($new_deps, sub { + push @unprocessed_pkgs, + $_[0]->{package} . (defined $_[0]->{archqual} ? ':' . $_[0]->{archqual} : ''); + 1 }); + } elsif (defined $facts->{virtualpkg}->{$pkg_name}) { + # virtual package: we can't know for sure which implementation + # is the one that has been used, so let's add them all... + foreach my $provided (@{$facts->{virtualpkg}->{$pkg_name}}) { + my ($provided_by, $provided_rel, $provided_ver) = @{$provided}; + push @unprocessed_pkgs, $provided_by; + } + } + # else: it's a package in an OR dependency that has been satisfied otherwise +} +$installed_deps->sort(); +$installed_deps = "\n" . $installed_deps->output(); +$installed_deps =~ s/, /,\n/g; +$fields->{'Installed-Build-Depends'} = $installed_deps; + +my $toolchain = + qr{( CC | CPP | CXX + | LD | AR | RANLIB + | MAKE | AWK + )}x; +my $toolchain_flags = + qr{( CFLAGS | CPPFLAGS | CXXFLAGS + | OBJCFLAGS | OBJCXXFLAGS + | GCJFLAGS | FFLAGS + | LDFLAGS | ARFLAGS | MAKEFLAGS + )}x; +my $environment_whitelist = + qr{\A( PATH + | ${toolchain} + | ${toolchain_flags} + | LD_LIBRARY_PATH # see ld(1) + | LANG | LC_(CTYPE|NUMERIC|TIME|COLLATE|MONETARY|MESSAGES + |PAPER|NAME|ADDRESS|TELEPHONE|MEASUREMENT + |IDENTIFICATION|ALL) # documented in locale(1) + | DEB_BUILD_OPTIONS # documented in dpkg-buildpackage(1) + | DEB_BUILD_PROFILES # documented in dpkg-buildpackage(1) + # env var will be set if -P is given + # DEB_flag_{SET,STRIP,APPEND,PREPEND} will be recorded after + # being merged with system config and user config + | DEB_VENDOR # documented in deb-vendor(1) + | DPKG_DATADIR # documented in dpkg-architecure(1) + | DPKG_ORIGINS_DIR # used by Dpkg::Vendor + | SOURCE_DATE_EPOCH # see https://reproducible-builds.org/specs/source-date-epoch + )\z}x; + +my %environment = map { $_, $ENV{$_} } (grep /$environment_whitelist/, sort keys %ENV); + +# Record flags from dpkg-buildflags +my $bf = Dpkg::BuildFlags->new(); +$bf->load_system_config(); +$bf->load_user_config(); +$bf->load_environment_config(); +foreach my $flag ($bf->list()) { + if ($bf->get_origin($flag) ne 'vendor') { + $environment{"DEB_${flag}_SET"} = $bf->get($flag); + # We don't need to record *_{STRIP,APPEND,PREPEND} as they + # have been used already to compute the above value + } +} + +$fields->{'Environment'} = "\n" . + join "\n", map { $_ . '="' . ($environment{$_} =~ s/"/\\"/gr) . '"' } + (sort keys %environment); + +$fields->output(\*STDOUT); diff --git a/scripts/po/POTFILES.in b/scripts/po/POTFILES.in index e662514..1407103 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
signature.asc
Description: Digital signature