diff options
-rwxr-xr-x | build_archive | 175 | ||||
-rwxr-xr-x | extract_archive | 248 | ||||
-rw-r--r-- | gendepslist2.cc | 348 | ||||
-rw-r--r-- | genhdlist_cz2 | 50 | ||||
-rw-r--r-- | hdlist2prereq.cc | 53 | ||||
-rw-r--r-- | rpmtools.spec | 4 |
6 files changed, 877 insertions, 1 deletions
diff --git a/build_archive b/build_archive new file mode 100755 index 0000000..e2b21f2 --- /dev/null +++ b/build_archive @@ -0,0 +1,175 @@ +#!/usr/bin/perl + +#- Mandrake Simple Archive Builder. +#- Copyright (C) 1999 MandrakeSoft (fpons@mandrakesoft.com) +#- +#- This program is free software; you can redistribute it and/or modify +#- it under the terms of the GNU General Public License as published by +#- the Free Software Foundation; either version 2, or (at your option) +#- any later version. +#- +#- This program is distributed in the hope that it will be useful, +#- but WITHOUT ANY WARRANTY; without even the implied warranty of +#- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#- GNU General Public License for more details. +#- +#- You should have received a copy of the GNU General Public License +#- along with this program; if not, write to the Free Software +#- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#- Simple cat archive with bzip2 for perl. +#- read file list and produce an $ARGV[0].cz2 archive file. +#- uncompressing sheme is: +#- | | +#- | | | | +#- $off1 =|*| } | | +#- |*| } $off2 =|+| } +#- |*| } $siz1 => 'bzip2 -d' => |+| } $siz2 => $filename +#- |*| } |+| } +#- |*| } | | +#- | | | | +#- | | | | +#- | | +#- where %data has the following format: +#- { 'filename' => [ 'f', $off1, $siz1, $off2, $siz2 ] } +#- except for symbolink link where it is: +#- { 'filename_symlink' => [ 'l', $symlink_value ] } +#- and directory where it is only +#- { 'filename_directory' => [ 'd' ] } +#- as you can see, there is no owner, group, filemode... an extension could be +#- made with 'F' (instead of 'f'), 'L' instead of 'l' for exemple. +#- we do not need them as it is used for DrakX for fast archive extraction and +#- owner/filemode is for user running only (ie root). +#- +#- archive file contains concatenation of all bzip2'ed group of files whose +#- filenames are on input, +#- then a TOC (describing %data, concatenation of toc_line) follow and a +#- TOC_TRAILER for summary. + +use strict qw(subs vars refs); + +sub toc_line { + my ($file, $data) = @_; + + for ($data->[0]) { + return(/l/ && pack("anna*", 'l', length($file), length($data->[1]), "$file$data->[1]") || + /d/ && pack("ana*", 'd', length($file), $file) || + /f/ && pack("anNNNNa*", 'f', length($file), $data->[1], $data->[2], $data->[3], $data->[4], $file) || + die "unknown extension $_\n"); + } +} + +sub main { + my ($archivename, $maxsiz) = @_; + my ($compress, $uncompress, $off1, $siz1, $off2, $siz2) = ('', '', 0, 0, 0, 0); + my @filelist = (); + my @data = (); + my %data = (); + + die "usage: $0 <archivename> <maxsiz>\n" unless $maxsiz >= 100000; + + #- guess compress method to use. + if ($archivename =~ /\.cz$/) { + ($compress, $uncompress) = ("gzip -9", "gzip -d"); + } elsif ($archivename =~ /\.cz2$/) { + ($compress, $uncompress) = ("bzip2 -9", "bzip2 -d"); + } else { + die "how to choose a compression which such a filename $archivename\n"; + } + print STDERR "choosing compression method with \"$compress\" for archive $archivename\n"; + + unlink "$archivename"; + unlink "tmp.z"; + + foreach (<STDIN>) { + chomp; + + my $file = $_; -e $file or die "unable to find file $file\n"; + + push @data, $file; + #- now symbolic link and directory are supported, extension is + #- available with the first field of $data{$file}. + if (-l $file) { + $data{$file} = [ 'l', readlink $file ]; + } elsif (-d $file) { + $data{$file} = [ 'd' ]; + } else { + $siz2 = -s $file; + + push @filelist, $file; + $data{$file} = [ 'f', -1, -1, $off2, $siz2 ]; + + if ($off2 + $siz2 > $maxsiz) { #- need compression. + system "cat @filelist | $compress >tmp.z"; + $siz1 = -s "tmp.z"; + + $data{$_} = [ 'f', $off1, $siz1, $data{$_}[3], $data{$_}[4] ] foreach @filelist; + + system "cat tmp.z >>$archivename"; + $off1 += $siz1; + $off2 = 0; $siz2 = 0; + @filelist = (); + } + $off2 += $siz2; + } + } + if (scalar @filelist) { + system "cat @filelist | $compress >tmp.z"; + $siz1 = -s "tmp.z"; + + $data{$_} = [ 'f', $off1, $siz1, $data{$_}[3], $data{$_}[4] ] foreach @filelist; + + system "cat tmp.z >>$archivename"; + $off1 += $siz1; + print STDERR "real archive size of $archivename is $off1\n"; + } + + #- produce a TOC directly at the end of the file, follow with + #- a trailer with TOC summary and archive summary. + local *OUTPUT; + open OUTPUT, ">>$archivename"; + + my ($toc_str, $toc_data) = ('', ''); + my @data_d = (); + my @data_l = (); + my @data_f = (); + + foreach (@data) { + my $file = $_; + $data{$file} or die "build_archive: internal error on $_\n"; + + #- specific according to type. + #- with this version, only f has specific data other than strings. + for ($data{$file}[0]) { + /d/ && do { push @data_d, $file; last; }; + /l/ && do { push @data_l, $file; last; }; + /f/ && do { push @data_f, $file; $toc_data .= pack("NNNN", + $data{$file}[1], + $data{$file}[2], + $data{$file}[3], + $data{$file}[4]); last; }; + die "unknown extension $_\n"; + } + } + + foreach (@data_d) { $toc_str .= $_ . "\n" } + foreach (@data_l) { $toc_str .= $_ . "\n" . $data{$_}[1] . "\n" } + foreach (@data_f) { $toc_str .= $_ . "\n" } + + print OUTPUT $toc_str; + print OUTPUT $toc_data; + print OUTPUT toc_trailer(scalar(@data_d), scalar(@data_l), scalar(@data_f), + length($toc_str), $uncompress); + close OUTPUT; +} + +sub toc_trailer { + my ($toc_d_count, $toc_l_count, $toc_f_count, $toc_str_size, $uncompress) = @_; + + #- 'cz[0' is toc_trailer header where 0 is version information, only 0 now. + #- '0]cz' is toc_trailer trailer that match the corresponding header for information. + return pack "a4NNNNa40a4", 'cz[0', $toc_d_count, $toc_l_count, $toc_f_count, $toc_str_size, $uncompress, '0]cz'; +} + +main(@ARGV); +unlink "tmp.z"; diff --git a/extract_archive b/extract_archive new file mode 100755 index 0000000..cdd98da --- /dev/null +++ b/extract_archive @@ -0,0 +1,248 @@ +#!/usr/bin/perl + +#- Mandrake Simple Archive Extracter. +#- Copyright (C) 1999 MandrakeSoft (fpons@mandrakesoft.com) +#- +#- This program is free software; you can redistribute it and/or modify +#- it under the terms of the GNU General Public License as published by +#- the Free Software Foundation; either version 2, or (at your option) +#- any later version. +#- +#- This program is distributed in the hope that it will be useful, +#- but WITHOUT ANY WARRANTY; without even the implied warranty of +#- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#- GNU General Public License for more details. +#- +#- You should have received a copy of the GNU General Public License +#- along with this program; if not, write to the Free Software +#- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#- Simple cat archive with gzip/bzip2 for perl. +#- see build_archive for more information. +#- +#- uncompressing sheme is: +#- | | +#- | | | | +#- $off1 =|*| } | | +#- |*| } $off2 =|+| } +#- |*| } $siz1 => 'gzip/bzip2 -d' => |+| } $siz2 => $filename +#- |*| } |+| } +#- |*| } | | +#- | | | | +#- | | | | +#- | | + +use strict qw(subs vars refs); + +#- used for uncompressing archive and other. +my %toc_trailer; +my @data; +my %data; + +#- taken from DrakX common stuff, for conveniance and modified to match our expectation. +sub dirname { @_ == 1 or die "usage: dirname <name>\n"; local $_ = shift; s|[^/]*/*\s*$||; s|(.)/*$|$1|; $_ || '.' } +sub basename { @_ == 1 or die "usage: basename <name>\n"; local $_ = shift; s|/*\s*$||; s|.*/||; $_ } +sub mkdir_ { + my $root = dirname $_[0]; + if (-e $root) { + -d $root or die "mkdir: error creating directory $_[0]: $root is a file and i won't delete it\n"; + } else { + mkdir_($root); + } + -d $_[0] and return; + mkdir $_[0], 0755 or die "mkdir: error creating directory $_: $!\n"; +} +sub symlink_ { mkdir_ dirname($_[1]); unlink $_[1]; symlink $_[0], $_[1] } + +#- compute the closure of filename list according to symlinks or directory +#- contents inside the archive. +sub compute_closure { + my %file; + my @file; + + #- keep in mind when a filename already exist and remove doublons. + @file{@_} = (); + + #- navigate through filename list to follow symlinks. + do { + @file = grep { !$file{$_} } keys %file; + foreach (@file) { + my $file = $_; + + #- keep in mind this one has been processed and does not need + #- to be examined again. + $file{$file} = 1; + + exists $data{$file} or next; + + for ($data{$file}[0]) { + #- on symlink, try to follow it and mark %file if + #- it is still inside the archive contents. + /l/ && do { + my ($source, $target) = ($file, $data{$file}[1]); + + $source =~ s|[^/]*$||; #- remove filename to navigate directory. + if ($source) { + while ($target =~ s|^\./|| || $target =~ s|//+|/| || $target =~ s|/$|| or + $source and $target =~ s|^\.\./|| and $source =~ s|[^/]*/$||) {} + } + + #- FALL THROUGH with new selection. + $file = $target =~ m|^/| ? $target : $source.$target; + }; + + #- on directory, try all files on data starting with + #- this directory, provided they are not already taken + #- into account. + /[ld]/ && do { + @file{grep { !$file{$_} && m|^$file$| || m|^$file/| } keys %data} = (); + last; + }; + } + } + } while (@file > 0); + + keys %file; +} + +#- read toc at end of archive. +sub read_toc { + my ($file) = @_; + my ($toc, $toc_trailer, $toc_size); + my @toc_str; + my @toc_data; + + local *ARCHIVE; + open ARCHIVE, "<$file" or die "cannot open archive file $file\n"; + + #- seek to end of file minus 64, size of trailer. + #- read toc_trailer, check header/trailer for version 0. + seek ARCHIVE, -64, 2; + read ARCHIVE, $toc_trailer, 64 or die "cannot read toc_trailer of archive file $file\n"; + @toc_trailer{qw(header toc_d_count toc_l_count toc_f_count toc_str_size uncompress trailer)} = + unpack "a4NNNNZ40a4", $toc_trailer; + $toc_trailer{header} eq 'cz[0' && $toc_trailer{trailer} eq '0]cz' or die "bad toc_trailer in archive file $file\n"; + + #- read toc, extract data hashes. + $toc_size = $toc_trailer{toc_str_size} + 16*$toc_trailer{toc_f_count}; + seek ARCHIVE, -64-$toc_size, 2; + + #- read strings separated by \n, so this char cannot be inside filename, oops. + read ARCHIVE, $toc, $toc_trailer{toc_str_size} or die "cannot read toc of archive file $file\n"; + @toc_str = split "\n", $toc; + + #- read data for file. + read ARCHIVE, $toc, 16*$toc_trailer{toc_f_count} or die "cannot read toc of archive file $file\n"; + @toc_data = unpack "N". 4*$toc_trailer{toc_f_count}, $toc; + + close ARCHIVE; + + foreach (0..$toc_trailer{toc_d_count}-1) { + my $file = $toc_str[$_]; + push @data, $file; + $data{$file} = [ 'd' ]; + } + foreach (0..$toc_trailer{toc_l_count}-1) { + my ($file, $symlink) = ($toc_str[$toc_trailer{toc_d_count}+2*$_], + $toc_str[$toc_trailer{toc_d_count}+2*$_+1]); + push @data, $file; + $data{$file} = [ 'l', $symlink ]; + } + foreach (0..$toc_trailer{toc_f_count}-1) { + my $file = $toc_str[$toc_trailer{toc_d_count}+2*$toc_trailer{toc_l_count}+$_]; + push @data, $file; + $data{$file} = [ 'f', @toc_data[4*$_ .. 4*$_+3] ]; + } + + scalar keys %data == $toc_trailer{toc_d_count}+$toc_trailer{toc_l_count}+$toc_trailer{toc_f_count} or + die "mismatch count when reading toc, bad archive file $file\n"; +} + +sub catsksz { + my ($input, $seek, $siz, $output) = @_; + my ($buf, $sz); + + while (($sz = sysread($input, $buf, $seek > 4096 ? 4096 : $seek))) { + $seek -= $sz; + last unless $seek > 0; + } + while (($sz = sysread($input, $buf, $siz > 4096 ? 4096 : $siz))) { + $siz -= $sz; + syswrite($output, $buf); + last unless $siz > 0; + } +} + +sub main { + my ($archivename, $dir, @file) = @_; + my %extract_table; + + #- update %data according to TOC of archive. + read_toc($archivename); + + #- as a special features, if both $dir and $file are empty, list contents of archive. + if (!$dir && !@file) { + my $count = scalar keys %data; + print "$count files in archive, uncompression method is \"$toc_trailer{uncompress}\"\n"; + foreach my $file (@data) { + for ($data{$file}[0]) { + /l/ && do { printf "l %13c %s -> %s\n", ' ', $file, $data{$file}[1]; last; }; + /d/ && do { printf "d %13c %s\n", ' ', $file; last; }; + /f/ && do { printf "f %12d %s\n", $data{$file}[4], $file; last; }; + } + } + exit 0; + } + + #- compute closure. + @file = compute_closure(@file); + + #- check all file given are in the archive before continuing. + foreach (@file) { $data{$_} or die "unable to find file $_ in archive $archivename\n"; } + + foreach my $file (@file) { + my $newfile = "$dir/$file"; + + print "extracting $file\n"; + for ($data{$file}[0]) { + /l/ && do { symlink_ $data{$file}[1], $newfile; last; }; + /d/ && do { mkdir_ $newfile; last; }; + /f/ && do { + mkdir_ dirname $newfile; + $extract_table{$data{$file}[1]} ||= [ $data{$file}[2], [] ]; + push @{$extract_table{$data{$file}[1]}[1]}, [ $newfile, $data{$file}[3], $data{$file}[4] ]; + $extract_table{$data{$file}[1]}[0] == $data{$file}[2] or die "mismatched relocation in toc\n"; + last; + }; + die "unknown extension $_ when uncompressing archive $archivename\n"; + } + } + + #- delayed extraction is done on each block for a single execution + #- of uncompress executable. + foreach (sort { $a <=> $b } keys %extract_table) { + local *OUTPUT; + if (open OUTPUT, "-|") { + #- $curr_off is used to handle the reading in a pipe and simulating + #- a seek on it as done by catsksz, so last file position is + #- last byte not read (ie last block read start + last block read size). + my $curr_off = 0; + foreach (sort { $a->[1] <=> $b->[1] } @{$extract_table{$_}[1]}) { + my ($newfile, $off, $siz) = @$_; + local *FILE; + open FILE, $dir ? ">$newfile" : ">&STDOUT"; + catsksz(\*OUTPUT, $off - $curr_off, $siz, \*FILE); + $curr_off = $off + $siz; + } + } else { + local *BUNZIP2; + open BUNZIP2, "| $toc_trailer{uncompress}"; + local *ARCHIVE; + open ARCHIVE, "<$archivename" or die "cannot open archive $archivename\n"; + catsksz(\*ARCHIVE, $_, $extract_table{$_}[0], \*BUNZIP2); + exit 0; + } + } +} + +main(@ARGV); diff --git a/gendepslist2.cc b/gendepslist2.cc new file mode 100644 index 0000000..faaf953 --- /dev/null +++ b/gendepslist2.cc @@ -0,0 +1,348 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <rpm/rpmlib.h> +#include <rpm/header.h> +#include <string> +#include <vector> +#include <map> +#include <set> +#include <fstream> +#include <algorithm> + +#define COMPATIBILITY + +string put_first = "filesystem setup"; + + +/********************************************************************************/ +/* C++ template functions *******************************************************/ +/********************************************************************************/ +template<class V, class C> C sum(const V &v, const C &join = C()) { + typename V::const_iterator p, q; + C s = C(); + if (v.begin() != v.end()) { + for (p = q = v.begin(), q++; q != v.end(); p = q, q++) s += *p + join; + s += *p; + } + return s; +} + +vector<string> split(char sep, const string &l) { + vector<string> r; + for (int pos = 0, pos2 = 0; pos2 >= 0;) { + pos2 = l.find(sep, pos); + r.push_back(l.substr(pos, pos2)); + pos = pos2 + 1; + } + return r; +} + +template<class A, class B> void map_insert(map<A, set<B> > &m, const A &a, const B &b) { + if (m.find(a) == m.end()) m[a] = *(new set<B>); + m[a].insert(b); +} + +template<class A> bool in(const A &a, const vector<A> &v) { + vector<A>::const_iterator p; + for (p = v.begin(); p != v.end(); p++) if (*p == a) return 1; + return 0; +} +template<class A, class B> bool in(const A &a, const map<A,B> &m) { + return m.find(a) != m.end(); +} + +template<class A, class B> map<A,B> &set2map(const set<A> &s) { + map<A,B> map; + set<A>::const_iterator p; + for (p = s.begin(); p != s.end(); p++) map[*p] = *(new B); + return map; +} + +template<class A, class B> void add(set<A> &v1, const B &v2) { + typename B::const_iterator p; + for (p = v2.begin(); p != v2.end(); p++) v1.insert(*p); +} +template<class A, class B> void add(vector<A> &v1, const B &v2) { + typename B::const_iterator p; + for (p = v2.begin(); p != v2.end(); p++) v1.push_back(*p); +} + +typedef vector<string>::iterator ITv; +typedef set<string>::iterator ITs; +typedef map<string, set<string> >::iterator ITms; + + + + +/********************************************************************************/ +/* header extracting functions **************************************************/ +/********************************************************************************/ +string get_name(Header header, int_32 tag) { + int_32 type, count; + char *name; + + headerGetEntry(header, tag, &type, (void **) &name, &count); + return string(name); +} + +int get_int(Header header, int_32 tag) { + int_32 type, count; + int *i; + + headerGetEntry(header, tag, &type, (void **) &i, &count); + return *i; +} + +vector<string> get_info(Header header, int_32 tag) { + int_32 type, count, i; + vector<string> r; + char **list; + + headerGetEntry(header, tag, &type, (void **) &list, &count); + if (list) { + r.reserve(count); + for (i = 0; i < count; i++) r.push_back(list[i]); + free(list); + } + return r; +} + +vector<string> get_files(Header header) { + int_32 type, count, i; + char ** baseNames, ** dirNames; + int_32 * dirIndexes; + +#ifdef COMPATIBILITY + // deprecated one + vector<string> r = get_info(header, RPMTAG_OLDFILENAMES); +#else + vector<string> r; +#endif + + headerGetEntry(header, RPMTAG_BASENAMES, &type, (void **) &baseNames, &count); + headerGetEntry(header, RPMTAG_DIRINDEXES, &type, (void **) &dirIndexes, NULL); + headerGetEntry(header, RPMTAG_DIRNAMES, &type, (void **) &dirNames, NULL); + + if (baseNames && dirNames && dirIndexes) { + r.reserve(count); + for(i = 0; i < count; i++) { + string s(dirNames[dirIndexes[i]]); + s += baseNames[i]; + r.push_back(s); + } + free(baseNames); + free(dirNames); + } + return r; +} + +/********************************************************************************/ +/* gendepslist ******************************************************************/ +/********************************************************************************/ +vector<string> packages; +map<string, int> sizes; +map<string, string> name2fullname; +map<string, vector<string> > requires, frequires; +map<string, vector<string> > provided_by, fprovided_by; + +void getRequires(FD_t fd) { + set<string> all_requires, all_frequires; + Header header; + + while ((header=headerRead(fd, HEADER_MAGIC_YES))) + { + string s_name = get_name(header, RPMTAG_NAME); + string name = s_name + "-" + get_name(header, RPMTAG_VERSION) + "-" + get_name(header, RPMTAG_RELEASE); + vector<string> l = get_info(header, RPMTAG_REQUIRENAME); + + for (ITv p = l.begin(); p != l.end(); p++) { + ((*p)[0] == '/' ? frequires : requires)[name].push_back(*p); + ((*p)[0] == '/' ? all_frequires : all_requires).insert(*p); + } + headerFree(header); + } + for (ITs p = all_requires.begin(); p != all_requires.end(); p++) provided_by[*p] = *(new vector<string>); + for (ITs p = all_frequires.begin(); p != all_frequires.end(); p++) fprovided_by[*p] = *(new vector<string>); +} + +void getProvides(FD_t fd) { + Header header; + while ((header=headerRead(fd, HEADER_MAGIC_YES))) + { + string s_name = get_name(header, RPMTAG_NAME); + string name = s_name + "-" + get_name(header, RPMTAG_VERSION) + "-" + get_name(header, RPMTAG_RELEASE); + + packages.push_back(name); + name2fullname[s_name] = name; + sizes[name] = get_int(header, RPMTAG_SIZE); + + if (in(s_name, provided_by)) provided_by[s_name].push_back(name); + + vector<string> provides = get_info(header, RPMTAG_PROVIDES); + for (ITv p = provides.begin(); p != provides.end(); p++) + if (in(*p, provided_by)) provided_by[*p].push_back(name); + + vector<string> fprovides = get_files(header); + for (ITv p = fprovides.begin(); p != fprovides.end(); p++) + if (in(*p, fprovided_by)) fprovided_by[*p].push_back(name); + + headerFree(header); + } +} + +set<string> getDep_(const string &dep, vector<string> &l) { + set<string> r; + switch (l.size()) + { + case 0: + r.insert((string) "NOTFOUND_" + dep); + break; + case 1: + r.insert(l[0]); + break; + default: + r.insert(sum(l, (string)"|")); + } + return r; +} + +set<string> getDep(const string &name) { + set<string> r; + r.insert(name); + for (ITv p = requires[name].begin(); p != requires[name].end(); p++) add(r, getDep_(*p, provided_by[*p])); + for (ITv p = frequires[name].begin(); p != frequires[name].end(); p++) add(r, getDep_(*p, fprovided_by[*p])); + return r; +} + +map<string, set<string> > closure(const map<string, set<string> > &names) { + map<string, set<string> > r = names; + + map<string, set<string> > reverse; + for (ITv i = packages.begin(); i != packages.end(); i++) reverse[*i] = *(new set<string>); + + for (ITms i = r.begin(); i != r.end(); i++) + for (ITs j = i->second.begin(); j != i->second.end(); j++) + reverse[*j].insert(i->first); + + for (ITms i = r.begin(); i != r.end(); i++) { + set<string> rev = reverse[i->first]; + for (ITs j = rev.begin(); j != rev.end(); j++) { + + for (ITs k = i->second.begin(); k != i->second.end(); k++) { + r[*j].insert(*k); + reverse[*k].insert(*j); + } + + } + } + return r; +} + + +//struct cmp : public binary_function<string,string,bool> { +// bool operator()(const string &a, const string &b) { +// int na = closed[a].size(); +// int nb = closed[b].size(); +// return na < nb; +// } +//}; + +void printDepslist(ofstream *out1, ofstream *out2) { + + map<string, set<string> > names; + for (ITv p = packages.begin(); p != packages.end(); p++) { + set<string> s = getDep(*p); + s.erase(*p); + names[*p] = s; + if (out1) *out1 << *p << " " << sizes[*p] << " " << sum(s, (string) " ") << "\n"; + } + if (out2 == 0) return; + + map<string, set<string> > closed = closure(names); + for (ITms p = closed.begin(); p != closed.end(); p++) p->second.erase(p->first); + + names = closed; + map<string,int> length; + for (ITms p = names.begin(); p != names.end(); p++) { + int l = p->second.size(); + for (ITs q = p->second.begin(); q != p->second.end(); q++) if (q->find('|') >= 0) l += 1000; + length[p->first] = l; + } + + vector<string> put_first_ = split(' ', put_first); + vector<string> packages; + while (names.begin() != names.end()) { + string n; + unsigned int l_best = 9999; + + for (ITv p = put_first_.begin(); p != put_first_.end(); p++) + if (in(name2fullname[*p], names)) { n = name2fullname[*p]; goto found; } + + for (ITms p = names.begin(); p != names.end(); p++) + if (p->second.size() < l_best) { + l_best = p->second.size(); + n = p->first; + if (l_best == 0) break; + } + found: + names.erase(n); + packages.push_back(n); + for (ITms p = names.begin(); p != names.end(); p++) p->second.erase(n); + } + + + int i = 0; + map<string,int> where; + for (ITv p = packages.begin(); p != packages.end(); p++, i++) where[*p] = i; + + i = 0; + for (ITv p = packages.begin(); p != packages.end(); p++, i++) { + set<string> dep = closed[*p]; + *out2 << *p << " " << sizes[*p]; + for (ITs q = dep.begin(); q != dep.end(); q++) { + if (q->find('|') >= 0) { + vector<string> l = split('|', *q); + for (ITv k = l.begin(); k != l.end(); k++) *out2 << " " << where[*k]; + } else if (q->compare("NOTFOUND_") > 1) { + *out2 << " " << *q; + } else { + int j = where[*q]; + if (j > i) cerr << *p << "\n"; + *out2 << " " << j; + } + } + *out2 << "\n"; + } +} + +FD_t hdlists(const char *cmd) { + return fdDup(fileno(popen(cmd, "r"))); +} + +int main(int argc, char **argv) +{ + ofstream *out1 = 0, *out2 = 0; + if (argc > 2 && (string)argv[1] == "-o") { + out1 = new ofstream(argv[2]); + out2 = new ofstream(((string)argv[2] + ".ordered").c_str()); + argc -= 2; argv += 2; + } else { + out1 = new ofstream(STDOUT_FILENO); + } + if (argc < 2) { + cerr << "usage: gendepslist2 [-o <depslist>] hdlists_cz2...\n"; + return 1; + } + string cmd = "bzip2 -dc "; + for (int i = 1; i < argc; i++) cmd = cmd + argv[i] + " "; + cmd += "2>/dev/null"; + + getRequires(hdlists(cmd.c_str())); + cerr << "getRequires done\n"; + getProvides(hdlists(cmd.c_str())); + cerr << "getProvides done\n"; + printDepslist(out1, out2); + delete out1; + delete out2; +} diff --git a/genhdlist_cz2 b/genhdlist_cz2 new file mode 100644 index 0000000..7512d68 --- /dev/null +++ b/genhdlist_cz2 @@ -0,0 +1,50 @@ +#!/usr/bin/perl + +($noclean, @ARGV) = @ARGV if $ARGV[0] eq "--noclean"; +(undef, $depslist, @ARGV) = @ARGV if $ARGV[0] eq "--ordered-depslist"; +(undef, $hdlist, @ARGV) = @ARGV if $ARGV[0] eq "-o"; +(undef, $root, @ARGV) = @ARGV if $ARGV[0] eq "--distrib"; + +$hdlist && @ARGV == 1 || $root && @ARGV == 0 or die +"usage: genhdlist_cz2 [--noclean] [--ordered-depslist <depslist>] -o <hdlist_cz2> <rpm dir> + or genhdlist_cz2 [--noclean] --distrib <root distrib> +"; + +if ($root) { + $depslist = "$root/Mandrake/base/depslist.ordered"; + $hdlist = "$root/Mandrake/base/hdlist.cz2"; + $dir = "$root/Mandrake/RPMS"; + $ENV{PATH} = "$ENV{PATH}:$root/misc"; +} else { + ($dir) = @ARGV; +} + + +$work_dir = "/tmp/.build_hdlist"; + + +-e $work_dir && !-d $work_dir and unlink($work_dir) || die "cannot use $work_dir as a working directory"; +chmod 0755, $work_dir or system("rm -rf $work_dir"); +-d $work_dir or mkdir $work_dir, 0755 or die "cannot create working directory $work_dir\n"; +chdir $work_dir; + +my (%keys, @keys); + +opendir DIR, $dir or die "unable to opendir $dir: $!\n"; +while ($_ = readdir DIR) { + my ($key) = /(.*)\..*\.rpm$/ or next; + system("rpm2header $dir/$_ > $key") unless -e $key; + $? == 0 or unlink($key), die "bad rpm $dir/$_\n"; + $keys{$key} = 1; +} +if (-e $depslist) { + open F, $depslist; + @keys = map { (split)[0] } <F>; +} +@keys = grep { delete $keys{$_} } @keys; + +open B, "| build_archive $hdlist 400000"; +print B "$_\n" foreach @keys, keys %keys; +close B or die "build_archive failed\n"; + +system("rm -rf $work_dir") unless $noclean; diff --git a/hdlist2prereq.cc b/hdlist2prereq.cc new file mode 100644 index 0000000..68434f0 --- /dev/null +++ b/hdlist2prereq.cc @@ -0,0 +1,53 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <rpm/rpmlib.h> +#include <rpm/header.h> +#include <iostream> + + +char *get_name(Header header, int_32 tag) { + int_32 type, count; + char *name; + + headerGetEntry(header, tag, &type, (void **) &name, &count); + return name; +} + +int get_int(Header header, int_32 tag) { + int_32 type, count; + int *i; + + headerGetEntry(header, tag, &type, (void **) &i, &count); + return *i; +} + +int main(int argc, char **argv) +{ + if (argc <= 1) { + cerr << "usage: hdlist2prereq <hdlist> [<hdlists...>]\n"; + exit(1); + } + for (int i = 1; i < argc; i++) { + FD_t fd = strcmp(argv[i], "-") == 0 ? fdDup(STDIN_FILENO) : fdOpen(argv[i], O_RDONLY, 0); + if (fdFileno(fd) < 0) cerr << "rpmpackdeps: cannot open file " << argv[i] << "\n"; + else { + Header header; + int_32 type, count; + char **list; + int *flags; + + while ((header=headerRead(fd, HEADER_MAGIC_YES))) { + char *name = get_name(header, RPMTAG_NAME); + + headerGetEntry(header, RPMTAG_REQUIRENAME, &type, (void **) &list, &count); + headerGetEntry(header, RPMTAG_REQUIREFLAGS, &type, (void **) &flags, &count); + + if (flags && list) + for(i = 0; i < count; i++) + if (flags[i] & RPMSENSE_PREREQ) printf("%s:%s\n", name, list[i]); + } + } + fdClose(fd); + } +} diff --git a/rpmtools.spec b/rpmtools.spec index c54fa30..8c77900 100644 --- a/rpmtools.spec +++ b/rpmtools.spec @@ -47,6 +47,8 @@ rm -rf $RPM_BUILD_ROOT /usr/bin/hdlist2names /usr/bin/rpm2header /usr/bin/genhdlist_cz2 +/usr/bin/extract_archive +/usr/bin/build_archive %files devel %defattr(-,root,root) @@ -55,7 +57,7 @@ rm -rf $RPM_BUILD_ROOT %changelog * Tue Mar 7 2000 Pixel <pixel@mandrakesoft.com> 1.1-1mdk - new version (gendepslist2 instead of gendepslist, hdlist2prereq) -- missing Requires, must wait for francois to choose the names for build_archive/extract_archive :) +- host build_archive/extract_archive until francois put them somewhere else :) * Fri Feb 18 2000 Chmouel Boudjnah <chmouel@mandrakesoft.com> 1.0-9mdk - Really fix with rpm-3.0.4 (Fredl). |