diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2016-10-27 14:54:32 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2016-10-27 14:54:33 +0900 |
commit | 9d82811ac90c5db61fca60e3e7c95ba58bc66393 (patch) | |
tree | 14fd1327bfb65babc5a84f7c719eb3c723035b6b /examples | |
parent | 1a93853889c819ac2d3c8e83e856f4775e664b00 (diff) | |
download | libsolv-9d82811ac90c5db61fca60e3e7c95ba58bc66393.tar.gz libsolv-9d82811ac90c5db61fca60e3e7c95ba58bc66393.tar.bz2 libsolv-9d82811ac90c5db61fca60e3e7c95ba58bc66393.zip |
Imported Upstream version 0.6.12upstream/0.6.12
Change-Id: I57ee1847c5c25f2602e0348213fa145f97cc3434
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
Diffstat (limited to 'examples')
-rwxr-xr-x | examples/p5solv | 83 | ||||
-rwxr-xr-x | examples/pysolv | 92 | ||||
-rwxr-xr-x | examples/rbsolv | 82 | ||||
-rw-r--r-- | examples/solv.c | 30 | ||||
-rwxr-xr-x | examples/tclsolv | 803 |
5 files changed, 946 insertions, 144 deletions
diff --git a/examples/p5solv b/examples/p5solv index 330ec63..0a1dbb0 100755 --- a/examples/p5solv +++ b/examples/p5solv @@ -42,9 +42,7 @@ sub calc_cookie_ext { $chksum->add("1.1"); $chksum->add($cookie); $chksum->add_fstat(fileno($f)); - my $extcookie = $chksum->raw(); - substr($extcookie, 0, 1) = chr(1) if ord(substr($extcookie, 0, 1)) == 0; - return $extcookie; + return $chksum->raw(); } sub cachepath { @@ -67,6 +65,7 @@ sub load { $dorefresh = 0 if @s && ($self->{metadata_expire} == -1 || time() - $s[9] < $self->{metadata_expire}); } $self->{cookie} = ''; + $self->{extcookie} = ''; if (!$dorefresh && $self->usecachedrepo()) { print "repo: '$self->{alias}' cached\n"; return 1; @@ -88,7 +87,7 @@ sub download { $url =~ s!/$!!; $url .= "/$file"; open(my $f, '+>', undef) || die; - fcntl($f, Fcntl::F_SETFD, 0); + fcntl($f, Fcntl::F_SETFD, 0); # turn off CLOEXEC my $st = system('curl', '-f', '-s', '-L', '-o', "/dev/fd/" . fileno($f), '--', $url); if (POSIX::lseek(fileno($f), 0, POSIX::SEEK_END) == 0 && ($st == 0 || !$chksum)) { return undef; @@ -145,7 +144,7 @@ sub usecachedrepo { } sub writecachedrepo { - my ($self, $ext, $info) = @_; + my ($self, $ext, $repodata) = @_; return if $self->{incomplete}; mkdir("/var/cache/solv", 0755) unless -d "/var/cache/solv"; my ($f, $tmpname); @@ -155,10 +154,10 @@ sub writecachedrepo { return unless $f; chmod 0444, $f; my $ff = solv::xfopen_fd(undef, fileno($f)); - if (!$info) { + if (!$repodata) { $self->{handle}->write($ff); } elsif ($ext) { - $info->write($ff); + $repodata->write($ff); } else { $self->{handle}->write_first_repodata($ff); } @@ -174,12 +173,12 @@ sub writecachedrepo { if ($f) { if (!$ext) { $self->{handle}->empty(); - die("internal error, cannot reload solv file\n") unless $self->{handle}->add_solv($f, $solv::Repo::SOLV_ADD_NO_STUBS); + die("internal error, cannot reload solv file\n") unless $self->{handle}->add_solv($f, $repodata ? 0 : $solv::Repo::SOLV_ADD_NO_STUBS); } else { - $info->extend_to_repo(); + $repodata->extend_to_repo(); my $flags = $solv::Repo::REPO_EXTEND_SOLVABLES; $flags |= $solv::Repo::REPO_LOCALPOOL if $ext ne 'DL'; - $info->add_solv($f, $flags); + $repodata->add_solv($f, $flags); } } } @@ -191,6 +190,34 @@ sub packagespath { return ''; } +my %langtags = ( + $solv::SOLVABLE_SUMMARY => $solv::REPOKEY_TYPE_STR, + $solv::SOLVABLE_DESCRIPTION => $solv::REPOKEY_TYPE_STR, + $solv::SOLVABLE_EULA => $solv::REPOKEY_TYPE_STR, + $solv::SOLVABLE_MESSAGEINS => $solv::REPOKEY_TYPE_STR, + $solv::SOLVABLE_MESSAGEDEL => $solv::REPOKEY_TYPE_STR, + $solv::SOLVABLE_CATEGORY => $solv::REPOKEY_TYPE_ID, +); + +sub add_ext_keys { + my ($self, $ext, $repodata, $handle) = @_; + if ($ext eq 'DL') { + $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOSITORY_DELTAINFO); + $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_FLEXARRAY); + } elsif ($ext eq 'DU') { + $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::SOLVABLE_DISKUSAGE); + $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_DIRNUMNUMARRAY); + } elsif ($ext eq 'FL') { + $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::SOLVABLE_FILELIST); + $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_DIRSTRARRAY); + } else { + for my $langid (sort { $a <=> $b } keys %langtags) { + $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $self->{handle}->{pool}->id2langid($langid, $ext, 1)); + $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $langtags{$langid}); + } + } +} + package Repo::rpmmd; our @ISA = ('Repo::generic'); @@ -222,13 +249,7 @@ sub add_ext { $repodata->set_poolstr($handle, $solv::REPOSITORY_REPOMD_TYPE, $what); $repodata->set_str($handle, $solv::REPOSITORY_REPOMD_LOCATION, $filename); $repodata->set_checksum($handle, $solv::REPOSITORY_REPOMD_CHECKSUM, $chksum); - if ($ext eq 'DL') { - $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOSITORY_DELTAINFO); - $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_FLEXARRAY); - } elsif ($ext eq 'FL') { - $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::SOLVABLE_FILELIST); - $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_DIRSTRARRAY); - } + $self->add_ext_keys($ext, $repodata, $handle); $repodata->add_flexarray($solv::SOLVID_META, $solv::REPOSITORY_EXTERNAL, $handle); } @@ -328,36 +349,15 @@ sub find { return (undef, undef); } -my %langtags = ( - $solv::SOLVABLE_SUMMARY => $solv::REPOKEY_TYPE_STR, - $solv::SOLVABLE_DESCRIPTION => $solv::REPOKEY_TYPE_STR, - $solv::SOLVABLE_EULA => $solv::REPOKEY_TYPE_STR, - $solv::SOLVABLE_MESSAGEINS => $solv::REPOKEY_TYPE_STR, - $solv::SOLVABLE_MESSAGEDEL => $solv::REPOKEY_TYPE_STR, - $solv::SOLVABLE_CATEGORY => $solv::REPOKEY_TYPE_ID, -); sub add_ext { my ($self, $repodata, $what, $ext) = @_; my ($filename, $chksum) = $self->find($what); + return unless $filename; my $handle = $repodata->new_handle(); $repodata->set_str($handle, $solv::SUSETAGS_FILE_NAME, $filename); $repodata->set_checksum($handle, $solv::SUSETAGS_FILE_CHECKSUM, $chksum); - if ($ext eq 'DL') { - $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOSITORY_DELTAINFO); - $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_FLEXARRAY); - } elsif ($ext eq 'DU') { - $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::SOLVABLE_DISKUSAGE); - $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_DIRNUMNUMARRAY); - } elsif ($ext eq 'FL') { - $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::SOLVABLE_FILELIST); - $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_DIRSTRARRAY); - } else { - for my $langid (sort { $a <=> $b } keys %langtags) { - $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $self->{handle}->{pool}->id2langid($langid, $ext, 1)); - $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $langtags{$langid}); - } - } + $self->add_ext_keys($ext, $repodata, $handle); $repodata->add_flexarray($solv::SOLVID_META, $solv::REPOSITORY_EXTERNAL, $handle); } @@ -710,7 +710,7 @@ my %newpkgsfps; if (@newpkgs) { my $downloadsize = 0; $downloadsize += $_->lookup_num($solv::SOLVABLE_DOWNLOADSIZE) for @newpkgs; - printf "Downloading %d packages, %d K\n", scalar(@newpkgs), $downloadsize; + printf "Downloading %d packages, %d K\n", scalar(@newpkgs), $downloadsize / 1024; for my $p (@newpkgs) { my $repo = $p->{repo}->{appdata}; my ($location) = $p->lookup_location(); @@ -740,6 +740,7 @@ for my $p ($trans->steps()) { print "install ".$p->str()."\n"; my $f = $newpkgsfps{$p->{id}}; my $mode = $steptype == $solv::Transaction::SOLVER_TRANSACTION_INSTALL ? '-U' : '-i'; + $f->cloexec(0); system('rpm', $mode, '--force', '--nodeps', '--nodigest', '--nosignature', "/dev/fd/".$f->fileno()) && die("rpm failed: $?\n"); delete $newpkgsfps{$p->{id}}; } diff --git a/examples/pysolv b/examples/pysolv index 22ae209..3d6ca07 100755 --- a/examples/pysolv +++ b/examples/pysolv @@ -68,16 +68,7 @@ class repo_generic(dict): chksum.add("1.1"); chksum.add(cookie) chksum.add_fstat(f.fileno()) - extcookie = chksum.raw() - if sys.version > '3': - # compatibility to c code - if extcookie[0] == 0: - extcookie[0] = 1 - else: - # compatibility to c code - if ord(extcookie[0]) == 0: - extcookie[0] = chr(1) - return extcookie + return chksum.raw() def cachepath(self, ext = None): path = re.sub(r'^\.', '_', self.name) @@ -100,6 +91,7 @@ class repo_generic(dict): except OSError: pass self['cookie'] = '' + self['extcookie'] = '' if not dorefresh and self.usecachedrepo(None): print("repo: '%s': cached" % self.name) return True @@ -237,7 +229,7 @@ class repo_generic(dict): return False return True - def writecachedrepo(self, ext, info=None): + def writecachedrepo(self, ext, repodata=None): if 'incomplete' in self: return tmpname = None @@ -248,21 +240,21 @@ class repo_generic(dict): os.fchmod(fd, 0o444) f = os.fdopen(fd, 'wb+') f = solv.xfopen_fd(None, f.fileno()) - if not info: + if not repodata: self.handle.write(f) elif ext: - info.write(f) - else: # rewrite_repos case + repodata.write(f) + else: # rewrite_repos case, do not write stubs self.handle.write_first_repodata(f) f.flush() if self.type != 'system' and not ext: - if 'extcookie' not in self: + if not self['extcookie']: self['extcookie'] = self.calc_cookie_ext(f, self['cookie']) - os.write(f.fileno(), self['extcookie']) + f.write(self['extcookie']) if not ext: - os.write(f.fileno(), self['cookie']) + f.write(self['cookie']) else: - os.write(f.fileno(), self['extcookie']) + f.write(self['extcookie']) f.close if self.handle.iscontiguous(): # switch to saved repo to activate paging and save memory @@ -270,17 +262,20 @@ class repo_generic(dict): if not ext: # main repo self.handle.empty() - if not self.handle.add_solv(nf, solv.Repo.SOLV_ADD_NO_STUBS): + flags = solv.Repo.SOLV_ADD_NO_STUBS + if repodata: + flags = 0 # rewrite repos case, recreate stubs + if not self.handle.add_solv(nf, flags): sys.exit("internal error, cannot reload solv file") else: # extension repodata # need to extend to repo boundaries, as this is how - # info.write() has written the data - info.extend_to_repo() + # repodata.write() has written the data + repodata.extend_to_repo() flags = solv.Repo.REPO_EXTEND_SOLVABLES if ext != 'DL': flags |= solv.Repo.REPO_LOCALPOOL - info.add_solv(nf, flags) + repodata.add_solv(nf, flags) os.rename(tmpname, self.cachepath(ext)) except (OSError, IOError): if tmpname: @@ -307,6 +302,29 @@ class repo_generic(dict): def packagespath(self): return '' + def add_ext_keys(self, ext, repodata, handle): + if ext == 'DL': + repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOSITORY_DELTAINFO) + repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_FLEXARRAY) + elif ext == 'DU': + repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_DISKUSAGE) + repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRNUMNUMARRAY) + elif ext == 'FL': + repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_FILELIST) + repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRSTRARRAY) + else: + for langtag, langtagtype in [ + (solv.SOLVABLE_SUMMARY, solv.REPOKEY_TYPE_STR), + (solv.SOLVABLE_DESCRIPTION, solv.REPOKEY_TYPE_STR), + (solv.SOLVABLE_EULA, solv.REPOKEY_TYPE_STR), + (solv.SOLVABLE_MESSAGEINS, solv.REPOKEY_TYPE_STR), + (solv.SOLVABLE_MESSAGEDEL, solv.REPOKEY_TYPE_STR), + (solv.SOLVABLE_CATEGORY, solv.REPOKEY_TYPE_ID) + ]: + repodata.add_idarray(handle, solv.REPOSITORY_KEYS, self.handle.pool.id2langid(langtag, ext, 1)) + repodata.add_idarray(handle, solv.REPOSITORY_KEYS, langtagtype) + + class repo_repomd(repo_generic): def load(self, pool): if super(repo_repomd, self).load(pool): @@ -368,12 +386,7 @@ class repo_repomd(repo_generic): repodata.set_poolstr(handle, solv.REPOSITORY_REPOMD_TYPE, what) repodata.set_str(handle, solv.REPOSITORY_REPOMD_LOCATION, filename) repodata.set_checksum(handle, solv.REPOSITORY_REPOMD_CHECKSUM, chksum) - if ext == 'DL': - repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOSITORY_DELTAINFO) - repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_FLEXARRAY) - elif ext == 'FL': - repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_FILELIST) - repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRSTRARRAY) + self.add_ext_keys(ext, repodata, handle) repodata.add_flexarray(solv.SOLVID_META, solv.REPOSITORY_EXTERNAL, handle) def add_exts(self): @@ -469,23 +482,7 @@ class repo_susetags(repo_generic): repodata.set_str(handle, solv.SUSETAGS_FILE_NAME, filename) if chksum: repodata.set_checksum(handle, solv.SUSETAGS_FILE_CHECKSUM, chksum) - if ext == 'DU': - repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_DISKUSAGE) - repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRNUMNUMARRAY) - elif ext == 'FL': - repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_FILELIST) - repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRSTRARRAY) - else: - for langtag, langtagtype in [ - (solv.SOLVABLE_SUMMARY, solv.REPOKEY_TYPE_STR), - (solv.SOLVABLE_DESCRIPTION, solv.REPOKEY_TYPE_STR), - (solv.SOLVABLE_EULA, solv.REPOKEY_TYPE_STR), - (solv.SOLVABLE_MESSAGEINS, solv.REPOKEY_TYPE_STR), - (solv.SOLVABLE_MESSAGEDEL, solv.REPOKEY_TYPE_STR), - (solv.SOLVABLE_CATEGORY, solv.REPOKEY_TYPE_ID) - ]: - repodata.add_idarray(handle, solv.REPOSITORY_KEYS, self.handle.pool.id2langid(langtag, ext, 1)) - repodata.add_idarray(handle, solv.REPOSITORY_KEYS, langtagtype) + self.add_ext_keys(ext, repodata, handle) repodata.add_flexarray(solv.SOLVID_META, solv.REPOSITORY_EXTERNAL, handle) def add_exts(self): @@ -852,7 +849,7 @@ if newpkgs: downloadsize = 0 for p in newpkgs: downloadsize += p.lookup_num(solv.SOLVABLE_DOWNLOADSIZE) - print("Downloading %d packages, %d K" % (len(newpkgs), downloadsize)) + print("Downloading %d packages, %d K" % (len(newpkgs), downloadsize / 1024)) for p in newpkgs: repo = p.repo.appdata location, medianr = p.lookup_location() @@ -866,7 +863,7 @@ if newpkgs: continue if not sysrepo.handle.isempty() and os.access('/usr/bin/applydeltarpm', os.X_OK): pname = p.name - di = p.repo.Dataiterator(solv.SOLVID_META, solv.DELTA_PACKAGE_NAME, pname, solv.Dataiterator.SEARCH_STRING) + di = p.repo.Dataiterator_meta(solv.DELTA_PACKAGE_NAME, pname, solv.Dataiterator.SEARCH_STRING) di.prepend_keyname(solv.REPOSITORY_DELTAINFO) for d in di: dp = d.parentpos() @@ -893,6 +890,7 @@ if newpkgs: continue nf = tempfile.TemporaryFile() nf = os.dup(nf.fileno()) # get rid of CLOEXEC + f.cloexec(0) st = subprocess.call(['/usr/bin/applydeltarpm', '-a', p.arch, "/dev/fd/%d" % f.fileno(), "/dev/fd/%d" % nf]) if st: os.close(nf) diff --git a/examples/rbsolv b/examples/rbsolv index 470438d..be633f3 100755 --- a/examples/rbsolv +++ b/examples/rbsolv @@ -44,9 +44,7 @@ class Repo_generic chksum.add("1.1") chksum.add(cookie) chksum.add_fstat(f.fileno) - extcookie = chksum.raw() - extcookie[0] = 1 if extcookie[0] == 0 - return extcookie + return chksum.raw() end def cachepath(ext = nil) @@ -68,6 +66,7 @@ class Repo_generic end end @cookie = nil + @extcookie = nil if !dorefresh && usecachedrepo(nil) puts "repo: '#{@name}' cached" return true @@ -152,17 +151,17 @@ class Repo_generic return true end - def writecachedrepo(ext, info = nil) + def writecachedrepo(ext, repodata = nil) return if @incomplete begin Dir::mkdir("/var/cache/solv", 0755) unless FileTest.directory?("/var/cache/solv") f = Tempfile.new('.newsolv-', '/var/cache/solv') f.chmod(0444) sf = Solv::xfopen_fd('', f.fileno) - if !info + if !repodata @handle.write(sf) elsif ext - info.write(sf) + repodata.write(sf) else @handle.write_first_repodata(sf) end @@ -179,12 +178,12 @@ class Repo_generic if sf if !ext @handle.empty() - abort("internal error, cannot reload solv file") unless @handle.add_solv(sf, Solv::Repo::SOLV_ADD_NO_STUBS) + abort("internal error, cannot reload solv file") unless @handle.add_solv(sf, repodata ? 0 : Solv::Repo::SOLV_ADD_NO_STUBS) else - info.extend_to_repo() + repodata.extend_to_repo() flags = Solv::Repo::REPO_EXTEND_SOLVABLES flags |= Solv::Repo::REPO_LOCALPOOL if ext != 'DL' - info.add_solv(sf, flags) + repodata.add_solv(sf, flags) end sf.close end @@ -214,6 +213,33 @@ class Repo_generic def packagespath() return '' end + + @@langtags = { + Solv::SOLVABLE_SUMMARY => Solv::REPOKEY_TYPE_STR, + Solv::SOLVABLE_DESCRIPTION => Solv::REPOKEY_TYPE_STR, + Solv::SOLVABLE_EULA => Solv::REPOKEY_TYPE_STR, + Solv::SOLVABLE_MESSAGEINS => Solv::REPOKEY_TYPE_STR, + Solv::SOLVABLE_MESSAGEDEL => Solv::REPOKEY_TYPE_STR, + Solv::SOLVABLE_CATEGORY => Solv::REPOKEY_TYPE_ID, + } + + def add_ext_keys(ext, repodata, h) + if ext == 'DL' + repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOSITORY_DELTAINFO) + repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_FLEXARRAY) + elsif ext == 'DU' + repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_DISKUSAGE) + repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRNUMNUMARRAY) + elsif ext == 'FL' + repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_FILELIST) + repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRSTRARRAY) + else + @@langtags.sort.each do |langid, langtype| + repodata.add_idarray(h, Solv::REPOSITORY_KEYS, @handle.pool.id2langid(langid, ext, true)) + repodata.add_idarray(h, Solv::REPOSITORY_KEYS, langtype) + end + end + end end class Repo_rpmmd < Repo_generic @@ -285,13 +311,7 @@ class Repo_rpmmd < Repo_generic repodata.set_poolstr(h, Solv::REPOSITORY_REPOMD_TYPE, what) repodata.set_str(h, Solv::REPOSITORY_REPOMD_LOCATION, filename) repodata.set_checksum(h, Solv::REPOSITORY_REPOMD_CHECKSUM, filechksum) - if ext == 'DL' - repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOSITORY_DELTAINFO) - repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_FLEXARRAY) - elsif ext == 'FL' - repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_FILELIST) - repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRSTRARRAY) - end + add_ext_keys(ext, repodata, h) repodata.add_flexarray(Solv::SOLVID_META, Solv::REPOSITORY_EXTERNAL, h) end @@ -394,35 +414,12 @@ class Repo_susetags < Repo_generic return true end - @@langtags = { - Solv::SOLVABLE_SUMMARY => Solv::REPOKEY_TYPE_STR, - Solv::SOLVABLE_DESCRIPTION => Solv::REPOKEY_TYPE_STR, - Solv::SOLVABLE_EULA => Solv::REPOKEY_TYPE_STR, - Solv::SOLVABLE_MESSAGEINS => Solv::REPOKEY_TYPE_STR, - Solv::SOLVABLE_MESSAGEDEL => Solv::REPOKEY_TYPE_STR, - Solv::SOLVABLE_CATEGORY => Solv::REPOKEY_TYPE_ID, - } - def add_ext(repodata, what, ext) (filename, filechksum) = find(what) h = repodata.new_handle() repodata.set_str(h, Solv::SUSETAGS_FILE_NAME, filename) repodata.set_checksum(h, Solv::SUSETAGS_FILE_CHECKSUM, filechksum) - if ext == 'DL' - repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOSITORY_DELTAINFO) - repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_FLEXARRAY) - elsif ext == 'DU' - repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_DISKUSAGE) - repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRNUMNUMARRAY) - elsif ext == 'FL' - repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_FILELIST) - repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRSTRARRAY) - else - @@langtags.sort.each do |langid, langtype| - repodata.add_idarray(h, Solv::REPOSITORY_KEYS, @handle.pool.id2langid(langid, ext, true)) - repodata.add_idarray(h, Solv::REPOSITORY_KEYS, langtype) - end - end + add_ext_keys(ext, repodata, h) repodata.add_flexarray(Solv::SOLVID_META, Solv::REPOSITORY_EXTERNAL, h) end @@ -494,7 +491,7 @@ class Repo_system < Repo_generic end f = Solv::xfopen(cachepath()) @handle.add_rpmdb_reffp(f, Solv::Repo::REPO_REUSE_REPODATA) - f.close + f.close if f writecachedrepo(nil) return true end @@ -727,7 +724,7 @@ if !newpkgs.empty? for p in newpkgs downloadsize += p.lookup_num(Solv::SOLVABLE_DOWNLOADSIZE) end - puts "Downloading #{newpkgs.length} packages, #{downloadsize} K" + puts "Downloading #{newpkgs.length} packages, #{downloadsize / 1024} K" for p in newpkgs repo = p.repo.appdata location, medianr = p.lookup_location() @@ -758,6 +755,7 @@ for p in trans.steps f = newpkgsfp.delete(p.id) next unless f mode = steptype == Solv::Transaction::SOLVER_TRANSACTION_INSTALL ? '-U' : '-i' + f.cloexec(0) system('rpm', mode, '--force', '--nodeps', '--nodigest', '--nosignature', "/dev/fd/#{f.fileno().to_s}") || abort("rpm failed: #{$? >> 8}") f.close end diff --git a/examples/solv.c b/examples/solv.c index 8b0d6cc..fc420b3 100644 --- a/examples/solv.c +++ b/examples/solv.c @@ -124,8 +124,8 @@ struct repoinfo { int metadata_expire; char **components; int ncomponents; - unsigned char cookie[32]; + int extcookieset; unsigned char extcookie[32]; int incomplete; }; @@ -1133,7 +1133,7 @@ usecachedrepo(Repo *repo, const char *repoext, unsigned char *cookie, int mark) fclose(fp); return 0; } - if (cookie && memcmp(cookie, mycookie, sizeof(mycookie))) + if (cookie && memcmp(cookie, mycookie, sizeof(mycookie)) != 0) { fclose(fp); return 0; @@ -1165,6 +1165,7 @@ usecachedrepo(Repo *repo, const char *repoext, unsigned char *cookie, int mark) { memcpy(cinfo->cookie, mycookie, sizeof(mycookie)); memcpy(cinfo->extcookie, myextcookie, sizeof(myextcookie)); + cinfo->extcookieset = 1; } if (mark) futimens(fileno(fp), 0); /* try to set modification time */ @@ -1173,7 +1174,7 @@ usecachedrepo(Repo *repo, const char *repoext, unsigned char *cookie, int mark) } void -writecachedrepo(Repo *repo, Repodata *info, const char *repoext, unsigned char *cookie) +writecachedrepo(Repo *repo, Repodata *repodata, const char *repoext, unsigned char *cookie) { FILE *fp; int i, fd; @@ -1211,22 +1212,22 @@ writecachedrepo(Repo *repo, Repodata *info, const char *repoext, unsigned char * if (i < repo->end) onepiece = 0; - if (!info) + if (!repodata) repo_write(repo, fp); else if (repoext) - repodata_write(info, fp); + repodata_write(repodata, fp); else { int oldnrepodata = repo->nrepodata; repo->nrepodata = oldnrepodata > 2 ? 2 : oldnrepodata; /* XXX: do this right */ repo_write(repo, fp); repo->nrepodata = oldnrepodata; - onepiece = 0; + onepiece = 0; /* don't bother for the added file provides */ } if (!repoext && cinfo) { - if (!cinfo->extcookie[0]) + if (!cinfo->extcookieset) { /* create the ext cookie and append it */ /* we just need some unique ID */ @@ -1234,8 +1235,7 @@ writecachedrepo(Repo *repo, Repodata *info, const char *repoext, unsigned char * if (!fstat(fileno(fp), &stb)) memset(&stb, 0, sizeof(stb)); calc_checksum_stat(&stb, REPOKEY_TYPE_SHA256, cookie, cinfo->extcookie); - if (cinfo->extcookie[0] == 0) - cinfo->extcookie[0] = 1; + cinfo->extcookieset = 1; } if (fwrite(cinfo->extcookie, 32, 1, fp) != 1) { @@ -1281,12 +1281,12 @@ writecachedrepo(Repo *repo, Repodata *info, const char *repoext, unsigned char * int flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES; /* make sure repodata contains complete repo */ /* (this is how repodata_write saves it) */ - repodata_extend_block(info, repo->start, repo->end - repo->start); - info->state = REPODATA_LOADING; + repodata_extend_block(repodata, repo->start, repo->end - repo->start); + repodata->state = REPODATA_LOADING; if (strcmp(repoext, "DL") != 0) flags |= REPO_LOCALPOOL; repo_add_solv(repo, fp, flags); - info->state = REPODATA_AVAILABLE; /* in case the load failed */ + repodata->state = REPODATA_AVAILABLE; /* in case the load failed */ } fclose(fp); } @@ -1400,7 +1400,8 @@ repomd_load_ext(Repo *repo, Repodata *data) printf("%s\n", pool_errstr(repo->pool)); return 0; } - writecachedrepo(repo, data, ext, cinfo->extcookie); + if (cinfo->extcookieset) + writecachedrepo(repo, data, ext, cinfo->extcookie); return 1; } @@ -1546,7 +1547,8 @@ susetags_load_ext(Repo *repo, Repodata *data) return 0; } fclose(fp); - writecachedrepo(repo, data, ext, cinfo->extcookie); + if (cinfo->extcookieset) + writecachedrepo(repo, data, ext, cinfo->extcookie); return 1; } #endif diff --git a/examples/tclsolv b/examples/tclsolv new file mode 100755 index 0000000..6f819aa --- /dev/null +++ b/examples/tclsolv @@ -0,0 +1,803 @@ +#!/usr/bin/tclsh + +package require solv +package require inifile +package require fileutil + +set reposdir /etc/zypp/repos.d + +### some helpers + +proc fileno {file} { + if [regexp -- {^file(\d+)$} $file match fd] { + return $fd + } + error "file not open" +} + +set ::globalarray_cnt 0 + +proc globalarray {} { + set name "::globalarray_[incr ::globalarray_cnt]" + array set $name [list varName $name] + return $name +} + +### generic repo handling (cache reading/writing) + +proc repo_calc_cookie_file {selfName filename} { + upvar $selfName self + set chksum [solv::new_Chksum $solv::REPOKEY_TYPE_SHA256] + $chksum add "1.1" + $chksum add_stat $filename + return [$chksum raw] +} + +proc repo_calc_cookie_fp {selfName fp} { + upvar $selfName self + set chksum [solv::new_Chksum $solv::REPOKEY_TYPE_SHA256] + $chksum add "1.1" + $chksum add_fp $fp + return [$chksum raw] +} + +proc repo_calc_cookie_ext {selfName f cookie} { + upvar $selfName self + set chksum [solv::new_Chksum $solv::REPOKEY_TYPE_SHA256] + $chksum add "1.1" + $chksum add $cookie + $chksum add_fstat [$f fileno] + return [$chksum raw] +} + +proc repo_cachepath {selfName {ext "-"}} { + upvar $selfName self + regsub {^\.} $self(name) _ path + if {$ext ne "-"} { + set path "${path}_$ext.solvx" + } else { + set path "${path}.solv" + } + regsub -all / $path _ path + return "/var/cache/solv/$path" +} + +proc repo_generic_load {selfName pool} { + upvar $selfName self + set handle [ $pool add_repo $self(name) ] + set self(handle) $handle + $handle configure -priority [expr 99 - $self(priority)] -appdata $self(varName) + set dorefresh $self(autorefresh) + set metadata_expire $self(metadata_expire) + catch { + if {$metadata_expire == -1 || [clock seconds] - [file mtime [repo_cachepath self]] < $metadata_expire} { + set dorefresh 0 + } + } + set self(cookie) {} + set self(extcookie) {} + if { !$dorefresh && [repo_usecachedrepo self] } { + puts "repo $self(name): cached" + return 1 + } + return 0 +} + +proc repo_free_handle {selfName} { + upvar $selfName self + set handle $self(handle) + unset self(handle) + $handle free 1 +} + +proc repo_usecachedrepo {selfName {ext "-"} {mark 0}} { + upvar $selfName self + set repopath [repo_cachepath self $ext] + set code [catch { + set f [open $repopath "rb"] + seek $f -32 end + set fcookie [read $f 32] + set cookie [expr {$ext eq "-" ? $self(cookie) : $self(extcookie)}] + if {$cookie ne {} && $cookie ne $fcookie} { + close $f + return 0 + } + set fextcookie {} + if {$ext eq "-" && $self(type) ne "system"} { + seek $f -64 end + set fextcookie [read $f 32] + } + seek $f 0 start + set ff [solv::xfopen_fd {} [fileno $f]] + close $f + set flags 0 + if {$ext ne "-"} { + set flags [expr $solv::Repo_REPO_USE_LOADING | $solv::Repo_REPO_EXTEND_SOLVABLES] + if {$ext ne "DL"} { + set flags [expr $flags | $solv::Repo_REPO_LOCALPOOL] + } + } + if {! [$self(handle) add_solv $ff $flags]} { + $ff close + return 0 + } + $ff close + if {$self(type) ne "system" && $ext eq "-"} { + set self(cookie) $fcookie + set self(extcookie) $fextcookie + } + if {$mark} { + catch { + ::fileutil::touch -c -m -t [clock seconds] $repopath + } + } + return 1 + } res] + return [expr {$code == 2 ? $res : 0}] +} + +proc repo_writecachedrepo {selfName {ext "-"} {repodata "NULL"}} { + upvar $selfName self + if [info exists self(incomplete)] { + return + } + file mkdir "/var/cache/solv" + ::fileutil::tempdir "/var/cache/solv" + set tempfilename [::fileutil::tempfile ".newsolv-"] + ::fileutil::tempdirReset + set f [solv::xfopen $tempfilename "w+"] + file attributes $tempfilename -permissions 0444 + if {$repodata eq {NULL}} { + $self(handle) write $f + } else { + $repodata write $f + } + $f flush + if {$self(type) ne "system" && $ext eq "-"} { + if {$self(extcookie) eq {}} { + set self(extcookie) [repo_calc_cookie_ext self $f $self(cookie)] + } + $f write $self(extcookie) + } + $f write [expr {$ext eq "-" ? $self(cookie) : $self(extcookie)}] + $f close + file rename -force -- $tempfilename [repo_cachepath self $ext] +} + +proc repo_download {selfName file uncompress chksum {markincomplete 0}} { + upvar $selfName self + regsub {/$} $self(baseurl) {} url + set url "$url/$file" + set tempfilename [::fileutil::tempfile] + set f [open $tempfilename rb+] + file delete -- $tempfilename + if [catch { + exec -ignorestderr -- curl -f -s -L $url ">@$f" + }] { + seek $f 0 end + if {($chksum ne "" && $chksum ne "NULL") || [tell $f] != 0} { + puts "$file: download error" + } + close $f + return {NULL} + } + seek $f 0 start + if {$chksum ne "" && $chksum ne "NULL"} { + set fchksum [solv::new_Chksum [$chksum cget -type]] + if {$fchksum eq "" || $fchksum eq "NULL"} { + puts "$file: unknown checksum type" + if {$markincomplete} { + set self(incomplete) 1 + } + close $f + return {NULL} + } + $fchksum add_fd [fileno $f] + if {[$fchksum != $chksum]} { + puts "$file: checksum mismatch" + if {$markincomplete} { + set self(incomplete) 1 + } + close $f + return {NULL} + } + } + set ff [solv::xfopen_fd [expr {$uncompress ? $file : ""}] [fileno $f]] + close $f + return $ff +} + +proc repo_generic_add_ext_keys {selfName ext repodata h} { + upvar $selfName self + if {$ext eq "DL"} { + $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::REPOSITORY_DELTAINFO + $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::REPOKEY_TYPE_FLEXARRAY + } elseif {$ext eq "DU"} { + $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::SOLVABLE_DISKUSAGE + $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::REPOKEY_TYPE_DIRNUMNUMARRAY + } elseif {$ext eq "FL"} { + $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::SOLVABLE_FILELIST + $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::REPOKEY_TYPE_DIRSTRARRAY + } +} + +### system + +proc repo_system_load {selfName pool} { + upvar $selfName self + set handle [ $pool add_repo $self(name) ] + set self(handle) $handle + $handle configure -appdata $self(varName) + $pool configure -installed $handle + puts -nonewline "rpm database: " + set self(cookie) [repo_calc_cookie_file self "/var/lib/rpm/Packages"] + if [repo_usecachedrepo self] { + puts "cached" + return 1 + } + puts "reading" + set f [solv::xfopen [repo_cachepath self]] + $handle add_rpmdb_reffp $f $solv::Repo_REPO_REUSE_REPODATA + repo_writecachedrepo self +} + +### repomd + +proc repo_repomd_add_ext {selfName repodata what ext} { + upvar $selfName self + set where [repo_repomd_find self $what] + if {$where eq {}} { + return + } + set h [$repodata new_handle] + $repodata set_poolstr $h $solv::REPOSITORY_REPOMD_TYPE $what + $repodata set_str $h $solv::REPOSITORY_REPOMD_LOCATION [lindex $where 0] + $repodata set_checksum $h $solv::REPOSITORY_REPOMD_CHECKSUM [lindex $where 1] + repo_generic_add_ext_keys self $ext $repodata $h + $repodata add_flexarray $solv::SOLVID_META $solv::REPOSITORY_EXTERNAL $h +} + +proc repo_repomd_add_exts {selfName} { + upvar $selfName self + set repodata [$self(handle) add_repodata 0] + repo_repomd_add_ext self $repodata "filelists" "FL" + $repodata internalize +} + +proc repo_repomd_find {selfName what} { + upvar $selfName self + set di [$self(handle) Dataiterator_meta $solv::REPOSITORY_REPOMD_TYPE $what $solv::Dataiterator_SEARCH_STRING] + $di prepend_keyname $solv::REPOSITORY_REPOMD + solv::iter d $di { + set dp [$d parentpos] + set filename [$dp lookup_str $solv::REPOSITORY_REPOMD_LOCATION] + set checksum [$dp lookup_checksum $solv::REPOSITORY_REPOMD_CHECKSUM] + if {$filename ne "" && $checksum eq "NULL"} { + puts "no $filename file checksum" + } elseif {$filename ne ""} { + return [list $filename $checksum] + } + } + return {} +} + +proc repo_repomd_load {selfName pool} { + upvar $selfName self + if [repo_generic_load self $pool] { + return 1 + } + puts -nonewline "rpmmd repo '$self(name)': " + set f [repo_download self {repodata/repomd.xml} 0 {}] + if {$f eq {NULL}} { + puts "no repomd.xml file, skipped" + repo_free_handle self + return 0 + } + set self(cookie) [repo_calc_cookie_fp self $f] + if [repo_usecachedrepo self "-" 1] { + puts "cached" + return 1 + } + set handle $self(handle) + $handle add_repomdxml $f + puts "fetching" + set primary [repo_repomd_find self primary] + if {$primary ne {}} { + set f [repo_download self [lindex $primary 0] 1 [lindex $primary 1] 1] + if {$f ne {NULL}} { + $handle add_rpmmd $f {} + $f close + } + if [info exists self(incomplete)] { + return 0 + } + } + set updateinfo [repo_repomd_find self primary] + if {$updateinfo ne {}} { + set f [repo_download self [lindex $updateinfo 0] 1 [lindex $updateinfo 1] 1] + if {$f ne {NULL}} { + $handle add_updateinfoxml $f + $f close + } + } + repo_repomd_add_exts self + repo_writecachedrepo self + $self(handle) create_stubs + return 1 +} + +proc repo_repomd_packagespath {selfName} { + return "" +} + +proc repo_repomd_load_ext {selfName repodata} { + upvar $selfName self + switch -- [$repodata lookup_str $solv::SOLVID_META $solv::REPOSITORY_REPOMD_TYPE] { + "deltainfo" { + set ext DL + } + "filelists" { + set ext FL + } + default { + return 0 + } + } + puts -nonewline "\[$self(name):$ext: " + flush stdout + if [repo_usecachedrepo self $ext] { + puts "cached]" + return 1 + } + puts "fetching]" + set handle $self(handle) + set filename [$repodata lookup_str $solv::SOLVID_META $solv::REPOSITORY_REPOMD_LOCATION] + set filechecksum [$repodata lookup_checksum $solv::SOLVID_META $solv::REPOSITORY_REPOMD_CHECKSUM] + set f [repo_download self $filename 1 $filechecksum] + if {$f eq {NULL}} { + return 0 + } + if {$ext eq "FL"} { + $handle add_rpmmd $f "FL" [ expr $solv::Repo_REPO_USE_LOADING | $solv::Repo_REPO_EXTEND_SOLVABLES | $solv::Repo_REPO_LOCALPOOL] + } + $f close + repo_writecachedrepo self $ext $repodata + return 1 +} + +### susetags + +proc repo_susetags_add_ext {selfName repodata what ext} { + upvar $selfName self + set where [repo_susetags_find self $what] + if {$where eq {}} { + return + } + set h [$repodata new_handle] + $repodata set_str $h $solv::SUSETAGS_FILE_NAME [lindex $where 0] + $repodata set_checksum $h $solv::SUSETAGS_FILE_CHECKSUM [lindex $where 1] + repo_generic_add_ext_keys self $ext $repodata $h + $repodata add_flexarray $solv::SOLVID_META $solv::REPOSITORY_EXTERNAL $h +} + +proc repo_susetags_add_exts {selfName} { + upvar $selfName self + set repodata [$self(handle) add_repodata 0] + repo_susetags_add_ext self $repodata "packages.FL" "FL" + repo_susetags_add_ext self $repodata "packages.FL.gz" "FL" + $repodata internalize +} + +proc repo_susetags_find {selfName what} { + upvar $selfName self + set di [$self(handle) Dataiterator_meta $solv::SUSETAGS_FILE_NAME $what $solv::Dataiterator_SEARCH_STRING] + $di prepend_keyname $solv::SUSETAGS_FILE + solv::iter d $di { + set dp [$d parentpos] + set checksum [$dp lookup_checksum $solv::SUSETAGS_FILE_CHECKSUM] + return [list $what $checksum] + } + return {} +} + +proc repo_susetags_load {selfName pool} { + upvar $selfName self + if [repo_generic_load self $pool] { + return 1 + } + puts -nonewline "susetags repo '$self(name)': " + set f [repo_download self {content} 0 {}] + if {$f eq {NULL}} { + puts "no content file, skipped" + repo_free_handle self + return 0 + } + set self(cookie) [repo_calc_cookie_fp self $f] + if [repo_usecachedrepo self "-" 1] { + puts "cached" + return 1 + } + set handle $self(handle) + $handle add_content $f + puts "fetching" + set defvendorid [[$handle cget -meta] lookup_id $solv::SUSETAGS_DEFAULTVENDOR] + set descrdir [[$handle cget -meta] lookup_str $solv::SUSETAGS_DESCRDIR] + if {$descrdir eq {NULL}} { + set descrdir "suse/setup/descr" + } + set packages [repo_susetags_find self "packages.gz"] + if {$packages eq {}} { + set packages [repo_susetags_find self "packages"] + } + if {$packages ne {}} { + set f [repo_download self "$descrdir/[lindex $packages 0]" 1 [lindex $packages 1] 1] + if {$f ne {NULL}} { + $handle add_susetags $f $defvendorid {} [expr $solv::Repo_REPO_NO_INTERNALIZE | $solv::Repo_SUSETAGS_RECORD_SHARES] + $f close + set packages [repo_susetags_find self "packages.en.gz"] + if {$packages eq {}} { + set packages [repo_susetags_find self "packages.en"] + } + if {$packages ne {}} { + set f [repo_download self "$descrdir/[lindex $packages 0]" 1 [lindex $packages 1] 1] + if {$f ne {NULL}} { + $handle add_susetags $f $defvendorid {} [expr $solv::Repo_REPO_NO_INTERNALIZE | $solv::Repo_REPO_REUSE_REPODATA | $solv::Repo_REPO_EXTEND_SOLVABLES ] + $f close + } + } + $handle internalize + } + } + repo_susetags_add_exts self + repo_writecachedrepo self + $self(handle) create_stubs + return 1 +} + +proc repo_susetags_packagespath {selfName} { + upvar $selfName self + set datadir [[$self(handle) cget -meta] lookup_str $solv::SUSETAGS_DATADIR] + return [expr {$datadir ne {} ? "$datadir/" : "suse/"}] +} + +proc repo_susetags_load_ext {selfName repodata} { + upvar $selfName self + set filename [$repodata lookup_str $solv::SOLVID_META $solv::SUSETAGS_FILE_NAME] + set ext [string range $filename 9 10] + puts -nonewline "\[$self(name):$ext: " + flush stdout + if [repo_usecachedrepo self $ext] { + puts "cached]" + return 1 + } + puts "fetching]" + set handle $self(handle) + set defvendorid [[$handle cget -meta] lookup_id $solv::SUSETAGS_DEFAULTVENDOR] + set descrdir [[$handle cget -meta] lookup_str $solv::SUSETAGS_DESCRDIR] + if {$descrdir eq {NULL}} { + set descrdir "suse/setup/descr" + } + set filechecksum [$repodata lookup_checksum $solv::SOLVID_META $solv::SUSETAGS_FILE_CHECKSUM] + set f [repo_download self "$descrdir/$filename" 1 $filechecksum] + if {$f eq {NULL}} { + return 0 + } + set flags [expr $solv::Repo_REPO_USE_LOADING | $solv::Repo_REPO_EXTEND_SOLVABLES] + if {$ext ne "DL"} { + set flags [expr $flags | $solv::Repo_REPO_LOCALPOOL] + } + $handle add_susetags $f $defvendorid $ext $flags + $f close + repo_writecachedrepo self $ext $repodata + return 1 +} + +### unknown + +proc repo_unknown_load {selfName pool} { + upvar $selfName self + puts "unsupported repo '$self(name)': skipped" + return 0 +} + +### poor man's OO + +proc repo_load {selfName pool} { + upvar $selfName self + "repo_$self(type)_load" self $pool +} + +proc repo_packagespath {selfName} { + upvar $selfName self + "repo_$self(type)_packagespath" self +} + +proc repo_load_ext {selfName repodata} { + upvar $selfName self + "repo_$self(type)_load_ext" self $repodata +} + +### + +proc load_stub {repodata} { + set code [catch { + upvar #0 [[$repodata cget -repo] cget -appdata] repo + if [info exists repo(handle)] { + return [repo_load_ext repo $repodata] + } + return 0 + } res] + if {$code == 2} { + return $res + } + puts stderr $res + return 0 +} + +### + +set repoNames {} +foreach reponame [lsort [glob -nocomplain -directory $reposdir *.repo]] { + set ini [::ini::open $reponame r] + foreach alias [::ini::sections $ini] { + upvar #0 [globalarray] repo + array set repo {enabled 0 priority 99 autorefresh 1 type rpm-md metadata_expire 900} + array set repo [::ini::get $ini $alias] + set repo(name) $alias + switch -exact -- $repo(type) { + rpm-md { set repo(type) repomd } + yast2 { set repo(type) susetags } + default { set repo(type) unknown } + } + lappend repoNames $repo(varName) + } + ::ini::close $ini +} + +set pool [solv::new_Pool] +$pool setarch +$pool set_loadcallback load_stub + +upvar #0 [globalarray] sysrepo +array set sysrepo [list name {@System} type system] +repo_load sysrepo $pool + +foreach repoName $repoNames { + upvar 0 $repoName repo + if {$repo(enabled)} { + repo_load repo $pool + } +} + + +set cmd [lindex $::argv 0] +set ::argv [lreplace $::argv 0 0] + +array set cmdabbrev [ list \ + in install \ + rm erase \ + ls list \ + ve verify \ + se search \ +] +if [info exists cmdabbrev($cmd)] { + set cmd $cmdabbrev($cmd) +} + +if {$cmd eq "search"} { + set arg [lindex $::argv 0] + $pool createwhatprovides + set sel [$pool Selection] + set di [$pool Dataiterator $solv::SOLVABLE_NAME $arg [ expr $solv::Dataiterator_SEARCH_SUBSTRING | $solv::Dataiterator_SEARCH_NOCASE ]] + solv::iter d $di { + $sel add_raw $solv::Job_SOLVER_SOLVABLE [$d cget -solvid] + } + foreach s [$sel solvables] { + puts [format { - %s [%s]: %s} [$s str] [[$s cget -repo] cget -name] [$s lookup_str $solv::SOLVABLE_SUMMARY]] + } + exit +} + +$pool addfileprovides +$pool createwhatprovides + +array set cmdactionmap [ list \ + install $solv::Job_SOLVER_INSTALL \ + erase $solv::Job_SOLVER_ERASE \ + up $solv::Job_SOLVER_UPDATE \ + dup $solv::Job_SOLVER_DISTUPGRADE \ + verify $solv::Job_SOLVER_VERIFY \ + list 0 \ + info 0 \ +] + +set jobs {} +foreach arg $::argv { + set flags [expr $solv::Selection_SELECTION_NAME | $solv::Selection_SELECTION_PROVIDES | $solv::Selection_SELECTION_GLOB | \ + $solv::Selection_SELECTION_CANON | $solv::Selection_SELECTION_DOTARCH | $solv::Selection_SELECTION_REL ] + switch -glob -- $arg { + "/*" { + set flags [expr $flags | $solv::Selection_SELECTION_FILELIST ] + if {$cmd eq "erase"} { + set flags [expr $flags | $solv::Selection_SELECTION_INSTALLED_ONLY ] + } + } + } + set sel [$pool select $arg $flags] + if [$sel isempty] { + set sel [$pool select $arg [expr $flags | $solv::Selection_SELECTION_NOCASE]] + if {![$sel isempty]} { + puts "\[ignoring case for '$arg']" + } + } + if [$sel isempty] { + puts "nothing matches '$arg'" + exit 1 + } + if {[$sel flags] & $solv::Selection_SELECTION_FILELIST} { + puts "\[using file list match for '$arg']" + } + if {[$sel flags] & $solv::Selection_SELECTION_PROVIDES} { + puts "\[using capability match for '$arg']" + } + lappend jobs {*}[$sel jobs $cmdactionmap($cmd)] +} + +if {$jobs eq {} && ($cmd eq "up" || $cmd eq "dup" || $cmd eq "verify") } { + set sel [$pool Selection_all] + lappend jobs {*}[$sel jobs $cmdactionmap($cmd)] +} + +if {$jobs eq {}} { + puts "no package matched." + exit 1 +} + +if {$cmd eq "list" || $cmd eq "info"} { + foreach job $jobs { + foreach s [$job solvables] { + if {$cmd eq "info"} { + puts [format {Name: %s} [$s str]] + puts [format {Repo: %s} [[$s cget -repo] cget -name]] + puts [format {Summary: %s} [$s lookup_str $solv::SOLVABLE_SUMMARY]] + set str [$s lookup_str $solv::SOLVABLE_URL] + if {$str ne {}} { + puts [format {Url: %s} $str] + } + set str [$s lookup_str $solv::SOLVABLE_LICENSE] + if {$str ne {}} { + puts [format {License %s} $str] + } + puts [format {Description: %s} [$s lookup_str $solv::SOLVABLE_DESCRIPTION]] + puts {} + } else { + puts [format { - %s [%s]} [$s str] [[$s cget -repo] cget -name]] + puts [format { %s} [$s lookup_str $solv::SOLVABLE_SUMMARY]] + } + } + } + exit +} + +#$pool set_debuglevel 1 +set solver [$pool Solver] +$solver set_flag $solv::Solver_SOLVER_FLAG_SPLITPROVIDES 1 +if {$cmd eq "erase"} { + $solver set_flag $solv::Solver_SOLVER_FLAG_ALLOW_UNINSTALL 1 +} + +set problems [$solver solve $jobs] +if {$problems ne {}} { + set pcnt 1 + foreach problem $problems { + puts [format {Problem %d/%d:} $pcnt [llength $problems]] + puts [$problem str] + incr pcnt + } + exit 1 +} + +set trans [$solver transaction] + +if [$trans isempty] { + puts "Nothing to do." + exit +} + +puts {} +puts "Transaction summary:" +puts {} +foreach cl [$trans classify [expr $solv::Transaction_SOLVER_TRANSACTION_SHOW_OBSOLETES | $solv::Transaction_SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE]] { + switch -- [$cl cget -type] \ + $solv::Transaction_SOLVER_TRANSACTION_ERASE { + puts [format {%d erased packages:} [$cl cget -count]] + } \ + $solv::Transaction_SOLVER_TRANSACTION_INSTALL { + puts [format {%d installed packages:} [$cl cget -count]] + } \ + $solv::Transaction_SOLVER_TRANSACTION_REINSTALLED { + puts [format {%d reinstalled packages:} [$cl cget -count]] + } \ + $solv::Transaction_SOLVER_TRANSACTION_DOWNGRADED { + puts [format {%d downgraded packages:} [$cl cget -count]] + } \ + $solv::Transaction_SOLVER_TRANSACTION_CHANGED { + puts [format {%d changed packages:} [$cl cget -count]] + } \ + $solv::Transaction_SOLVER_TRANSACTION_UPGRADED { + puts [format {%d upgraded packages:} [$cl cget -count]] + } \ + $solv::Transaction_SOLVER_TRANSACTION_VENDORCHANGE { + puts [format {%d vendor changes from '%s' to '%s':} [$cl cget -count] [$cl cget -fromstr] [$cl cget -tostr]] + } \ + $solv::Transaction_SOLVER_TRANSACTION_ARCHCHANGE { + puts [format {%d archchanges from '%s' to '%s':} [$cl cget -count] [$cl cget -fromstr] [$cl cget -tostr]] + } \ + default continue + foreach p [$cl solvables] { + set cltype [$cl cget -type] + if {$cltype == $solv::Transaction_SOLVER_TRANSACTION_UPGRADED || $cltype ==$solv::Transaction_SOLVER_TRANSACTION_DOWNGRADED} { + set op [$trans othersolvable $p] + puts [format { - %s -> %s} [$p str] [$p str]] + } else { + puts [format { - %s} [$p str]] + } + } + puts {} +} +puts [format {install size change: %d K} [$trans calc_installsizechange]] +puts {} + +while 1 { + puts -nonewline "OK to continue (y/n)? " + flush stdout + set yn [gets stdin] + if {$yn eq "y"} { + break + } + if {$yn eq "n" || $yn eq "q"} { + exit + } +} + +set newpkgs [$trans newsolvables] +array set newpkgs_f {} +if {$newpkgs ne {}} { + set downloadsize 0 + foreach p $newpkgs { + set downloadsize [expr $downloadsize + [$p lookup_num $solv::SOLVABLE_DOWNLOADSIZE]] + } + puts [format {Downloading %d packages, %d K} [llength $newpkgs] [expr $downloadsize / 1024]] + foreach p $newpkgs { + upvar #0 [[$p cget -repo] cget -appdata] repo + set location [$p lookup_location] + if {$location eq {}} { + continue + } + set location "[repo_packagespath repo][lindex $location 0]" + set checksum [$p lookup_checksum $solv::SOLVABLE_CHECKSUM] + set f [repo_download repo $location 0 $checksum] + set newpkgs_f([$p cget -id]) $f + puts -nonewline "." + flush stdout + } + puts {} +} + +puts "Committing transaction:" +$trans order +foreach p [$trans steps] { + set steptype [$trans steptype $p $solv::Transaction_SOLVER_TRANSACTION_RPM_ONLY] + if {$steptype == $solv::Transaction_SOLVER_TRANSACTION_ERASE} { + puts "erase [$p str]" + regsub {^[0-9]+:} [$p cget -evr] {} nvr + set nvr "[$p cget -name]-$nvr.[$p cget -arch]" + exec -ignorestderr -- rpm -e --nodeps --nodigest --nosignature $nvr + } elseif {$steptype == $solv::Transaction_SOLVER_TRANSACTION_INSTALL || $steptype == $solv::Transaction_SOLVER_TRANSACTION_MULTIINSTALL} { + puts "install [$p str]" + set f $newpkgs_f([$p cget -id]) + set mode [expr {$steptype == $solv::Transaction_SOLVER_TRANSACTION_INSTALL ? "-U" : "-i"}] + $f cloexec 0 + exec -ignorestderr -- rpm $mode --force --nodeps --nodigest --nosignature "/dev/fd/[$f fileno]" + } +} |