<pre style='margin:0'>
Joshua Root (jmroot) pushed a commit to branch master
in repository macports-base.
</pre>
<p><a href="https://github.com/macports/macports-base/commit/4504942d2283f2950d273b0aee93b9ed867007ea">https://github.com/macports/macports-base/commit/4504942d2283f2950d273b0aee93b9ed867007ea</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit 4504942d2283f2950d273b0aee93b9ed867007ea
</span>Author: Joshua Root <jmr@macports.org>
AuthorDate: Mon Jun 24 14:21:10 2024 +1000
<span style='display:block; white-space:pre;color:#404040;'> Use clonefile for port images, and detect hardlinks
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> New portimage_mode config option controls whether the extracted
</span><span style='display:block; white-space:pre;color:#404040;'> directory, the archive, or both are kept for port images. Default is
</span><span style='display:block; white-space:pre;color:#404040;'> directory if the filesystem that the software directory is on supports
</span><span style='display:block; white-space:pre;color:#404040;'> cloning. Otherwise the default is archive.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> In directory mode, downloaded archives are extracted only once.
</span><span style='display:block; white-space:pre;color:#404040;'> Subsequent activations just clone the files. If activation is across
</span><span style='display:block; white-space:pre;color:#404040;'> devices for some files, fall back to copying for those files.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> In all cases, hard links are now recreated correctly whenever possible
</span><span style='display:block; white-space:pre;color:#404040;'> even if the activated location is on a different device than the port
</span><span style='display:block; white-space:pre;color:#404040;'> image.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> Closes: https://trac.macports.org/ticket/69555
</span>---
configure | 18 ++++
configure.ac | 7 +-
doc/macports.conf.in | 19 +++-
src/config.h.in | 9 ++
src/images_to_archives.tcl.in | 3 +-
src/macports1.0/macports.tcl | 26 +++++-
src/pextlib1.0/Pextlib.c | 41 ++++++++
src/port1.0/portinstall.tcl | 43 +++++++--
src/registry2.0/portimage.tcl | 191 ++++++++++++++++++++++++++------------
src/registry2.0/portuninstall.tcl | 26 +++++-
10 files changed, 306 insertions(+), 77 deletions(-)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/configure b/configure
</span><span style='display:block; white-space:pre;color:#808080;'>index c20027d7a..f5dbc2f26 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/configure
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/configure
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -7446,12 +7446,24 @@ if test "x$ac_cv_header_spawn_h" = xyes
</span> then :
printf "%s\n" "#define HAVE_SPAWN_H 1" >>confdefs.h
<span style='display:block; white-space:pre;background:#e0ffe0;'>+fi
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ac_fn_c_check_header_compile "$LINENO" "sys/attr.h" "ac_cv_header_sys_attr_h" "$ac_includes_default"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+if test "x$ac_cv_header_sys_attr_h" = xyes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+then :
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf "%s\n" "#define HAVE_SYS_ATTR_H 1" >>confdefs.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> fi
ac_fn_c_check_header_compile "$LINENO" "sys/cdefs.h" "ac_cv_header_sys_cdefs_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_cdefs_h" = xyes
then :
printf "%s\n" "#define HAVE_SYS_CDEFS_H 1" >>confdefs.h
<span style='display:block; white-space:pre;background:#e0ffe0;'>+fi
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ac_fn_c_check_header_compile "$LINENO" "sys/clonefile.h" "ac_cv_header_sys_clonefile_h" "$ac_includes_default"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+if test "x$ac_cv_header_sys_clonefile_h" = xyes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+then :
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf "%s\n" "#define HAVE_SYS_CLONEFILE_H 1" >>confdefs.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> fi
ac_fn_c_check_header_compile "$LINENO" "sys/event.h" "ac_cv_header_sys_event_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_event_h" = xyes
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -7527,6 +7539,12 @@ if test "x$ac_cv_func_clearenv" = xyes
</span> then :
printf "%s\n" "#define HAVE_CLEARENV 1" >>confdefs.h
<span style='display:block; white-space:pre;background:#e0ffe0;'>+fi
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ac_fn_c_check_func "$LINENO" "clonefile" "ac_cv_func_clonefile"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+if test "x$ac_cv_func_clonefile" = xyes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+then :
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf "%s\n" "#define HAVE_CLONEFILE 1" >>confdefs.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> fi
ac_fn_c_check_func "$LINENO" "copyfile" "ac_cv_func_copyfile"
if test "x$ac_cv_func_copyfile" = xyes
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/configure.ac b/configure.ac
</span><span style='display:block; white-space:pre;color:#808080;'>index ab77f3746..8c1883b5a 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/configure.ac
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/configure.ac
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -249,13 +249,14 @@ MP_CHECK_STARTUPITEMS
</span> MP_UNIVERSAL_OPTIONS
# Check for standard header files.
<span style='display:block; white-space:pre;background:#ffe0e0;'>-AC_CHECK_HEADERS([crt_externs.h err.h fcntl.h libkern/OSAtomic.h libproc.h limits.h paths.h pwd.h \
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- readline/history.h readline/readline.h stdatomic.h spawn.h sys/cdefs.h sys/event.h \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+AC_CHECK_HEADERS([crt_externs.h err.h fcntl.h libkern/OSAtomic.h libproc.h \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ limits.h paths.h pwd.h readline/history.h readline/readline.h \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ stdatomic.h spawn.h sys/attr.h sys/cdefs.h sys/clonefile.h sys/event.h \
</span> sys/fcntl.h sys/file.h sys/paths.h sys/socket.h sys/sysctl.h utime.h])
# Checks for library functions.
AC_CHECK_FUNCS([OSAtomicCompareAndSwap32 OSAtomicCompareAndSwap64 \
<span style='display:block; white-space:pre;background:#ffe0e0;'>- OSAtomicCompareAndSwapPtr __getdirentries64 clearenv copyfile \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ OSAtomicCompareAndSwapPtr __getdirentries64 clearenv clonefile copyfile \
</span> _dyld_shared_cache_contains_path flock fls kqueue posix_spawn setmode \
sysctlbyname])
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/doc/macports.conf.in b/doc/macports.conf.in
</span><span style='display:block; white-space:pre;color:#808080;'>index 3443c0c59..809826ff7 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/doc/macports.conf.in
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/doc/macports.conf.in
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -46,10 +46,25 @@ variants_conf @MPCONFIGDIR_EXPANDED@/variants.conf
</span> # unavailable.
#buildfromsource ifneeded
<span style='display:block; white-space:pre;background:#ffe0e0;'>-# Type of archive to use for port images. Supported types are cpgz,
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-# cpio, tar, tbz, tbz2, tgz, tlz, txz, xar, zip.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# Type of archive to use for port images created by local builds.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# Supported types are cpgz, cpio, tar, tbz, tbz2, tgz, tlz, txz, xar, zip.
</span> #portarchivetype tbz2
<span style='display:block; white-space:pre;background:#e0ffe0;'>+# How to store port images.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# - archive: Image is kept in the archive as downloaded (format
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# determined by the archive site configuration) or built locally
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# (format determined by portarchivetype). Must be extracted to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# activate the port. This is the default if the filesystem does not
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# support cloning.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# - directory: Image is stored as a directory. Downloaded archives are
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# extracted to create the directory and then deleted. This is the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# default if the filesystem supports cloning.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# - directory_and_archive: Both archives and extracted directories are
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# kept. This is useful if you want to distribute the ports that you
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# build as archives, and also get the performance benefits of the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# directory mode on a filesystem that supports cloning.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#portimage_mode directory_and_archive
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> # Apply transparent filesystem compression to files on activation.
# Requires bsdtar with support for --hfsCompression in binpath, which can be
# provided by installing the libarchive port. This will work with HFS+ or APFS
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/config.h.in b/src/config.h.in
</span><span style='display:block; white-space:pre;color:#808080;'>index dafa3daf4..49b06de0e 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/config.h.in
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/config.h.in
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -7,6 +7,9 @@
</span> /* Define to 1 if you have the 'clearenv' function. */
#undef HAVE_CLEARENV
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Define to 1 if you have the 'clonefile' function. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef HAVE_CLONEFILE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> /* Define if CommonCrypto is available. */
#undef HAVE_COMMONCRYPTO_COMMONDIGEST_H
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -187,9 +190,15 @@
</span> /* Define to 1 if you have the 'sysctlbyname' function. */
#undef HAVE_SYSCTLBYNAME
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Define to 1 if you have the <sys/attr.h> header file. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef HAVE_SYS_ATTR_H
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> /* Define to 1 if you have the <sys/cdefs.h> header file. */
#undef HAVE_SYS_CDEFS_H
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Define to 1 if you have the <sys/clonefile.h> header file. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef HAVE_SYS_CLONEFILE_H
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> /* Define to 1 if you have the <sys/event.h> header file. */
#undef HAVE_SYS_EVENT_H
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/images_to_archives.tcl.in b/src/images_to_archives.tcl.in
</span><span style='display:block; white-space:pre;color:#808080;'>index 69eb980cc..9adfcd1ec 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/images_to_archives.tcl.in
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/images_to_archives.tcl.in
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -32,6 +32,7 @@ puts "This could take a while..."
</span> set archived_list [list]
set installed_len [llength $ilist]
set counter 0
<span style='display:block; white-space:pre;background:#e0ffe0;'>+set archive_required [expr {$macports::portimage_mode eq "archive"}]
</span>
foreach installed $ilist {
incr counter
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -50,7 +51,7 @@ foreach installed $ilist {
</span> set location ""
}
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if {$location eq "" || ![file isfile $location]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {$location eq "" || ![file exists $location] || ($archive_required && ![file isfile $location])} {
</span> # no image archive present, so make one
set archs [$installed archs]
if {$archs eq "" || $archs == 0} {
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/macports1.0/macports.tcl b/src/macports1.0/macports.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 7d378de5a..d7ec17e12 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/macports1.0/macports.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/macports1.0/macports.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -50,7 +50,7 @@ namespace eval macports {
</span> variable bootstrap_options [dict create]
# Config file options with no special handling
foreach opt [list binpath auto_path extra_env portdbformat \
<span style='display:block; white-space:pre;background:#ffe0e0;'>- portarchivetype hfscompression portautoclean \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ portarchivetype portimage_mode hfscompression portautoclean \
</span> porttrace portverbose keeplogs destroot_umask rsync_server rsync_options \
rsync_dir startupitem_autostart startupitem_type startupitem_install \
place_worksymlink xcodeversion xcodebuildcmd xcodecltversion xcode_license_unaccepted \
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -74,7 +74,8 @@ namespace eval macports {
</span> variable portinterp_options [list \
portdbpath porturl portpath portbuildpath auto_path prefix prefix_frozen portsharepath \
registry.path registry.format user_home user_path user_ssh_auth_sock \
<span style='display:block; white-space:pre;background:#ffe0e0;'>- portarchivetype archivefetch_pubkeys portautoclean porttrace keeplogs portverbose destroot_umask \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ portarchivetype portarchive_hfscompression archivefetch_pubkeys \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ portautoclean portimage_mode porttrace keeplogs portverbose destroot_umask \
</span> rsync_server rsync_options rsync_dir startupitem_autostart startupitem_type startupitem_install \
place_worksymlink macportsuser sudo_user \
configureccache ccache_dir ccache_size configuredistcc configurepipe buildnicevalue buildmakejobs \
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -954,6 +955,7 @@ proc mportinit {{up_ui_options {}} {up_options {}} {up_variations {}}} {
</span> macports::portarchivetype \
macports::portautoclean \
macports::portautoclean_frozen \
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ macports::portimage_mode \
</span> macports::porttrace \
macports::porttrace_frozen \
macports::portverbose \
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -976,6 +978,7 @@ proc mportinit {{up_ui_options {}} {up_options {}} {up_variations {}}} {
</span> macports::delete_la_files \
macports::cxx_stdlib \
macports::hfscompression \
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ macports::portarchive_hfscompression \
</span> macports::host_cache \
macports::porturl_prefix_map \
macports::ui_options \
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -1405,10 +1408,29 @@ Please edit sources.conf and change '$url' to '[string range $url 0 end-6]tarbal
</span> set portarchivetype [lindex $portarchivetype 0]
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ # How to store port images
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[info exists portimage_mode] &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $portimage_mode ni {archive directory directory_and_archive}} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_warn "Unknown portimage_mode value '$portimage_mode', using default"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ unset portimage_mode
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![info exists portimage_mode]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Using an extracted directory is usually only a good idea if
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # the filesystem supports COW clones.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![catch {fs_clone_capable [file join $portdbpath software]} result] && $result} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set portimage_mode directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set portimage_mode archive
</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 portimage::keep_imagedir [expr {$portimage_mode ne "archive"}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set portimage::keep_archive [expr {$portimage_mode ne "directory"}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> # Enable HFS+ compression by default
if {![info exists hfscompression]} {
set hfscompression yes
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ set portarchive_hfscompression $hfscompression
</span>
# Set rync options
if {![info exists rsync_server]} {
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/pextlib1.0/Pextlib.c b/src/pextlib1.0/Pextlib.c
</span><span style='display:block; white-space:pre;color:#808080;'>index 97ca985cd..4d0ccadcc 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/pextlib1.0/Pextlib.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/pextlib1.0/Pextlib.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -70,6 +70,14 @@
</span> #include <unistd.h>
#include <assert.h>
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/* For clonefile */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifdef HAVE_SYS_ATTR_H
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/attr.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifdef HAVE_SYS_CLONEFILE_H
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/clonefile.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> #ifdef __MACH__
#include <mach-o/loader.h>
#include <mach-o/fat.h>
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -1110,6 +1118,38 @@ int FSCloneCapableCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc
</span> return TCL_OK;
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/**
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Interface to clonefile(2)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int ClonefileCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (objc != 3) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_WrongNumArgs(interp, 1, objv, "srcpath dstpath");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return TCL_ERROR;
</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;'>+#ifdef HAVE_CLONEFILE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char *srcpath = Tcl_GetString(objv[1]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char *dstpath = Tcl_GetString(objv[2]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!srcpath || !dstpath) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return TCL_ERROR;
</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;'>+ ret = clonefile(srcpath, dstpath, CLONE_NOFOLLOW);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (ret != 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_SetErrno(errno);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_ResetResult(interp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_AppendResult(interp, "clonefile failed: ", (char *)Tcl_PosixError(interp), NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif /* HAVE_CLONEFILE */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (ret == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return TCL_OK;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return TCL_ERROR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> int Pextlib_Init(Tcl_Interp *interp)
{
if (Tcl_InitStubs(interp, "8.4", 0) == NULL)
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -1172,6 +1212,7 @@ int Pextlib_Init(Tcl_Interp *interp)
</span>
Tcl_CreateObjCommand(interp, "fs_case_sensitive", FSCaseSensitiveCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "fs_clone_capable", FSCloneCapableCmd, NULL, NULL);
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_CreateObjCommand(interp, "clonefile", ClonefileCmd, NULL, NULL);
</span>
if (Tcl_PkgProvide(interp, "Pextlib", "1.0") != TCL_OK)
return TCL_ERROR;
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/port1.0/portinstall.tcl b/src/port1.0/portinstall.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 33ee3509e..18a5a2de7 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/port1.0/portinstall.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/port1.0/portinstall.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -74,7 +74,8 @@ proc portinstall::create_archive {location archive.type} {
</span> global workpath destpath portpath subport version revision portvariants \
epoch configure.cxx_stdlib cxx_stdlib PortInfo \
archive.env archive.cmd archive.pre_args archive.args \
<span style='display:block; white-space:pre;background:#ffe0e0;'>- archive.post_args archive.dir depends_lib depends_run
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ archive.post_args archive.dir depends_lib depends_run \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ portarchive_hfscompression
</span> set archive.env {}
set archive.cmd {}
set archive.pre_args {}
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -119,7 +120,7 @@ proc portinstall::create_archive {location archive.type} {
</span> return -code error "No '$pax' was found on this system!"
}
}
<span style='display:block; white-space:pre;background:#ffe0e0;'>- t(ar|bz|lz|xz|gz) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ t(ar|bz|lz|xz|gz|mptar) {
</span> set tar "tar"
if {[catch {set tar [findBinary $tar ${portutil::autoconf::tar_path}]} errmsg] == 0} {
ui_debug "Using $tar"
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -159,7 +160,25 @@ proc portinstall::create_archive {location archive.type} {
</span> return -code error "No '$gzip' was found on this system!"
}
} else {
<span style='display:block; white-space:pre;background:#ffe0e0;'>- set archive.args "[shellescape ${location}] ."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {${archive.type} eq "tmptar"} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Pass through tar for hardlink detection and HFS compression,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # but extract without saving the tar file.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {${portarchive_hfscompression} && [getuid] == 0 &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ![catch {binaryInPath bsdtar}] &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ![catch {exec bsdtar -x --hfsCompression < /dev/null >& /dev/null}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } then {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set extract_tar bsdtar
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set extract_tar_args {-xvp --hfsCompression -f}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set extract_tar $tar
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set extract_tar_args {-xvpf}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set archive.args {- .}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set archive.post_args "| $extract_tar -C $location $extract_tar_args -"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ file mkdir $location
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set archive.args "[shellescape ${location}] ."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span> }
} else {
ui_debug $errmsg
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -322,7 +341,7 @@ proc portinstall::create_archive {location archive.type} {
</span> # Now create the archive
ui_debug "Creating [file tail $location]"
command_exec archive
<span style='display:block; white-space:pre;background:#ffe0e0;'>- ui_debug "Archive [file tail $location] packaged"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_debug "Port image [file tail $location] created"
</span>
# Cleanup all control files when finished
set control_files [glob -nocomplain -types f [file join $destpath +*]]
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -339,7 +358,7 @@ proc portinstall::extract_contents {location type} {
</span> proc portinstall::install_main {args} {
global subport version portpath depends_run revision user_options \
portvariants requested_variants depends_lib PortInfo epoch \
<span style='display:block; white-space:pre;background:#ffe0e0;'>- portarchivetype
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ portarchivetype portimage_mode
</span> variable file_is_binary
variable actual_cxx_stdlib
variable cxx_stdlib_overridden
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -366,10 +385,18 @@ proc portinstall::install_main {args} {
</span> set cxxinfo [extract_archive_metadata $location $current_archive_type cxx_info]
lassign $cxxinfo actual_cxx_stdlib cxx_stdlib_overridden
} else {
<span style='display:block; white-space:pre;background:#ffe0e0;'>- # throws an error if an unsupported value has been configured
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- archiveTypeIsSupported $portarchivetype
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {$portimage_mode eq "directory"} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Special value to avoid writing archive out to disk, since
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # only the extracted dir should be kept.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set archivetype tmptar
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set location [file rootname $location]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # throws an error if an unsupported value has been configured
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ archiveTypeIsSupported $portarchivetype
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set archivetype $portarchivetype
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span> # create archive from the destroot
<span style='display:block; white-space:pre;background:#ffe0e0;'>- create_archive $location $portarchivetype
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ create_archive $location $archivetype
</span> }
# can't do this inside the write transaction due to deadlock issues with _get_dep_port
<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 339f478c1..62ffbca37 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;'>@@ -114,7 +114,7 @@ proc activate {name {version ""} {revision ""} {variants 0} {options ""}} {
</span> #registry::entry close $requested
return -code error "Image error: ${name} @${specifier} not installed as an image."
}
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if {![::file isfile $location]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![::file exists $location]} {
</span> #registry::entry close $requested
return -code error "Image error: Can't find image file $location"
}
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -316,54 +316,124 @@ proc _check_registry {name version revision variants {return_all 0}} {
</span> throw registry::invalid "Registry error: ${name}${composite_spec} is not installed."
}
<span style='display:block; white-space:pre;background:#ffe0e0;'>-## Activates a file from an image into the filesystem. Deals with symlinks
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-## and regular files.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# Mapping of directory paths to device numbers. Used to check if files
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# can be hardlinked or cloned, or must be copied.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+variable dir_devices [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+## Activates a list of files from an image into the filesystem. Deals
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+## with symlinks and regular files.
</span> ##
<span style='display:block; white-space:pre;background:#ffe0e0;'>-## @param [in] srcfile path to file in image
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-## @param [in] dstfile path to activate file to
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-## @return 1 if file needs to be explicitly deleted if we have to roll back, 0 otherwise
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-proc _activate_file {srcfile dstfile} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[catch {::file type $srcfile} result]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+## @param [in] files list of target file paths
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+## @param [in] imageroot path to root of image directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+## @param [in] imageroot path to root of image directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+## @param [in] rollback_var list name to append activated files to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+## @return list of files that need to be explicitly deleted if we have to roll back
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc _activate_files {srcfiles dstfiles imageroot rollback_var} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable progress_step; variable progress_total_steps
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable dir_devices; variable keep_imagedir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upvar $rollback_var rollback_list
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set use_clone [expr {$keep_imagedir && [fs_clone_capable $imageroot]}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ::file stat $imageroot statinfo
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set imagedev $statinfo(dev)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set all_attrs [expr {[getuid] == 0}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set hardlinks [dict create]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ foreach srcfile $srcfiles dstfile $dstfiles {
</span> # this can happen if the archive was built on case-sensitive and we're case-insensitive
# we know any existing dstfile is ours because we checked for conflicts earlier
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if {![catch {file type $dstfile}]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![catch {::file type $dstfile}]} {
</span> ui_debug "skipping case-conflicting file: $srcfile"
<span style='display:block; white-space:pre;background:#ffe0e0;'>- return 0
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- error $result
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ continue
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_debug "activating file: $dstfile"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set hardlinked 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ::file lstat $srcfile statinfo
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {$statinfo(nlink) > 1} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Hard linked file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[dict exists $hardlinks $statinfo(ino)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Link to the primary link
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![catch {::file link -hard $dstfile [dict get $hardlinks $statinfo(ino)]}]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set hardlinked 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Fall back to normal method if hardlinking failed. The destinations
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # for the links could be on different devices, or a destination
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # filesystem might not even support hard links.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Set this as the primary link and activate as normal.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ dict set hardlinks $statinfo(ino) $dstfile
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span> }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {!$hardlinked} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {$use_clone && [dict get $dir_devices [::file dirname $dstfile]] == $imagedev} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ clonefile $srcfile $dstfile
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # not all permissions are preserved by clonefile
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {$statinfo(type) ne "link"} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ::file attributes $dstfile -permissions {*}[::file attributes $srcfile -permissions]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } elseif {$keep_imagedir} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ::file copy $srcfile $dstfile
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {$statinfo(type) ne "link"} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {$all_attrs} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ::file attributes $dstfile {*}[::file attributes ${srcfile}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # not root, so can't set owner/group
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ::file attributes $dstfile -permissions {*}[::file attributes ${srcfile} -permissions]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ::file mtime $dstfile [::file mtime $srcfile]
</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;'>+ ::file rename $srcfile $dstfile
</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;'>+ lappend rollback_list $dstfile
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ _progress update $progress_step $progress_total_steps
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ incr progress_step
</span> }
<span style='display:block; white-space:pre;background:#ffe0e0;'>- ui_debug "activating file: $dstfile"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- ::file rename $srcfile $dstfile
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- return 1
</span> }
## Activates a directory from an image into the filesystem.
##
<span style='display:block; white-space:pre;background:#ffe0e0;'>-## @param [in] srcdir path to dir in image
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-## @param [in] dstdir path to activate dir to
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-proc _activate_directory {srcdir dstdir} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- # Don't recursively copy directories
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- ui_debug "activating directory: $dstdir"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- # Don't do anything if the directory already exists.
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if {![::file isdirectory $dstdir]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- ::file mkdir $dstdir
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- # fix attributes on the directory.
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[getuid] == 0} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- ::file attributes $dstdir {*}[::file attributes $srcdir]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- # not root, so can't set owner/group
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- ::file attributes $dstdir -permissions {*}[::file attributes $srcdir -permissions]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+## @param [in] dirs list of destination directory paths
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+## @param [in] imageroot path to root of image directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc _activate_directories {dirs imageroot} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable progress_step; variable progress_total_steps
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable dir_devices
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set all_attrs [expr {[getuid] == 0}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ foreach dir $dirs {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_debug "activating directory: $dir"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Don't do anything if the directory already exists.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![::file isdirectory $dir]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ::file mkdir $dir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set srcdir ${imageroot}${dir}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # fix attributes on the directory.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {$all_attrs} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ::file attributes $dir {*}[::file attributes ${srcdir}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # not root, so can't set owner/group
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ::file attributes $dir -permissions {*}[::file attributes ${srcdir} -permissions]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # set mtime on installed element
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ::file mtime $dir [::file mtime ${srcdir}]
</span> }
<span style='display:block; white-space:pre;background:#ffe0e0;'>- # set mtime on installed element
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- ::file mtime $dstdir [::file mtime $srcdir]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![dict exists $dir_devices $dir]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ::file stat $dir statinfo
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ dict set dir_devices $dir $statinfo(dev)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ _progress update $progress_step $progress_total_steps
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ incr progress_step
</span> }
}
<span style='display:block; white-space:pre;background:#ffe0e0;'>-# extract an archive to a temporary location
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# extract an archive to a directory
</span> # returns: path to the extracted directory
<span style='display:block; white-space:pre;background:#ffe0e0;'>-proc extract_archive_to_tmpdir {location} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- set extractdir [mkdtemp [::file dirname $location]/mpextractXXXXXXXX]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc extract_archive_to_imagedir {location} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set extractdir [file rootname $location]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[file exists $extractdir]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set extractdir [mkdtemp ${extractdir}XXXXXXXX]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ file mkdir $extractdir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span> set startpwd [pwd]
try {
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -568,6 +638,8 @@ proc _progress {args} {
</span> proc _activate_contents {port {rename_list {}}} {
variable force
variable noexec
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable keep_archive
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable keep_imagedir
</span> variable progress_step
variable progress_total_steps
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -577,8 +649,24 @@ proc _activate_contents {port {rename_list {}}} {
</span> set location [$port location]
set imagefiles [$port imagefiles]
set num_imagefiles [llength $imagefiles]
<span style='display:block; white-space:pre;background:#ffe0e0;'>- set progress_total_steps [expr {$num_imagefiles * 3}]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- set extracted_dir [extract_archive_to_tmpdir $location]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set progress_step 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[::file isfile $location]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set progress_total_steps [expr {$num_imagefiles * 3}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set extracted_dir [extract_archive_to_imagedir $location]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # extract phase complete, assume 1/3 is done
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set progress_step $num_imagefiles
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {!$keep_archive} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ registry::write {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $port location $extracted_dir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ file delete $location
</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;'>+ set extracted_dir $location
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set progress_total_steps [expr {$num_imagefiles * 2}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ _progress start
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span>
set backups [list]
set seendirs [dict create]
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -593,8 +681,6 @@ proc _activate_contents {port {rename_list {}}} {
</span> set todeactivate [list]
try {
registry::write {
<span style='display:block; white-space:pre;background:#ffe0e0;'>- # extract phase complete, assume 1/3 is done
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- set progress_step $num_imagefiles
</span> foreach file $imagefiles {
incr progress_step
_progress update $progress_step $progress_total_steps
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -709,27 +795,16 @@ proc _activate_contents {port {rename_list {}}} {
</span>
try {
$port activate $imagefiles
<span style='display:block; white-space:pre;background:#ffe0e0;'>- foreach dir $directories {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- _activate_directory ${extracted_dir}${dir} $dir
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- _progress update $progress_step $progress_total_steps
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- incr progress_step
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- foreach file $files {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[_activate_file ${extracted_dir}${file} $file] == 1} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- lappend rollback_filelist $file
</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;'>- _progress update $progress_step $progress_total_steps
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- incr progress_step
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ _activate_directories $directories $extracted_dir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ _activate_files [lmap f $files {string cat ${extracted_dir}${f}}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $files $extracted_dir rollback_filelist
</span> foreach {src dest} $confirmed_rename_list {
$port deactivate [list $src]
$port activate [list $src] [list $dest]
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[_activate_file ${extracted_dir}${src} $dest] == 1} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- lappend rollback_filelist $dest
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span> }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ _activate_files [lmap {src _} $confirmed_rename_list {string cat ${extracted_dir}${src}}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ [lmap {_ dst} $confirmed_rename_list {set dst}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $extracted_dir rollback_filelist
</span>
# Recording that the port has been activated should be done
# here so that this information cannot be inconsistent with the
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -800,8 +875,10 @@ proc _activate_contents {port {rename_list {}}} {
</span> #foreach entry $todeactivate {
# registry::entry close $entry
#}
<span style='display:block; white-space:pre;background:#ffe0e0;'>- # remove temp image dir
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- ::file delete -force $extracted_dir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {!$keep_imagedir} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # remove temp image dir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ::file delete -force $extracted_dir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span> }
}
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/registry2.0/portuninstall.tcl b/src/registry2.0/portuninstall.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index ff70a8a81..0b3f5855d 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/registry2.0/portuninstall.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/registry2.0/portuninstall.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -267,12 +267,30 @@ proc uninstall {portname {version ""} {revision ""} {variants 0} {options ""}} {
</span> } else {
ui_msg "$UI_PREFIX [format [msgcat::mc "Uninstalling %s @%s"] $portname $composite_spec]"
<span style='display:block; white-space:pre;background:#ffe0e0;'>- # Get the full path to the image file
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- set imagefile [$port location]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- file delete $imagefile
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Get the full path to the port image
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set imagepath [$port location]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set imagedir [file dirname $imagepath]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[file isfile $imagepath]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ file delete $imagepath
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Also delete extracted image dir if present
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set extracted_path [file rootname $imagepath]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[file isdirectory $extracted_path]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ file delete -force $extracted_path
</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;'>+ # Image is a directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ file delete -force $imagepath
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Also delete any associated archives
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set imagename [file tail $imagepath]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ foreach archive [glob -nocomplain -directory $imagedir ${imagename}.*] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[file rootname [file tail $archive]] eq $imagename} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ file delete -force $archive
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span> # Try to delete the port's image dir; will fail if there are more image
# files so just ignore the failure
<span style='display:block; white-space:pre;background:#ffe0e0;'>- catch {file delete [::file dirname $imagefile]}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ catch {file delete $imagedir}
</span>
# We want to delete the portfile if not referenced by any other ports
set portfile [$port portfile]
</pre><pre style='margin:0'>
</pre>