Opened 3 months ago

Last modified 3 months 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) 3 months ago.
macports-1.0-buildpath-truncate.patch (1.8 KB) - added by nanigashi-uji (Nanigashi Uji) 3 months ago.

Download all attachments as: .zip

Change History (9)

Changed 3 months ago by nanigashi-uji (Nanigashi Uji)

Attachment: MacPorts-2.10.0.diff added

Changed 3 months ago by nanigashi-uji (Nanigashi Uji)

comment:1 Changed 3 months 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 3 months 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 3 months 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 3 months 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 3 months 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 3 months 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 3 months 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.