<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/f77aca31d164cf5ba0b7dd7ed3daa684793c1329">https://github.com/macports/macports-base/commit/f77aca31d164cf5ba0b7dd7ed3daa684793c1329</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit f77aca31d164cf5ba0b7dd7ed3daa684793c1329
</span>Author: Clemens Lang <cal@macports.org>
AuthorDate: Mon Dec 18 23:11:44 2023 +0100

<span style='display:block; white-space:pre;color:#404040;'>    macports/snapshot: Add diff implementation
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Support diffing the snapshot and the current set of installed ports.
</span><span style='display:block; white-space:pre;color:#404040;'>    This will also be helpful after migration to show which ports could not
</span><span style='display:block; white-space:pre;color:#404040;'>    be restored, or which ports were restored with changes.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Additionally, provide a framework to implement snapshot listing and
</span><span style='display:block; white-space:pre;color:#404040;'>    deletion later.
</span>---
 src/macports1.0/snapshot.tcl | 297 ++++++++++++++++++++++++++++++++++++++++++-
 src/port/port.tcl            |   2 +-
 2 files changed, 296 insertions(+), 3 deletions(-)

<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 628db3d28..64452c0b1 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;'>@@ -44,6 +44,110 @@ namespace eval snapshot {
</span> 
         array set options $opts
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {![info exists options(options_snapshot_order)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set operation "create"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set operation ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            foreach op {list create diff delete} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                set opname "ports_snapshot_$op"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {[info exists options($opname)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {$operation ne ""} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        ui_error "Only one of the --list, --create, --diff, and --delete options can be specified."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        error "Incorrect usage, see port snapshot --help."
</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;'>+                    set operation $op
</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;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {[info exists options(ports_snapshot_help)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            ui_msg "Usage: One of:"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            ui_msg "  port snapshot \[--create\] \[--note '<message>'\]"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            ui_msg "  port snapshot --list"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            ui_msg "  port snapshot --diff <snapshot-id> \[--requested-only\]"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            ui_msg "  port snapshot --delete <snapshot-id>"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            return 0
</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;'>+        switch $operation {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            "create" {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                return [create [array get options]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            "list" {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                ui_error "list operation not implemented"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            "diff" {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                set snapshot [registry::snapshot get_by_id $options(ports_snapshot_diff)]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                array set diff [diff $snapshot]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                set show_all [expr {[info exists options(ports_snapshot_all)]}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                set note ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {!$show_all} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    append note "Showing differences in requested ports only. Re-run with --all to see all differences.\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    foreach field {added removed changed} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        set result {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        foreach port $diff($field) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            lassign $port _ requested
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            if {$requested} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                lappend result $port
</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;'>+                        set diff($field) $result
</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;'>+                if {[llength $diff(added)] > 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    append note "The following ports are installed but not in the snapshot:\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    foreach added_port [lsort -ascii -index 0 $diff(added)] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        lassign $added_port name _ _ _ requested_variants
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        if {$requested_variants ne ""} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            append note " - $name\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            append note " - $name $requested_variants\n"
</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;'>+                if {[llength $diff(removed)] > 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    append note "The following ports are in the snapshot but not installed:\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    foreach removed_port [lsort -ascii -index 0 $diff(removed)] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        lassign $removed_port name _ _ _ requested_variants
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        if {$requested_variants ne ""} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            append note " - $name\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            append note " - $name $requested_variants\n"
</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;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {[llength $diff(changed)] > 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    append note "The following ports are in the snapshot and installed, but with changes:\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    foreach changed_port [lsort -ascii -index 0 $diff(changed)] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        lassign $changed_port name _ _ _ requested_variants changes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        if {$requested_variants ne ""} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            append note " - $name\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            append note " - $name $requested_variants\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        foreach change $changes {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            lassign $change field old new
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            append note "   $field changed from '$old' to '$new'\n"
</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;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                ui_msg [string trimright $note "\n"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            "delete" {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                ui_error "delete operation not implemented"
</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;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    proc create {opts} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        array set options $opts
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span>         registry::write {
             # An option used by user while creating snapshot manually
             # to identify a snapshot, usually followed by `port restore`
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -52,7 +156,7 @@ namespace eval snapshot {
</span>             } else {
                 set note "snapshot created for migration"
             }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            set inactive_ports  [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set inactive_ports [list]
</span>             foreach port [registry::entry imaged] {
                 if {[$port state] eq "imaged"} {
                     lappend inactive_ports "[$port name] @[$port version]_[$port revision] [$port variants]"
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -75,8 +179,197 @@ namespace eval snapshot {
</span>                 }
             }
             set snapshot [registry::snapshot create $note]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            # TODO: catch
</span>         }
         return $snapshot
     }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    proc _os_mismatch {iplatform iosmajor} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {($iplatform ne "" && $iosmajor != 0) && ($iplatform != $macports::os_platform || $iosmajor != $macports::os_major)} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            return 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return 0
</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;'>+    proc _find_best_match {port installed} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lassign $port name requested active variants requested_variants
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set active [expr {$active eq "installed"}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set requested [expr {$requested == 1}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set best_match {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set best_match_score -1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        foreach iport $installed {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            lassign $iport iname iversion irevision ivariants iactive iepoch
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set regref [registry::open_entry $iname $iversion $irevision $ivariants $iepoch]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set iplatform [registry::property_retrieve $regref os_platform]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set iosmajor [registry::property_retrieve $regref os_major]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set irequested [expr {[registry::property_retrieve $regref requested] == 1}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set irequested_variants [registry::property_retrieve $regref requested_variants]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {[_os_mismatch $iplatform $iosmajor]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                # ignore ports that were not built on the current macOS version
</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;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set score 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {$irequested_variants eq $requested_variants} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                incr score
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {$irequested == $requested} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                incr score
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {$ivariants eq $variants} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                incr score
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {$active == $iactive} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                incr score
</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 {$score > $best_match_score} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                set best_match_score $score
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                set best_match [list {*}$iport $irequested $irequested_variants]
</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;'>+        return $best_match
</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;'>+    # Compute the difference between the given snapshot registry object, and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    # the currently installed ports.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    #
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    # Callers that do not care about differences in unrequested ports are
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    # expected to filter the results themselves.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    #
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    # Args:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    #       snapshot - The snapshot object
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    # Returns:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    #       A array in list form with the three entries removed, added, and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    #       changed. Each array value is a list with entries that were removed,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    #       added, or changed. The format is as follows:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    #       - Added entries: a 5-tuple of (name, requested, active, variants, requested variants)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    #       - Removed entries: a 5-tuple of (name, requested, active, variants, requested variants)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    #       - Changed entries: a 6-typle of (name, requested, active, variants, requested variants, changes)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    #       where changes is a list of 3-tuples of (changed field, old value, new value)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    proc diff {snapshot} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set portlist [$snapshot ports]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set removed {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set added {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set changed {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        array set snapshot_ports {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        foreach port $portlist {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            lassign $port name requested active variants requested_variants
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set active [expr {$active eq "installed"}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set requested [expr {$requested == 1}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set snapshot_ports($name) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {[catch {set installed [registry::installed $name]}]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                # registry::installed failed, the port probably isn't installed
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                lappend removed $port
</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;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {$active} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                # for ports that were active in the snapshot, always compare
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                # with the installed active port, if any
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                set found 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                foreach installed_port $installed {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    lassign $installed_port iname iversion irevision ivariants iactive iepoch
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    set regref [registry::open_entry $iname $iversion $irevision $ivariants $iepoch]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    set iplatform [registry::property_retrieve $regref os_platform]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    set iosmajor [registry::property_retrieve $regref os_major]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    set irequested [expr {[registry::property_retrieve $regref requested] == 1}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    set irequested_variants [registry::property_retrieve $regref requested_variants]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {[_os_mismatch $iplatform $iosmajor]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        # ignore ports that were not built on the current macOS version
</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;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {$iactive} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        set found 1
</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;'>+                if {$found} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    set changes {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {$requested_variants ne $irequested_variants} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        lappend changes [list "requested variants" $requested_variants $irequested_variants]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {$variants ne $ivariants} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        lappend changes [list "variants" $variants $ivariants]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {$requested != $irequested} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        lappend changes [list "requested" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            [expr {$requested == 1 ? "requested" : "unrequested"}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            [expr {$irequested == 1 ? "requested" : "unrequested"}]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {[llength $changes] > 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        lappend changed [list {*}$port $changes]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    }
</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;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            # Either the port wasn't active in the snapshot, or the port is now no longer active.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            # This may still mean that it is missing completely, e.g., because only the version for an older OS is installed
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set best_match [_find_best_match $port $installed]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {[llength $best_match] <= 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                # There is no matching port, so it seems this one is actually missing
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                lappend removed $port
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                continue
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                lassign $best_match iname iversion irevision ivariants iactive iepoch irequested irequested_variants
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                set changes {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {$requested_variants ne $irequested_variants} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    lappend changes [list "requested variants" $requested_variants $irequested_variants]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {$variants ne $ivariants} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    lappend changes [list "variants" $variants $ivariants]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {$requested != $irequested} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    lappend changes [list "requested" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        [expr {$requested == 1 ? "requested" : "unrequested $requested"}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        [expr {$irequested == 1 ? "requested" : "unrequested $irequested"}]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {$active != $iactive} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    lappend changes [list "state" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        [expr {$active == 1 ? "installed" : "inactive"}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        [expr {$iactive == 1 ? "installed" : "inactive"}]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {[llength $changes] > 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    lappend changed [list {*}$port $changes]
</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;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        foreach port [registry::entry imaged] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            lassign $installed_port iname iversion irevision ivariants iactive iepoch
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set regref [registry::open_entry $iname $iversion $irevision $ivariants $iepoch]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set iplatform [registry::property_retrieve $regref os_platform]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set iosmajor [registry::property_retrieve $regref os_major]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set irequested [registry::property_retrieve $regref requested]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set irequested_variants [registry::property_retrieve $regref requested_variants]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {[_os_mismatch $iplatform $iosmajor]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                # port was installed on old OS, ignore
</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 {[info exists snapshot_ports($iname)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                # port was 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;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            # port was not in the snapshot, it is new
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            lappend added [list $iname $irequested $iactive $ivariants $irequested_variants]
</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;'>+        return [list removed $removed added $added changed $changed]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span> }
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/port/port.tcl b/src/port/port.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 4d14a9af0..eb1afc7f6 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/port/port.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/port/port.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -4163,7 +4163,7 @@ set cmd_opts_array [dict create {*}{
</span>     reclaim     {enable-reminders disable-reminders}
     fetch       {no-mirrors}
     bump        {patch}
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    snapshot    {{note 1}}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    snapshot    {create list {diff 1} all {delete 1} help {note 1}}
</span>     restore     {{snapshot-id 1} last}
     migrate     {continue}
 }]
</pre><pre style='margin:0'>

</pre>