Opened 5 weeks ago

Last modified 5 weeks ago

#70539 new defect

base: failure for building some ports (depending on conditions) when Macports is installed at deeper directory hierarchy with "--prefix" option

Reported by: nanigashi-uji (Nanigashi Uji) Owned by:
Priority: Normal Milestone:
Component: base Version: 2.10.0
Keywords: Cc:
Port:

Description

I have installed Macports as follows

% tar xvf MacPorts-2.9.3.tar.bz2 
% cd MacPorts-2.9.3
% ./configure --prefix=${HOME}/Documents/workspace/opr/depot/macports-2.9.3.arm64 \
  --with-no-root-privileges --enable-readline \
  --enable-shared  --without-startupitems \
  --with-applications-dir=${HOME}/Documents/workspace/opr/depot/macports-2.9.3.arm64/Applications \
  --with-frameworks-dir=${HOME}/Documents/workspace/opr/depot/macports-2.9.3.arm64/Library/Frameworks
% make && make install && ${HOME}/Documents/workspace/opr/depot/macports-2.9.3.arm64/bin/port -v selfupdate

Then we can basically use port command with out trouble, but sometimes we fail to build some ports almost randomly. The reason why some ports are failed to be build is intermediate file name become longer than the FILENAME_MAX or PATH_MAX of macOS. One of the reason of the too long intermediate filename is that "${portbuildpath}" is generated based on the full path of Portfile like "${prefix}/var/macports/build/_Users_{username}_Documents_workspace_opr_depot_macports-2.9.3.arm64_var_macports_sources_rsync.macports.org_macports_release_tarballs_ports_{category}_{portname}" in the example above.

So, I propose to modify "macports.tcl" as follows to reduce the possibility the probability of the error due to too long filename during the build.

diff -rupN MacPorts-2.10.0.orig/src/macports1.0/macports.tcl MacPorts-2.10.0/src/macports1.0/macports.tcl
--- MacPorts-2.10.0.orig/src/macports1.0/macports.tcl	2024-08-07 23:17:43
+++ MacPorts-2.10.0/src/macports1.0/macports.tcl	2024-08-13 20:25:36
@@ -3028,16 +3028,29 @@ proc _source_is_obsolete_svn_repo {source_dir} {
     return 0
 }
 
+proc macports::trim_prefix {fullpath prefix} {
+    set fullpath [file normalize $fullpath]
+    set prefix   [file normalize $prefix]
+    if {[string first $prefix $fullpath] != 0} {
+        return $fullpath
+    }
+    set relative_path [string range $fullpath [string length $prefix] end]
+    set relative_path [string trimleft $relative_path "/\\"]
+    return $relative_path
+}
+
 proc macports::getportbuildpath {id {portname {}}} {
     variable portdbpath
-    regsub {://} $id {.} port_path
+    set s_id [macports::trim_prefix $id [file join $portdbpath sources]]
+    regsub {://} $s_id {.} port_path
     regsub -all {/} $port_path {_} port_path
     return [file join $portdbpath build $port_path $portname]
 }
 
 proc macports::getportlogpath {id {portname {}}} {
     variable portdbpath
-    regsub {://} $id {.} port_path
+    set s_id [macports::trim_prefix $id [file join $portdbpath sources]]
+    regsub {://} $s_id {.} port_path
     regsub -all {/} $port_path {_} port_path
     return [file join $portdbpath logs $port_path $portname]
 }
diff -rupN MacPorts-2.10.0.orig/src/port1.0/tests/portutil.test MacPorts-2.10.0/src/port1.0/tests/portutil.test
--- MacPorts-2.10.0.orig/src/port1.0/tests/portutil.test	2024-08-07 23:17:43
+++ MacPorts-2.10.0/src/port1.0/tests/portutil.test	2024-08-13 20:25:56
@@ -52,9 +52,21 @@ proc init_eval_targets {} {
 
     set mport [mportopen file://.]
 
+    proc trim_prefix {fullpath prefix} {
+        set fullpath [file normalize $fullpath]
+        set prefix   [file normalize $prefix]
+        if {[string first $prefix $fullpath] != 0} {
+            return $fullpath
+        }
+        set relative_path [string range $fullpath [string length $prefix] end]
+        set relative_path [string trimleft $relative_path "/\\"]
+        return $relative_path
+    }
+
     proc getportbuildpath {id {portname ""}} {
         global portdbpath
-        regsub {://} $id {.} port_path
+        set s_id [trim_prefix $id [file join $portdbpath sources]]
+        regsub {://} $s_id {.} port_patha
         regsub -all {/} $port_path {_} port_path
         return [file join $portdbpath build $port_path $portname]
     }

Attachments (2)

MacPorts-2.10.0.diff (2.5 KB) - added by nanigashi-uji (Nanigashi Uji) 5 weeks ago.
macports-1.0-buildpath-truncate.patch (1.8 KB) - added by nanigashi-uji (Nanigashi Uji) 5 weeks ago.

Download all attachments as: .zip

Change History (9)

Changed 5 weeks ago by nanigashi-uji (Nanigashi Uji)

Attachment: MacPorts-2.10.0.diff added

Changed 5 weeks ago by nanigashi-uji (Nanigashi Uji)

comment:1 Changed 5 weeks ago by ryandesign (Ryan Carsten Schmidt)

I've also encountered some build failures due to too-long paths.

I haven't tried your code… could you give an example of what the build/log path would be after your changes?

comment:2 Changed 5 weeks ago by nanigashi-uji (Nanigashi Uji)

The build/log path become as follows:

${prefix}/var/macports/build/rsync.macports.org_macports_release_tarballs_ports_{category}_{portname}

and

${prefix}/var/macports/logs/rsync.macports.org_macports_release_tarballs_ports_{category}_{portname}

comment:3 Changed 5 weeks ago by ryandesign (Ryan Carsten Schmidt)

That seems like an improvement. It is of course possible to build ports that are not in one of the configured ports trees. I assume in that case the full path will still be used as before.

comment:4 Changed 5 weeks ago by jmroot (Joshua Root)

If we abbreviate the path at all, we need to handle collisions, maybe by storing the full path in a file. And if we're doing that, maybe we might as well abandon any attempt at human-readability and just use something like a short checksum of the path. Most of the time you're going to be using command like port work to find the path anyway, and if you have to look in there manually, the next subdir down still has the subport name.

comment:5 Changed 5 weeks ago by jmroot (Joshua Root)

There will also need to be a script that moves existing old-style paths to their new-style equivalent when upgrading.

comment:6 in reply to:  4 Changed 5 weeks ago by ryandesign (Ryan Carsten Schmidt)

Replying to jmroot:

Most of the time you're going to be using command like port work to find the path anyway,

I often don't because it doesn't work with subports; see #57391.

comment:7 Changed 5 weeks ago by nanigashi-uji (Nanigashi Uji)

The above patch keeps the paths for each port under "${prefix}/var/macports/sources", so there is no problem in terms of avoiding conflicts between ports, and the full path can be reproduced by adding "${portdbpath}/sources" at the beginning. On the other hand, in the original code, if "${prefix}" contains "_", the name conversion is not one-to-one mapping, so this is not the best method, I think.

Note: See TracTickets for help on using tickets.