<pre style='margin:0'>
Joshua Root (jmroot) pushed a commit to branch release-2.10
in repository macports-base.

</pre>
<p><a href="https://github.com/macports/macports-base/commit/ad5b94d4c1efd39aeb97992c781c5d9692ba1e92">https://github.com/macports/macports-base/commit/ad5b94d4c1efd39aeb97992c781c5d9692ba1e92</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit ad5b94d4c1efd39aeb97992c781c5d9692ba1e92
</span>Author: Joshua Root <jmr@macports.org>
AuthorDate: Mon Aug 12 12:28:07 2024 +1000

<span style='display:block; white-space:pre;color:#404040;'>    _activate_contents: find all conflicts in one query
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    (cherry picked from commit ef2bc782b789f94e07537ff59cd078763eeb4dfa)
</span>---
 src/registry2.0/portimage.tcl | 159 ++++++++++++++++++++++++++++++------------
 1 file changed, 116 insertions(+), 43 deletions(-)

<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/registry2.0/portimage.tcl b/src/registry2.0/portimage.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 1da893500..66da39c49 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/registry2.0/portimage.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/registry2.0/portimage.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -634,6 +634,57 @@ proc _progress {args} {
</span>     ui_progress_generic {*}${args}
 }
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+proc _get_port_conflicts {port} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    global registry::tdbc_connection
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {![info exists tdbc_connection]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        registry::tdbc_connect
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    variable conflicts_stmt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {![info exists conflicts_stmt]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set query {SELECT files.id, files.path, files.actual_path FROM
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                (SELECT path FROM files where id = :thisport_id)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                AS thisport_files
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                INNER JOIN files ON thisport_files.path = files.actual_path
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                WHERE files.active = 1}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set conflicts_stmt [$tdbc_connection prepare $query]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set thisport_id [$port id]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    $tdbc_connection transaction {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set results [$conflicts_stmt execute]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set id_to_port [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set path_to_port [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set port_to_paths [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set is_replaced [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set todeactivate [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set thisport_name [$port name]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    foreach result [$results allrows] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set id [dict get $result id]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {![dict exists $id_to_port $id]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            dict set id_to_port $id [lindex [registry::entry search id $id] 0]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set conflicting_port [dict get $id_to_port $id]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {![dict exists $is_replaced $conflicting_port]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            lassign [mportlookup [$conflicting_port name]] _ portinfo
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {[dict exists $portinfo replaced_by] && [lsearch -exact -nocase [dict get $portinfo replaced_by] $thisport_name] != -1} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                dict set is_replaced $conflicting_port 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                dict set todeactivate $conflicting_port 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                dict set is_replaced $conflicting_port 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set actual_path [dict get $result actual_path]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        dict set path_to_port $actual_path $conflicting_port
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {![dict get $is_replaced $conflicting_port]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set imagepath [dict get $result path]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            dict lappend port_to_paths $conflicting_port [list $imagepath $actual_path]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    $results close
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return [list $path_to_port $port_to_paths $todeactivate]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> ## Activates the contents of a port
 proc _activate_contents {port {rename_list {}}} {
     variable force
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -679,7 +730,7 @@ proc _activate_contents {port {rename_list {}}} {
</span>     # Last, if the file exists, and belongs to another port, and force is set
     #  we remove the file from the file_map, take ownership of it, and
     #  clobber it
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    set todeactivate [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set todeactivate [dict create]
</span>     try {
         registry::write {
             foreach file $imagefiles {
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -694,51 +745,73 @@ proc _activate_contents {port {rename_list {}}} {
</span>                     throw registry::image-error "Image error: Source file $srcfile does not appear to exist.  Unable to activate port ${portname}."
                 }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                set owner [registry::entry owner $file]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                if {$owner ne {} && $owner ne $port} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    # deactivate conflicting port if it is replaced_by this one
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    set result [mportlookup [$owner name]]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    set portinfo [lindex $result 1]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    if {[dict exists $portinfo replaced_by] && [lsearch -exact -nocase [dict get $portinfo replaced_by] $portname] != -1} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        # we'll deactivate the owner later, but before activating our files
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        lappend todeactivate $owner
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        set owner "replaced"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                if {$owner ne "replaced"} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    if {$force} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        # if we're forcing the activation, then we move any existing
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        # files to a backup file, both in the filesystem and in the
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        # registry
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        if { ![catch {::file type $file}] } {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                            set bakfile "${file}${baksuffix}"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                            _progress intermission
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                            ui_warn "File $file already exists.  Moving to: $bakfile."
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                            ::file rename -force -- $file $bakfile
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                            lappend backups $file
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        if { $owner ne {} } {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                            $owner deactivate [list $file]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                            $owner activate [list $file] [list "${file}${baksuffix}"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                if {![catch {::file type $file}]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {![info exists conflicts_path_to_port]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        # Check for conflicting ports. 'todeactivate' contains ports replaced by this one,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        # which we'll deactivate later, but before activating our files.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        lassign [_get_port_conflicts $port] conflicts_path_to_port conflicts_port_to_paths todeactivate
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        if {!$force && [dict size $conflicts_port_to_paths] > 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            set msg "The following ports have active files that conflict with ${portname}'s:\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            foreach conflicting_port [dict keys $conflicts_port_to_paths] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                append msg "[$conflicting_port name] @[$conflicting_port version]_[$conflicting_port revision][$conflicting_port variants]\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                set conflicting_paths [dict get $conflicts_port_to_paths $conflicting_port]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                set pathcounter 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                set pathtotal [llength $conflicting_paths]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                foreach {_ actual_path} $conflicting_paths {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                    if {$pathcounter >= 3 && $pathtotal > 4} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                        append msg "  (... [expr {$pathtotal - $pathcounter}] more not shown)\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                        break
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                    append msg "  ${actual_path}\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                    incr pathcounter
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            append msg "Image error: Conflicting file(s) present. Please deactivate the conflicting port(s) first, or use 'port -f activate $portname' to force the activation."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            throw registry::image-error $msg
</span>                         }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+                    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {[dict exists $conflicts_path_to_port $file]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        set owner [dict get $conflicts_path_to_port $file]
</span>                     } else {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                        # if we're not forcing the activation, then we bail out if
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        # we find any files that already exist, or have entries in
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        # the registry
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        if { $owner ne {} && $owner ne $port } {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                            set msg "Image error: $file is being used by the active [$owner name] port.  Please deactivate this port first, or use 'port -f activate $portname' to force the activation."
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                            #registry::entry close $owner
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                            throw registry::image-error $msg
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                        } elseif { $owner eq {} && ![catch {::file type $file}] } {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        set owner {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    if {$owner eq {} || ![dict exists $todeactivate $owner]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        if {$force} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            # if we're forcing the activation, then we move any existing
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            # files to a backup file, both in the filesystem and in the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            # registry
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            if {$owner ne {}} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                # Rename all conflicting files for this owner.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                set owner_paths [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                set owner_actual_paths [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                foreach {path actual_path} [dict get $conflicts_port_to_paths $owner] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                    lappend owner_deactivate_paths $path
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                    if {![catch {::file type $actual_path}]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                        lappend owner_activate_paths $path
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                        set bakfile ${actual_path}${baksuffix}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                        lappend owner_backup_paths $bakfile
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                        ui_warn "File $actual_path already exists.  Moving to: $bakfile."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                        ::file rename -force -- $actual_path $bakfile
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                        lappend backups $actual_path
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                $owner deactivate $owner_deactivate_paths
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                $owner activate $owner_activate_paths $owner_backup_paths
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                # Just rename this file.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                set bakfile ${file}${baksuffix}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                _progress intermission
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                ui_warn "File $file already exists.  Moving to: $bakfile."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                ::file rename -force -- $file $bakfile
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                lappend backups $file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            # if we're not forcing the activation, then we bail out if
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            # we find any files that already exist
</span>                             set msg "Image error: $file already exists and does not belong to a registered port.  Unable to activate port ${portname}. Use 'port -f activate $portname' to force the activation."
                             throw registry::image-error $msg
                         }
                     }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                    #if {$owner ne {}} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    #    registry::entry close $owner
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    #}
</span>                 }
 
                 # Split out the filename's subpaths and add them to the
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -775,7 +848,7 @@ proc _activate_contents {port {rename_list {}}} {
</span> 
         # deactivate ports replaced_by this one
         set deactivate_options [dict create ports_nodepcheck 1]
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        foreach owner $todeactivate {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        foreach owner [dict keys $todeactivate] {
</span>             _progress intermission
             if {$noexec || ![registry::run_target $owner deactivate $deactivate_options]} {
                 deactivate [$owner name] "" "" 0 $deactivate_options
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -860,7 +933,7 @@ proc _activate_contents {port {rename_list {}}} {
</span>                 ::file rename -force -- "${file}${baksuffix}" $file
             }
             # reactivate deactivated ports
<span style='display:block; white-space:pre;background:#ffe0e0;'>-            foreach entry $todeactivate {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            foreach entry [dict keys $todeactivate] {
</span>                 if {[$entry state] eq "imaged" && ($noexec || ![registry::run_target $entry activate ""])} {
                     activate [$entry name] [$entry version] [$entry revision] [$entry variants] [dict create ports_activate_no-exec $noexec]
                 }
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -873,7 +946,7 @@ proc _activate_contents {port {rename_list {}}} {
</span> 
         throw [dict get $eOptions -errorcode] [dict get $eOptions -errorinfo]
     } finally {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        #foreach entry $todeactivate {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        #foreach entry [dict keys $todeactivate] {
</span>         #    registry::entry close $entry
         #}
         # Only delete extracted dir if there is an archive to re-extract from
</pre><pre style='margin:0'>

</pre>