<pre style='margin:0'>
Joshua Root (jmroot) pushed a commit to branch master
in repository macports-base.
</pre>
<p><a href="https://github.com/macports/macports-base/commit/b418a8bb4a442194ef1f04988aa509e21c0240fc">https://github.com/macports/macports-base/commit/b418a8bb4a442194ef1f04988aa509e21c0240fc</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit b418a8bb4a442194ef1f04988aa509e21c0240fc
</span>Author: Joshua Root <jmr@macports.org>
AuthorDate: Tue May 28 09:14:09 2024 +1000
<span style='display:block; white-space:pre;color:#404040;'> restore::resolve_dependencies: better path dep handling
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> Resolve as though the files recorded in the snapshot were active.
</span>---
src/macports1.0/restore.tcl | 145 ++++++++++++++++++++++++++-----------------
src/macports1.0/snapshot.tcl | 21 +++++++
2 files changed, 110 insertions(+), 56 deletions(-)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/macports1.0/restore.tcl b/src/macports1.0/restore.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index e13bf6e22..dc54ef61f 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/macports1.0/restore.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/macports1.0/restore.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -93,7 +93,7 @@ namespace eval restore {
</span> deactivate_all
ui_msg "$restore::ui_prefix Restoring snapshot '[$snapshot note]' created at [$snapshot created_at]"
<span style='display:block; white-space:pre;background:#ffe0e0;'>- set failed [restore_state [$snapshot ports]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set failed [restore_state $snapshot]
</span>
if {[dict size $failed] > 0} {
set note "Migration finished with errors.\n"
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -270,17 +270,78 @@ namespace eval restore {
</span> return $result
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Get the port that satisfies a depspec, with respect to the files
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # in the snapshot for path-pased deps.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ proc resolve_depspec {depspec ports snapshot_id} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set remaining [lassign [split $depspec :] type next]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {$type eq "port"} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return $next
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set portname [lindex $remaining end]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[dict exists $ports $portname] && [lindex [dict get $ports $portname] 1]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Port is active in the snapshot.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return $portname
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ switch $type {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ bin {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable binpaths
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![info exists binpaths]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set binpaths [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ foreach p [split $::env(PATH) :] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ lappend binpaths $p
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ foreach path $binpaths {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set owners [snapshot::file_owner [file join $path $next] $snapshot_id]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {$owners ne ""} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ lib {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ global macports::prefix macports::frameworks_dir macports::os_platform
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set i [string first . $next]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {$i < 0} {set i [string length $next]}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set depname [string range $next 0 $i-1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set depversion [string range $next $i end]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {${os_platform} eq "darwin"} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set depfile ${depname}${depversion}.dylib
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set depfile ${depname}.so${depversion}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ foreach path [list ${frameworks_dir} ${prefix}/lib] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set owners [snapshot::file_owner [file join $path $depfile] $snapshot_id]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {$owners ne ""} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ path {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ global macports::prefix
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set owners [snapshot::file_owner [file join $prefix $next] $snapshot_id]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[info exists owners]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[llength $owners] > 1} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_warn "File for $depspec owned by multiple ports in snapshot, using first match"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return [lindex $owners 0]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> ##
# Sorts a list of port references such that ports appear after their
# dependencies. Ideal for installing a port.
#
# Args:
<span style='display:block; white-space:pre;background:#ffe0e0;'>- # portlist - the list of port references
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # snapshot - the snapshot from which to get the list of port references
</span> #
# Returns:
# The list in dependency-sorted order
# The dependency graph, to be destroyed by calling $dependencies destroy
<span style='display:block; white-space:pre;background:#ffe0e0;'>- proc resolve_dependencies {portlist} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ proc resolve_dependencies {snapshot} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set portlist [$snapshot ports]
</span> set ports [dict create]
set dep_ports [dict create]
set dependencies [::struct::graph]
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -325,7 +386,7 @@ namespace eval restore {
</span> # depth-first dependency resolution.
set worklist [list]
set seen [dict create]
<span style='display:block; white-space:pre;background:#ffe0e0;'>- set seen_conflicts [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set snapshot_id [$snapshot id]
</span> foreach port $portlist {
lassign $port name requested _ _ _
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -372,6 +433,7 @@ namespace eval restore {
</span> $progress intermission
error "Unable to open port '$portname': $result"
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ set portinfo [mportinfo $mport]
</span>
# Compute the dependencies for the 'install' target. Do not recurse into the dependencies: we'll do that
# here manually in order to
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -380,66 +442,37 @@ namespace eval restore {
</span> # (3) identify if an alternative provider was used based on the snapshot and the conflicts information
# (such as for example when a port depends on curl-ca-bundle, but the snapshot contains certsync, which
# conflicts with curl-ca-bundle).
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[mportdepends $mport install 0] != 0} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- $progress intermission
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- error "Unable to determine dependencies for port '$portname'"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set workername [ditem_key $mport workername]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set deptypes [macports::_deptypes_for_target install $workername]
</span>
set provides [ditem_key $mport provides]
if {![$dependencies node exists $provides]} {
$dependencies node insert $provides
}
<span style='display:block; white-space:pre;background:#ffe0e0;'>- foreach dependency [ditem_key $mport requires] {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- lassign [dlist_search $macports::open_mports provides $dependency] dep_ditem
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- set conflict_found 0
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- set portinfo [mportinfo $dep_ditem]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[dict exists $portinfo conflicts] && [llength [dict get $portinfo conflicts]] > 0} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- foreach conflict [dict get $portinfo conflicts] {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[dict exists $ports $conflict]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- # The conflicting port was installed in the snapshot. Assume that this happened because the
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- # conflicting port is an alternative provider for this dependency (e.g., curl-ca-bundle and
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- # certsync, or a -devel port replacing its non-devel variant).
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- #
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- # Do not add the dependency that mportdepends computed, but instead replace this dependency
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- # with the conflicting port.
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- #
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- # Warn only once for every combination, otherwise users might see the same message multiple
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- # times.
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if {![dict exists $seen_conflicts [dict get $portinfo name] $conflict]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- dict set seen_conflicts [dict get $portinfo name] $conflict 1
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- $progress intermission
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- ui_warn "Snapshot contains $conflict, which conflicts with dependency [dict get $portinfo name]; assuming $conflict provides the functionality of [dict get $portinfo name]"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- $progress update $requested_counter $requested_total
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if {![$dependencies node exists $conflict]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- $dependencies node insert $conflict
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- $dependencies arc insert $provides $conflict
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- set worklist [linsert $worklist 0 $conflict]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- set conflict_found 1
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- break
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if {$conflict_found} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ foreach deptype $deptypes {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![dict exists $portinfo $deptype]} {
</span> continue
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ foreach depspec [dict get $portinfo $deptype] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set dependency [resolve_depspec $depspec $ports $snapshot_id]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {$dependency eq ""} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Not fulfilled by a port in the snapshot
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ continue
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![$dependencies node exists $dependency]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $dependencies node insert $dependency
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[dict exists $ports $dependency]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set dependency_requested_variants [lindex [dict get $ports $dependency] 2]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set dependency_requested_variants {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ dict set dep_ports $dependency $dependency_requested_variants
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if {![$dependencies node exists $dependency]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- $dependencies node insert $dependency
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $dependencies arc insert $provides $dependency
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set worklist [linsert $worklist 0 $dependency]
</span> }
<span style='display:block; white-space:pre;background:#ffe0e0;'>- set dependency_requested_variants [[ditem_key $dep_ditem workername] eval {set requested_variants}]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- dict set dep_ports $dependency $dependency_requested_variants
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- $dependencies arc insert $provides $dependency
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- set worklist [linsert $worklist 0 $dependency]
</span> }
<span style='display:block; white-space:pre;background:#ffe0e0;'>- mportclose $mport
</span>
if {$requested} {
# Print a progress indicator if this is a requested port (or for every port if in verbose mode).
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -495,8 +528,8 @@ namespace eval restore {
</span> } $level]
}
<span style='display:block; white-space:pre;background:#ffe0e0;'>- proc restore_state {snapshot_portlist} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- lassign [resolve_dependencies $snapshot_portlist] sorted_snapshot_portlist dependencies
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ proc restore_state {snapshot} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ lassign [resolve_dependencies $snapshot] sorted_snapshot_portlist dependencies
</span>
# map from port name to an entry describing why the port failed or was
# skipped
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/macports1.0/snapshot.tcl b/src/macports1.0/snapshot.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index a944d99a7..5dbe8e1f5 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/macports1.0/snapshot.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/macports1.0/snapshot.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -180,6 +180,27 @@ namespace eval snapshot {
</span> return $snapshot
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Get the port name that owns the given file path in the given snapshot.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ proc file_owner {path snapshot_id} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ global registry::tdbc_connection
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![info exists tdbc_connection]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ registry::tdbc_connect
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable file_owner_stmt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![info exists file_owner_stmt]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set query {SELECT snapshot_ports.port_name FROM snapshot_ports
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ INNER JOIN snapshot_files ON snapshot_files.id = snapshot_ports.id
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ WHERE snapshot_files.path = :path AND snapshot_ports.snapshots_id = :snapshot_id}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set file_owner_stmt [$tdbc_connection prepare $query]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $tdbc_connection transaction {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set results [$file_owner_stmt execute]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set ret [lmap l [$results allrows] {lindex $l 1}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $results close
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return $ret
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> proc _os_mismatch {iplatform iosmajor} {
global macports::os_platform macports::os_major
if {$iplatform ne "any" && ($iplatform ne $os_platform
</pre><pre style='margin:0'>
</pre>