~ubuntu-branches/ubuntu/raring/sbuild/raring-proposed

« back to all changes in this revision

Viewing changes to lib/Sbuild/Build.pm

  • Committer: Bazaar Package Importer
  • Author(s): Laurent Bigonville
  • Date: 2011-06-26 13:59:34 UTC
  • mfrom: (8.1.21 upstream) (3.3.19 sid)
  • Revision ID: james.westby@ubuntu.com-20110626135934-8blyh9rnoiiqflgt
Tags: 0.62.4-1ubuntu1
* Merge from debian unstable, Remaining changes:
  - debian/patches/do-not-install-debfoster-into-chroots.patch:
    do not install debfoster into the chroots because it is in universe and
    not needed for package building itself.
  - debian/patches/run-pre-build-hooks-as-root.patch:
    run pre-build hooks as root

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
use GDBM_File;
36
36
use File::Copy qw(); # copy is already exported from Sbuild, so don't export
37
37
                     # anything.
38
 
use Cwd qw(:DEFAULT abs_path);
39
38
use Dpkg::Arch;
40
39
use Dpkg::Control;
 
40
use Dpkg::Version;
41
41
use MIME::Lite;
42
42
use Term::ANSIColor;
43
43
 
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);
45
45
use Sbuild::Base;
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;
55
54
 
62
61
    @EXPORT = qw();
63
62
}
64
63
 
 
64
our $saved_stdout = undef;
 
65
our $saved_stderr = undef;
 
66
 
65
67
sub new {
66
68
    my $class = shift;
67
69
    my $dsc = shift;
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();
104
107
 
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')));
132
134
 
133
135
    debug("Download = " . $self->get('Download') . "\n");
134
136
    debug("Invalid Source = " . $self->get('Invalid Source') . "\n");
160
162
 
161
163
    debug("Setting DSC: $dsc\n");
162
164
 
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.
165
 
    if (-d $dsc) {
166
 
        my $host = $self->get('Host');
167
 
        my $pipe = $host->pipe_command(
168
 
            { COMMAND => ['dpkg-parsechangelog', '-l' . abs_path($dsc) . '/debian/changelog'],
169
 
              PRIORITY => 0,
170
 
            });
171
 
 
172
 
        if (!defined($pipe)) {
173
 
            Sbuild::Exception::Build->throw(error => "Could not parse $dsc/debian/changelog: $!",
174
 
                                            failstage => "set-dsc");
175
 
        }
176
 
 
177
 
        my $stanzas = parse_file($pipe);
178
 
 
179
 
        my $stanza = @{$stanzas}[0];
180
 
        my $package = ${$stanza}{'Source'};
181
 
        my $version = ${$stanza}{'Version'};
182
 
 
183
 
        if (!defined($package) || !defined($version)) {
184
 
            Sbuild::Exception::Build->throw(error => "Missing Source or Version in $dsc/debian/changelog",
185
 
                                            failstage => "set-dsc");
186
 
        }
187
 
 
188
 
        my $dir = getcwd();
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);
197
 
        }
198
 
        $self->set('Debian Source Dir', abs_path($dsc));
199
 
 
200
 
        $self->set_version("${package}_${version}");
201
 
        $dsc = "$dir/" . $self->get('Package_OSVersion') . ".dsc";
202
 
    }
203
 
 
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");
218
179
 
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();
221
187
 
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;
226
193
 
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'));
231
198
    }
232
199
 
 
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();
 
206
 
233
207
    # Version with binNMU or other additions and stripped epoch
234
 
    (my $sversion = $version) =~ s/^\d+://;
235
 
 
236
 
    my ($epoch, $uversion, $dversion) = split_version($version);
 
208
    my $sversion = $b_version;
 
209
    $sversion .= '-' . $b_revision if $b_revision;
237
210
 
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}");
252
225
 
253
226
    debug("Package = " . $self->get('Package') . "\n");
254
227
    debug("Version = " . $self->get('Version') . "\n");
350
323
 
351
324
    eval {
352
325
        $self->check_abort();
353
 
        $self->run_pack_source();
354
 
        $self->check_abort();
355
326
        $self->run_chroot_session();
356
327
    };
357
328
 
377
348
    }
378
349
}
379
350
 
380
 
# Pack up local source tree
381
 
sub run_pack_source {
382
 
    my $self=shift;
383
 
 
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");
388
 
 
389
 
        $self->log_subsubsection('clean');
390
 
        $self->get('Host')->run_command(
391
 
            { COMMAND => [$self->get_conf('FAKEROOT'),
392
 
                          'debian/rules',
393
 
                          'clean'],
394
 
              DIR => $self->get('Debian Source Dir'),
395
 
              PRIORITY => 0,
396
 
            });
397
 
        if ($?) {
398
 
            Sbuild::Exception::Build->throw(error => "Failed to clean source directory",
399
 
                                            failstage => "pack-source");
400
 
        }
401
 
 
402
 
        $self->check_abort();
403
 
 
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'),
412
 
              PRIORITY => 0,
413
 
            });
414
 
        if ($?) {
415
 
            Sbuild::Exception::Build->throw(error => "Failed to clean source directory",
416
 
                                            failstage => "pack-source");
417
 
        }
418
 
    }
419
 
}
420
 
 
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"));
474
404
 
475
405
        $self->set('Build Dir', $session->strip_chroot_path($self->get('Chroot Build Dir')));
 
406
 
 
407
        # Log colouring
 
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$');
 
415
 
 
416
        # Log filtering
476
417
        my $filter;
477
418
        $filter = $self->get('Build Dir') . '/' . $self->get('DSC Dir');
478
419
        $filter =~ s;^/;;;
483
424
        $filter = $session->get('Location');
484
425
        $filter =~ s;^/;;;
485
426
        $self->build_log_filter($filter , 'CHROOT');
 
427
 
486
428
        # Need tempdir to be writable and readable by sbuild group.
487
429
        $self->check_abort();
488
430
        $session->run_command(
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');
521
464
 
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.
874
817
        my $file;
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
877
820
            return 0;
878
 
        debug("Parsing $dsc\n");
879
821
        my @cwd_files = dsc_files($file);
 
822
 
880
823
        if (-f "$dir/$dsc") {
881
824
            # Copy the local source files into the build directory.
882
825
            $self->log_subsubsection("Local sources");
1335
1278
        }
1336
1279
    }
1337
1280
 
 
1281
    my $cpipe = $self->get('Session')->pipe_command(
 
1282
        { COMMAND => ['dpkg-parsechangelog'],
 
1283
          USER => $self->get_conf('BUILD_USER'),
 
1284
          PRIORITY => 0,
 
1285
          DIR => $self->get('Session')->strip_chroot_path($dscdir) });
 
1286
    my $clog = do { local $/; <$cpipe> };
 
1287
    close($cpipe);
 
1288
    if ($?) {
 
1289
        $self->log("FAILED [dpkg-parsechangelog died]\n");
 
1290
        return 0;
 
1291
    }
 
1292
 
 
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') . "\$");
 
1301
    }
 
1302
 
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> };
1348
1313
            close( F );
1349
1314
 
1350
 
            my $pipe = $self->get('Session')->pipe_command(
1351
 
                { COMMAND => ['dpkg-parsechangelog'],
1352
 
                  USER => $self->get_conf('BUILD_USER'),
1353
 
                  PRIORITY => 0,
1354
 
                  DIR => $self->get('Session')->strip_chroot_path($dscdir) });
1355
 
            my $clog = do { local $/; <$pipe> };
1356
 
            close($pipe);
1357
 
            if ($?) {
1358
 
                $self->log("FAILED [dpkg-parsechangelog died]\n");
1359
 
                return 0;
1360
 
            }
1361
 
 
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;
1367
1315
 
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')});
1485
1433
    }
1486
1434
 
1487
 
    my $buildenv = {};
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'));
1491
1440
 
 
1441
    # Explicitly add any needed environment to the environment filter
 
1442
    # temporarily for dpkg-buildpackage.
 
1443
    my @env_filter;
 
1444
    foreach my $envvar (keys %buildenv) {
 
1445
        push(@env_filter, "^$envvar\$");
 
1446
    }
 
1447
 
1492
1448
    # Dump build environment
1493
1449
    $self->log_subsubsection("User Environment");
1494
1450
    {
1495
1451
        my $pipe = $self->get('Session')->pipe_command(
1496
1452
            { COMMAND => ['env'],
1497
 
              ENV => $buildenv,
 
1453
              ENV => \%buildenv,
 
1454
              ENV_FILTER => \@env_filter,
1498
1455
              USER => $self->get_conf('BUILD_USER'),
1499
1456
              SETSID => 1,
1500
1457
              PRIORITY => 0,
1515
1472
 
1516
1473
    my $command = {
1517
1474
        COMMAND => $buildcmd,
1518
 
        ENV => $buildenv,
 
1475
        ENV => \%buildenv,
 
1476
        ENV_FILTER => \@env_filter,
1519
1477
        USER => $self->get_conf('BUILD_USER'),
1520
1478
        SETSID => 1,
1521
1479
        PRIORITY => 0,
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");
1591
1549
 
1592
1550
    my @space_files = ("$dscdir");
1593
1551
 
2051
2009
    }
2052
2010
}
2053
2011
 
 
2012
sub build_log_colour {
 
2013
    my $self = shift;
 
2014
    my $regex = shift;
 
2015
    my $colour = shift;
 
2016
 
 
2017
    if ($self->get_conf('LOG_COLOUR')) {
 
2018
        $self->log($self->get('COLOUR_PREFIX') . $colour . ':' . $regex . "\n");
 
2019
    }
 
2020
}
 
2021
 
2054
2022
sub open_build_log {
2055
2023
    my $self = shift;
2056
2024
 
2058
2026
 
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);
2061
2031
 
2062
2032
    my $filename = $self->get_conf('LOG_DIR') . '/' .
2063
2033
        $self->get('Package_SVersion') . '-' .
2064
2034
        $self->get('Arch') .
2065
2035
        "-$date";
2066
2036
 
 
2037
    open($saved_stdout, ">&STDOUT") or warn "Can't redirect stdout\n";
 
2038
    open($saved_stderr, ">&STDERR") or warn "Can't redirect stderr\n";
 
2039
 
2067
2040
    my $PLOG;
2068
2041
 
2069
2042
    my $pid;
2105
2078
        my $verbose = $self->get_conf('VERBOSE');
2106
2079
        my $log_colour = $self->get_conf('LOG_COLOUR');
2107
2080
        my @filter = ();
 
2081
        my @colour = ();
2108
2082
        my ($text, $replacement);
2109
2083
        my $filter_regex = "^$filter_prefix(.*):(.*)\$";
 
2084
        my $colour_regex = "^$colour_prefix(.*):(.*)\$";
2110
2085
        my @ignore = ();
2111
2086
 
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";
 
2100
                next;
2120
2101
            } else {
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];
 
2123
                        }
 
2124
                    }
2144
2125
                    print $saved_stdout color $colour;
2145
2126
                }
2146
2127
 
2162
2143
    }
2163
2144
 
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);
2167
2150
 
2240
2223
            $subject .= " (dist=" . $self->get_conf('DISTRIBUTION') . ")";
2241
2224
    }
2242
2225
 
 
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