36
36
use File::Copy qw(); # copy is already exported from Sbuild, so don't export
38
use Cwd qw(:DEFAULT abs_path);
42
42
use Term::ANSIColor;
44
use Sbuild qw($devnull binNMU_version version_compare split_version copy isin debug df send_mail);
44
use Sbuild qw($devnull binNMU_version copy isin debug df send_mail dsc_files);
46
46
use Sbuild::ChrootInfoSchroot;
47
47
use Sbuild::ChrootInfoSudo;
48
48
use Sbuild::ChrootRoot;
49
49
use Sbuild::Sysconfig qw($version $release_date);
50
use Sbuild::LogBase qw($saved_stdout);
51
50
use Sbuild::Sysconfig;
52
use Sbuild::Utility qw(check_url download parse_file dsc_files);
51
use Sbuild::Utility qw(check_url download);
53
52
use Sbuild::Resolver qw(get_resolver);
54
53
use Sbuild::Exception;
99
101
$host_defaults->{'STREAMIN'} = $devnull;
100
102
$host_defaults->{'ENV'}->{'LC_ALL'} = 'POSIX';
101
103
$host_defaults->{'ENV'}->{'SHELL'} = '/bin/sh';
104
$host_defaults->{'ENV_FILTER'} = $self->get_conf('ENVIRONMENT_FILTER');
102
105
# Note, this should never fail. But, we should handle failure anyway.
103
106
$self->get('Host')->begin_session();
127
130
if ((!$self->get('Download') ||
128
131
(!($self->get('DSC Base') =~ m/\.dsc$/) &&
129
132
$self->get('DSC') ne $self->get('Package_OVersion')) ||
130
!defined $self->get('Version')) &&
131
!defined $self->get('Debian Source Dir'));
133
!defined $self->get('Version')));
133
135
debug("Download = " . $self->get('Download') . "\n");
134
136
debug("Invalid Source = " . $self->get('Invalid Source') . "\n");
161
163
debug("Setting DSC: $dsc\n");
163
# Check if the DSC given is a directory on the local system. This
164
# means we'll build the source package with dpkg-source first.
166
my $host = $self->get('Host');
167
my $pipe = $host->pipe_command(
168
{ COMMAND => ['dpkg-parsechangelog', '-l' . abs_path($dsc) . '/debian/changelog'],
172
if (!defined($pipe)) {
173
Sbuild::Exception::Build->throw(error => "Could not parse $dsc/debian/changelog: $!",
174
failstage => "set-dsc");
177
my $stanzas = parse_file($pipe);
179
my $stanza = @{$stanzas}[0];
180
my $package = ${$stanza}{'Source'};
181
my $version = ${$stanza}{'Version'};
183
if (!defined($package) || !defined($version)) {
184
Sbuild::Exception::Build->throw(error => "Missing Source or Version in $dsc/debian/changelog",
185
failstage => "set-dsc");
189
# Note: need to support cases when invoked from a subdirectory
190
# of the build directory, i.e. $dsc/foo -> $dsc/.. in addition
191
# to $dsc -> $dsc/.. as below.
192
if ($dir eq abs_path($dsc)) {
193
# We won't attempt to build the source package from the source
194
# directory so the source package files will go to the parent dir.
195
$dir = abs_path("$dir/..");
196
$self->set_conf('BUILD_DIR', $dir);
198
$self->set('Debian Source Dir', abs_path($dsc));
200
$self->set_version("${package}_${version}");
201
$dsc = "$dir/" . $self->get('Package_OSVersion') . ".dsc";
204
165
$self->set('DSC', $dsc);
205
166
$self->set('Source Dir', dirname($dsc));
206
167
$self->set('DSC Base', basename($dsc));
217
178
debug("Setting package version: $pkgv\n");
219
180
my ($pkg, $version) = split /_/, $pkgv;
220
return if (!defined($pkg) || !defined($version));
181
my $pver = Dpkg::Version->new($version, check => 1);
182
return if (!defined($pkg) || !defined($version) || !defined($pver));
183
my ($o_epoch, $o_version, $o_revision);
184
$o_epoch = $pver->epoch();
185
$o_version = $pver->version();
186
$o_revision = $pver->revision();
222
188
# Original version (no binNMU or other addition)
223
189
my $oversion = $version;
224
190
# Original version with stripped epoch
225
(my $osversion = $version) =~ s/^\d+://;
191
my $osversion = $o_version;
192
$osversion .= '-' . $o_revision if $o_revision;
227
194
# Add binNMU to version if needed.
228
195
if ($self->get_conf('BIN_NMU') || $self->get_conf('APPEND_TO_VERSION')) {
230
197
$self->get_conf('APPEND_TO_VERSION'));
200
my $bver = Dpkg::Version->new($version, check => 1);
201
return if (!defined($bver));
202
my ($b_epoch, $b_version, $b_revision);
203
$b_epoch = $bver->epoch();
204
$b_version = $bver->version();
205
$b_revision = $bver->revision();
233
207
# Version with binNMU or other additions and stripped epoch
234
(my $sversion = $version) =~ s/^\d+://;
236
my ($epoch, $uversion, $dversion) = split_version($version);
208
my $sversion = $b_version;
209
$sversion .= '-' . $b_revision if $b_revision;
238
211
$self->set('Package', $pkg);
239
212
$self->set('Version', $version);
244
217
$self->set('OVersion', $oversion);
245
218
$self->set('OSVersion', $osversion);
246
219
$self->set('SVersion', $sversion);
247
$self->set('VersionEpoch', $epoch);
248
$self->set('VersionUpstream', $uversion);
249
$self->set('VersionDebian', $dversion);
220
$self->set('VersionEpoch', $b_epoch);
221
$self->set('VersionUpstream', $b_version);
222
$self->set('VersionDebian', $b_revision);
250
223
$self->set('DSC File', "${pkg}_${osversion}.dsc");
251
$self->set('DSC Dir', "${pkg}-${uversion}");
224
$self->set('DSC Dir', "${pkg}-${b_version}");
253
226
debug("Package = " . $self->get('Package') . "\n");
254
227
debug("Version = " . $self->get('Version') . "\n");
380
# Pack up local source tree
381
sub run_pack_source {
384
$self->check_abort();
385
# Build the source package if given a Debianized source directory
386
if ($self->get('Debian Source Dir')) {
387
$self->log_subsection("Build Source Package");
389
$self->log_subsubsection('clean');
390
$self->get('Host')->run_command(
391
{ COMMAND => [$self->get_conf('FAKEROOT'),
394
DIR => $self->get('Debian Source Dir'),
398
Sbuild::Exception::Build->throw(error => "Failed to clean source directory",
399
failstage => "pack-source");
402
$self->check_abort();
404
$self->log_subsubsection('dpkg-source');
405
my @dpkg_source_command = ($self->get_conf('DPKG_SOURCE'), '-b');
406
push @dpkg_source_command, @{$self->get_conf('DPKG_SOURCE_OPTIONS')}
407
if ($self->get_conf('DPKG_SOURCE_OPTIONS'));
408
push @dpkg_source_command, $self->get('Debian Source Dir');
409
$self->get('Host')->run_command(
410
{ COMMAND => \@dpkg_source_command,
411
DIR => $self->get_conf('BUILD_DIR'),
415
Sbuild::Exception::Build->throw(error => "Failed to clean source directory",
416
failstage => "pack-source");
421
351
# Create main chroot session and package resolver. Creates a lock in
422
352
# the chroot to prevent concurrent chroot usage (only important for
423
353
# non-snapshot chroots). Ends chroot session on return/failure.
473
403
DIR => $session->get('Location') . "/build"));
475
405
$self->set('Build Dir', $session->strip_chroot_path($self->get('Chroot Build Dir')));
408
$self->build_log_colour('red', '^E: ');
409
$self->build_log_colour('yellow', '^W: ');
410
$self->build_log_colour('green', '^I: ');
411
$self->build_log_colour('red', '^Status:');
412
$self->build_log_colour('green', '^Status: successful$');
413
$self->build_log_colour('red', '^Lintian:');
414
$self->build_log_colour('green', '^Lintian: pass$');
477
418
$filter = $self->get('Build Dir') . '/' . $self->get('DSC Dir');
478
419
$filter =~ s;^/;;;
517
459
$chroot_defaults->{'STREAMERR'} = $self->get('Log Stream');
518
460
$chroot_defaults->{'ENV'}->{'LC_ALL'} = 'POSIX';
519
461
$chroot_defaults->{'ENV'}->{'SHELL'} = '/bin/sh';
520
$chroot_defaults->{'ENV'}->{'HOME'} = '/nonexistent';
462
$chroot_defaults->{'ENV'}->{'HOME'} = '/sbuild-nonexistent';
463
$chroot_defaults->{'ENV_FILTER'} = $self->get_conf('ENVIRONMENT_FILTER');
522
465
my $resolver = get_resolver($self->get('Config'), $session, $host);
523
466
$resolver->set('Log Stream', $self->get('Log Stream'));
873
816
# $file is the name of the downloaded dsc file written in a tempfile.
875
818
$file = download($self->get('DSC')) or
876
$self->log_error("Could not download " . $self->get('DSC')) and
819
$self->log_error("Could not download " . $self->get('DSC') . "\n") and
878
debug("Parsing $dsc\n");
879
821
my @cwd_files = dsc_files($file);
880
823
if (-f "$dir/$dsc") {
881
824
# Copy the local source files into the build directory.
882
825
$self->log_subsubsection("Local sources");
1281
my $cpipe = $self->get('Session')->pipe_command(
1282
{ COMMAND => ['dpkg-parsechangelog'],
1283
USER => $self->get_conf('BUILD_USER'),
1285
DIR => $self->get('Session')->strip_chroot_path($dscdir) });
1286
my $clog = do { local $/; <$cpipe> };
1289
$self->log("FAILED [dpkg-parsechangelog died]\n");
1293
my ($name) = $clog =~ /^Source:\s*(.*)$/m;
1294
my ($version) = $clog =~ /^Version:\s*(.*)$/m;
1295
my ($dists) = $clog =~ /^Distribution:\s*(.*)$/m;
1296
my ($urgency) = $clog =~ /^Urgency:\s*(.*)$/m;
1297
my ($date) = $clog =~ /^Date:\s*(.*)$/m;
1298
if ($dists ne $self->get_conf('DISTRIBUTION')) {
1299
$self->build_log_colour('yellow',
1300
"^Distribution: " . $self->get_conf('DISTRIBUTION') . "\$");
1338
1303
if ($self->get_conf('BIN_NMU') || $self->get_conf('APPEND_TO_VERSION')) {
1339
1304
if (!$self->get_conf('MAINTAINER_NAME')) {
1340
1305
Sbuild::Exception::Build->throw(error => "No maintainer specified.",
1347
1312
my $text = do { local $/; <F> };
1350
my $pipe = $self->get('Session')->pipe_command(
1351
{ COMMAND => ['dpkg-parsechangelog'],
1352
USER => $self->get_conf('BUILD_USER'),
1354
DIR => $self->get('Session')->strip_chroot_path($dscdir) });
1355
my $clog = do { local $/; <$pipe> };
1358
$self->log("FAILED [dpkg-parsechangelog died]\n");
1362
my ($name) = $clog =~ /^Source:\s*(.*)$/m;
1363
my ($version) = $clog =~ /^Version:\s*(.*)$/m;
1364
my ($dists) = $clog =~ /^Distribution:\s*(.*)$/m;
1365
my ($urgency) = $clog =~ /^Urgency:\s*(.*)$/m;
1366
my ($date) = $clog =~ /^Date:\s*(.*)$/m;
1368
1316
my $NMUversion = $self->get('Version');
1369
1317
if (!open( F, ">$dscdir/debian/changelog" )) {
1484
1432
push (@{$buildcmd}, @{$self->get_conf('DPKG_BUILDPACKAGE_USER_OPTIONS')});
1488
$buildenv->{'PATH'} = $self->get_conf('PATH');
1489
$buildenv->{'LD_LIBRARY_PATH'} = $self->get_conf('LD_LIBRARY_PATH')
1435
# Set up additional build environment variables.
1436
my %buildenv = %{$self->get_conf('BUILD_ENVIRONMENT')};
1437
$buildenv{'PATH'} = $self->get_conf('PATH');
1438
$buildenv{'LD_LIBRARY_PATH'} = $self->get_conf('LD_LIBRARY_PATH')
1490
1439
if defined($self->get_conf('LD_LIBRARY_PATH'));
1441
# Explicitly add any needed environment to the environment filter
1442
# temporarily for dpkg-buildpackage.
1444
foreach my $envvar (keys %buildenv) {
1445
push(@env_filter, "^$envvar\$");
1492
1448
# Dump build environment
1493
1449
$self->log_subsubsection("User Environment");
1495
1451
my $pipe = $self->get('Session')->pipe_command(
1496
1452
{ COMMAND => ['env'],
1454
ENV_FILTER => \@env_filter,
1498
1455
USER => $self->get_conf('BUILD_USER'),
1585
1543
$self->get('Build End Time')-$self->get('Build Start Time'));
1586
1544
$self->write_stats('install-download-time',
1587
1545
$self->get('Install End Time')-$self->get('Install Start Time'));
1588
my $date = strftime("%Y%m%d-%H%M",localtime($self->get('Build End Time')));
1546
my $finish_date = strftime("%Y%m%d-%H%M",localtime($self->get('Build End Time')));
1589
1547
$self->log_sep();
1590
$self->log("Build finished at $date\n");
1548
$self->log("Build finished at $finish_date\n");
1592
1550
my @space_files = ("$dscdir");
2059
2027
my $filter_prefix = '__SBUILD_FILTER_' . $$ . ':';
2060
2028
$self->set('FILTER_PREFIX', $filter_prefix);
2029
my $colour_prefix = '__SBUILD_COLOUR_' . $$ . ':';
2030
$self->set('COLOUR_PREFIX', $colour_prefix);
2062
2032
my $filename = $self->get_conf('LOG_DIR') . '/' .
2063
2033
$self->get('Package_SVersion') . '-' .
2064
2034
$self->get('Arch') .
2037
open($saved_stdout, ">&STDOUT") or warn "Can't redirect stdout\n";
2038
open($saved_stderr, ">&STDERR") or warn "Can't redirect stderr\n";
2105
2078
my $verbose = $self->get_conf('VERBOSE');
2106
2079
my $log_colour = $self->get_conf('LOG_COLOUR');
2107
2080
my @filter = ();
2108
2082
my ($text, $replacement);
2109
2083
my $filter_regex = "^$filter_prefix(.*):(.*)\$";
2084
my $colour_regex = "^$colour_prefix(.*):(.*)\$";
2110
2085
my @ignore = ();
2112
2087
while (<STDIN>) {
2117
2092
$replacement = "«$replacement»";
2118
2093
push (@filter, [$text, $replacement]);
2119
2094
$_ = "I: NOTICE: Log filtering will replace '$text' with '$replacement'\n";
2095
} elsif (m/$colour_regex/) {
2096
my ($colour, $regex);
2097
($colour,$regex)=($1,$2);
2098
push (@colour, [$colour, $regex]);
2099
# $_ = "I: NOTICE: Log colouring will colour '$regex' in $colour\n";
2121
2102
# Filter out any matching patterns
2122
2103
foreach my $pattern (@filter) {
2136
2117
if ($nolog || $verbose) {
2137
2118
if (-t $saved_stdout && $log_colour) {
2138
2119
my $colour = 'reset';
2139
$colour = 'red' if (m/^E: /);
2140
$colour = 'yellow' if (m/^W: /);
2141
$colour = 'green' if (m/^I: /);
2142
$colour = 'red' if (m/^Status:/);
2143
$colour = 'green' if (m/^Status: successful$/);
2120
foreach my $pattern (@colour) {
2121
if (m/$$pattern[0]/) {
2122
$colour = $$pattern[1];
2144
2125
print $saved_stdout color $colour;
2164
2145
$PLOG->autoflush(1);
2146
open(STDOUT, '>&', $PLOG) or warn "Can't redirect stdout\n";
2147
open(STDERR, '>&', $PLOG) or warn "Can't redirect stderr\n";
2165
2148
$self->set('Log File', $filename);
2166
2149
$self->set('Log Stream', $PLOG);
2240
2223
$subject .= " (dist=" . $self->get_conf('DISTRIBUTION') . ")";
2226
open(STDERR, '>&', $saved_stderr) or warn "Can't redirect stderr\n"
2227
if defined($saved_stderr);
2228
open(STDOUT, '>&', $saved_stdout) or warn "Can't redirect stdout\n"
2229
if defined($saved_stdout);
2230
$saved_stderr->close();
2231
undef $saved_stderr;
2232
$saved_stdout->close();
2233
undef $saved_stdout;
2243
2234
$self->set('Log File', undef);
2244
2235
if (defined($self->get('Log Stream'))) {
2245
2236
$self->get('Log Stream')->close(); # Close child logger process