3 use List
::Util
qw(min);
5 my @packagesFiles = ();
8 # rpm-closure.pl (<package-file> <url-prefix>)+ <toplevel-pkg>+
11 my $packagesFile = shift @ARGV;
12 my $urlPrefix = shift @ARGV;
13 push(@packagesFiles, $packagesFile);
14 push(@urlPrefixes, $urlPrefix);
19 my ($version1, $version2) = @_;
20 my @vercmps1 = split /\./, $version1;
21 my @vercmps2 = split /\./, $version2;
22 my $l1 = scalar(@vercmps1);
23 my $l2 = scalar(@vercmps2);
24 my $l = min
($l1, $l2);
26 for(my $i=0; $i<$l; $i++) {
27 my $v1 = $vercmps1[$i];
28 my $v2 = $vercmps2[$i];
30 if($v1 =~ /^[0-9]*$/ && $v2 =~ /^[0-9]*$/) {
31 if ( int($v1) > int($v2) ) {
34 elsif ( int($v1) < int($v2) ) {
41 elsif ( $v1 lt $v2 ) {
55 my @toplevelPkgs = @ARGV;
57 my @archs = split ' ', ($ENV{'archs'} or "");
60 for (my $i = 0; $i < scalar(@packagesFiles); $i++) {
61 my $packagesFile = $packagesFiles[$i];
62 print STDERR
"parsing packages in $packagesFile...\n";
64 my $xml = XMLin
($packagesFile, ForceArray
=> ['package', 'rpm:entry', 'file'], KeyAttr
=> []) or die;
66 print STDERR
"$packagesFile contains $xml->{packages} packages\n";
68 foreach my $pkg (@
{$xml->{'package'}}) {
69 if (scalar @archs > 0) {
70 my $arch = $pkg->{arch
};
72 foreach my $a (@archs) { $found = 1 if $arch eq $a; }
75 if (defined $pkgs{$pkg->{name
}}) {
76 my $earlierPkg = $pkgs{$pkg->{name
}};
77 print STDERR
"WARNING: duplicate occurrence of package $pkg->{name}\n";
78 # <version epoch="0" ver="1.28.0" rel="2.el6"/>
79 my $cmp = rpmvercmp
($pkg->{'version'}->{ver
}, $earlierPkg->{'version'}->{ver
});
80 if ($cmp > 0 || ($cmp == 0 && rpmvercmp
($pkg->{'version'}->{rel
}, $earlierPkg->{'version'}->{rel
})>0)) {
81 print STDERR
"WARNING: replaced package $pkg->{name} (".$earlierPkg->{'version'}->{ver
}." ".$earlierPkg->{'version'}->{rel
}.") with newer one (".$pkg->{'version'}->{ver
}." ".$pkg->{'version'}->{rel
}.")\n";
82 $pkg->{urlPrefix
} = $urlPrefixes[$i];
83 $pkgs{$pkg->{name
}} = $pkg;
87 $pkg->{urlPrefix
} = $urlPrefixes[$i];
88 $pkgs{$pkg->{name
}} = $pkg;
93 PKG
: foreach my $pkgName (sort(keys %pkgs)) {
94 #print STDERR "looking at $pkgName\n";
95 my $pkg = $pkgs{$pkgName};
97 # Skip packages that conflict with a required package.
98 my $conflicts = $pkg->{format
}->{'rpm:conflicts'}->{'rpm:entry'} // [];
99 foreach my $conflict (@
{$conflicts}) {
100 next if $conflict->{flags
} // "" eq "LT" || $conflict->{flags
} // "" eq "LE";
101 #print STDERR " $pkgName conflicts with $conflict->{name}\n";
102 if (grep { $_ eq $conflict->{name
} } @toplevelPkgs) {
103 print STDERR
"skipping package $pkgName because it conflicts with a required package\n";
108 my $provides = $pkg->{format
}->{'rpm:provides'}->{'rpm:entry'} or die;
109 foreach my $req (@
{$provides}) {
110 #print STDERR " $pkgName provides $req->{name}\n";
111 #die "multiple provides for $req->{name}" if defined $provides{$req->{name}};
112 $provides{$req->{name
}} = $pkgName;
115 if (defined $pkg->{format
}->{file
}) {
116 foreach my $file (@
{$pkg->{format
}->{file
}}) {
117 #print STDERR " provides file $file\n";
118 $provides{$file} = $pkgName;
130 return if defined $donePkgs{$pkgName};
131 $donePkgs{$pkgName} = 1;
133 print STDERR
">>> $pkgName\n";
135 my $pkg = $pkgs{$pkgName} or die "package $pkgName doesn't exist";
137 my $requires = $pkg->{format
}->{'rpm:requires'}->{'rpm:entry'} || [];
140 foreach my $req (@
{$requires}) {
141 next if $req->{name
} =~ /^rpmlib\(/;
142 #print STDERR " needs $req->{name}\n";
143 my $provider = $provides{$req->{name
}};
144 if (!defined $provider) {
145 print STDERR
" WARNING: no provider for $req->{name}\n";
148 #print STDERR " satisfied by $provider\n";
149 push @deps, $provider;
152 closePackage
($_) foreach @deps;
154 push @needed, $pkgName;
158 foreach my $pkgName (@toplevelPkgs) {
159 closePackage
$pkgName;
163 # Generate the output Nix expression.
164 print "# This is a generated file. Do not modify!\n";
165 print "# Following are the RPM packages constituting the closure of: @toplevelPkgs\n\n";
166 print "{fetchurl}:\n\n";
169 foreach my $pkgName (@needed) {
170 my $pkg = $pkgs{$pkgName};
171 print " (fetchurl {\n";
172 print " url = $pkg->{urlPrefix}/$pkg->{location}->{href};\n";
173 if ($pkg->{checksum
}->{type
} eq "sha") {
174 print " sha1 = \"$pkg->{checksum}->{content}\";\n";
175 } elsif ($pkg->{checksum
}->{type
} eq "sha256") {
176 print " sha256 = \"$pkg->{checksum}->{content}\";\n";
178 die "unsupported hash type";