<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>