Skip to content

Commit 71c0390

Browse files
lnusselblucaAdrian Schröter
authored
mkosi fixes (openSUSE#985)
* mkosi: implement obsbinlnk Allow to build mkosi images using other mkosi images (systemd-sysext) * mkosi: implement query() and queryhrdmd5() for image dependencies * vm-type:qemu use virtio on x86_64 * Fix mkosi recipe detection * Make mkosi call more readable * mkosi fixes This makes baseimage builds with mkosi somehow possible. This not a proper solution. With mkiso the codepath of kiwimode needs to be activated really and repos be used instead of .build.binaries. --------- Co-authored-by: Luca Boccassi <[email protected]> Co-authored-by: Adrian Schröter <[email protected]>
1 parent cdc4b5b commit 71c0390

8 files changed

+162
-6
lines changed

Build.pm

+2
Original file line numberDiff line numberDiff line change
@@ -1367,6 +1367,7 @@ sub query {
13671367
return Build::Kiwi::queryiso($handle, %opts) if $do_kiwi && $binname =~ /\.iso$/;
13681368
return Build::Arch::query($handle, %opts) if $do_arch && $binname =~ /\.pkg\.tar(?:\.gz|\.xz|\.zst)?$/;
13691369
return Build::Arch::query($handle, %opts) if $do_arch && $binname =~ /\.arch$/;
1370+
return Build::Mkosi::queryiso($handle, %opts) if $do_mkosi && $binname =~ /\.(raw|tar|cpio|qcow2)(?:\.gz|\.xz|\.zstd)?$/;
13701371
return undef;
13711372
}
13721373

@@ -1392,6 +1393,7 @@ sub queryhdrmd5 {
13921393
my ($binname) = @_;
13931394
return Build::Rpm::queryhdrmd5(@_) if $do_rpm && $binname =~ /\.d?rpm$/;
13941395
return Build::Deb::queryhdrmd5(@_) if $do_deb && $binname =~ /\.deb$/;
1396+
return Build::Mkosi::queryhdrmd5(@_) if $do_mkosi && $binname =~ /\.(raw|tar|cpio|qcow2)(?:\.gz|\.xz|\.zstd)?$/;
13951397
return Build::Kiwi::queryhdrmd5(@_) if $do_kiwi && $binname =~ /\.iso$/;
13961398
return Build::Kiwi::queryhdrmd5(@_) if $do_kiwi && $binname =~ /\.raw$/;
13971399
return Build::Kiwi::queryhdrmd5(@_) if $do_kiwi && $binname =~ /\.raw.install$/;

Build/Mkosi.pm

+65
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,76 @@ sub parse {
6767
if (length $cfg->val('Content', 'BuildPackages')) {
6868
push(@packages, split /\s+/, $cfg->val('Content', 'BuildPackages'));
6969
}
70+
# XXX: split by comma
71+
if (length $cfg->val('Content', 'BaseTrees')) {
72+
push(@packages, "mkosi:".$cfg->val('Content', 'BaseTrees'));
73+
}
7074

7175
$ret->{'name'} = $fn;
7276
$ret->{'deps'} = \@packages;
7377

7478
return $ret;
7579
}
7680

81+
sub queryiso {
82+
my ($file, %opts) = @_;
83+
my $json_fh;
84+
my $md5 = Digest::MD5->new;
85+
86+
open(my $fh, '<', $file) or die("Error opening $file: $!\n");
87+
$md5->addfile($fh);
88+
close($fh);
89+
# If we also have split verity artifacts, the manifest file is the same as the main image,
90+
# so remove the suffixes to find it
91+
$file =~ s/(\.root|\.usr)//g;
92+
$file = $file . ".manifest.gz";
93+
94+
eval { require JSON; };
95+
*JSON::decode_json = sub {die("JSON::decode_json is not available\n")} unless defined &JSON::decode_json;
96+
97+
eval { require IO::Uncompress::Gunzip; };
98+
*IO::Uncompress::Gunzip::new = sub {die("IO::Uncompress::Gunzip is not available\n")} unless defined &IO::Uncompress::Gunzip::new;
99+
100+
my $json_text = do {
101+
open($json_fh, "<", $file) or die("Error opening $file: $!\n");
102+
$json_fh = IO::Uncompress::Gunzip->new($json_fh) or die("Error opening $file: $IO::Uncompress::Gunzip::GunzipError\n");
103+
local $/;
104+
<$json_fh>
105+
};
106+
107+
my $metadata = JSON::decode_json($json_text);
108+
close $json_fh;
109+
110+
if (!$metadata || !$metadata->{'config'}) {
111+
return {};
112+
}
113+
114+
my $distribution = $metadata->{'config'}->{'distribution'};
115+
my $release = $metadata->{'config'}->{'release'};
116+
my $architecture = $metadata->{'config'}->{'architecture'};
117+
my $name = $metadata->{'config'}->{'name'};
118+
my $version = $metadata->{'config'}->{'version'};
119+
my @provides = ("$distribution:$release");
120+
121+
return {
122+
'provides' => \@provides,
123+
'version' => $version,
124+
'arch' => $architecture,
125+
'name' => $name,
126+
'source' => $name,
127+
'hdrmd5' => $md5->hexdigest(),
128+
};
129+
}
130+
131+
sub queryhdrmd5 {
132+
my ($bin) = @_;
133+
134+
open(my $fh, '<', $bin) or croak("could not open $bin");
135+
my $md5 = Digest::MD5->new;
136+
$md5->addfile($fh);
137+
close($fh);
138+
139+
return $md5->hexdigest();
140+
}
141+
77142
1;

PBuild/BuildResult.pm

+7
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,13 @@ sub integrate_build_result {
130130
PBuild::Util::cp_a($result->{$file}, "$dst/$file");
131131
next;
132132
}
133+
if ($file =~ /(.*)\.manifest(?:\.(?:gz|bz2|xz|zst|zstd))?$/) {
134+
# create an obsbinlnk file from the mkosi manifest
135+
my $prefix = $1;
136+
die unless $result->{$file} =~ /^(.*)\/([^\/]+)$/;
137+
my $obsbinlnk = PBuild::Container::manifest2obsbinlnk($1, $2, $prefix, $p->{'pkg'});
138+
PBuild::Util::store("$dst/$prefix.obsbinlnk", undef, $obsbinlnk) if $obsbinlnk;
139+
}
133140
PBuild::Util::cp($result->{$file}, "$dst/$file");
134141
}
135142
# create new bininfo

PBuild/Container.pm

+62
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,70 @@ use PBuild::Verify;
2828
eval { require JSON::XS };
2929
*JSON::XS::decode_json = sub {die("JSON::XS is not available\n")} unless defined &JSON::XS::decode_json;
3030

31+
eval { require IO::Uncompress::Gunzip; };
32+
*IO::Uncompress::Gunzip::new = sub {die("IO::Uncompress::Gunzip is not available\n")} unless defined &IO::Uncompress::Gunzip::new;
33+
3134
use strict;
3235

36+
sub manifest2obsbinlnk {
37+
my ($dir, $file, $prefix, $packid) = @_;
38+
my $json_fh;
39+
my $md5 = Digest::MD5->new;
40+
my $image;
41+
my $json_text = do {
42+
unless (open($json_fh, "<", "$dir/$file")) {
43+
warn("Error opening $dir/$file: $!\n");
44+
return {};
45+
}
46+
if ($file =~ /\.gz$/) {
47+
$json_fh = IO::Uncompress::Gunzip->new($json_fh) or die("Error opening $dir/$file: $IO::Uncompress::Gunzip::GunzipError\n");
48+
}
49+
local $/;
50+
<$json_fh>
51+
};
52+
53+
my $metadata = JSON::XS::decode_json($json_text);
54+
if (!$metadata || !$metadata->{'config'}) {
55+
return {};
56+
}
57+
58+
for my $ext ("", ".raw", ".gz", ".xz", ".zst", ".zstd") {
59+
my $fn = "$dir/$prefix$ext";
60+
if (-e $fn) {
61+
if (-l $fn) {
62+
$prefix = readlink($fn);
63+
}
64+
open(my $fh, '<', "$dir/$prefix$ext") or die("Error opening $dir/$prefix$ext: $!\n");
65+
$md5->addfile($fh);
66+
close($fh);
67+
$image = $prefix . $ext;
68+
last;
69+
}
70+
}
71+
if (!$image) {
72+
return {};
73+
}
74+
75+
my $distribution = $metadata->{'config'}->{'distribution'};
76+
my $release = $metadata->{'config'}->{'release'};
77+
my $architecture = $metadata->{'config'}->{'architecture'};
78+
my $name = $metadata->{'config'}->{'name'};
79+
my $version = $metadata->{'config'}->{'version'} || '0';
80+
# Note: release here is not the RPM release, but the distribution release (eg: Debian 10)
81+
my @provides = ("$distribution:$release", "mkosi:$name = $version", "mkosi:$packid = $version");
82+
83+
return {
84+
'provides' => \@provides,
85+
'source' => $packid,
86+
'name' => "mkosi:$name",
87+
'version' => $version,
88+
'release' => '0',
89+
'arch' => $architecture,
90+
'hdrmd5' => $md5->hexdigest(),
91+
'lnk' => $image,
92+
};
93+
}
94+
3395
sub containerinfo2nevra {
3496
my ($d) = @_;
3597
my $lnk = {};

PBuild/Job.pm

+4-2
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ sub createjob {
215215
my $kiwimode = $p->{'buildtype'} eq 'kiwi' || $p->{'buildtype'} eq 'docker' || $p->{'buildtype'} eq 'fissile' || $p->{'buildtype'} eq 'productcompose' ? $p->{'buildtype'} : undef;
216216
if ($kiwimode) {
217217
@alldeps = PBuild::Util::unify(@$pdeps, @$vmdeps, @$sysdeps);
218+
} elsif ($p->{'buildtype'} eq 'mkosi') {
219+
@alldeps = PBuild::Util::unify(@$pdeps, @$vmdeps, grep {!/^mkosi:/} @$bdeps, @$sysdeps);
218220
} else {
219221
@alldeps = PBuild::Util::unify(@$pdeps, @$vmdeps, @$bdeps, @$sysdeps);
220222
}
@@ -262,7 +264,7 @@ sub createjob {
262264
my $copy_sources_asis;
263265
# for kiwi/docker we need to copy the sources to $buildroot/.build-srcdir
264266
# so that we can set up the "repos" and "containers" directories
265-
if ($kiwimode || $p->{'asset_files'} || grep {/\/$/} keys %{$p->{'files'} || {}}) {
267+
if ($kiwimode || $p->{'buildtype'} eq 'mkosi' || $p->{'asset_files'} || grep {/\/$/} keys %{$p->{'files'} || {}}) {
266268
$srcdir = "$buildroot/.build-srcdir";
267269
copy_sources($p, $srcdir);
268270
$ctx->{'assetmgr'}->copy_assets($p, $srcdir) if $p->{'asset_files'};
@@ -340,7 +342,7 @@ sub createjob {
340342
push @args, "--rpm-recipe-in-subdir" if $p->{'recipe'} =~ /^(?:package|dist)\/.*\.spec$/;
341343
push @args, "$srcdir/$p->{'recipe'}";
342344

343-
if ($kiwimode) {
345+
if ($kiwimode || $p->{'buildtype'} eq 'mkosi') {
344346
# now setup the repos/containers directories
345347
$ctx->{'repomgr'}->copyimagebinaries($ctx->dep2bins(@$bdeps), $srcdir);
346348
# and tell kiwi how to use them

PBuild/Recipe.pm

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ sub find_recipe {
8282
}
8383
}
8484
if (1) {
85-
@files = grep {/mkosi\.$/} keys %files;
85+
@files = grep {/^mkosi\./} keys %files;
8686
return $files{$files[0]} if @files == 1;
8787
if (@files > 1) {
8888
@files = sort @files;

PBuild/RepoMgr.pm

+2
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ sub copyimagebinaries {
170170
$to =~ s/[\/:]/_/g;
171171
PBuild::Verify::verify_filename($to);
172172
$to = "$dstdir/containers/$to";
173+
} elsif ($q->{'name'} =~ /^mkosi:/) {
174+
$to = "$dstdir/$q->{'lnk'}";
173175
} else {
174176
die("package $q->{'name'} is not available\n") unless $q->{'filename'};
175177
PBuild::Verify::verify_filename($q->{'filename'});

build-recipe-mkosi

+19-3
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,23 @@ recipe_build_mkosi() {
9393
if [ -n "$RELEASE" ]; then
9494
image_version="--image-version=${RELEASE}"
9595
fi
96-
chroot "$BUILD_ROOT" sh -c \
97-
"cd $TOPDIR/SOURCES && mkosi --default $RECIPEFILE $RELEASE_ARG $image_version --nspawn-keep-unit --output-dir $TOPDIR/OTHER --checksum --repository-key-check=no --with-network=never --local-mirror file:///.build.binaries/ --cache /.build.binaries/ build" \
98-
|| cleanup_and_exit 1
96+
set -- mkosi \
97+
--directory "$TOPDIR/SOURCES" \
98+
--default \
99+
"$RECIPEFILE" \
100+
$RELEASE_ARG \
101+
$image_version \
102+
--nspawn-keep-unit \
103+
--output-dir "$TOPDIR/OTHER" \
104+
--checksum \
105+
--repository-key-check=no \
106+
--with-network=never \
107+
--local-mirror file:///.build.binaries/ \
108+
--cache /.build.binaries/ \
109+
build
110+
111+
echo "running $*"
112+
chroot "$BUILD_ROOT" "$@" || cleanup_and_exit 1
99113

100114
# move the output files from the subdirectory, as only files in the OTHER/ directory
101115
# are published, but they get deposited in OTHER/$DIST~$RELEASE/
@@ -130,3 +144,5 @@ recipe_resultdirs_mkosi() {
130144
recipe_cleanup_mkosi() {
131145
:
132146
}
147+
148+
# vim: syntax=sh

0 commit comments

Comments
 (0)