<pre style='margin:0'>
Joshua Root (jmroot) pushed a commit to branch master
in repository mpbb.

</pre>
<p><a href="https://github.com/macports/mpbb/commit/4deeb43aa7645dd82863d98b038ff83fafa68ca0">https://github.com/macports/mpbb/commit/4deeb43aa7645dd82863d98b038ff83fafa68ca0</a></p>
<pre style="white-space: pre; background: #F8F8F8">The following commit(s) were added to refs/heads/master by this push:
<span style='display:block; white-space:pre;color:#404040;'>     new 4deeb43  Use dict for portinfo, options, variations etc
</span>4deeb43 is described below

<span style='display:block; white-space:pre;color:#808000;'>commit 4deeb43aa7645dd82863d98b038ff83fafa68ca0
</span>Author: Joshua Root <jmr@macports.org>
AuthorDate: Mon Feb 26 18:31:33 2024 +1100

<span style='display:block; white-space:pre;color:#404040;'>    Use dict for portinfo, options, variations etc
</span>---
 tools/archive-path.tcl             |  10 +-
 tools/canonical-variants.tcl       |  14 +--
 tools/dependencies.tcl             | 167 +++++++++++++-------------
 tools/failcache-cleanup.tcl        |   5 +-
 tools/gather-archives.tcl          |   7 +-
 tools/mirror-multi.tcl             |  99 +++++++---------
 tools/portgroups.tcl               |  16 +--
 tools/reclaim-space.tcl            |  18 +--
 tools/sort-with-subports.tcl       | 234 +++++++++++++++++++------------------
 tools/supported-archs.tcl          |  13 +--
 tools/uninstall-unneeded-ports.tcl |  44 +++----
 11 files changed, 305 insertions(+), 322 deletions(-)

<span style='display:block; white-space:pre;color:#808080;'>diff --git a/tools/archive-path.tcl b/tools/archive-path.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 1a21e55..7a1bce0 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/tools/archive-path.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/tools/archive-path.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -30,10 +30,10 @@
</span> # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 proc split_variants {variants} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    set result {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set result [dict create]
</span>     set l [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $variants]
     foreach { match sign variant } $l {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        lappend result $variant $sign
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        dict set result $variant $sign
</span>     }
     return $result
 }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -59,9 +59,9 @@ if {[catch {set one_result [mportlookup $portname]}] || [llength $one_result] <
</span>     exit 0
 }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-array set portinfo [lindex $one_result 1]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-if {[info exists portinfo(porturl)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {[catch {set mport [mportopen $portinfo(porturl) [list subport $portinfo(name)] $variations]}]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+lassign $one_result portname portinfo
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+if {[dict exists $portinfo porturl]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {[catch {set mport [mportopen [dict get $portinfo porturl] [dict create subport $portname] $variations]}]} {
</span>         ui_warn "failed to open port: $portname"
         puts "nonexistent"
         exit 0
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/tools/canonical-variants.tcl b/tools/canonical-variants.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 5c0dabe..80ac2fb 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/tools/canonical-variants.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/tools/canonical-variants.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -61,22 +61,22 @@ try {
</span> }
 
 # parse the given variants from the command line
<span style='display:block; white-space:pre;background:#ffe0e0;'>-array set variants {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set variants [dict create]
</span> foreach item [lrange $::argv 1 end] {
     foreach {_ sign variant} [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $item] {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        set variants($variant) $sign
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        dict set variants $variant $sign
</span>     }
 }
 
 # open the port to get its active variants
<span style='display:block; white-space:pre;background:#ffe0e0;'>-array set portinfo [lindex $result 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+lassign $result portname portinfo
</span> #try -pass_signal {...}
 try {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    set mport [mportopen $portinfo(porturl) [list subport $portname] [array get variants]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set mport [mportopen [dict get $portinfo porturl] [dict create subport $portname] $variants]
</span> } on error {eMessage} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    ui_error "mportopen ${portinfo(porturl)} failed: $eMessage"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ui_error "mportopen $portname from [dict get $portinfo porturl] failed: $eMessage"
</span>     exit 1
 }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-array set info [mportinfo $mport]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-puts $info(canonical_active_variants)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set portinfo [mportinfo $mport]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+puts [dict get $portinfo canonical_active_variants]
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/tools/dependencies.tcl b/tools/dependencies.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 7f3f54b..15d554a 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/tools/dependencies.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/tools/dependencies.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -94,26 +94,26 @@ try {
</span> }
 
 # parse the given variants from the command line
<span style='display:block; white-space:pre;background:#ffe0e0;'>-array set variants {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set variants [dict create]
</span> foreach item [lrange $::argv 1 end] {
     foreach {_ sign variant} [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $item] {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        set variants($variant) $sign
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        dict set variants $variant $sign
</span>     }
 }
 
 # open the port so we can run dependency calculation
<span style='display:block; white-space:pre;background:#ffe0e0;'>-array set portinfo [lindex $result 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+lassign $result portname portinfo
</span> #try -pass_signal {...}
 try {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    set mport [mportopen $portinfo(porturl) [list subport $portinfo(name)] [array get variants]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set mport [mportopen [dict get $portinfo porturl] [dict create subport $portname] $variants]
</span> } on error {eMessage} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    ui_error "mportopen ${portinfo(porturl)} failed: $eMessage"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ui_error "mportopen of $portname from [dict get $portinfo porturl] failed: $eMessage"
</span>     exit 2
 }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-array set portinfo [mportinfo $mport]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set portinfo [mportinfo $mport]
</span> # Also checking for matching archive, in case supported_archs changed
<span style='display:block; white-space:pre;background:#ffe0e0;'>-if {[registry::entry imaged $portinfo(name) $portinfo(version) $portinfo(revision) $portinfo(canonical_active_variants)] ne ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+if {[registry::entry imaged $portname [dict get $portinfo version] [dict get $portinfo revision] [dict get $portinfo canonical_active_variants]] ne ""
</span>         && [[ditem_key $mport workername] eval [list _archive_available]]} {
     puts "$::argv already installed, not installing or activating dependencies"
     exit 0
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -182,12 +182,11 @@ proc check_dep_needs_port {depspec retvar} {
</span> }
 
 # Get the ports needed by a given port.
<span style='display:block; white-space:pre;background:#ffe0e0;'>-proc collect_deps {portinfovar retvar} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    upvar $portinfovar portinfo
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc collect_deps {portinfo retvar} {
</span>     upvar $retvar ret
     foreach deptype $::recursive_depstypes {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {[info exists portinfo($deptype)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            foreach depspec $portinfo($deptype) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {[dict exists $portinfo $deptype]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            foreach depspec [dict get $portinfo $deptype] {
</span>                 check_dep_needs_port $depspec ret
             }
         }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -207,13 +206,10 @@ proc get_maintainers {args} {
</span>             ui_error "mportlookup $portname failed: $eMessage"
             continue
         }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        array unset portinfo
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        array set portinfo [lindex $result 1]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        foreach sublist [macports::unobscure_maintainers $portinfo(maintainers)] {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            foreach {key value} $sublist {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                if {$key eq "email"} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    lappend retlist $value
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set portinfo [lindex $result 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        foreach maintainer [macports::unobscure_maintainers [dict get $portinfo maintainers]] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {[dict exists $maintainer email]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                lappend retlist [dict get $maintainer email]
</span>             }
         }
     }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -225,26 +221,26 @@ proc open_port {portname} {
</span>         set result [mportlookup $portname]
         if {[llength $result] < 2} {
             ui_error "No such port: $portname"
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            puts $::log_subports_progress "Building '$::portname' ... \[ERROR\] (unknown dependency '$portname') maintainers: [get_maintainers $::portname]."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            puts $::log_subports_progress "Building '$::portname' ... \[FAIL\] (unknown dependency '$portname') maintainers: [get_maintainers $::portname]."
</span>             exit 1
         }
     } on error {eMessage} {
         ui_error "mportlookup $portname failed: $eMessage"
         exit 2
     }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    array set portinfo [lindex $result 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    lassign $result portname portinfo
</span>     try {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        set mport [mportopen $portinfo(porturl) [list subport $portinfo(name)] [list]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set mport [mportopen [dict get $portinfo porturl] [dict create subport $portname] ""]
</span>     } on error {eMessage} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        ui_error "mportopen $portinfo(porturl) failed: $eMessage"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        ui_error "mportopen $portname from [dict get $portinfo porturl] failed: $eMessage"
</span>         exit 2
     }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {![info exists ::mportinfo_array($mport)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        set ::mportinfo_array($mport) [mportinfo $mport]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set portinfo [mportinfo $mport]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {![dict exists $::mportinfo_array $mport]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        dict set ::mportinfo_array $mport $portinfo
</span>     }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    array set portinfo $::mportinfo_array($mport)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    return [list $mport [array get portinfo]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return [list $mport $portinfo]
</span> }
 
 # Deactivate the given port, first deactivating any active dependents
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -256,41 +252,41 @@ proc deactivate_with_dependents {e} {
</span>     foreach dependent [$e dependents] {
         deactivate_with_dependents $dependent
     }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {![registry::run_target $e deactivate [list ports_nodepcheck 1]]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-              && [catch {portimage::deactivate [$e name] [$e version] [$e revision] [$e variants] [list ports_nodepcheck 1]} result]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set options [dict create ports_nodepcheck 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {![registry::run_target $e deactivate $options]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+              && [catch {portimage::deactivate [$e name] [$e version] [$e revision] [$e variants] $options} result]} {
</span>         puts stderr $::errorInfo
         puts stderr "Deactivating [$e name] @[$e version]_[$e revision][$e variants] failed: $result"
         exit 2
     }
 }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-proc deactivate_unneeded {portinfovar} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    upvar $portinfovar portinfo
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc deactivate_unneeded {portinfo} {
</span>     # Unfortunately mportdepends doesn't have quite the right semantics
     # to be useful here. It's concerned with what is needed and not
     # present, whereas here we're concerned with removing what we can do
     # without. Future API opportunity?
     set deplist [list]
     foreach deptype $::toplevel_depstypes {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {[info exists portinfo($deptype)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            foreach depspec $portinfo($deptype) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {[dict exists $portinfo $deptype]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            foreach depspec [dict get $portinfo $deptype] {
</span>                 check_dep_needs_port $depspec deplist
             }
         }
     }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+    set needed_array [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set mports_array [dict create]
</span>     while {$deplist ne ""} {
         set dep [lindex $deplist end]
         set deplist [lreplace ${deplist}[set deplist {}] end end]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {![info exists needed_array($dep)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            set needed_array($dep) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {![dict exists $needed_array $dep]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            dict set needed_array $dep 1
</span>             set needed [list]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            lassign [open_port $dep] mports_array($dep) infolist
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            array unset depportinfo
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            array set depportinfo $infolist
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            collect_deps depportinfo needed
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            lassign [open_port $dep] mport depportinfo
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            dict set mports_array $dep $mport
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            collect_deps $depportinfo needed
</span>             foreach newdep $needed {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                if {![info exists needed_array($newdep)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {![dict exists $needed_array $newdep]} {
</span>                     lappend deplist $newdep
                 }
             }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -305,16 +301,15 @@ proc deactivate_unneeded {portinfovar} {
</span>         # latter will reduce performance for universal installations a
         # bit, but those are much less common and this ensures
         # consistent behaviour.
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {![info exists needed_array([$e name])]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {![dict exists $needed_array [$e name]]} {
</span>             deactivate_with_dependents $e
         } else {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            array unset entryinfo
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            array set entryinfo $::mportinfo_array($mports_array([$e name]))
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            if {$entryinfo(version) ne [$e version]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    || $entryinfo(revision) != [$e revision]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    || $entryinfo(canonical_active_variants) ne [$e variants]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set entryinfo [dict get $::mportinfo_array [dict get $mports_array [$e name]]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {[dict get $entryinfo version] ne [$e version]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    || [dict get $entryinfo revision] != [$e revision]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    || [dict get $entryinfo canonical_active_variants] ne [$e variants]} {
</span>                 lappend dependents_check_list $e
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                puts stderr "[$e name] installed version @[$e version]_[$e revision][$e variants] doesn't match tree version $entryinfo(version)_$entryinfo(revision)$entryinfo(canonical_active_variants)"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                puts stderr "[$e name] installed version @[$e version]_[$e revision][$e variants] doesn't match tree version [dict get $entryinfo version]_[dict get $entryinfo revision][dict get $entryinfo canonical_active_variants]"
</span>             }
         }
     }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -329,14 +324,15 @@ proc deactivate_unneeded {portinfovar} {
</span>     # earlier - it most likely won't be used again (and will be
     # reopened in the uncommon case that it is needed.)
     foreach e [registry::entry installed] {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        mportclose $mports_array([$e name])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        mportclose [dict get $mports_array [$e name]]
</span>     }
 }
 
 puts stderr "init took [expr {[clock seconds] - $start_time}] seconds"
 set start_time [clock seconds]
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-if {[catch {deactivate_unneeded portinfo} result]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set mportinfo_array [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+if {[catch {deactivate_unneeded $portinfo} result]} {
</span>     ui_error $::errorInfo
     ui_error "deactivate_unneeded failed: $result"
     exit 2
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -360,7 +356,7 @@ if {[catch {mportdepends $mport "activate" 1 1 0 dlist} result]} {
</span> 
 proc append_it {ditem} {
     lappend ::dlist_sorted $ditem
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    set ::mportinfo_array($ditem) [mportinfo $ditem]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    dict set ::mportinfo_array $ditem [mportinfo $ditem]
</span>     return 0
 }
 try {
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -391,12 +387,12 @@ puts $log_status_dependencies ""
</span> 
 ## ensure dependencies are installed and active
 proc checkdep_failcache {ditem} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    array set depinfo $::mportinfo_array($ditem)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set depinfo [dict get $::mportinfo_array $ditem]
</span> 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {[check_failcache $depinfo(name) [ditem_key $ditem porturl] $depinfo(canonical_active_variants)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        tee "Dependency '$depinfo(name)' with variants '$depinfo(canonical_active_variants)' has previously failed and is required." $::log_status_dependencies stderr
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        puts "Port $depinfo(name) previously failed in build [check_failcache $depinfo(name) [ditem_key $ditem porturl] $depinfo(canonical_active_variants) yes]"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        puts $::log_subports_progress "Building '$::portname' ... \[ERROR\] (failed to install dependency '$depinfo(name)') maintainers: [get_maintainers $::portname $depinfo(name)]."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {[check_failcache [dict get $depinfo name] [ditem_key $ditem porturl] [dict get $depinfo canonical_active_variants]]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        tee "Dependency '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]' has previously failed and is required." $::log_status_dependencies stderr
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts "Port [dict get $depinfo name] previously failed in build [check_failcache [dict get $depinfo name] [ditem_key $ditem porturl] [dict get $depinfo canonical_active_variants] yes]"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts $::log_subports_progress "Building '$::portname' ... \[FAIL\] (failed to install dependency '[dict get $depinfo name]') maintainers: [get_maintainers $::portname [dict get $depinfo name]]."
</span>         # could keep going to report all deps in the failcache, but failing fast seems better
         exit 1
     }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -426,12 +422,12 @@ proc clean_workdirs {} {
</span> 
 # Returns 0 if dep is installed, 1 if not
 proc install_dep_archive {ditem} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    array set depinfo $::mportinfo_array($ditem)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set depinfo [dict get $::mportinfo_array $ditem]
</span>     incr ::dependencies_counter
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    set msg "Installing dependency ($::dependencies_counter of $::dependencies_count) '$depinfo(name)' with variants '$depinfo(canonical_active_variants)'"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set msg "Installing dependency ($::dependencies_counter of $::dependencies_count) '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]'"
</span>     puts -nonewline $::log_status_dependencies "$msg ... "
     puts "----> ${msg}"
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {[registry::entry imaged $depinfo(name) $depinfo(version) $depinfo(revision) $depinfo(canonical_active_variants)] ne ""} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {[registry::entry imaged [dict get $depinfo name] [dict get $depinfo version] [dict get $depinfo revision] [dict get $depinfo canonical_active_variants]] ne ""} {
</span>         puts "Already installed, nothing to do"
         puts $::log_status_dependencies {[OK]}
         return 0
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -449,14 +445,14 @@ proc install_dep_archive {ditem} {
</span>     if {$fail || $result > 0 || [$workername eval [list find_portarchive_path]] eq ""} {
         # The known_fail case should normally be caught before now, but
         # it's quick and easy to check and may save a build.
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {[info exists depinfo(known_fail)] && [string is true -strict $depinfo(known_fail)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            puts stderr "Dependency '$depinfo(name)' with variants '$depinfo(canonical_active_variants)' is known to fail, aborting."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {[dict exists $depinfo known_fail] && [string is true -strict [dict get $depinfo known_fail]]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            puts stderr "Dependency '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]' is known to fail, aborting."
</span>             puts $::log_status_dependencies {[FAIL] (known_fail)}
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            puts $::log_subports_progress "Building '$::portname' ... \[ERROR\] (dependency '$depinfo(name)' known to fail) maintainers: [get_maintainers $::portname $depinfo(name)]."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            puts $::log_subports_progress "Building '$::portname' ... \[FAIL\] (dependency '[dict get $depinfo name]' known to fail) maintainers: [get_maintainers $::portname [dict get $depinfo name]]."
</span>             exit 1
         }
         # This dep will have to be built, not just installed
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        puts stderr "Fetching archive for dependency '$depinfo(name)' with variants '$depinfo(canonical_active_variants)' failed."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts stderr "Fetching archive for dependency '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]' failed."
</span>         puts $::log_status_dependencies {[MISSING]}
         return 1
     }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -467,9 +463,9 @@ proc install_dep_archive {ditem} {
</span>         set fail 1
     }
     if {$fail || $result > 0} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        puts stderr "Installing from archive for dependency '$depinfo(name)' with variants '$depinfo(canonical_active_variants)' failed, aborting."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts stderr "Installing from archive for dependency '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]' failed, aborting."
</span>         puts $::log_status_dependencies {[FAIL]}
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        puts $::log_subports_progress "Building '$::portname' ... \[ERROR\] (failed to install dependency '$depinfo(name)')."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts $::log_subports_progress "Building '$::portname' ... \[FAIL\] (failed to install dependency '$depinfo(name)')."
</span>         exit 1
     }
 
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -487,10 +483,9 @@ proc close_open_mports {} {
</span>     set macports::open_mports [list]
 }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-proc install_dep_source {portinfo_list} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    array set depinfo $portinfo_list
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc install_dep_source {depinfo} {
</span>     incr ::build_counter
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    set msg "Building dependency ($::build_counter of $::build_count) '$depinfo(name)' with variants '$depinfo(canonical_active_variants)'"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set msg "Building dependency ($::build_counter of $::build_count) '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]'"
</span>     puts -nonewline $::log_status_dependencies "$msg ... "
     puts "----> ${msg}"
 
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -499,15 +494,15 @@ proc install_dep_source {portinfo_list} {
</span>     set macports::channels(info) {}
     close_open_mports
     clean_workdirs
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    array unset ::mportinfo_array
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    set ditem [lindex [open_port $depinfo(name)] 0]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set ::mportinfo_array [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set ditem [lindex [open_port [dict get $depinfo name]] 0]
</span>     # Ensure archivefetch is not attempted at all
     set workername [ditem_key $ditem workername]
     $workername eval [list set portutil::archive_available_result 0]
     $workername eval [list archive_sites]
 
     # deactivate ports not needed for this dep
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {[catch {deactivate_unneeded depinfo} result]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {[catch {deactivate_unneeded $depinfo} result]} {
</span>         ui_error $::errorInfo
         ui_error "deactivate_unneeded failed: $result"
         exit 2
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -525,9 +520,9 @@ proc install_dep_source {portinfo_list} {
</span>         set fail 1
     }
     if {$fail || $result > 0} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        puts stderr "Fetch of dependency '$depinfo(name)' with variants '$depinfo(canonical_active_variants)' failed, aborting."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts stderr "Fetch of dependency '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]' failed, aborting."
</span>         puts $::log_status_dependencies {[FAIL] (fetch)}
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        puts $::log_subports_progress "Building '$::portname' ... \[ERROR\] (failed to fetch dependency '$depinfo(name)') maintainers: [get_maintainers $::portname $depinfo(name)]."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts $::log_subports_progress "Building '$::portname' ... \[FAIL\] (failed to fetch dependency '[dict get $depinfo name]') maintainers: [get_maintainers $::portname [dict get $depinfo name]]."
</span>         exit 1
     }
     if {[catch {mportexec $ditem checksum} result]} {
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -536,9 +531,9 @@ proc install_dep_source {portinfo_list} {
</span>         set fail 1
     }
     if {$fail || $result > 0} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        puts stderr "Checksum of dependency '$depinfo(name)' with variants '$depinfo(canonical_active_variants)' failed, aborting."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts stderr "Checksum of dependency '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]' failed, aborting."
</span>         puts $::log_status_dependencies {[FAIL] (checksum)}
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        puts $::log_subports_progress "Building '$::portname' ... \[ERROR\] (failed to checksum dependency '$depinfo(name)') maintainers: [get_maintainers $::portname $depinfo(name)]."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts $::log_subports_progress "Building '$::portname' ... \[FAIL\] (failed to checksum dependency '[dict get $depinfo name]') maintainers: [get_maintainers $::portname [dict get $depinfo name]]."
</span>         exit 1
     }
 
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -549,12 +544,12 @@ proc install_dep_source {portinfo_list} {
</span>         set fail 1
     }
     if {$fail || $result > 0} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        puts stderr "Build of dependency '$depinfo(name)' with variants '$depinfo(canonical_active_variants)' failed, aborting."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts stderr "Build of dependency '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]' failed, aborting."
</span>         puts $::log_status_dependencies {[FAIL]}
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        puts $::log_subports_progress "Building '$::portname' ... \[ERROR\] (failed to install dependency '$depinfo(name)') maintainers: [get_maintainers $::portname $depinfo(name)]."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts $::log_subports_progress "Building '$::portname' ... \[FAIL\] (failed to install dependency '[dict get $depinfo name]') maintainers: [get_maintainers $::portname [dict get $depinfo name]]."
</span> 
         if {$::failcache_dir ne ""} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            failcache_update $depinfo(name) [ditem_key $ditem porturl] $depinfo(canonical_active_variants) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            failcache_update [dict get $depinfo name] [ditem_key $ditem porturl] [dict get $depinfo canonical_active_variants] 1
</span>         }
         ui_debug "Open mports:"
         foreach mport $macports::open_mports {
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -565,7 +560,7 @@ proc install_dep_source {portinfo_list} {
</span> 
     # Success. Clear any failcache entry.
     if {$::failcache_dir ne ""} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        failcache_update $depinfo(name) [ditem_key $ditem porturl] $depinfo(canonical_active_variants) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        failcache_update [dict get $depinfo name] [ditem_key $ditem porturl] [dict get $depinfo canonical_active_variants] 0
</span>     }
     puts $::log_status_dependencies {[OK]}
 }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -578,7 +573,7 @@ set missing_deps [list]
</span> try {
     foreach ditem $dlist_sorted {
         if {[install_dep_archive $ditem]} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            lappend missing_deps $::mportinfo_array($ditem)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            lappend missing_deps [dict get $::mportinfo_array $ditem]
</span>         }
     }
 } on error {eMessage} {
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -610,15 +605,15 @@ if {$build_count > 0} {
</span>     set macports::channels(debug) {}
     set macports::channels(info) {}
     close_open_mports
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    array unset ::mportinfo_array
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set ::mportinfo_array [dict create]
</span>     try {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        set mport [mportopen $portinfo(porturl) [list subport $portinfo(name)] [array get variants]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set mport [mportopen [dict get $portinfo porturl] [dict create subport $portname] $variants]
</span>     } on error {eMessage} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        ui_error "mportopen $portinfo(porturl) failed: $eMessage"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        ui_error "mportopen $portname from [dict get $portinfo porturl] failed: $eMessage"
</span>         exit 2
     }
     [ditem_key $mport workername] eval [list set portutil::archive_available_result 0]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {[catch {deactivate_unneeded portinfo} result]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {[catch {deactivate_unneeded $portinfo} result]} {
</span>         ui_error $::errorInfo
         ui_error "deactivate_unneeded failed: $result"
         exit 2
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -666,9 +661,9 @@ proc activate_dep {ditem} {
</span>         set fail 1
     }
     if {$fail || $result > 0} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        array set depinfo $::mportinfo_array($ditem)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        puts stderr "Activation of dependency '$depinfo(name)' with variants '$depinfo(canonical_active_variants)' failed, aborting."
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        puts $::log_subports_progress "Building '$::portname' ... \[ERROR\] (failed to activate dependency '$depinfo(name)') maintainers: [get_maintainers $::portname $depinfo(name)]."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set depinfo [dict get $::mportinfo_array $ditem]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts stderr "Activation of dependency '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]' failed, aborting."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts $::log_subports_progress "Building '$::portname' ... \[FAIL\] (failed to activate dependency '[dict get $depinfo name]') maintainers: [get_maintainers $::portname [dict get $depinfo name]]."
</span>         exit 1
     }
 }
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/tools/failcache-cleanup.tcl b/tools/failcache-cleanup.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index e840919..fae588b 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/tools/failcache-cleanup.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/tools/failcache-cleanup.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -33,9 +33,8 @@ if {$failcache_dir eq ""} {
</span>         file delete -force [file join $failcache_dir $f]
         continue
     }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    array unset portinfo
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    array set portinfo [lindex $result 1]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    set hash [port_files_checksum $portinfo(porturl)]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set portinfo [lindex $result 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set hash [port_files_checksum [dict get $portinfo porturl]]
</span>     if {$entry_hash ne $hash} {
         puts "Removing stale failcache entry: $f"
         file delete -force [file join $failcache_dir $f]
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/tools/gather-archives.tcl b/tools/gather-archives.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 3dda4da..79b3ee3 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/tools/gather-archives.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/tools/gather-archives.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -73,11 +73,10 @@ while {[gets $infd line] >= 0} {
</span>         continue
     }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    array unset portinfo
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    array set portinfo [lindex $result 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    lassign $result portname portinfo
</span> 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    foreach e [registry::entry imaged $portinfo(name)] {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {[$e version] ne $portinfo(version) || [$e revision] != $portinfo(revision)} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    foreach e [registry::entry imaged $portname] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {[$e version] ne [dict get $portinfo version] || [$e revision] != [dict get $portinfo revision]} {
</span>             puts "Skipping [$e name] @[$e version]_[$e revision][$e variants] (not current)"
             continue
         }
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/tools/mirror-multi.tcl b/tools/mirror-multi.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 0379d0d..b9a9c90 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/tools/mirror-multi.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/tools/mirror-multi.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -58,13 +58,13 @@ foreach vers {20 21 22 23} {
</span> }
 set deptypes [list depends_fetch depends_extract depends_patch depends_build depends_lib depends_run depends_test]
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-array set processed [list]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-array set mirror_done [list]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-array set distfiles_results [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set processed [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set mirror_done [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set distfiles_results [dict create]
</span> 
 proc check_mirror_done {portname} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {[info exists ::mirror_done($portname)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        return $::mirror_done($portname)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {[dict exists $::mirror_done $portname]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return [dict get $::mirror_done $portname]
</span>     }
     set cache_entry [file join $::mirrorcache_dir [string toupper [string index $portname 0]] $portname]
     if {[file isfile $cache_entry]} {
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -72,9 +72,8 @@ proc check_mirror_done {portname} {
</span>         if {[llength $result] < 2} {
             return 0
         }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        array unset portinfo
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        array set portinfo [lindex $result 1]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        set portfile [file join [macports::getportdir $portinfo(porturl)] Portfile]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set portinfo [lindex $result 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set portfile [file join [macports::getportdir [dict get $portinfo porturl]] Portfile]
</span>         if {[file isfile $portfile]} {
             set portfile_hash [sha256 file $portfile]
             set fd [open $cache_entry]
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -83,29 +82,28 @@ proc check_mirror_done {portname} {
</span>             close $fd
             if {$portfile_hash eq $entry_hash} {
                 if {$partial eq ""} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    set ::mirror_done($portname) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    dict set ::mirror_done $portname 1
</span>                     return 1
                 } else {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    set ::mirror_done($portname) $partial
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    dict set ::mirror_done $portname $partial
</span>                     return $partial
                 }
             } else {
                 file delete -force $cache_entry
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                set ::mirror_done($portname) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                dict set ::mirror_done $portname 0
</span>             }
         }
     } else {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        set ::mirror_done($portname) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        dict set ::mirror_done $portname 0
</span>     }
     return 0
 }
 
 proc set_mirror_done {portname value} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {![info exists ::mirror_done($portname)] || $::mirror_done($portname) != 1} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {![dict exists $::mirror_done $portname] || [dict get $::mirror_done $portname] != 1} {
</span>         set result [mportlookup $portname]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        array unset portinfo
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        array set portinfo [lindex $result 1]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        set portfile [file join [macports::getportdir $portinfo(porturl)] Portfile]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set portinfo [lindex $result 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set portfile [file join [macports::getportdir [dict get $portinfo porturl]] Portfile]
</span>         set portfile_hash [sha256 file $portfile]
 
         set cache_dir [file join $::mirrorcache_dir [string toupper [string index $portname 0]]]
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -117,16 +115,15 @@ proc set_mirror_done {portname value} {
</span>             puts $fd $value
         }
         close $fd
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        set ::mirror_done($portname) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        dict set ::mirror_done $portname 1
</span>     }
 }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-proc get_dep_list {portinfovar} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    upvar $portinfovar portinfo
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    set deps {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc get_dep_list {portinfo} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set deps [list]
</span>     foreach deptype $::deptypes {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {[info exists portinfo($deptype)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            foreach dep $portinfo($deptype) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {[dict exists $portinfo $deptype]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            foreach dep [dict get $portinfo $deptype] {
</span>                 lappend deps [lindex [split $dep :] end]
             }
         }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -134,18 +131,14 @@ proc get_dep_list {portinfovar} {
</span>     return $deps
 }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-proc get_variants {portinfovar} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    upvar $portinfovar portinfo
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {![info exists portinfo(vinfo)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc get_variants {portinfo} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {![dict exists $portinfo vinfo]} {
</span>         return {}
     }
     set variants {}
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    array set vinfo $portinfo(vinfo)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    foreach v [array names vinfo] {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        array unset variant
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        array set variant $vinfo($v)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {![info exists variant(is_default)] || $variant(is_default) ne "+"} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            lappend variants $v
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    dict for {vname variant} [dict get $portinfo vinfo] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {![dict exists $variant is_default] || [dict get $variant is_default] ne "+"} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            lappend variants $vname
</span>         }
     }
     return $variants
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -161,7 +154,7 @@ proc save_distfiles_results {mport succeeded} {
</span>     set distpath [_mportkey $mport distpath]
     foreach distfile $all_dist_files {
         set filepath [file join $distpath $distfile]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        set ::distfiles_results($filepath) $succeeded
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        dict set ::distfiles_results $filepath $succeeded
</span>     }
 }
 
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -201,9 +194,9 @@ proc skip_mirror {mport identifier} {
</span>         }
         set distfile [getdistname $distfile]
         set filepath [file join $distpath $distfile]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {![info exists ::distfiles_results($filepath)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {![dict exists $::distfiles_results $filepath]} {
</span>             set any_unmirrored 1
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        } elseif {$::distfiles_results($filepath) == 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        } elseif {[dict get $::distfiles_results $filepath] == 0} {
</span>             ui_msg "Skipping ${identifier}: $distfile already failed checksum"
             return 2
         }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -216,24 +209,22 @@ proc skip_mirror {mport identifier} {
</span> }
 
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-proc mirror_port {portinfo_list} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    array set portinfo $portinfo_list
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    set portname $portinfo(name)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    set porturl $portinfo(porturl)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    set ::processed($portname) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc mirror_port {portinfo} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set portname [dict get $portinfo name]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set porturl [dict get $portinfo porturl]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    dict set ::processed $portname 1
</span>     set do_mirror 1
     set attempted 0
     set succeeded 0
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {[lsearch -exact -nocase $portinfo(license) "nomirror"] >= 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {[lsearch -exact -nocase [dict get $portinfo license] "nomirror"] >= 0} {
</span>         ui_msg "Not mirroring $portname due to license"
         set do_mirror 0
     }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {[catch {mportopen $porturl [list subport $portname] {}} mport]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {[catch {mportopen $porturl [dict create subport $portname] {}} mport]} {
</span>         ui_error "mportopen $porturl failed: $mport"
         return 1
     }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    array unset portinfo
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    array set portinfo [mportinfo $mport]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set portinfo [mportinfo $mport]
</span> 
     set skip_result [skip_mirror $mport $portname]
     if {$do_mirror && $skip_result == 0} {
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -251,18 +242,17 @@ proc mirror_port {portinfo_list} {
</span>     }
     mportclose $mport
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    set deps [get_dep_list portinfo]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    set variants [get_variants portinfo]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set deps [get_dep_list $portinfo]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set variants [get_variants $portinfo]
</span> 
     foreach variant $variants {
         ui_msg "$portname +${variant}"
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {[catch {mportopen $porturl [list subport $portname] [list $variant +]} mport]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {[catch {mportopen $porturl [dict create subport $portname] [dict create $variant +]} mport]} {
</span>             ui_error "mportopen $porturl failed: $mport"
             continue
         }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        array unset portinfo
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        array set portinfo [mportinfo $mport]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        lappend deps {*}[get_dep_list portinfo]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set portinfo [mportinfo $mport]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lappend deps {*}[get_dep_list $portinfo]
</span>         set skip_result [skip_mirror $mport "$portname +${variant}"]
         if {$do_mirror && $skip_result == 0} {
             incr attempted
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -281,13 +271,12 @@ proc mirror_port {portinfo_list} {
</span> 
     foreach {os_major os_arch} $::platforms {
         ui_msg "$portname with platform 'darwin $os_major $os_arch'"
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {[catch {mportopen $porturl [list subport $portname os_major $os_major os_arch $os_arch] {}} mport]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {[catch {mportopen $porturl [dict create subport $portname os_major $os_major os_arch $os_arch] {}} mport]} {
</span>             ui_error "mportopen $porturl failed: $mport"
             continue
         }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        array unset portinfo
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        array set portinfo [mportinfo $mport]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        lappend deps {*}[get_dep_list portinfo]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set portinfo [mportinfo $mport]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lappend deps {*}[get_dep_list $portinfo]
</span>         set skip_result [skip_mirror $mport "$portname darwin $os_major $os_arch"]
         if {$do_mirror && $skip_result == 0} {
             incr attempted
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -306,7 +295,7 @@ proc mirror_port {portinfo_list} {
</span> 
     set dep_failed 0
     foreach dep [lsort -unique $deps] {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {![info exists ::processed($dep)] && [check_mirror_done $dep] == 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {![dict exists $::processed $dep] && [check_mirror_done $dep] == 0} {
</span>             set result [mportlookup $dep]
             if {[llength $result] < 2} {
                 ui_error "No such port: $dep"
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -338,7 +327,7 @@ if {[lindex $::argv 0] eq "-c"} {
</span> 
 set exitval 0
 foreach portname $::argv {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {[info exists ::processed($portname)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {[dict exists $::processed $portname]} {
</span>         ui_msg "skipping ${portname}, already processed"
         continue
     }
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/tools/portgroups.tcl b/tools/portgroups.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 726f071..393786b 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/tools/portgroups.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/tools/portgroups.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -32,10 +32,10 @@
</span> # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 proc split_variants {variants} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    set result {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set result [dict create]
</span>     set l [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $variants]
     foreach { match sign variant } $l {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        lappend result $variant $sign
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        dict set result $variant $sign
</span>     }
     return $result
 }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -74,21 +74,21 @@ try {
</span> }
 
 # open the port so we can run dependency calculation
<span style='display:block; white-space:pre;background:#ffe0e0;'>-array set portinfo [lindex $result 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+lassign $result portname portinfo
</span> #try -pass_signal {...}
 try {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    set mport [mportopen $portinfo(porturl) [list subport $portname] $variations]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set mport [mportopen [dict get $portinfo porturl] [dict create subport $portname] $variations]
</span> } on error {eMessage} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    ui_error "mportopen ${portinfo(porturl)} failed: $eMessage"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ui_error "mportopen for $portname with url [dict get $portinfo porturl] failed: $eMessage"
</span>     exit 1
 }
 
 # obtain PortInfo array for this port and print the list of included
 # PortGroups
<span style='display:block; white-space:pre;background:#ffe0e0;'>-array set portinfo [mportinfo $mport]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set portinfo [mportinfo $mport]
</span> # only ports that include at least one PortGroup have portinfo(portgroups) set
<span style='display:block; white-space:pre;background:#ffe0e0;'>-if {[info exists portinfo(portgroups)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    foreach portgroup $portinfo(portgroups) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+if {[dict exists $portinfo portgroups]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    foreach portgroup [dict get $portinfo portgroups] {
</span>         lassign $portgroup group version
         puts "$group-$version"
     }
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/tools/reclaim-space.tcl b/tools/reclaim-space.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index c116349..98a9bd7 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/tools/reclaim-space.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/tools/reclaim-space.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -19,18 +19,18 @@ package require Tclx
</span> mportinit
 
 random seed
<span style='display:block; white-space:pre;background:#ffe0e0;'>-array set candidates {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set candidates [dict create]
</span> 
 fs-traverse -ignoreErrors -- f [list ${macports::portdbpath}/distfiles] {
     if {[file type $f] eq "file"} {
         # 0 for distfile, 1 for port
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        set candidates($f) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        dict set candidates $f 0
</span>     }
 }
 
 foreach port [registry::entry imaged] {
     if {[$port dependents] eq ""} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        set candidates($port) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        dict set candidates $port 1
</span>     }
 }
 
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -44,7 +44,7 @@ proc active_files_size {port} {
</span>     return $total
 }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-set candidate_list [array names candidates]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set candidate_list [dict keys $candidates]
</span> # It is tempting to sort by size and delete the largest things first,
 # but picking randomly greatly reduces the chance that we will just
 # uninstall one huge port that will immediately be reinstalled as a
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -53,7 +53,7 @@ while {$cur_free < $target && [llength $candidate_list] > 0} {
</span>     set i [random [llength $candidate_list]]
     set chosen [lindex $candidate_list $i]
     set candidate_list [lreplace ${candidate_list}[set candidate_list {}] $i $i]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {$candidates($chosen) == 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {[dict get $candidates $chosen] == 0} {
</span>         set size [file size $chosen]
         incr cur_free $size
         puts "Deleting $chosen ($size bytes)"
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -69,14 +69,14 @@ while {$cur_free < $target && [llength $candidate_list] > 0} {
</span>         set deps [$chosen dependencies]
         puts "Uninstalling [$chosen name] @[$chosen version]_[$chosen revision][$chosen variants] ($size bytes)"
         if {!$dryrun} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            if {![registry::run_target $chosen uninstall [list]]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {![registry::run_target $chosen uninstall ""]} {
</span>                 # Portfile failed, use the registry directly
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                registry_uninstall::uninstall [$chosen name] [$chosen version] [$chosen revision] [$chosen variants] [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                registry_uninstall::uninstall [$chosen name] [$chosen version] [$chosen revision] [$chosen variants] ""
</span>             }
         }
         foreach dep $deps {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            if {![info exists candidates($dep)] && [$dep dependents] eq ""} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                set candidates($dep) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {![dict exists $candidates $dep] && [$dep dependents] eq ""} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                dict set candidates $dep 1
</span>                 lappend candidate_list $dep
             }
         }
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/tools/sort-with-subports.tcl b/tools/sort-with-subports.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 48b709f..be61dd8 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/tools/sort-with-subports.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/tools/sort-with-subports.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -48,14 +48,14 @@ proc ui_channels {priority} {
</span> 
 
 proc process_port_deps {portname} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    set deplist $::portdepinfo($portname)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    unset ::portdepinfo($portname)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {[info exists ::portsoftdeps($portname)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        lappend deplist {*}$::portsoftdeps($portname)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        unset ::portsoftdeps($portname)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set deplist [dict get $::portdepinfo $portname]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    dict unset ::portdepinfo $portname
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {[dict exists $::portsoftdeps $portname]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lappend deplist {*}[dict get $::portsoftdeps $portname]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        dict unset ::portsoftdeps $portname
</span>     }
     foreach portdep $deplist {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {[info exists ::portdepinfo($portdep)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {[dict exists $::portdepinfo $portdep]} {
</span>             process_port_deps $portdep
         }
     }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -63,45 +63,45 @@ proc process_port_deps {portname} {
</span> }
 
 proc check_failing_deps {portname} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {[info exists ::failingports($portname)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        return $::failingports($portname)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {[dict exists ::failingports $portname]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return [dict get $::failingports $portname]
</span>     }
     # Protect against dependency cycles
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    set ::failingports($portname) [list 3 $portname]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    foreach portdep $::portdepinfo($portname) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    dict set ::failingports $portname [list 3 $portname]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    foreach portdep [dict get $::portdepinfo $portname] {
</span>         set dep_ret [check_failing_deps $portdep]
         # 0 = ok, 1 = known_fail, 2 = failcache, 3 = dep cycle
         set status [lindex $dep_ret 0]
         if {$status != 0} {
             set failed_dep [lindex $dep_ret 1]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            if {$::outputports($portname) == 1} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {[dict get $::outputports $portname] == 1} {
</span>                 if {$status == 1} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    if {[info exists ::requestedports($portname)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        puts stderr "Excluding $::canonicalnames($portname) because its dependency '$failed_dep' is known to fail"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {[dict exists $::requestedports $portname]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        puts stderr "Excluding [dict get $::canonicalnames $portname] because its dependency '$failed_dep' is known to fail"
</span>                     }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    set ::outputports($portname) 0
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                } elseif {$status == 2 && ![info exists ::requestedports($portname)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    dict set ::outputports $portname 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                } elseif {$status == 2 && ![dict exists $::requestedports $portname]} {
</span>                     # Exclude deps that will fail due to their own dep being in the failcache.
                     # But still output requested ports so the failure will be reported.
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    set ::outputports($portname) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    dict set ::outputports $portname 0
</span>                 } elseif {$status == 3} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    if {[info exists ::requestedports($portname)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        puts stderr "Warning: $::canonicalnames($portname) appears to have a cyclic dependency involving '$portdep'"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {[dict exists $::requestedports $portname]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        puts stderr "Warning: [dict get $::canonicalnames $portname] appears to have a cyclic dependency involving '$portdep'"
</span>                     }
                     # Some cycles involving depends_test exist, which don't cause
                     # problems yet only because we don't run tests.
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    #set ::outputports($portname) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    #dict set ::outputports $portname 0
</span>                 }
             }
             # keep processing other deps for now if there was a dep cycle
             if {$status != 3} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                set ::failingports($portname) [list $status $failed_dep]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                return $::failingports($portname)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                dict set ::failingports $portname [list $status $failed_dep]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                return [dict get $::failingports $portname]
</span>             }
         }
     }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    set ::failingports($portname) [list 0 ""]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    return $::failingports($portname)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    dict set ::failingports $portname [list 0 ""]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return [dict get $::failingports $portname]
</span> }
 
 source [file join [file dirname [info script]] failcache.tcl]
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -158,9 +158,10 @@ if {$jobs_dir ne "" && $archive_site_public ne "" && $archive_site_private ne ""
</span> 
 set is_64bit_capable [sysctl hw.cpu64bit_capable]
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-array set portdepinfo {}
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-array set portsoftdeps {}
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-array set canonicalnames {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set portdepinfo [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set portsoftdeps [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set canonicalnames [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set failingports [dict create]
</span> set todo [list]
 if {[lindex $argv 0] eq "-"} {
     while {[gets stdin line] >= 0} {
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -172,10 +173,13 @@ if {[lindex $argv 0] eq "-"} {
</span>     }
 }
 # save the ones that the user actually wants to know about
<span style='display:block; white-space:pre;background:#e0ffe0;'>+set inputports [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set outputports [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set requestedports [dict create]
</span> foreach p $todo {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    set inputports($p) 1
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    set outputports($p) 1
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    set requestedports($p) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    dict set inputports $p 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    dict set outputports $p 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    dict set requestedports $p 1
</span> }
 # process all recursive deps
 set depstypes [list depends_fetch depends_extract depends_patch depends_build depends_lib depends_run]
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -183,87 +187,87 @@ while {[llength $todo] > 0} {
</span>     set p [lindex $todo 0]
     set todo [lreplace ${todo}[set todo {}] 0 0]
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {![info exists portdepinfo($p)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {![dict exists $portdepinfo $p]} {
</span>         if {[catch {mportlookup $p} result]} {
             puts stderr "$errorInfo"
             error "Failed to find port '$p': $result"
         }
         if {[llength $result] < 2} {
             puts stderr "port $p not found in the index"
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            set portdepinfo($p) [list]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            set outputports($p) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            dict set portdepinfo $p ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            dict set outputports $p 0
</span>             continue
         }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        array set portinfo [lindex $result 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set portinfo [lindex $result 1]
</span> 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {[info exists inputports($p)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {[dict exists $inputports $p]} {
</span>             if {$failcache_dir ne ""} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                failcache_clear_all $portinfo(name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                failcache_clear_all [dict get $portinfo name]
</span>             }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            if {[info exists portinfo(subports)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                foreach subport $portinfo(subports) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {[dict exists $portinfo subports]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                foreach subport [dict get $portinfo subports] {
</span>                     set splower [string tolower $subport]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    if {![info exists portdepinfo($splower)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {![dict exists $portdepinfo $splower]} {
</span>                         lappend todo $splower
                     }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    if {![info exists requestedports($splower)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        set outputports($splower) 1
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        set requestedports($splower) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {![dict exists $requestedports $splower]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        dict set outputports $splower 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        dict set requestedports $splower 1
</span>                     }
                 }
             }
         }
 
         set opened 0
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {$outputports($p) == 1} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            if {[info exists portinfo(replaced_by)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                if {[info exists requestedports($p)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    puts stderr "Excluding $portinfo(name) because it is replaced by $portinfo(replaced_by)"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {[dict get $outputports $p] == 1} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {[dict exists $portinfo replaced_by]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {[dict exists $requestedports $p]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    puts stderr "Excluding [dict get $portinfo name] because it is replaced by [dict get $portinfo replaced_by]"
</span>                 }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                set outputports($p) 0
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            } elseif {[info exists portinfo(known_fail)] && [string is true -strict $portinfo(known_fail)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                if {[info exists requestedports($p)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    puts stderr "Excluding $portinfo(name) because it is known to fail"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                dict set outputports $p 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            } elseif {[dict exists $portinfo known_fail] && [string is true -strict [dict get $portinfo known_fail]]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {[dict exists $requestedports $p]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    puts stderr "Excluding [dict get $portinfo name] because it is known to fail"
</span>                 }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                set outputports($p) 0
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                set failingports($p) [list 1 $portinfo(name)]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            } elseif {$failcache_dir ne "" && ![info exists requestedports($p)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                dict set outputports $p 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                dict set failingports $p [list 1 [dict get $portinfo name]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            } elseif {$failcache_dir ne "" && ![dict exists $requestedports $p]} {
</span>                 # exclude dependencies with a failcache entry
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                if {![catch {mportopen $portinfo(porturl) [list subport $portinfo(name)] ""} result]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {![catch {mportopen [dict get $portinfo porturl] [dict create subport [dict get $portinfo name]] ""} result]} {
</span>                     set opened 1
                     set mport $result
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    array set portinfo [mportinfo $mport]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    if {![info exists portinfo(canonical_active_variants)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        puts stderr "Warning: $portinfo(name) has no canonical_active_variants"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        set outputports($p) 0
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    } elseif {[check_failcache $portinfo(name) $portinfo(porturl) $portinfo(canonical_active_variants)] != 0} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        set outputports($p) 0
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        set failingports($p) [list 2 $portinfo(name)]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    set portinfo [mportinfo $mport]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {![dict exists $portinfo canonical_active_variants]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        puts stderr "Warning: [dict get $portinfo name] has no canonical_active_variants"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        dict set outputports $p 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    } elseif {[check_failcache [dict get $portinfo name] [dict get $portinfo porturl] [dict get $portinfo canonical_active_variants]] != 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        dict set outputports $p 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        dict set failingports $p [list 2 [dict get $portinfo name]]
</span>                     }
                 } else {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    set outputports($p) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    dict set outputports $p 0
</span>                 }
             }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            if {$archive_site_public ne "" && $outputports($p) == 1} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {$archive_site_public ne "" && [dict get $outputports $p] == 1} {
</span>                 # FIXME: support non-default variants
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                if {$opened == 1 || ![catch {mportopen $portinfo(porturl) [list subport $portinfo(name)] ""} result]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {$opened == 1 || ![catch {mportopen [dict get $portinfo porturl] [dict create subport [dict get $portinfo name]] ""} result]} {
</span>                     if {$opened != 1} {
                         set opened 1
                         set mport $result
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                        array set portinfo [mportinfo $mport]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        set portinfo [mportinfo $mport]
</span>                     }
                     set workername [ditem_key $mport workername]
                     set archive_name [$workername eval {get_portimage_name}]
                     set archive_name_encoded [portfetch::percent_encode $archive_name]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    if {![catch {curl getsize ${archive_site_public}/$portinfo(name)/${archive_name_encoded}} size] && $size > 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {![catch {curl getsize ${archive_site_public}/[dict get $portinfo name]/${archive_name_encoded}} size] && $size > 0} {
</span>                         # Check for other installed variants that might not have been uploaded
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                        set archives_prefix ${macports::portdbpath}/software/$portinfo(name)/$portinfo(name)-$portinfo(version)_$portinfo(revision)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        set archives_prefix ${macports::portdbpath}/software/[dict get $portinfo name]/[dict get $portinfo name]-[dict get $portinfo version]_[dict get $portinfo revision]
</span>                         set any_archive_missing 0
                         foreach installed_archive [glob -nocomplain -tails -path ${archives_prefix} *] {
                             if {$installed_archive ne $archive_name} {
                                 set installed_archive_encoded [portfetch::percent_encode $installed_archive]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                                if {[catch {curl getsize ${archive_site_public}/$portinfo(name)/${installed_archive_encoded}} size] || $size <= 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                if {[catch {curl getsize ${archive_site_public}/[dict get $portinfo name]/${installed_archive_encoded}} size] || $size <= 0} {
</span>                                     set any_archive_missing 1
                                     puts stderr "$installed_archive installed but not uploaded"
                                     break
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -271,75 +275,75 @@ while {[llength $todo] > 0} {
</span>                             }
                         }
                         if {!$any_archive_missing} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                            if {[info exists requestedports($p)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                puts stderr "Excluding $portinfo(name) because it has already been built and uploaded to the public server"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            if {[dict exists $requestedports $p]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                puts stderr "Excluding [dict get $portinfo name] because it has already been built and uploaded to the public server"
</span>                             }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                            set outputports($p) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            dict set outputports $p 0
</span>                         }
                     }
                 } else {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    if {[info exists requestedports($p)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        puts stderr "Excluding $portinfo(name) because it failed to open: $result"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {[dict exists $requestedports $p]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        puts stderr "Excluding [dict get $portinfo name] because it failed to open: $result"
</span>                     }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    set outputports($p) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    dict set outputports $p 0
</span>                 }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                if {$outputports($p) == 1 && $archive_site_private ne "" && $jobs_dir ne ""} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {[dict get $outputports $p] == 1 && $archive_site_private ne "" && $jobs_dir ne ""} {
</span>                     # FIXME: support non-default variants
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    set results [check_licenses $portinfo(name) [list]]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    if {[lindex $results 0] == 1 && ![catch {curl getsize ${archive_site_private}/$portinfo(name)/${archive_name_encoded}} size] && $size > 0} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        if {[info exists requestedports($p)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                            puts stderr "Excluding $portinfo(name) because it is not distributable and it has already been built and uploaded to the private server"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    set results [check_licenses [dict get $portinfo name] [list]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {[lindex $results 0] == 1 && ![catch {curl getsize ${archive_site_private}/[dict get $portinfo name]/${archive_name_encoded}} size] && $size > 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        if {[dict exists $requestedports $p]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            puts stderr "Excluding [dict get $portinfo name] because it is not distributable and it has already been built and uploaded to the private server"
</span>                         }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                        set outputports($p) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        dict set outputports $p 0
</span>                     }
                 }
             }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            if {$outputports($p) == 1 &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {[dict get $outputports $p] == 1 &&
</span>                 ($::macports::os_major <= 10 || $::macports::os_major >= 18)} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                if {$opened == 1 || ![catch {mportopen $portinfo(porturl) [list subport $portinfo(name)] ""} result]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {$opened == 1 || ![catch {mportopen [dict get $portinfo porturl] [dict create subport [dict get $portinfo name]] ""} result]} {
</span>                     if {$opened != 1} {
                         set opened 1
                         set mport $result
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                        array set portinfo [mportinfo $mport]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        set portinfo [mportinfo $mport]
</span>                     }
                     set supported_archs [_mportkey $mport supported_archs]
                     switch $::macports::os_arch {
                         arm {
                             if {$supported_archs ne "" && $supported_archs ne "noarch" && "arm64" ni $supported_archs} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                                if {[info exists requestedports($p)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                    puts stderr "Excluding $portinfo(name) because it does not support the arm64 arch"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                if {[dict exists $requestedports $p]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                    puts stderr "Excluding [dict get $portinfo name] because it does not support the arm64 arch"
</span>                                 }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                                set outputports($p) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                dict set outputports $p 0
</span>                             }
                         }
                         i386 {
                             if {${is_64bit_capable}} {
                                 if {$::macports::os_major >= 18 && $supported_archs ne "" && $supported_archs ne "noarch" && "x86_64" ni $supported_archs} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                                    if {[info exists requestedports($p)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                        puts stderr "Excluding $portinfo(name) because it does not support the x86_64 arch"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                    if {[dict exists $requestedports $p]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                        puts stderr "Excluding [dict get $portinfo name] because it does not support the x86_64 arch"
</span>                                     }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                                    set outputports($p) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                    dict set outputports $p 0
</span>                                 }
                             } elseif {$supported_archs ne "" && $supported_archs ne "noarch" && ("x86_64" ni $supported_archs || "i386" ni $supported_archs)} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                                if {[info exists requestedports($p)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                    puts stderr "Excluding $portinfo(name) because the ${::macports::macosx_version}_x86_64 builder will build it"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                if {[dict exists $requestedports $p]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                    puts stderr "Excluding [dict get $portinfo name] because the ${::macports::macosx_version}_x86_64 builder will build it"
</span>                                 }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                                set outputports($p) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                dict set outputports $p 0
</span>                             }
                         }
                         powerpc {
                             if {$supported_archs ne "" && $supported_archs ne "noarch" && "ppc" ni $supported_archs} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                                if {[info exists requestedports($p)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                    puts stderr "Excluding $portinfo(name) because it does not support the ppc arch"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                if {[dict exists $requestedports $p]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                    puts stderr "Excluding [dict get $portinfo name] because it does not support the ppc arch"
</span>                                 }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                                set outputports($p) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                dict set outputports $p 0
</span>                             }
                         }
                         default {}
                     }
                 } else {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    puts stderr "Excluding $portinfo(name) because it failed to open: $result"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    set outputports($p) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    puts stderr "Excluding [dict get $portinfo name] because it failed to open: $result"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    dict set outputports $p 0
</span>                 }
             }
         }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -348,34 +352,34 @@ while {[llength $todo] > 0} {
</span>             mportclose $mport
         }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {$outputports($p) == 1} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            set canonicalnames($p) $portinfo(name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {[dict get $outputports $p] == 1} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            dict set canonicalnames $p [dict get $portinfo name]
</span>         }
 
         # If $requestedports($p) == 0, we're seeing the port again as a dependency of
         # something else and thus need to follow its deps even if it was excluded.
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {$outputports($p) == 1 || ![info exists requestedports($p)] || $requestedports($p) == 0} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            set portdepinfo($p) [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {[dict get $outputports $p] == 1 || ![dict exists $requestedports $p] || [dict get $requestedports $p] == 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            dict set portdepinfo $p [list]
</span>             foreach depstype $depstypes {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                if {[info exists portinfo($depstype)] && $portinfo($depstype) ne ""} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    foreach onedep $portinfo($depstype) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {[dict exists $portinfo $depstype] && [dict get $portinfo $depstype] ne ""} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    foreach onedep [dict get $portinfo $depstype] {
</span>                         set depname [string tolower [lindex [split [lindex $onedep 0] :] end]]
                         if {[string match port:* $onedep]} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                            lappend portdepinfo($p) $depname
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            dict lappend portdepinfo $p $depname
</span>                         } else {
                             # soft deps are installed before their dependents, but
                             # don't cause exclusion if they are failing
                             # real problematic example: bin:xattr:xattr
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                            lappend portsoftdeps($p) $depname
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            dict lappend portsoftdeps $p $depname
</span>                         }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                        if {![info exists outputports($depname)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        if {![dict exists $outputports $depname]} {
</span>                             lappend todo $depname
                             if {$include_deps} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                                set outputports($depname) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                dict set outputports $depname 1
</span>                             } else {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                                set outputports($depname) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                dict set outputports $depname 0
</span>                             }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                        } elseif {[info exists requestedports($depname)] && ![info exists portdepinfo($depname)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        } elseif {[dict exists $requestedports $depname] && ![dict exists $portdepinfo $depname]} {
</span>                             # may or may not have been checked for exclusion yet
                             lappend todo $depname
                         }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -385,11 +389,9 @@ while {[llength $todo] > 0} {
</span>         }
 
         # Mark as having been processed at least once.
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {[info exists requestedports($p)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            set requestedports($p) 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {[dict exists $requestedports $p]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            dict set requestedports $p 0
</span>         }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        array unset portinfo
</span>     }
 }
 
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -397,20 +399,20 @@ if {$jobs_dir ne "" && $license_db_dir ne "" && $archive_site_public ne "" && $a
</span>     write_license_db $license_db_dir
 }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-set sorted_portnames [lsort -dictionary [array names portdepinfo]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set sorted_portnames [lsort -dictionary [dict keys $portdepinfo]]
</span> foreach portname $sorted_portnames {
     check_failing_deps $portname
 }
 
 set portlist [list]
 foreach portname $sorted_portnames {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-   if {[info exists portdepinfo($portname)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if {[dict exists $portdepinfo $portname]} {
</span>       process_port_deps $portname
    }
 }
 
 foreach portname $portlist {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {$outputports($portname) == 1} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        puts $canonicalnames($portname)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {[dict get $outputports $portname] == 1} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts [dict get $canonicalnames $portname]
</span>     }
 }
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/tools/supported-archs.tcl b/tools/supported-archs.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 29b421e..106bb86 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/tools/supported-archs.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/tools/supported-archs.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -31,10 +31,10 @@
</span> # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 proc split_variants {variants} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    set result {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set result [dict create]
</span>     set l [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $variants]
     foreach { match sign variant } $l {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        lappend result $variant $sign
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        dict set result $variant $sign
</span>     }
     return $result
 }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -64,14 +64,13 @@ if {[catch {set one_result [mportlookup $portname]}] || [llength $one_result] <
</span>     exit 1
 }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-array set portinfo [lindex $one_result 1]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-set portname $portinfo(name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+lassign $one_result portname portinfo
</span> 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-if {[info exists portinfo(porturl)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {[catch {set mport [mportopen $portinfo(porturl) [list subport $portname] $variations]}]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+if {[dict exists $portinfo porturl]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {[catch {set mport [mportopen [dict get $portinfo porturl] [dict create subport $portname] $variations]}]} {
</span>         ui_warn "failed to open port: $portname"
     } else {
         set archs [_mportkey $mport supported_archs]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        puts [expr {$archs ne "" ? $archs : "x86_64 i386 ppc64 ppc"}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts [expr {$archs ne "" ? $archs : "arm64 i386 ppc ppc64 x86_64"}]
</span>     }
 }
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/tools/uninstall-unneeded-ports.tcl b/tools/uninstall-unneeded-ports.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index a7594f9..4cc052a 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/tools/uninstall-unneeded-ports.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/tools/uninstall-unneeded-ports.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -41,6 +41,8 @@ if {$showVersion} {
</span> 
 # Create a lookup table for determining whether a port has dependents
 # (regardless of whether or not those dependents are currently installed)
<span style='display:block; white-space:pre;background:#e0ffe0;'>+set dependents [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set a_dependency [dict create]
</span> foreach source $macports::sources {
     set source [lindex $source 0]
     macports_try -pass_signal {
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -48,19 +50,16 @@ foreach source $macports::sources {
</span> 
         macports_try -pass_signal {
             while {[gets $fd line] >= 0} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                array unset portinfo
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                set name [lindex $line 0]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                set len  [lindex $line 1]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                set line [read $fd $len]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                array set portinfo $line
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                lassign $line name len
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                set portinfo [read $fd $len]
</span> 
                 # depends_test is not included because mpbb doesn't run `port test'
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                foreach field {depends_build depends_extract depends_fetch depends_lib depends_patch depends_run} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    if {[info exists portinfo($field)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        foreach dependency $portinfo($field) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                foreach field [list depends_build depends_extract depends_fetch depends_lib depends_patch depends_run] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {[dict exists $portinfo $field]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        foreach dependency [dict get $portinfo $field] {
</span>                             set lowercase_dependency_name [string tolower [lindex [split $dependency :] end]]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                            incr dependents($lowercase_dependency_name)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                            set a_dependency($lowercase_dependency_name) $name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            dict incr dependents $lowercase_dependency_name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            dict set a_dependency $lowercase_dependency_name $name
</span>                         }
                     }
                 }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -80,12 +79,12 @@ proc removal_reason {installed_name} {
</span>     global dependents a_dependency
     set reason ""
     set lowercase_name [string tolower $installed_name]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {![info exists dependents($lowercase_name)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {![dict exists $dependents $lowercase_name]} {
</span>         set reason "no port in the PortIndex depends on $installed_name"
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    } elseif {$dependents($lowercase_name) == 1} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        set dependency_reason [removal_reason $a_dependency($lowercase_name)]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } elseif {[dict get $dependents $lowercase_name] == 1} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set dependency_reason [removal_reason [dict get $a_dependency $lowercase_name]]
</span>         if {$dependency_reason ne ""} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            set reason "only $a_dependency($lowercase_name) depends on $installed_name and $dependency_reason"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set reason "only [dict get $a_dependency $lowercase_name] depends on $installed_name and $dependency_reason"
</span>         }
     }
     return $reason
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -100,13 +99,15 @@ proc deactivate_with_dependents {e} {
</span>     foreach dependent [$e dependents] {
         deactivate_with_dependents $dependent
     }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    if {![registry::run_target $e deactivate [list ports_nodepcheck 1]]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-              && [catch {portimage::deactivate [$e name] [$e version] [$e revision] [$e variants] [list ports_nodepcheck 1]} result]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set options [dict create ports_nodepcheck 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {![registry::run_target $e deactivate $options]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+              && [catch {portimage::deactivate [$e name] [$e version] [$e revision] [$e variants] $options} result]} {
</span>         puts stderr $::errorInfo
         puts stderr "Deactivating [$e name] @[$e version]_[$e revision][$e variants] failed: $result"
     }
 }
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+set uninstall_options [dict create ports_force 1]
</span> foreach port [registry::entry imaged] {
     # Set to yes if a port should be uninstalled
     set uninstall no
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -122,11 +123,10 @@ foreach port [registry::entry imaged] {
</span>         ui_msg "Removing ${installed_name} @${installed_version}_${installed_revision}${installed_variants} because it is no longer in the PortIndex"
         set uninstall yes
     } else {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        array unset portinfo
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        array set portinfo [lindex $portindex_match 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set portinfo [lindex $portindex_match 1]
</span> 
         set portspec "$installed_name @${installed_version}_$installed_revision$installed_variants"
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {$portinfo(version) ne $installed_version || $portinfo(revision) != $installed_revision} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {[dict get $portinfo version] ne $installed_version || [dict get $portinfo revision] != $installed_revision} {
</span>             # The version in the index is different than the installed one
             ui_msg "Removing $portspec because there is a newer version in the PortIndex"
             set uninstall yes
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -139,7 +139,7 @@ foreach port [registry::entry imaged] {
</span>                 set uninstall no
                 if {no} {
                     set lowercase_name [string tolower $installed_name]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    ui_msg "Not removing $portspec because it has $dependents($lowercase_name) dependents"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    ui_msg "Not removing $portspec because it has [dict get $dependents $lowercase_name] dependents"
</span>                 }
             }
         }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -150,9 +150,9 @@ foreach port [registry::entry imaged] {
</span>             deactivate_with_dependents $dependent
         }
         # Try to run the target via the portfile first, so pre/post code runs
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if {![registry::run_target $port uninstall [list ports_force 1]]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {![registry::run_target $port uninstall $uninstall_options]} {
</span>             # Portfile failed, use the registry directly
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            registry_uninstall::uninstall $installed_name $installed_version $installed_revision $installed_variants [list ports_force 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            registry_uninstall::uninstall $installed_name $installed_version $installed_revision $installed_variants $uninstall_options
</span>         }
     }
 }
</pre><pre style='margin:0'>

</pre>