summaryrefslogtreecommitdiff
path: root/examples/tclsolv
diff options
context:
space:
mode:
Diffstat (limited to 'examples/tclsolv')
-rwxr-xr-xexamples/tclsolv803
1 files changed, 803 insertions, 0 deletions
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]"
+ }
+}