37
37
use File::Basename qw(basename dirname);
40
use Sbuild qw(binNMU_version version_compare copy);
40
use Sbuild qw($devnull binNMU_version version_compare copy);
42
42
use File::Temp qw(tempdir);
43
use Sbuild::ChrootInfoSchroot;
44
use Sbuild::ChrootInfoSudo;
44
45
use Sbuild::Log qw(open_log close_log);
45
use Sbuild::Sysconfig qw($arch $version);
46
use Sbuild::Sysconfig qw(%programs);
46
47
use Sbuild::Options;
51
sub check_group_membership ();
52
sub check_group_membership ($);
52
53
sub dump_main_state ();
55
my $conf = Sbuild::Conf->new();
56
exit 1 if !defined($conf);
57
my $options = Sbuild::Options->new($conf);
58
exit 1 if !defined($options);
60
check_group_membership($conf);
64
$main::build_object = undef;
55
# Be verbose by default if on a tty
56
if (-t STDIN && -t STDOUT && $Sbuild::Conf::verbose == 0) {
60
my $options = Sbuild::Options::new();
61
exit 1 if !defined($options);
63
print "Selected distribution " . $options->get('Distribution') . "\n"
65
print "Selected chroot " . $options->get('Chroot') . "\n"
66
if $conf::debug and defined $options->get('Chroot');
67
print "Selected architecture " . $options->get('User Arch') . "\n"
70
$conf::mailto = $conf::mailto{$options->get('Distribution')}
71
if $conf::mailto{$options->get('Distribution')};
69
print "Selected distribution " . $conf->get('DISTRIBUTION') . "\n"
70
if $conf->get('DEBUG');
71
print "Selected chroot " . $conf->get('CHROOT') . "\n"
72
if $conf->get('DEBUG') and defined $conf->get('CHROOT');
73
print "Selected architecture " . $conf->get('ARCH') . "\n"
74
if $conf->get('DEBUG' && defined($conf->get('ARCH')));
77
$conf->get('MAILTO_HASH')->{$conf->get('DISTRIBUTION')})
78
if $conf->get('MAILTO_HASH')->{$conf->get('DISTRIBUTION')};
73
80
# see debsign for priorities, we will follow the same order
74
$options->set('Signing Options',
75
"-m\"".$conf::maintainer_name."\"")
76
if defined $conf::maintainer_name;
77
$options->set('Signing Options',
78
"-e\"".$conf::uploader_name."\"")
79
if defined $conf::uploader_name;
80
$options->set('Signing Options',
81
"-k\"".$conf::key_id."\"")
82
if defined $conf::key_id;
83
$conf::maintainer_name=$conf::uploader_name if defined $conf::uploader_name;
84
$conf::maintainer_name=$conf::key_id if defined $conf::key_id;
81
$conf->set('SIGNING_OPTIONS',
82
"-m".$conf->get('MAINTAINER_NAME')."")
83
if defined $conf->get('MAINTAINER_NAME');
84
$conf->set('SIGNING_OPTIONS',
85
"-e".$conf->get('UPLOADER_NAME')."")
86
if defined $conf->get('UPLOADER_NAME');
87
$conf->set('SIGNING_OPTIONS',
88
"-k".$conf->get('KEY_ID')."")
89
if defined $conf->get('KEY_ID');
90
$conf->set('MAINTAINER_NAME', $conf->get('UPLOADER_NAME')) if defined $conf->get('UPLOADER_NAME');
91
$conf->set('MAINTAINER_NAME', $conf->get('KEY_ID')) if defined $conf->get('KEY_ID');
86
if (!defined($conf::maintainer_name) &&
87
$options->get('binNMU')) {
93
if (!defined($conf->get('MAINTAINER_NAME')) &&
94
$conf->get('BIN_NMU')) {
88
95
die "A maintainer name, uploader name or key ID must be specified in .sbuildrc,\nor use -m, -e or -k, when performing a binNMU\n";
91
98
# variables for scripts:
92
open_log($options->get('Distribution'));
99
open_log($conf->get('DISTRIBUTION'), $conf);
93
100
$SIG{'INT'} = \&shutdown;
94
101
$SIG{'TERM'} = \&shutdown;
95
102
$SIG{'ALRM'} = \&shutdown;
99
106
foreach $dscfile (@ARGV) {
101
108
# TODO: Append to build list, to allow parallel builds.
102
my $build = Sbuild::Build::new($dscfile, $options);
109
my $build = Sbuild::Build->new($dscfile, $conf);
103
110
$main::build_object = $build;
105
$build->{'Pkg Start Time'} = time;
112
$build->set('Pkg Start Time', time);
107
114
$main::build_object->write_jobs_file("");
108
115
$build->parse_manual_srcdeps(map { m,(?:.*/)?([^_/]+)[^/]*, } @ARGV);
110
if ($build->{'Invalid Source'}) {
111
print PLOG "Invalid source: $dscfile\n";
112
print PLOG "Skipping " . $build->{'Package'} . " \n";
113
$build->{'Pkg Status'} = "skipped";
117
if ($build->get('Invalid Source')) {
118
$build->log("Invalid source: $dscfile\n");
119
$build->log("Skipping " . $build->get('Package') . " \n");
120
$build->set('Pkg Status', 'skipped');
114
121
goto cleanup_skip;
125
if ($conf->get('CHROOT_MODE') eq 'schroot') {
126
$chroot_info = Sbuild::ChrootInfoSchroot->new($conf);
128
$chroot_info = Sbuild::ChrootInfoSudo->new($conf);
131
my $session = $chroot_info->create($conf->get('DISTRIBUTION'),
132
$conf->get('CHROOT'),
135
if (!$session->begin_session()) {
136
$build->log("Error creating chroot session: skipping " .
137
$build->get('Package') . "\n");
138
$build->set('Pkg Status', 'skipped');
142
$build->set('Session', $session);
143
$build->set('Arch', $build->chroot_arch());
145
$build->set('Chroot Dir', $session->get('Location'));
146
$build->set('Chroot Build Dir',
147
tempdir($conf->get('USERNAME') . '-' .
148
$build->get('Package_SVersion') . '-' .
149
$build->get('Arch') . '-XXXXXX',
150
DIR => $session->get('Build Location')));
151
# TODO: Don't hack the build location in; add a means to customise
152
# the chroot directly.
153
$session->set('Build Location', $build->get('Chroot Build Dir'));
118
my $tpkg = basename($build->{'Package_Version'});
156
my $tpkg = basename($build->get('Package_Version'));
119
157
# TODO: This should be 'Pkg Start Time', set in build().
120
158
my $date = strftime("%Y%m%d-%H%M",localtime);
122
if ($options->get('binNMU')) {
160
if ($conf->get('BIN_NMU')) {
123
161
$tpkg =~ /^([^_]+)_([^_]+)(.*)$/;
124
$tpkg = $1 . "_" . binNMU_version($2,$options->get('binNMU Version'));
125
$options->set('binNMU Name', $tpkg);
162
$tpkg = $1 . "_" . binNMU_version($2,$conf->get('BIN_NMU_VERSION'));
163
$build->set('binNMU Name', $tpkg);
130
168
next if !$build->open_build_log($tpkg);
133
$build->{'Pkg Status'} = "failed"; # assume for now
134
$main::current_job = $build->{'Package_Version'};
135
$build->{'Additional Deps'} = [];
171
# Needed so chroot commands log to build log
172
$session->set('Log Stream', $build->get('Log Stream'));
174
# Chroot execution defaults
175
my $chroot_defaults = $session->get('Defaults');
176
$chroot_defaults->{'DIR'} =
177
$session->strip_chroot_path($session->get('Build Location'));
178
$chroot_defaults->{'STREAMIN'} = $devnull;
179
$chroot_defaults->{'STREAMOUT'} = $build->get('Log Stream');
180
$chroot_defaults->{'STREAMERR'} = $build->get('Log Stream');
181
$chroot_defaults->{'ENV'}->{'LC_ALL'} = 'POSIX';
182
$chroot_defaults->{'ENV'}->{'SHELL'} = $programs{'SHELL'};
184
$build->set('Session', $session);
186
$build->set('Pkg Status', 'failed'); # assume for now
187
$main::current_job = $build->get('Package_Version');
188
$build->set('Additional Deps', []);
136
189
$main::build_object->write_jobs_file("currently building");
137
190
if ($build->should_skip()) {
138
$build->{'Pkg Status'} = "skipped";
142
my $session = Sbuild::Chroot::new($options->get('Distribution'),
143
$options->get('Chroot'),
144
$options->get('User Arch'));
145
$build->{'Session'} = $session;
147
if (!$session->begin_session()) {
148
print PLOG "Error creating schroot session: skipping " .
149
$build->{'Package'} . "\n";
150
$build->{'Pkg Status'} = "skipped";
153
$build->{'Chroot Dir'} = $session->{'Location'};
154
$build->{'Chroot Build Dir'} =
155
tempdir("$Sbuild::Conf::username-" .
156
$build->{'Package_SVersion'} .
158
DIR => $session->{'Build Location'});
159
# TODO: Don't hack the build location in; add a means to customise
160
# the chroot directly.
161
$session->{'Build Location'} = $build->{'Chroot Build Dir'};
163
$build->{'Arch'} = $build->chroot_arch();
191
$build->set('Pkg Status', 'skipped');
165
196
# Update APT cache.
166
if ($conf::apt_update) {
167
if (!open(PIPE, $session->get_apt_command("$conf::apt_get", "-q update", "root", 1, '/') . " 2>&1 |")) {
168
print PLOG "Can't open pipe to apt-get: $!\n";
197
if ($conf->get('APT_UPDATE')) {
198
$session->run_apt_command(
199
{ COMMAND => [$conf->get('APT_GET'), 'update'],
176
print PLOG "apt-get update failed\n" ;
177
$build->{'Pkg Status'} = "skipped";
205
$build->log("apt-get update failed\n");
206
$build->set('Pkg Status', 'skipped');
178
207
goto cleanup_close;
182
$build->{'Pkg Fail Stage'} = "fetch-src";
211
$build->set('Pkg Fail Stage', 'fetch-src');
183
212
if (!$build->fetch_source_files()) {
184
213
goto cleanup_close;
188
if ($conf::setup_cmd) {
189
my $cmd = $session->get_command("$conf::setup_cmd *.dsc ".$options->get('Distribution'), "root", 1);
190
if (!open(PIPE, $cmd." 2>&1 |")) {
191
print PLOG "Can't open pipe to setup-cmd ($cmd): $!\n";
217
if ($conf->get('SETUP_HOOK')) {
218
my $pipe = $session->pipe_command({
219
COMMAND => [$conf->get('SETUP_HOOK')],
220
ENV => $build->get_env('SBUILD_BUILD_'),
199
print PLOG "setup-cmd ($cmd) failed\n" ;
200
$build->{'Pkg Status'} = "skipped";
229
$build->log("setup-hook failed\n");
230
$build->set('Pkg Status', 'skipped');
201
231
goto cleanup_packages;
205
$build->{'Pkg Fail Stage'} = "install-deps";
235
$build->set('Pkg Fail Stage', 'install-deps');
206
236
if (!$build->install_deps()) {
207
print PLOG "Source-dependencies not satisfied; skipping " .
208
$build->{'Package'} . "\n";
237
$build->log("Source-dependencies not satisfied; skipping " .
238
$build->get('Package') . "\n");
209
239
goto cleanup_packages;
212
$build->{'Pkg Status'} = "successful"
213
# TODO: Don't pass version info
242
$build->set('Pkg Status', 'successful')
214
243
if $build->build();
215
$main::build_object->write_jobs_file($build->{'Pkg Status'});
244
$build->write_jobs_file($build->get('Pkg Status'));
216
245
$build->append_to_FINISHED();
218
247
cleanup_packages:
219
if (defined ($session->{'Session Purged'}) &&
220
$session->{'Session Purged'} == 1) {
221
print PLOG "Not removing build depends: cloned chroot in use\n";
248
if (defined ($session->get('Session Purged')) &&
249
$session->get('Session Purged') == 1) {
250
$build->log("Not removing build depends: cloned chroot in use\n");
223
252
$build->uninstall_deps();
225
254
$build->remove_srcdep_lock_file();
227
256
$build->analyze_fail_stage();
228
$main::build_object->write_jobs_file($build->{'Pkg Status'});
257
$main::build_object->write_jobs_file($build->get('Pkg Status'));
230
259
$session->end_session();
231
260
$session = undef;
232
$build->{'Session'} = undef;
261
$build->set('Session', undef);
234
263
$build->close_build_log();
237
undef $build->{'binNMU Name'};
266
$build->set('binNMU Name', undef);
238
267
$main::current_job = "";
239
if ( $options->get('Batch Mode') and (-f "$conf::HOME/EXIT-DAEMON-PLEASE") ) {
268
if ($conf->get('BATCH_MODE') and (-f $conf->get('HOME') . '/EXIT-DAEMON-PLEASE') ) {
240
269
main::shutdown("NONE (flag file exit)");
242
dump_main_state() if $conf::debug;
271
dump_main_state() if $conf->get('DEBUG');
243
272
$main::build_object->write_jobs_file("");
247
unlink( $main::build_object->{'Jobs File'} )
248
if $options->get('Batch Mode');
249
unlink( "SBUILD-FINISHED" ) if $options->get('Batch Mode');
250
if ($conf::sbuild_mode eq "user" && defined($main::build_object)) {
251
exit ($main::build_object->{'Pkg Status'} ne "successful") ? 1 : 0;
276
unlink($main::build_object->get('Jobs File'))
277
if $conf->get('BATCH_MODE');
278
unlink("SBUILD-FINISHED") if $conf->get('BATCH_MODE');
279
if ($conf->get('SBUILD_MODE') eq "user" && defined($main::build_object)) {
280
exit ($main::build_object->get('Pkg Status') ne "successful") ? 1 : 0;
325
355
# next: kill currently running command (if one)
326
if ($main::build_object->{'Sub PID'}) {
327
print "Killing $main::build_object->{'Sub Task'} subprocess $main::build_object->{'Sub PID'}\n";
328
$main::build_object->{'Session'}->run_command("perl -e \"kill( \\\"TERM\\\", $main::build_object->{'Sub PID'} )\"", "root", 1, 0, '/');
356
if ($main::build_object->get('Sub PID')) {
357
print "Killing " . $main::build_object->get('Sub Task') .
358
" subprocess " . $main::build_object->get('Sub PID') . "\n";
359
$main::build_object->get('Session')->run_command(
360
{ COMMAND => ['perl', '-e',
361
"\"kill( \\\"TERM\\\", " .
362
$main::build_object->get('Sub PID') .
330
369
$main::build_object->remove_srcdep_lock_file();
332
371
# close logs and send mails
333
if ( $main::current_job && defined($main::build_object->{'Session'})) {
334
if ($conf::purge_build_directory eq "always") {
335
print PLOG "Purging $main::build_object->{'Chroot Build Dir'}\n";
336
my $bdir = $main::build_object->{'Session'}->strip_chroot_path($main::build_object->{'Chroot Build Dir'});
337
$main::build_object->{'Session'}->run_command("rm -rf '$bdir'", "root", 1, 0, '/');
372
if ( $main::current_job && defined($main::build_object->get('Session'))) {
373
if ($conf->get('PURGE_BUILD_DIRECTORY') eq "always") {
374
$main::build_object->log("Purging " . $main::build_object->get('Chroot Build Dir') . "\n");
375
my $bdir = $main::build_object->get('Session')->strip_chroot_path($main::build_object->get('Chroot Build Dir'));
376
$main::build_object->get('Session')->run_command(
377
{ COMMAND => [$Sbuild::Sysconfig::programs{'RM'},
340
385
$main::current_job =
341
386
$main::build_object->fixup_pkgv($main::current_job);
343
$main::build_object->{'Session'}->end_session();
344
undef $main::build_object->{'Session'};
388
$main::build_object->get('Session')->end_session();
389
$main::build_object->set('Session', undef);
346
391
$main::build_object->close_build_log();
347
undef $main::build_object->{'binNMU Name'};
392
$main::build_object->set('binNMU Name', undef);
350
unlink( $main::build_object->{'Jobs File'} ) if $main::build_object->{'Batch Mode'};
395
unlink( $main::build_object->get('Jobs File') ) if $conf->get('BATCH_MODE');
352
if ($conf::sbuild_mode eq "user") {
397
if ($conf->get('SBUILD_MODE') eq "user") {
358
sub check_group_membership () {
403
sub check_group_membership ($) {
359
406
my $user = getpwuid($<);
360
407
my ($name,$passwd,$gid,$members) = getgrnam("sbuild");