forked from josch/mmdebstrap
add --setup-hook, --essential-hook and rename --customize to --customize-hook
This commit is contained in:
parent
d72a582a8b
commit
0b058c7db1
2 changed files with 176 additions and 50 deletions
61
coverage.sh
61
coverage.sh
|
@ -300,8 +300,8 @@ cat << END > shared/test.sh
|
|||
set -eu
|
||||
export LC_ALL=C.UTF-8
|
||||
mount -t tmpfs -o nodev,nosuid,size=300M tmpfs /tmp
|
||||
# use --customize to exercise the mounting/unmounting code of block devices in root mode
|
||||
$CMD --mode=root --variant=apt --customize='mount | grep /dev/full' --customize='test "\$(echo foo | tee /dev/full 2>&1 1>/dev/null)" = "tee: /dev/full: No space left on device"' unstable /tmp/unstable-chroot.tar $mirror
|
||||
# use --customize-hook to exercise the mounting/unmounting code of block devices in root mode
|
||||
$CMD --mode=root --variant=apt --customize-hook='mount | grep /dev/full' --customize-hook='test "\$(echo foo | tee /dev/full 2>&1 1>/dev/null)" = "tee: /dev/full: No space left on device"' unstable /tmp/unstable-chroot.tar $mirror
|
||||
tar -tf /tmp/unstable-chroot.tar | sort > tar2.txt
|
||||
diff -u tar1.txt tar2.txt
|
||||
rm /tmp/unstable-chroot.tar
|
||||
|
@ -528,7 +528,60 @@ else
|
|||
./run_null.sh SUDO
|
||||
fi
|
||||
|
||||
print_header "mode=root,variant=apt: test --customize"
|
||||
print_header "mode=root,variant=apt: test --setup-hook"
|
||||
cat << END > shared/test.sh
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
export LC_ALL=C.UTF-8
|
||||
cat << 'SCRIPT' > customize.sh
|
||||
#!/bin/sh
|
||||
for d in sbin lib; do ln -s usr/\$d "\$1/\$d"; mkdir -p "\$1/usr/\$d"; done
|
||||
SCRIPT
|
||||
chmod +x customize.sh
|
||||
$CMD --mode=root --variant=apt --setup-hook='ln -s usr/bin "\$1/bin"; mkdir -p "\$1/usr/bin"' --setup-hook=./customize.sh unstable /tmp/debian-unstable $mirror
|
||||
tar -C /tmp/debian-unstable --one-file-system -c . | tar -t | sort > tar2.txt
|
||||
{ sed -e 's/^\.\/bin\//.\/usr\/bin\//;s/^\.\/lib\//.\/usr\/lib\//;s/^\.\/sbin\//.\/usr\/sbin\//;' tar1.txt; echo ./bin; echo ./lib; echo ./sbin; } | sort -u | diff -u - tar2.txt
|
||||
rm customize.sh
|
||||
rm -r /tmp/debian-unstable
|
||||
END
|
||||
if [ "$HAVE_QEMU" = "yes" ]; then
|
||||
./run_qemu.sh
|
||||
else
|
||||
./run_null.sh SUDO
|
||||
fi
|
||||
|
||||
print_header "mode=root,variant=apt: test --essential-hook"
|
||||
cat << END > shared/test.sh
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
export LC_ALL=C.UTF-8
|
||||
cat << 'SCRIPT' > customize.sh
|
||||
#!/bin/sh
|
||||
echo tzdata tzdata/Zones/Europe select Berlin | chroot "\$1" debconf-set-selections
|
||||
SCRIPT
|
||||
chmod +x customize.sh
|
||||
$CMD --mode=root --variant=apt --include=tzdata --essential-hook='echo tzdata tzdata/Areas select Europe | chroot "\$1" debconf-set-selections' --essential-hook=./customize.sh unstable /tmp/debian-unstable $mirror
|
||||
echo Europe/Berlin | cmp /tmp/debian-unstable/etc/timezone
|
||||
tar -C /tmp/debian-unstable --one-file-system -c . | tar -t | sort \
|
||||
| grep -v '^./etc/localtime' \
|
||||
| grep -v '^./etc/timezone' \
|
||||
| grep -v '^./usr/sbin/tzconfig' \
|
||||
| grep -v '^./usr/share/doc/tzdata' \
|
||||
| grep -v '^./usr/share/zoneinfo' \
|
||||
| grep -v '^./var/lib/dpkg/info/tzdata.' \
|
||||
| grep -v '^./var/log/apt/eipp.log.xz$' \
|
||||
> tar2.txt
|
||||
diff -u tar1.txt tar2.txt
|
||||
rm customize.sh
|
||||
rm -r /tmp/debian-unstable
|
||||
END
|
||||
if [ "$HAVE_QEMU" = "yes" ]; then
|
||||
./run_qemu.sh
|
||||
else
|
||||
./run_null.sh SUDO
|
||||
fi
|
||||
|
||||
print_header "mode=root,variant=apt: test --customize-hook"
|
||||
cat << END > shared/test.sh
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
@ -539,7 +592,7 @@ chroot "\$1" whoami > "\$1/output2"
|
|||
chroot "\$1" pwd >> "\$1/output2"
|
||||
SCRIPT
|
||||
chmod +x customize.sh
|
||||
$CMD --mode=root --variant=apt --customize='chroot "\$1" sh -c "whoami; pwd" > "\$1/output1"' --customize=./customize.sh unstable /tmp/debian-unstable $mirror
|
||||
$CMD --mode=root --variant=apt --customize-hook='chroot "\$1" sh -c "whoami; pwd" > "\$1/output1"' --customize-hook=./customize.sh unstable /tmp/debian-unstable $mirror
|
||||
printf "root\n/\n" | cmp /tmp/debian-unstable/output1
|
||||
printf "root\n/\n" | cmp /tmp/debian-unstable/output2
|
||||
rm /tmp/debian-unstable/output1
|
||||
|
|
165
mmdebstrap
165
mmdebstrap
|
@ -875,6 +875,40 @@ sub run_chroot(&$) {
|
|||
}
|
||||
}
|
||||
|
||||
sub run_hooks($$) {
|
||||
my $name = shift;
|
||||
my $options = shift;
|
||||
|
||||
if (scalar @{$options->{"${name}_hook"}} == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
my $runner = sub {
|
||||
foreach my $script (@{$options->{"${name}_hook"}}) {
|
||||
if ( -x $script || $script !~ m/[^\w@\%+=:,.\/-]/a) {
|
||||
info "running --$name-hook directly: $script $options->{root}";
|
||||
# execute it directly if it's an executable file
|
||||
# or if it there are no shell metacharacters
|
||||
# (the /a regex modifier makes \w match only ASCII)
|
||||
0 == system($script, $options->{root}) or error "command failed: $script";
|
||||
} else {
|
||||
info "running --$name-hook in shell: sh -c '$script' exec $options->{root}";
|
||||
# otherwise, wrap everything in sh -c
|
||||
0 == system('sh', '-c', $script, 'exec', $options->{root}) or error "command failed: $script";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if ($name eq 'setup') {
|
||||
# execute directly without mounting anything (the mount points do not
|
||||
# exist yet)
|
||||
&{$runner}();
|
||||
} else {
|
||||
run_chroot \&$runner, $options;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub setup {
|
||||
my $options = shift;
|
||||
|
||||
|
@ -1068,6 +1102,16 @@ sub setup {
|
|||
# into account.
|
||||
$ENV{"APT_CONFIG"} = "$tmpfile";
|
||||
|
||||
# setting PATH for chroot, ldconfig, start-stop-daemon...
|
||||
if (defined $ENV{PATH} && $ENV{PATH} ne "") {
|
||||
$ENV{PATH} = "$ENV{PATH}:/usr/sbin:/usr/bin:/sbin:/bin";
|
||||
} else {
|
||||
$ENV{PATH} = "/usr/sbin:/usr/bin:/sbin:/bin";
|
||||
}
|
||||
|
||||
# run setup hooks
|
||||
run_hooks('setup', $options);
|
||||
|
||||
info "running apt-get update...";
|
||||
run_apt_progress({ ARGV => ['apt-get', 'update'] });
|
||||
|
||||
|
@ -1085,13 +1129,6 @@ sub setup {
|
|||
}
|
||||
}
|
||||
|
||||
# setting PATH for chroot, ldconfig, start-stop-daemon...
|
||||
if (defined $ENV{PATH} && $ENV{PATH} ne "") {
|
||||
$ENV{PATH} = "$ENV{PATH}:/usr/sbin:/usr/bin:/sbin:/bin";
|
||||
} else {
|
||||
$ENV{PATH} = "/usr/sbin:/usr/bin:/sbin:/bin";
|
||||
}
|
||||
|
||||
my %pkgs_to_install;
|
||||
if (defined $options->{include}) {
|
||||
for my $pkg (split /,/, $options->{include}) {
|
||||
|
@ -1307,6 +1344,9 @@ sub setup {
|
|||
if (any { $_ eq $options->{variant} } ('extract', 'custom')) {
|
||||
# nothing to do
|
||||
} elsif (any { $_ eq $options->{variant} } ('essential', 'apt', 'standard', 'important', 'required', 'buildd', 'minbase')) {
|
||||
# run essential hooks
|
||||
run_hooks('essential', $options);
|
||||
|
||||
if (%pkgs_to_install) {
|
||||
run_apt_progress({
|
||||
ARGV => ['apt-get', '--yes',
|
||||
|
@ -1495,6 +1535,9 @@ sub setup {
|
|||
unlink "$options->{root}/$deb" or error "cannot unlink $deb";
|
||||
}
|
||||
|
||||
# run essential hooks
|
||||
run_hooks('essential', $options);
|
||||
|
||||
if (%pkgs_to_install) {
|
||||
# some packages have to be installed from the outside before anything
|
||||
# can be installed from the inside.
|
||||
|
@ -1592,23 +1635,7 @@ sub setup {
|
|||
error "unknown mode: $options->{mode}";
|
||||
}
|
||||
|
||||
if (scalar @{$options->{customize}} > 0) {
|
||||
run_chroot {
|
||||
foreach my $script (@{$options->{customize}}) {
|
||||
if ( -x $script || $script !~ m/[^\w@\%+=:,.\/-]/a) {
|
||||
info "running customize script directly: $script $options->{root}";
|
||||
# execute it directly if it's an executable file
|
||||
# or if it there are no shell metacharacters
|
||||
# (the /a regex modifier makes \w match only ASCII)
|
||||
0 == system($script, $options->{root}) or error "customization script failed: $script";
|
||||
} else {
|
||||
info "running customize script in shell: sh -c '$script' exec $options->{root}";
|
||||
# otherwise, wrap everything in sh -c
|
||||
0 == system('sh', '-c', $script, 'exec', $options->{root}) or error "customization script failed: $script";
|
||||
}
|
||||
}
|
||||
} $options;
|
||||
}
|
||||
run_hooks('customize', $options);
|
||||
|
||||
# clean up temporary configuration file
|
||||
unlink "$options->{root}/etc/apt/apt.conf.d/00mmdebstrap" or error "failed to unlink /etc/apt/apt.conf.d/00mmdebstrap: $!";
|
||||
|
@ -1663,7 +1690,9 @@ sub main() {
|
|||
dpkgopts => [],
|
||||
aptopts => [],
|
||||
noop => [],
|
||||
customize => [],
|
||||
setup_hook => [],
|
||||
essential_hook => [],
|
||||
customize_hook => [],
|
||||
};
|
||||
chomp ($options->{architectures} = `dpkg --print-architecture`);
|
||||
Getopt::Long::Configure ("bundling");
|
||||
|
@ -1685,8 +1714,10 @@ sub main() {
|
|||
'resolve-deps' => sub { push @{$options->{noop}}, 'resolve-deps'; },
|
||||
'merged-usr' => sub { push @{$options->{noop}}, 'merged-usr'; },
|
||||
'no-merged-usr' => sub { push @{$options->{noop}}, 'no-merged-usr'; },
|
||||
# option is hidden until I'm happy with it
|
||||
'customize=s@' => \$options->{customize},
|
||||
# hook options are hidden until I'm happy with them
|
||||
'setup-hook=s@' => \$options->{setup_hook},
|
||||
'essential-hook=s@' => \$options->{essential_hook},
|
||||
'customize-hook=s@' => \$options->{customize_hook},
|
||||
) or pod2usage(-exitval => 2, -verbose => 1);
|
||||
|
||||
foreach my $arg (@{$options->{noop}}) {
|
||||
|
@ -2465,23 +2496,65 @@ running mmdebstrap.
|
|||
|
||||
=begin comment
|
||||
|
||||
=item B<--customize>=I<command>
|
||||
=item B<--setup-hook>=I<command>
|
||||
|
||||
Execute arbitrary I<command>s after the chroot is set up and before it is
|
||||
cleaned up. Can be specified multiple times. The commands are executed in the
|
||||
order in which they are given on the command line. If I<command> is an
|
||||
existing executable file or if I<command> does not contain any shell
|
||||
metacharacters, then I<command> is directly exec-ed with the path to the
|
||||
chroot directory passed as the first argument. Otherwise, I<command> is
|
||||
executed under I<sh> and the chroot directory can be accessed via I<$1>.
|
||||
Execute arbitrary I<command>s right after initial setup (directory creation,
|
||||
configuration of apt and dpkg, ...) but before any packages are downloaded or
|
||||
installed. At that point, the chroot directory does not contain any
|
||||
executables and thus cannot be chroot-ed into. The option can be specified
|
||||
multiple times and the commands are executed in the order in which they are
|
||||
given on the command line. If I<command> is an existing executable file or if
|
||||
I<command> does not contain any shell metacharacters, then I<command> is
|
||||
directly exec-ed with the path to the chroot directory passed as the first
|
||||
argument. Otherwise, I<command> is executed under I<sh> and the chroot
|
||||
directory can be accessed via I<$1>. All environment variables used by
|
||||
B<mmdebstrap> (like C<APT_CONFIG>, C<DEBIAN_FRONTEND>, C<LC_ALL> and C<PATH>)
|
||||
are preserved.
|
||||
|
||||
Examples:
|
||||
|
||||
--customize='chroot "$1" passwd --delete root'
|
||||
--customize='chroot "$1" useradd --home-dir /home/user --create-home user'
|
||||
--customize='chroot "$1" passwd --delete user'
|
||||
--customize='echo host > "$1/etc/hostname"'
|
||||
--customize=/usr/share/autopkgtest/setup-commands/setup-testbed
|
||||
--setup-hook='for d in bin sbin lib; do ln -s usr/$d "$1/$d"; mkdir -p "$1/usr/$d"; done'
|
||||
|
||||
=item B<--essential-hook>=I<command>
|
||||
|
||||
Execute arbitrary I<command>s after the Essential:yes packages have been
|
||||
installed but before installing the remaining packages. The hook is not
|
||||
executed for the B<extract> and B<custom> variants. The option can be
|
||||
specified multiple times and the commands are executed in the order in which
|
||||
they are given on the command line. If I<command> is an existing executable
|
||||
file or if I<command> does not contain any shell metacharacters, then
|
||||
I<command> is directly exec-ed with the path to the chroot directory passed as
|
||||
the first argument. Otherwise, I<command> is executed under I<sh> and the
|
||||
chroot directory can be accessed via I<$1>. All environment variables used by
|
||||
B<mmdebstrap> (like C<APT_CONFIG>, C<DEBIAN_FRONTEND>, C<LC_ALL> and C<PATH>)
|
||||
are preserved.
|
||||
|
||||
Examples:
|
||||
|
||||
--essential-hook='echo unattended-upgrades unattended-upgrades/enable_auto_updates boolean true | chroot "$1" debconf-set-selections'
|
||||
--essential-hook='echo tzdata tzdata/Areas select Europe | chroot "$1" debconf-set-selections'
|
||||
--essential-hook='echo tzdata tzdata/Zones/Europe select Berlin | chroot "$1" debconf-set-selections'
|
||||
|
||||
=item B<--customize-hook>=I<command>
|
||||
|
||||
Execute arbitrary I<command>s after the chroot is set up and all packages got
|
||||
installed but before final cleanup actions are carried out. The option can be
|
||||
specified multiple times and the commands are executed in the order in which
|
||||
they are given on the command line. If I<command> is an existing executable
|
||||
file or if I<command> does not contain any shell metacharacters, then
|
||||
I<command> is directly exec-ed with the path to the chroot directory passed as
|
||||
the first argument. Otherwise, I<command> is executed under I<sh> and the
|
||||
chroot directory can be accessed via I<$1>. All environment variables used by
|
||||
B<mmdebstrap> (like C<APT_CONFIG>, C<DEBIAN_FRONTEND>, C<LC_ALL> and C<PATH>)
|
||||
are preserved.
|
||||
|
||||
Examples:
|
||||
|
||||
--customize-hook='chroot "$1" passwd --delete root'
|
||||
--customize-hook='chroot "$1" useradd --home-dir /home/user --create-home user'
|
||||
--customize-hook='chroot "$1" passwd --delete user'
|
||||
--customize-hook='echo host > "$1/etc/hostname"'
|
||||
--customize-hook=/usr/share/autopkgtest/setup-commands/setup-testbed
|
||||
|
||||
=end comment
|
||||
|
||||
|
@ -2643,12 +2716,12 @@ Use as debootstrap replacement in sbuild-createchroot:
|
|||
Use as replacement for autopkgtest-build-qemu and vmdb2:
|
||||
|
||||
$ mmdebstrap --variant=important --include=linux-image-amd64 \
|
||||
--customize='chroot "$1" passwd --delete root' \
|
||||
--customize='chroot "$1" useradd --home-dir /home/user --create-home user' \
|
||||
--customize='chroot "$1" passwd --delete user' \
|
||||
--customize='echo host > "$1/etc/hostname"' \
|
||||
--customize='echo "127.0.0.1 localhost host" > "$1/etc/hosts"' \
|
||||
--customize=/usr/share/autopkgtest/setup-commands/setup-testbed \
|
||||
--customize-hook='chroot "$1" passwd --delete root' \
|
||||
--customize-hook='chroot "$1" useradd --home-dir /home/user --create-home user' \
|
||||
--customize-hook='chroot "$1" passwd --delete user' \
|
||||
--customize-hook='echo host > "$1/etc/hostname"' \
|
||||
--customize-hook='echo "127.0.0.1 localhost host" > "$1/etc/hosts"' \
|
||||
--customize-hook=/usr/share/autopkgtest/setup-commands/setup-testbed \
|
||||
unstable debian-unstable.tar
|
||||
$ cat << END > extlinux.conf
|
||||
> default linux
|
||||
|
|
Loading…
Reference in a new issue