Split port1.0 targets a-d

See 0b375d0669
This commit is contained in:
Joshua Root
2026-06-26 10:27:16 +10:00
parent 06ff92efad
commit 05cc462c97
32 changed files with 2316 additions and 2274 deletions
+3
View File
@@ -13,6 +13,9 @@ SRCS= port.tcl portchecksum.tcl portconfigure.tcl portextract.tcl \
portdeactivate.tcl portstartupitem.tcl porttrace.tcl portlivecheck.tcl \
portdistcheck.tcl portmirror.tcl portload.tcl portunload.tcl portreload.tcl \
portdistfiles.tcl fetch_common.tcl portsandbox.tcl \
portactivate_run.tcl portbuild_run.tcl portbump_run.tcl portchecksum_run.tcl \
portclean_run.tcl portconfigure_run.tcl portdeactivate_run.tcl \
portdestroot_run.tcl portdistcheck_run.tcl portdistfiles_run.tcl \
portfetch_run.tcl
include $(srcdir)/../../Mk/macports.subdir.mk
+1 -92
View File
@@ -1,40 +1,8 @@
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
# portactivate.tcl
#
# Copyright (c) 2005, 2007, 2009-2011 The MacPorts Project
# Copyright (c) 2004 Robert Shaw <rshaw@opendarwin.org>
# Copyright (c) 2002 - 2003 Apple Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of Apple Inc. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# the 'activate' target is provided by this package
package provide portactivate 1.0
package require portutil 1.0
set org.macports.activate [target_new org.macports.activate portactivate::activate_main]
target_runtype ${org.macports.activate} always
@@ -43,66 +11,7 @@ target_provides ${org.macports.activate} activate
target_requires ${org.macports.activate} main archivefetch fetch checksum extract patch configure build destroot install
target_prerun ${org.macports.activate} portactivate::activate_start
target_postrun ${org.macports.activate} portactivate::activate_finish
namespace eval portactivate {
}
target_runpkg ${org.macports.activate} portactivate_run
options activate.asroot
default activate.asroot no
proc portactivate::activate_start {args} {
global prefix_frozen
if {![file writable $prefix_frozen] || ([getuid] == 0 && [geteuid] != 0)} {
# if install location is not writable, need root privileges
elevateToRoot "activate"
}
}
proc portactivate::activate_main {args} {
global subport _inregistry_version _inregistry_revision _inregistry_variants prefix user_options
foreach {var backup} {_inregistry_version version _inregistry_revision revision _inregistry_variants portvariants} {
if {![info exists $var]} {
set $var [option $backup]
}
}
set reg_options [dict create {*}[array get user_options]]
set renames [dict create]
portstartupitem::foreach_startupitem {
if {$si_install} {
dict set renames ${prefix}/etc/${si_location}/${si_plist} /Library/${si_location}/${si_plist}
} else {
dict set renames /Library/${si_location}/${si_plist} ${prefix}/etc/${si_location}/${si_plist}
}
}
dict set reg_options portactivate_rename_files $renames
registry_activate $subport $_inregistry_version $_inregistry_revision $_inregistry_variants $reg_options
return 0
}
proc portactivate::activate_finish {args} {
global subport PortInfo startupitem_autostart
# Do this _after_ activate_main, because post-activate hooks might create
# the files needed for this
# The option from macports.conf can override the portfile here.
if {[tbool startupitem_autostart]} {
global portstartupitem::autostart_only
set autostart_only yes
if {[eval_targets "load"]} {
ui_error [format [msgcat::mc "Failed to load %s"] $subport]
unset autostart_only
return 1
}
unset autostart_only
}
# Save notes for display by the port client
if {[info exists PortInfo(notes)] && [llength $PortInfo(notes)] > 0} {
ui_notifications_append $subport $PortInfo(notes)
}
return 0
}
+95
View File
@@ -0,0 +1,95 @@
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
#
# Copyright (c) 2005, 2007, 2009-2011 The MacPorts Project
# Copyright (c) 2004 Robert Shaw <rshaw@opendarwin.org>
# Copyright (c) 2002 - 2003 Apple Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of Apple Inc. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
package provide portactivate_run 1.0
package require portstartupitem 1.0
package require portutil 1.0
namespace eval portactivate {
proc activate_start {args} {
global prefix_frozen
if {![file writable $prefix_frozen] || ([getuid] == 0 && [geteuid] != 0)} {
# if install location is not writable, need root privileges
elevateToRoot "activate"
}
}
proc activate_main {args} {
global subport _inregistry_version _inregistry_revision _inregistry_variants prefix user_options
foreach {var backup} {_inregistry_version version _inregistry_revision revision _inregistry_variants portvariants} {
if {![info exists $var]} {
set $var [option $backup]
}
}
set reg_options [dict create {*}[array get user_options]]
set renames [dict create]
portstartupitem::foreach_startupitem {
if {$si_install} {
dict set renames ${prefix}/etc/${si_location}/${si_plist} /Library/${si_location}/${si_plist}
} else {
dict set renames /Library/${si_location}/${si_plist} ${prefix}/etc/${si_location}/${si_plist}
}
}
dict set reg_options portactivate_rename_files $renames
registry_activate $subport $_inregistry_version $_inregistry_revision $_inregistry_variants $reg_options
return 0
}
proc activate_finish {args} {
global subport PortInfo startupitem_autostart
# Do this _after_ activate_main, because post-activate hooks might create
# the files needed for this
# The option from macports.conf can override the portfile here.
if {[tbool startupitem_autostart]} {
global portstartupitem::autostart_only
set autostart_only yes
if {[eval_targets "load"]} {
ui_error [format [msgcat::mc "Failed to load %s"] $subport]
unset autostart_only
return 1
}
unset autostart_only
}
# Save notes for display by the port client
if {[info exists PortInfo(notes)] && [llength $PortInfo(notes)] > 0} {
ui_notifications_append $subport $PortInfo(notes)
}
return 0
}
}
+1 -29
View File
@@ -31,13 +31,12 @@
#
package provide portbuild 1.0
package require portutil 1.0
package require portprogress 1.0
set org.macports.build [target_new org.macports.build portbuild::build_main]
target_provides ${org.macports.build} build
target_requires ${org.macports.build} main fetch checksum extract patch configure
target_prerun ${org.macports.build} portbuild::build_start
target_runpkg ${org.macports.build} portbuild_run
namespace eval portbuild {
}
@@ -63,8 +62,6 @@ default build.target all
default build.type default
default use_parallel_build yes
set_ui_prefix
# Automatically called from macports1.0 after evaluating the Portfile. If
# ${build.type} == bsd, ensures bsdmake is present by adding a bin:-style
# dependency.
@@ -200,28 +197,3 @@ proc portbuild::build_getjobsarg {args} {
}
return " -j$jobs"
}
proc portbuild::build_start {args} {
global UI_PREFIX subport
ui_notice "$UI_PREFIX [format [msgcat::mc "Building %s"] ${subport}]"
global portconfigure::no_default_compiler_allowed
if {$no_default_compiler_allowed} {
ui_warn_once no_default_compiler_allowed "All compilers are either blacklisted or unavailable; defaulting to first fallback option"
}
}
proc portbuild::build_main {args} {
global build.cmd build.jobs_arg
if {${build.cmd} eq ""} {
error "No build command found"
}
set realcmd ${build.cmd}
append build.cmd ${build.jobs_arg}
command_exec -callback portprogress::target_progress_callback build
set build.cmd ${realcmd}
return 0
}
+32
View File
@@ -0,0 +1,32 @@
package provide portbuild_run 1.0
package require portutil 1.0
package require portprogress 1.0
namespace eval portbuild {
proc build_start {args} {
global UI_PREFIX subport
ui_notice "$UI_PREFIX [format [msgcat::mc "Building %s"] ${subport}]"
global portconfigure::no_default_compiler_allowed
if {$no_default_compiler_allowed} {
ui_warn_once no_default_compiler_allowed "All compilers are either blacklisted or unavailable; defaulting to first fallback option"
}
}
proc build_main {args} {
global build.cmd build.jobs_arg
if {${build.cmd} eq ""} {
error "No build command found"
}
set realcmd ${build.cmd}
append build.cmd ${build.jobs_arg}
command_exec -callback portprogress::target_progress_callback build
set build.cmd ${realcmd}
return 0
}
}
+1 -368
View File
@@ -1,377 +1,10 @@
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
# portbump.tcl
#
# Copyright (c) 2019 The MacPorts Project
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of Apple Inc. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
package provide portbump 1.0
package require portutil 1.0
package require portchecksum 1.0
set org.macports.bump [target_new org.macports.bump portbump::bump_main]
target_provides ${org.macports.bump} bump
target_runtype ${org.macports.bump} always
target_requires ${org.macports.bump} main fetch
target_prerun ${org.macports.bump} portbump::bump_start
namespace eval portbump {
}
# replace_checksums
#
# Replace old checksum hash values with new ones in a list of lines.
# Returns a list of two elements: the modified lines and a list of
# line indices where replacements were made.
#
# Checksum values (hex hashes and integer sizes) are matched as whole
# words using \y word-boundary anchors (Tcl ARE syntax), so a size
# like 123 cannot accidentally match inside a larger value such as
# 12345. All checksum values are alphanumeric ([0-9a-f]+ or [0-9]+)
# and contain no regex metacharacters, so they are safe to interpolate
# directly into the pattern.
#
# lines - list of Portfile lines
# both_checksums - list of {type old_sum new_sum} triples
proc portbump::replace_checksums {lines both_checksums} {
set checksum_lines [list]
foreach {type sum calculated_sum} $both_checksums {
if {$sum eq $calculated_sum} {
continue
}
for {set i 0} {$i < [llength $lines]} {incr i} {
set line [lindex $lines $i]
if {[regsub -all "\\y${sum}\\y" $line $calculated_sum new_line]} {
lset lines $i $new_line
lappend checksum_lines $i
}
}
}
return [list $lines $checksum_lines]
}
# find_revision_line
#
# Find the line index of the revision that should be reset for the
# given subport. Handles Portfiles with multiple revision lines across
# subport blocks, conditional branches, or inline subport declarations
# (e.g. "subport foo { revision 3 }").
#
# Strategy:
# 1. If the current subport has an inline revision on its subport
# declaration line, use that.
# 2. Otherwise, use the standalone revision line nearest to the
# anchor (typically the first checksum line that was modified).
# When bumping the parent port, revision lines inside subport { }
# blocks are excluded.
#
# lines - list of Portfile lines
# subport - current subport name
# portname - parent port name
# anchor - line index to measure proximity from
#
# Returns: line index, or -1 if no revision line found
proc portbump::find_revision_line {lines subport portname anchor} {
# For a subport, prefer an inline revision on its subport declaration line
# (e.g. "subport clang-16 { revision 9 }").
if {$subport ne $portname} {
set escaped_subport [string map {\\ \\\\ . \\. * \\* + \\+ ? \\? ( \\( ) \\) \{ \\\{ \} \\\} \[ \\\[ \] \\\]} $subport]
for {set i 0} {$i < [llength $lines]} {incr i} {
if {[regexp "^\\s*subport\\s+\\S*${escaped_subport}\\S*\\s+.*revision\\s+\\d+" [lindex $lines $i]]} {
return $i
}
}
}
# When bumping the parent port, build an exclusion set of lines inside
# subport { } blocks so their revision lines are not mistakenly targeted.
set in_subport_block [dict create]
if {$subport eq $portname} {
set brace_depth 0
set in_subport 0
for {set i 0} {$i < [llength $lines]} {incr i} {
set line [lindex $lines $i]
if {!$in_subport && [regexp {^\s*subport\s+} $line]} {
set in_subport 1
set opens [regexp -all {\{} $line]
set closes [regexp -all {\}} $line]
set brace_depth [expr {$opens - $closes}]
dict set in_subport_block $i 1
if {$brace_depth <= 0} {
set in_subport 0
set brace_depth 0
}
} elseif {$in_subport} {
dict set in_subport_block $i 1
set opens [regexp -all {\{} $line]
set closes [regexp -all {\}} $line]
incr brace_depth [expr {$opens - $closes}]
if {$brace_depth <= 0} {
set in_subport 0
set brace_depth 0
}
}
}
}
# Find the nearest standalone revision line, skipping any inside subport blocks.
set best_line -1
set best_dist 2147483647
for {set i 0} {$i < [llength $lines]} {incr i} {
if {[regexp {^\s*revision\s+\d+} [lindex $lines $i]]} {
if {[dict exists $in_subport_block $i]} {
continue
}
set dist [expr {abs($i - $anchor)}]
if {$dist < $best_dist} {
set best_dist $dist
set best_line $i
}
}
}
return $best_line
}
# reset_revision
#
# Reset the revision value to 0 on the specified line.
# Returns the modified list of lines.
#
# lines - list of Portfile lines
# line_idx - index of the line to modify
proc portbump::reset_revision {lines line_idx} {
set old_line [lindex $lines $line_idx]
set new_line [regsub {(revision\s+)\d+} $old_line {\10}]
if {$old_line ne $new_line} {
lset lines $line_idx $new_line
}
return $lines
}
# bump_start
#
# Target prerun procedure; simply prints a message about what we're doing.
#
proc portbump::bump_start {args} {
global UI_PREFIX subport
ui_notice "$UI_PREFIX [format [msgcat::mc "Bumping checksums for %s"] ${subport}]"
}
# bump_main
#
# Target main procedure. Bumps the checksums for distfiles.
#
proc portbump::bump_main {args} {
global UI_PREFIX all_dist_files checksums_array portpath ports_bump_patch
set portfile "${portpath}/Portfile"
# If no files have been downloaded, there is nothing to bump.
if {![info exists all_dist_files]} {
return 0
}
# So far, no mismatches yet.
set mismatch no
set wrong_mimetype no
# Read the declared checksums from the port options.
set checksums_str [option checksums]
# If everything is fine with the syntax, keep on and check the checksum of
# the distfiles.
if {[portchecksum::parse_checksums $checksums_str] eq "yes"} {
global distpath
set both_checksums [list]
foreach distfile $all_dist_files {
ui_info "$UI_PREFIX [format [msgcat::mc "Checksumming %s"] $distfile]"
# Get the full path of the distfile.
set fullpath [file join $distpath $distfile]
if {![file isfile $fullpath]} {
return -code error "$distfile does not exist in $distpath"
}
# Check that there is at least one checksum for the distfile.
if {![info exists checksums_array($distfile)] || [llength $checksums_array($distfile)] < 1} {
ui_error "[format [msgcat::mc "No checksum set for %s"] $distfile]"
set mismatch yes
} else {
# Retrieve the list of types/values from the array.
set portfile_checksums $checksums_array($distfile)
# Iterate on this list to check the actual values.
foreach {type sum} $portfile_checksums {
set calculated_sum [portchecksum::calc_$type $fullpath]
lappend both_checksums $type $sum $calculated_sum
if {$sum eq $calculated_sum} {
ui_debug "[format [msgcat::mc "Correct (%s) bump for %s"] $type $distfile]"
} else {
ui_info "[format [msgcat::mc "Portfile bump: %s %s %s"] $distfile $type $sum]"
ui_info "[format [msgcat::mc "Distfile bump: %s %s %s"] $distfile $type $calculated_sum]"
# Raise the failure flag
set mismatch yes
}
}
if {![regexp {\.html?$} ${distfile}] &&
![catch {strsed [exec [findBinary file $::portutil::autoconf::file_path] $fullpath --brief --mime] {s/;.*$//}} mimetype]
&& "text/html" eq $mimetype} {
# file --mime-type would be preferable to file --mime and strsed, but is only available as of Snow Leopard
set wrong_mimetype yes
set htmlfile_path ${fullpath}.html
file rename -force $fullpath $htmlfile_path
}
}
}
} else {
# Something went wrong with the syntax.
return -code error "[msgcat::mc "Unable to verify file checksums"]"
}
if {![tbool mismatch]} {
ui_msg "No changes needed."
return 0
}
if {[tbool wrong_mimetype]} {
# We got an HTML file, though the distfile name does not suggest that one was
# expected. Probably a helpful DNS server sent us to its search results page
# instead of admitting that the server we asked for doesn't exist, or a mirror that
# no longer has the file served its error page with a 200 response.
ui_notice "***"
ui_notice "The non-matching file appears to be HTML. See this page for possible reasons"
ui_notice "for the bump mismatch:"
ui_notice "<https://trac.macports.org/wiki/MisbehavingServers>"
ui_notice "***"
ui_notice "The file has been moved to: $htmlfile_path"
return -code error "[msgcat::mc "Unable to verify file checksums"]"
} else {
global version subport
ui_msg "We will bump these:"
foreach {type sum calculated_sum} $both_checksums {
if {$sum eq $calculated_sum} {
continue
}
ui_msg [format "Old %-8s %s" ${type}: $sum]
ui_msg [format "New %-8s %s" ${type}: $calculated_sum]
}
# Get the uid of Portfile owner
set owneruid [name_to_uid [file attributes ${portfile} -owner]]
# root -> owner id
exec_as_uid $owneruid {
# Read the Portfile
set fd [open $portfile r]
set lines [split [read $fd] \n]
close $fd
# Get Portfile attributes
set attributes [file attributes $portfile]
lassign [portbump::replace_checksums $lines $both_checksums] lines checksum_lines
foreach cl $checksum_lines {
ui_debug "Replaced checksum on line [expr {$cl + 1}]"
}
if {[llength $checksum_lines] > 0} {
set rev_line [portbump::find_revision_line $lines $subport [option name] [lindex $checksum_lines 0]]
if {$rev_line >= 0} {
set old_rev [lindex $lines $rev_line]
set lines [portbump::reset_revision $lines $rev_line]
if {[lindex $lines $rev_line] ne $old_rev} {
ui_debug "Reset revision to 0 on line [expr {$rev_line + 1}]"
}
}
}
set new_content [join $lines \n]
if {[tbool ports_bump_patch]} {
# Patch mode
if {[catch {set tmpfd [file tempfile tmpfile ${portpath}/Portfile.bump]} error]} {
ui_debug $::errorInfo
ui_error "file tempfile: $error"
return -code error "file tempfile failed"
}
puts -nonewline $tmpfd $new_content
close $tmpfd
set patchfile "${portpath}/Portfile.patch"
set patchfd [open $patchfile w]
# Construct diff command
set diffcmd [list]
lappend diffcmd $::portutil::autoconf::diff_path -u --label old/Portfile --label new/Portfile
lappend diffcmd $portfile $tmpfile >@$patchfd
# Create and write diff to Portfile.patch
if {[catch {exec -ignorestderr -- {*}$diffcmd} error]} {
file attributes $patchfile {*}$attributes
ui_msg "Portfile.patch successfully created at $patchfile"
} else {
ui_msg "No changes needed."
file delete "$patchfile"
close $patchfd
}
file delete "$tmpfile"
} else {
# Overwrite mode
if {[catch {set tmpfd [file tempfile tmpfile ${portpath}/Portfile.bump]} error]} {
ui_debug $::errorInfo
ui_error "file tempfile: $error"
return -code error "file tempfile failed"
}
puts -nonewline $tmpfd $new_content
close $tmpfd
if {[catch {move -force $tmpfile $portfile} error]} {
ui_debug $::errorInfo
ui_error "bump: $error"
file delete "$tmpfile"
return -code error "bump overwrite failed"
}
# Restore Portfile attributes
file attributes $portfile {*}$attributes
ui_msg "Checksums successfully bumped. Suggested commit message:"
ui_msg [format "%-8s%s: update to %s" "" ${subport} $version]
}
}
return 0
}
}
target_runpkg ${org.macports.bump} portbump_run
+373
View File
@@ -0,0 +1,373 @@
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
# Copyright (c) 2019 The MacPorts Project
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of Apple Inc. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
package provide portbump_run 1.0
package require portutil 1.0
package require portchecksum 1.0
namespace eval portbump {
# replace_checksums
#
# Replace old checksum hash values with new ones in a list of lines.
# Returns a list of two elements: the modified lines and a list of
# line indices where replacements were made.
#
# Checksum values (hex hashes and integer sizes) are matched as whole
# words using \y word-boundary anchors (Tcl ARE syntax), so a size
# like 123 cannot accidentally match inside a larger value such as
# 12345. All checksum values are alphanumeric ([0-9a-f]+ or [0-9]+)
# and contain no regex metacharacters, so they are safe to interpolate
# directly into the pattern.
#
# lines - list of Portfile lines
# both_checksums - list of {type old_sum new_sum} triples
proc replace_checksums {lines both_checksums} {
set checksum_lines [list]
foreach {type sum calculated_sum} $both_checksums {
if {$sum eq $calculated_sum} {
continue
}
for {set i 0} {$i < [llength $lines]} {incr i} {
set line [lindex $lines $i]
if {[regsub -all "\\y${sum}\\y" $line $calculated_sum new_line]} {
lset lines $i $new_line
lappend checksum_lines $i
}
}
}
return [list $lines $checksum_lines]
}
# find_revision_line
#
# Find the line index of the revision that should be reset for the
# given subport. Handles Portfiles with multiple revision lines across
# subport blocks, conditional branches, or inline subport declarations
# (e.g. "subport foo { revision 3 }").
#
# Strategy:
# 1. If the current subport has an inline revision on its subport
# declaration line, use that.
# 2. Otherwise, use the standalone revision line nearest to the
# anchor (typically the first checksum line that was modified).
# When bumping the parent port, revision lines inside subport { }
# blocks are excluded.
#
# lines - list of Portfile lines
# subport - current subport name
# portname - parent port name
# anchor - line index to measure proximity from
#
# Returns: line index, or -1 if no revision line found
proc find_revision_line {lines subport portname anchor} {
# For a subport, prefer an inline revision on its subport declaration line
# (e.g. "subport clang-16 { revision 9 }").
if {$subport ne $portname} {
set escaped_subport [string map {\\ \\\\ . \\. * \\* + \\+ ? \\? ( \\( ) \\) \{ \\\{ \} \\\} \[ \\\[ \] \\\]} $subport]
for {set i 0} {$i < [llength $lines]} {incr i} {
if {[regexp "^\\s*subport\\s+\\S*${escaped_subport}\\S*\\s+.*revision\\s+\\d+" [lindex $lines $i]]} {
return $i
}
}
}
# When bumping the parent port, build an exclusion set of lines inside
# subport { } blocks so their revision lines are not mistakenly targeted.
set in_subport_block [dict create]
if {$subport eq $portname} {
set brace_depth 0
set in_subport 0
for {set i 0} {$i < [llength $lines]} {incr i} {
set line [lindex $lines $i]
if {!$in_subport && [regexp {^\s*subport\s+} $line]} {
set in_subport 1
set opens [regexp -all {\{} $line]
set closes [regexp -all {\}} $line]
set brace_depth [expr {$opens - $closes}]
dict set in_subport_block $i 1
if {$brace_depth <= 0} {
set in_subport 0
set brace_depth 0
}
} elseif {$in_subport} {
dict set in_subport_block $i 1
set opens [regexp -all {\{} $line]
set closes [regexp -all {\}} $line]
incr brace_depth [expr {$opens - $closes}]
if {$brace_depth <= 0} {
set in_subport 0
set brace_depth 0
}
}
}
}
# Find the nearest standalone revision line, skipping any inside subport blocks.
set best_line -1
set best_dist 2147483647
for {set i 0} {$i < [llength $lines]} {incr i} {
if {[regexp {^\s*revision\s+\d+} [lindex $lines $i]]} {
if {[dict exists $in_subport_block $i]} {
continue
}
set dist [expr {abs($i - $anchor)}]
if {$dist < $best_dist} {
set best_dist $dist
set best_line $i
}
}
}
return $best_line
}
# reset_revision
#
# Reset the revision value to 0 on the specified line.
# Returns the modified list of lines.
#
# lines - list of Portfile lines
# line_idx - index of the line to modify
proc reset_revision {lines line_idx} {
set old_line [lindex $lines $line_idx]
set new_line [regsub {(revision\s+)\d+} $old_line {\10}]
if {$old_line ne $new_line} {
lset lines $line_idx $new_line
}
return $lines
}
# bump_start
#
# Target prerun procedure; simply prints a message about what we're doing.
#
proc bump_start {args} {
global UI_PREFIX subport
ui_notice "$UI_PREFIX [format [msgcat::mc "Bumping checksums for %s"] ${subport}]"
}
# bump_main
#
# Target main procedure. Bumps the checksums for distfiles.
#
proc bump_main {args} {
global UI_PREFIX all_dist_files checksums_array portpath ports_bump_patch
set portfile "${portpath}/Portfile"
# If no files have been downloaded, there is nothing to bump.
if {![info exists all_dist_files]} {
return 0
}
package require portchecksum_run
# So far, no mismatches yet.
set mismatch no
set wrong_mimetype no
# Read the declared checksums from the port options.
set checksums_str [option checksums]
# If everything is fine with the syntax, keep on and check the checksum of
# the distfiles.
if {[portchecksum::parse_checksums $checksums_str] eq "yes"} {
global distpath
set both_checksums [list]
foreach distfile $all_dist_files {
ui_info "$UI_PREFIX [format [msgcat::mc "Checksumming %s"] $distfile]"
# Get the full path of the distfile.
set fullpath [file join $distpath $distfile]
if {![file isfile $fullpath]} {
return -code error "$distfile does not exist in $distpath"
}
# Check that there is at least one checksum for the distfile.
if {![info exists checksums_array($distfile)] || [llength $checksums_array($distfile)] < 1} {
ui_error "[format [msgcat::mc "No checksum set for %s"] $distfile]"
set mismatch yes
} else {
# Retrieve the list of types/values from the array.
set portfile_checksums $checksums_array($distfile)
# Iterate on this list to check the actual values.
foreach {type sum} $portfile_checksums {
set calculated_sum [portchecksum::calc_$type $fullpath]
lappend both_checksums $type $sum $calculated_sum
if {$sum eq $calculated_sum} {
ui_debug "[format [msgcat::mc "Correct (%s) bump for %s"] $type $distfile]"
} else {
ui_info "[format [msgcat::mc "Portfile bump: %s %s %s"] $distfile $type $sum]"
ui_info "[format [msgcat::mc "Distfile bump: %s %s %s"] $distfile $type $calculated_sum]"
# Raise the failure flag
set mismatch yes
}
}
if {![regexp {\.html?$} ${distfile}] &&
![catch {strsed [exec [findBinary file $::portutil::autoconf::file_path] $fullpath --brief --mime] {s/;.*$//}} mimetype]
&& "text/html" eq $mimetype} {
# file --mime-type would be preferable to file --mime and strsed, but is only available as of Snow Leopard
set wrong_mimetype yes
set htmlfile_path ${fullpath}.html
file rename -force $fullpath $htmlfile_path
}
}
}
} else {
# Something went wrong with the syntax.
return -code error "[msgcat::mc "Unable to verify file checksums"]"
}
if {![tbool mismatch]} {
ui_msg "No changes needed."
return 0
}
if {[tbool wrong_mimetype]} {
# We got an HTML file, though the distfile name does not suggest that one was
# expected. Probably a helpful DNS server sent us to its search results page
# instead of admitting that the server we asked for doesn't exist, or a mirror that
# no longer has the file served its error page with a 200 response.
ui_notice "***"
ui_notice "The non-matching file appears to be HTML. See this page for possible reasons"
ui_notice "for the bump mismatch:"
ui_notice "<https://trac.macports.org/wiki/MisbehavingServers>"
ui_notice "***"
ui_notice "The file has been moved to: $htmlfile_path"
return -code error "[msgcat::mc "Unable to verify file checksums"]"
} else {
global version subport
ui_msg "We will bump these:"
foreach {type sum calculated_sum} $both_checksums {
if {$sum eq $calculated_sum} {
continue
}
ui_msg [format "Old %-8s %s" ${type}: $sum]
ui_msg [format "New %-8s %s" ${type}: $calculated_sum]
}
# Get the uid of Portfile owner
set owneruid [name_to_uid [file attributes ${portfile} -owner]]
# root -> owner id
exec_as_uid $owneruid {
# Read the Portfile
set fd [open $portfile r]
set lines [split [read $fd] \n]
close $fd
# Get Portfile attributes
set attributes [file attributes $portfile]
lassign [replace_checksums $lines $both_checksums] lines checksum_lines
foreach cl $checksum_lines {
ui_debug "Replaced checksum on line [expr {$cl + 1}]"
}
if {[llength $checksum_lines] > 0} {
set rev_line [find_revision_line $lines $subport [option name] [lindex $checksum_lines 0]]
if {$rev_line >= 0} {
set old_rev [lindex $lines $rev_line]
set lines [reset_revision $lines $rev_line]
if {[lindex $lines $rev_line] ne $old_rev} {
ui_debug "Reset revision to 0 on line [expr {$rev_line + 1}]"
}
}
}
set new_content [join $lines \n]
if {[tbool ports_bump_patch]} {
# Patch mode
if {[catch {set tmpfd [file tempfile tmpfile ${portpath}/Portfile.bump]} error]} {
ui_debug $::errorInfo
ui_error "file tempfile: $error"
return -code error "file tempfile failed"
}
puts -nonewline $tmpfd $new_content
close $tmpfd
set patchfile "${portpath}/Portfile.patch"
set patchfd [open $patchfile w]
# Construct diff command
set diffcmd [list]
lappend diffcmd $::portutil::autoconf::diff_path -u --label old/Portfile --label new/Portfile
lappend diffcmd $portfile $tmpfile >@$patchfd
# Create and write diff to Portfile.patch
if {[catch {exec -ignorestderr -- {*}$diffcmd} error]} {
file attributes $patchfile {*}$attributes
ui_msg "Portfile.patch successfully created at $patchfile"
} else {
ui_msg "No changes needed."
file delete "$patchfile"
close $patchfd
}
file delete "$tmpfile"
} else {
# Overwrite mode
if {[catch {set tmpfd [file tempfile tmpfile ${portpath}/Portfile.bump]} error]} {
ui_debug $::errorInfo
ui_error "file tempfile: $error"
return -code error "file tempfile failed"
}
puts -nonewline $tmpfd $new_content
close $tmpfd
if {[catch {move -force $tmpfile $portfile} error]} {
ui_debug $::errorInfo
ui_error "bump: $error"
file delete "$tmpfile"
return -code error "bump overwrite failed"
}
# Restore Portfile attributes
file attributes $portfile {*}$attributes
ui_msg "Checksums successfully bumped. Suggested commit message:"
ui_msg [format "%-8s%s: update to %s" "" ${subport} $version]
}
}
return 0
}
}
}
+2 -376
View File
@@ -1,43 +1,12 @@
# et:ts=4
# portchecksum.tcl
#
# Copyright (c) 2002 - 2004 Apple Inc.
# Copyright (c) 2004 - 2005 Paul Guyot <pguyot@kallisys.net>
# Copyright (c) 2006 - 2012, 2014 - 2016, 2018 The MacPorts Project
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of Apple Inc. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
package provide portchecksum 1.0
package require portutil 1.0
set org.macports.checksum [target_new org.macports.checksum portchecksum::checksum_main]
target_provides ${org.macports.checksum} checksum
target_requires ${org.macports.checksum} main fetch
target_prerun ${org.macports.checksum} portchecksum::checksum_start
target_runpkg ${org.macports.checksum} portchecksum_run
namespace eval portchecksum {
@@ -57,346 +26,3 @@ options checksums checksum.skip
# Defaults
default checksums {}
default checksum.skip false
set_ui_prefix
# verify_checksum_format
#
# Given a checksum type as string and the actual checksum:
#
# - return 1 if the value has the expected format
# - return 0 if the value does not look as expected
# - return -1 if the checksum type is unrecognized
proc portchecksum::verify_checksum_format {type value} {
set result 0
switch [string tolower $type] {
sha256 -
blake3 {
set result [regexp {^[0-9a-f]{64}$} $value]
}
rmd160 -
sha1 {
set result [regexp {^[0-9a-f]{40}$} $value]
}
md5 {
set result [regexp {^[0-9a-f]{32}$} $value]
}
size {
set result [regexp {^\d+$} $value]
}
default {
# unrecognized checksum type
set result -1
}
}
return $result
}
# Using global all_dist_files, parse the checksums and store them into the
# global array checksums_array.
#
# There are two formats:
# type value [type value [type value]] for a single file
# file1 type value [type value [type value]] [file2 ...] for multiple files.
#
# Portfile is in format #1 if:
# (1) There is only one distfile.
# (2) There are an even number of words in checksums (i.e. "md5 cksum sha1 cksum" = 4 words).
# (3) There are no more checksums specified than $portchecksum::checksum_types contains.
# (4) first word is one of the checksums types.
#
# return yes if the syntax was correct, no if there was a problem.
proc portchecksum::parse_checksums {checksums_str} {
global checksums_array all_dist_files
variable checksum_types
# Parse the string of checksums.
set nb_checksum [llength $checksums_str]
if {[llength $all_dist_files] == 1
&& [expr {$nb_checksum % 2}] == 0
&& [expr {$nb_checksum / 2}] <= [llength $checksum_types]
&& [lindex $checksums_str 0] in $checksum_types} {
# Convert to format #2
set checksums_str [linsert $checksums_str 0 [lindex $all_dist_files 0]]
# We increased the size.
incr nb_checksum
}
# Create the array with the checksums.
array set checksums_array {}
set result yes
# Catch out of bounds errors (they're syntax errors).
if {[catch {
# Parse the string as if it was in format #2.
for {set ix_checksum 0} {$ix_checksum < $nb_checksum} {incr ix_checksum} {
# first word is the file.
set checksum_filename [lindex $checksums_str $ix_checksum]
# retrieve the list of values we already know for this file.
set checksum_values {}
if {[info exists checksums_array($checksum_filename)]} {
set checksum_values $checksums_array($checksum_filename)
}
# append the new value
incr ix_checksum
while {1} {
set checksum_type [lindex $checksums_str $ix_checksum]
if {$checksum_type in $checksum_types} {
# append the type and the value.
incr ix_checksum
set checksum_value [lindex $checksums_str $ix_checksum]
incr ix_checksum
lappend checksum_values $checksum_type
lappend checksum_values $checksum_value
} else {
# this wasn't a type but the next dist file.
incr ix_checksum -1
break
}
# stop if we exhausted all the items in the list.
if {$ix_checksum == $nb_checksum} {
break
}
}
# set the values in the array.
set checksums_array($checksum_filename) $checksum_values
}
} error]} {
# An error occurred.
ui_debug $::errorInfo
ui_error "Couldn't parse checksum line ($checksums_str) [$error]"
# Something wrong happened.
set result no
}
return $result
}
# calc_md5
#
# Calculate the md5 checksum for the given file.
# Return the checksum.
#
proc portchecksum::calc_md5 {file} {
return [md5 file $file]
}
# calc_sha1
#
# Calculate the sha1 checksum for the given file.
# Return the checksum.
#
proc portchecksum::calc_sha1 {file} {
return [sha1 file $file]
}
# calc_rmd160
#
# Calculate the rmd160 checksum for the given file.
# Return the checksum.
#
proc portchecksum::calc_rmd160 {file} {
return [rmd160 file $file]
}
# calc_sha256
#
# Calculate the sha256 checksum for the given file.
# Return the checksum.
#
proc portchecksum::calc_sha256 {file} {
return [sha256 file $file]
}
# calc_blake3
#
# Calculate the blake3 checksum for the given file.
# Return the checksum.
#
proc portchecksum::calc_blake3 {file} {
return [blake3 file $file]
}
# calc_size
#
# Get the size of the given file.
# Return the size.
#
proc portchecksum::calc_size {file} {
return [file size $file]
}
# checksum_start
#
# Target prerun procedure; simply prints a message about what we're doing.
#
proc portchecksum::checksum_start {args} {
global UI_PREFIX
ui_notice "$UI_PREFIX [format [msgcat::mc "Verifying checksums for %s"] [option subport]]"
}
# checksum_main
#
# Target main procedure. Verifies the checksums of all distfiles.
#
proc portchecksum::checksum_main {args} {
global UI_PREFIX all_dist_files checksums_array checksum.skip distpath
# If no files have been downloaded, there is nothing to checksum.
if {![info exists all_dist_files]} {
return 0
}
# Completely bypass checksumming if checksum.skip=yes
# This should be considered an extreme measure
if {[tbool checksum.skip]} {
ui_info "$UI_PREFIX Skipping checksum phase"
return 0
}
# so far, everything went fine.
set fail no
# Set the list of checksums as the option checksums.
set checksums_str [option checksums]
# store the calculated checksums to avoid repeated calculations
array set calculated_checksums_array {}
# if everything is fine with the syntax, keep on and check the checksum of
# the distfiles.
if {[parse_checksums $checksums_str] eq "yes"} {
foreach distfile $all_dist_files {
ui_info "$UI_PREFIX [format [msgcat::mc "Checksumming %s"] $distfile]"
# get the full path of the distfile.
set fullpath [file join $distpath $distfile]
if {![file isfile $fullpath]} {
return -code error "$distfile does not exist in $distpath"
}
# check that there is at least one checksum for the distfile.
if {![info exists checksums_array($distfile)] || [llength $checksums_array($distfile)] < 1} {
ui_error "[format [msgcat::mc "No checksum set for %s"] $distfile]"
set fail yes
} else {
# retrieve the list of types/values from the array.
set portfile_checksums $checksums_array($distfile)
set calculated_checksums [list]
# iterate on this list to check the actual values.
foreach {type sum} $portfile_checksums {
set calculated_sum [calc_$type $fullpath]
lappend calculated_checksums $type
lappend calculated_checksums $calculated_sum
# Used for regression testing
ui_debug "[format [msgcat::mc "Calculated (%s) is %s"] $type $calculated_sum]"
if {$sum eq $calculated_sum} {
ui_debug "[format [msgcat::mc "Correct (%s) checksum for %s"] $type $distfile]"
} else {
ui_error "[format [msgcat::mc "Checksum (%s) mismatch for %s"] $type $distfile]"
ui_info "[format [msgcat::mc "Portfile checksum: %s %s %s"] $distfile $type $sum]"
ui_info "[format [msgcat::mc "Distfile checksum: %s %s %s"] $distfile $type $calculated_sum]"
# Raise the failure flag
set fail yes
}
}
# Save our calculated checksums in case we need them later
set calculated_checksums_array($distfile) $calculated_checksums
if {[tbool fail] && ![regexp {\.html?$} ${distfile}] &&
![catch {strsed [exec [findBinary file $::portutil::autoconf::file_path] $fullpath --brief --mime] {s/;.*$//}} mimetype]
&& "text/html" eq $mimetype} {
# file --mime-type would be preferable to file --mime and strsed, but is only available as of Snow Leopard
set wrong_mimetype yes
set htmlfile_path ${fullpath}.html
file rename -force $fullpath $htmlfile_path
}
}
}
} else {
# Something went wrong with the syntax.
set fail yes
}
if {[tbool fail]} {
if {[tbool wrong_mimetype]} {
# We got an HTML file, though the distfile name does not suggest that one was
# expected. Probably a helpful DNS server sent us to its search results page
# instead of admitting that the server we asked for doesn't exist, or a mirror that
# no longer has the file served its error page with a 200 response.
ui_notice "***"
ui_notice "The non-matching file appears to be HTML. See this page for possible reasons"
ui_notice "for the checksum mismatch:"
ui_notice "<https://trac.macports.org/wiki/MisbehavingServers>"
ui_notice "***"
ui_notice "The file has been moved to: $htmlfile_path"
} else {
# Show the desired checksum line for easy cut-paste
# based on the previously calculated values, plus our default types
set sums [list]
variable default_checksum_types
foreach distfile $all_dist_files {
if {[llength $all_dist_files] > 1} {
lappend sums $distfile
}
set missing_types $default_checksum_types
# Append the string for the calculated types and note any of
# our default types that were already calculated
if {[info exists calculated_checksums_array($distfile)] && [llength $calculated_checksums_array($distfile)]} {
set calculated_checksums $calculated_checksums_array($distfile)
foreach {type sum} $calculated_checksums {
lappend sums [format "%-8s%s" $type $sum]
set found [lsearch -exact ${missing_types} ${type}]
if { ${found} != -1} {
lpop missing_types ${found}
}
}
}
# Append the string for any of our default types that were
# note previously calculated
if {[llength $missing_types]} {
# get the full path of the distfile.
set fullpath [file join $distpath $distfile]
if {![file isfile $fullpath]} {
return -code error "$distfile does not exist in $distpath"
}
foreach type $missing_types {
lappend sums [format "%-8s%s" $type [calc_$type $fullpath]]
}
}
}
ui_info "The correct checksum line may be:"
ui_info [format "%-20s%s" "checksums" [join $sums [format " \\\n%-20s" ""]]]
}
return -code error "[msgcat::mc "Unable to verify file checksums"]"
}
return 0
}
+345
View File
@@ -0,0 +1,345 @@
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
#
# Copyright (c) 2002 - 2004 Apple Inc.
# Copyright (c) 2004 - 2005 Paul Guyot <pguyot@kallisys.net>
# Copyright (c) 2006 - 2012, 2014 - 2016, 2018 The MacPorts Project
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of Apple Inc. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
package provide portchecksum_run 1.0
package require portutil 1.0
package require Pextlib 1.0
namespace eval portchecksum {
# Using global all_dist_files, parse the checksums and store them into the
# global array checksums_array.
#
# There are two formats:
# type value [type value [type value]] for a single file
# file1 type value [type value [type value]] [file2 ...] for multiple files.
#
# Portfile is in format #1 if:
# (1) There is only one distfile.
# (2) There are an even number of words in checksums (i.e. "md5 cksum sha1 cksum" = 4 words).
# (3) There are no more checksums specified than $portchecksum::checksum_types contains.
# (4) first word is one of the checksums types.
#
# return yes if the syntax was correct, no if there was a problem.
proc parse_checksums {checksums_str} {
global checksums_array all_dist_files
variable checksum_types
# Parse the string of checksums.
set nb_checksum [llength $checksums_str]
if {[llength $all_dist_files] == 1
&& [expr {$nb_checksum % 2}] == 0
&& [expr {$nb_checksum / 2}] <= [llength $checksum_types]
&& [lindex $checksums_str 0] in $checksum_types} {
# Convert to format #2
set checksums_str [linsert $checksums_str 0 [lindex $all_dist_files 0]]
# We increased the size.
incr nb_checksum
}
# Create the array with the checksums.
array set checksums_array {}
set result yes
# Catch out of bounds errors (they're syntax errors).
if {[catch {
# Parse the string as if it was in format #2.
for {set ix_checksum 0} {$ix_checksum < $nb_checksum} {incr ix_checksum} {
# first word is the file.
set checksum_filename [lindex $checksums_str $ix_checksum]
# retrieve the list of values we already know for this file.
set checksum_values {}
if {[info exists checksums_array($checksum_filename)]} {
set checksum_values $checksums_array($checksum_filename)
}
# append the new value
incr ix_checksum
while {1} {
set checksum_type [lindex $checksums_str $ix_checksum]
if {$checksum_type in $checksum_types} {
# append the type and the value.
incr ix_checksum
set checksum_value [lindex $checksums_str $ix_checksum]
incr ix_checksum
lappend checksum_values $checksum_type
lappend checksum_values $checksum_value
} else {
# this wasn't a type but the next dist file.
incr ix_checksum -1
break
}
# stop if we exhausted all the items in the list.
if {$ix_checksum == $nb_checksum} {
break
}
}
# set the values in the array.
set checksums_array($checksum_filename) $checksum_values
}
} error]} {
# An error occurred.
ui_debug $::errorInfo
ui_error "Couldn't parse checksum line ($checksums_str) [$error]"
# Something wrong happened.
set result no
}
return $result
}
# calc_md5
#
# Calculate the md5 checksum for the given file.
# Return the checksum.
#
proc calc_md5 {file} {
return [md5 file $file]
}
# calc_sha1
#
# Calculate the sha1 checksum for the given file.
# Return the checksum.
#
proc calc_sha1 {file} {
return [sha1 file $file]
}
# calc_rmd160
#
# Calculate the rmd160 checksum for the given file.
# Return the checksum.
#
proc calc_rmd160 {file} {
return [rmd160 file $file]
}
# calc_sha256
#
# Calculate the sha256 checksum for the given file.
# Return the checksum.
#
proc calc_sha256 {file} {
return [sha256 file $file]
}
# calc_blake3
#
# Calculate the blake3 checksum for the given file.
# Return the checksum.
#
proc calc_blake3 {file} {
return [blake3 file $file]
}
# calc_size
#
# Get the size of the given file.
# Return the size.
#
proc calc_size {file} {
return [file size $file]
}
# checksum_start
#
# Target prerun procedure; simply prints a message about what we're doing.
#
proc checksum_start {args} {
global UI_PREFIX
ui_notice "$UI_PREFIX [format [msgcat::mc "Verifying checksums for %s"] [option subport]]"
}
# checksum_main
#
# Target main procedure. Verifies the checksums of all distfiles.
#
proc checksum_main {args} {
global UI_PREFIX all_dist_files checksums_array checksum.skip distpath
# If no files have been downloaded, there is nothing to checksum.
if {![info exists all_dist_files]} {
return 0
}
# Completely bypass checksumming if checksum.skip=yes
# This should be considered an extreme measure
if {[tbool checksum.skip]} {
ui_info "$UI_PREFIX Skipping checksum phase"
return 0
}
# so far, everything went fine.
set fail no
# Set the list of checksums as the option checksums.
set checksums_str [option checksums]
# store the calculated checksums to avoid repeated calculations
array set calculated_checksums_array {}
# if everything is fine with the syntax, keep on and check the checksum of
# the distfiles.
if {[parse_checksums $checksums_str] eq "yes"} {
foreach distfile $all_dist_files {
ui_info "$UI_PREFIX [format [msgcat::mc "Checksumming %s"] $distfile]"
# get the full path of the distfile.
set fullpath [file join $distpath $distfile]
if {![file isfile $fullpath]} {
return -code error "$distfile does not exist in $distpath"
}
# check that there is at least one checksum for the distfile.
if {![info exists checksums_array($distfile)] || [llength $checksums_array($distfile)] < 1} {
ui_error "[format [msgcat::mc "No checksum set for %s"] $distfile]"
set fail yes
} else {
# retrieve the list of types/values from the array.
set portfile_checksums $checksums_array($distfile)
set calculated_checksums [list]
# iterate on this list to check the actual values.
foreach {type sum} $portfile_checksums {
set calculated_sum [calc_$type $fullpath]
lappend calculated_checksums $type
lappend calculated_checksums $calculated_sum
# Used for regression testing
ui_debug "[format [msgcat::mc "Calculated (%s) is %s"] $type $calculated_sum]"
if {$sum eq $calculated_sum} {
ui_debug "[format [msgcat::mc "Correct (%s) checksum for %s"] $type $distfile]"
} else {
ui_error "[format [msgcat::mc "Checksum (%s) mismatch for %s"] $type $distfile]"
ui_info "[format [msgcat::mc "Portfile checksum: %s %s %s"] $distfile $type $sum]"
ui_info "[format [msgcat::mc "Distfile checksum: %s %s %s"] $distfile $type $calculated_sum]"
# Raise the failure flag
set fail yes
}
}
# Save our calculated checksums in case we need them later
set calculated_checksums_array($distfile) $calculated_checksums
if {[tbool fail] && ![regexp {\.html?$} ${distfile}] &&
![catch {strsed [exec [findBinary file $::portutil::autoconf::file_path] $fullpath --brief --mime] {s/;.*$//}} mimetype]
&& "text/html" eq $mimetype} {
# file --mime-type would be preferable to file --mime and strsed, but is only available as of Snow Leopard
set wrong_mimetype yes
set htmlfile_path ${fullpath}.html
file rename -force $fullpath $htmlfile_path
}
}
}
} else {
# Something went wrong with the syntax.
set fail yes
}
if {[tbool fail]} {
if {[tbool wrong_mimetype]} {
# We got an HTML file, though the distfile name does not suggest that one was
# expected. Probably a helpful DNS server sent us to its search results page
# instead of admitting that the server we asked for doesn't exist, or a mirror that
# no longer has the file served its error page with a 200 response.
ui_notice "***"
ui_notice "The non-matching file appears to be HTML. See this page for possible reasons"
ui_notice "for the checksum mismatch:"
ui_notice "<https://trac.macports.org/wiki/MisbehavingServers>"
ui_notice "***"
ui_notice "The file has been moved to: $htmlfile_path"
} else {
# Show the desired checksum line for easy cut-paste
# based on the previously calculated values, plus our default types
set sums [list]
variable default_checksum_types
foreach distfile $all_dist_files {
if {[llength $all_dist_files] > 1} {
lappend sums $distfile
}
set missing_types $default_checksum_types
# Append the string for the calculated types and note any of
# our default types that were already calculated
if {[info exists calculated_checksums_array($distfile)] && [llength $calculated_checksums_array($distfile)]} {
set calculated_checksums $calculated_checksums_array($distfile)
foreach {type sum} $calculated_checksums {
lappend sums [format "%-8s%s" $type $sum]
set found [lsearch -exact ${missing_types} ${type}]
if { ${found} != -1} {
lpop missing_types ${found}
}
}
}
# Append the string for any of our default types that were
# note previously calculated
if {[llength $missing_types]} {
# get the full path of the distfile.
set fullpath [file join $distpath $distfile]
if {![file isfile $fullpath]} {
return -code error "$distfile does not exist in $distpath"
}
foreach type $missing_types {
lappend sums [format "%-8s%s" $type [calc_$type $fullpath]]
}
}
}
ui_info "The correct checksum line may be:"
ui_info [format "%-20s%s" "checksums" [join $sums [format " \\\n%-20s" ""]]]
}
return -code error "[msgcat::mc "Unable to verify file checksums"]"
}
return 0
}
}
+1 -287
View File
@@ -1,40 +1,8 @@
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
#
# Copyright (c) 2005-2007, 2009-2011, 2013 The MacPorts Project
# Copyright (c) 2004 Robert Shaw <rshaw@opendarwin.org>
# Copyright (c) 2002 - 2003 Apple Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of Apple Inc. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# the 'clean' target is provided by this package
package provide portclean 1.0
package require portutil 1.0
package require Pextlib 1.0
set org.macports.clean [target_new org.macports.clean portclean::clean_main]
target_runtype ${org.macports.clean} always
@@ -42,258 +10,4 @@ target_state ${org.macports.clean} no
target_provides ${org.macports.clean} clean
target_requires ${org.macports.clean} main
target_prerun ${org.macports.clean} portclean::clean_start
namespace eval portclean {
}
set_ui_prefix
proc portclean::clean_start {args} {
global UI_PREFIX
ui_notice "$UI_PREFIX [format [msgcat::mc "Cleaning %s"] [option subport]]"
if {[getuid] == 0 && [geteuid] != 0} {
elevateToRoot "clean"
}
}
proc portclean::clean_main {args} {
global UI_PREFIX ports_clean_dist ports_clean_work ports_clean_logs \
ports_clean_archive ports_clean_all keeplogs
if {[info exists ports_clean_all] && $ports_clean_all eq "yes" || \
[info exists ports_clean_dist] && $ports_clean_dist eq "yes"} {
ui_info "$UI_PREFIX [format [msgcat::mc "Removing distfiles for %s"] [option subport]]"
clean_dist
}
if {[info exists ports_clean_all] && $ports_clean_all eq "yes" || \
[info exists ports_clean_archive] && $ports_clean_archive eq "yes"} {
ui_info "$UI_PREFIX [format [msgcat::mc "Removing temporary archives for %s"] [option subport]]"
clean_archive
}
if {[info exists ports_clean_all] && $ports_clean_all eq "yes" || \
[info exists ports_clean_work] && $ports_clean_work eq "yes" || \
[info exists ports_clean_archive] && $ports_clean_archive eq "yes" || \
[info exists ports_clean_dist] && $ports_clean_dist eq "yes" || \
!([info exists ports_clean_logs] && $ports_clean_logs eq "yes")} {
ui_info "$UI_PREFIX [format [msgcat::mc "Removing work directory for %s"] [option subport]]"
clean_work
}
if {([info exists ports_clean_logs] && $ports_clean_logs eq "yes") || ($keeplogs eq "no")} {
clean_logs
}
return 0
}
#
# Remove the directory where the distfiles reside.
# This is crude, but works.
#
proc portclean::clean_dist {args} {
global name ports_force distpath dist_subdir distfiles patchfiles portdbpath
# remove known distfiles for sure (if they exist)
set count 0
foreach file $distfiles {
set distfile [getdistname $file]
ui_debug "Looking for $distfile"
set distfile [file join $distpath $distfile]
if {[file isfile $distfile]} {
ui_debug "Removing file: $distfile"
if {[catch {delete $distfile} result]} {
ui_debug "$::errorInfo"
ui_error "$result"
}
incr count
}
}
if {$count > 0} {
ui_debug "$count distfile(s) removed."
} else {
ui_debug "No distfiles found to remove at $distpath"
}
set count 0
if {![info exists patchfiles]} {
set patchfiles [list]
}
foreach file $patchfiles {
set patchfile [getdistname $file]
ui_debug "Looking for $patchfile"
set patchfile [file join $distpath $patchfile]
if {[file isfile $patchfile]} {
ui_debug "Removing file: $patchfile"
if {[catch {delete $patchfile} result]} {
ui_debug "$::errorInfo"
ui_error "$result"
}
incr count
}
}
if {$count > 0} {
ui_debug "$count patchfile(s) removed."
} else {
ui_debug "No patchfiles found to remove at $distpath"
}
# next remove dist_subdir if only needed for this port,
# or if user forces us to
set dirlist [list]
if {$dist_subdir ne $name} {
if {!([info exists ports_force] && $ports_force eq "yes")
&& [file isdirectory $distpath]
&& ![dirempty $distpath]} {
ui_warn [format [msgcat::mc "Distfiles directory '%s' may contain distfiles needed for other ports, use the -f flag to force removal" ] $distpath]
} else {
lappend dirlist $dist_subdir
lappend dirlist $name
}
} else {
lappend dirlist $name
}
# loop through directories
set count 0
foreach dir $dirlist {
set distdir [file join ${portdbpath} distfiles $dir]
if {[file isdirectory $distdir]} {
ui_debug "Removing directory: ${distdir}"
if {[catch {delete $distdir} result]} {
ui_debug "$::errorInfo"
ui_error "$result"
}
incr count
}
}
if {$count > 0} {
ui_debug "$count distfile directory(s) removed."
} else {
ui_debug "No distfile directory found to remove."
}
return 0
}
proc portclean::clean_work {args} {
global portbuildpath subbuildpath worksymlink subport
if {[file isdirectory $subbuildpath]} {
ui_debug "Removing directory: ${subbuildpath}"
macports_try -pass_signal {
delete $subbuildpath
} on error {eMessage} {
ui_debug "$::errorInfo"
ui_error "$eMessage"
}
} else {
ui_debug "No work directory found to remove at ${subbuildpath}"
}
set old_buildpath [portutil::get_oldbuildpath]
set old_subbbuildpath [file join $old_buildpath $subport]
if {[catch {set old_subbbuildpath_norm [realpath $old_subbbuildpath]}]} {
set old_subbbuildpath_norm [file normalize $old_subbbuildpath]
}
if {$old_subbbuildpath_norm ne $old_subbbuildpath && [file isdirectory $old_subbbuildpath_norm]} {
ui_debug "Removing directory: ${old_subbbuildpath_norm}"
macports_try -pass_signal {
delete $old_subbbuildpath_norm
} on error {eMessage} {
ui_debug "$::errorInfo"
ui_error "$eMessage"
}
}
if {![catch {file type $old_subbbuildpath}]} {
ui_debug "Removing symlink: ${old_subbbuildpath}"
macports_try -pass_signal {
delete $old_subbbuildpath
} on error {eMessage} {
ui_debug "$::errorInfo"
ui_error "$eMessage"
}
}
# silently fail if non-empty (other subports might be using old_buildpath)
catch {file delete $old_buildpath}
# Clean symlink, if necessary
if {![catch {file type $worksymlink} result] && $result eq "link"} {
ui_debug "Removing symlink: $worksymlink"
delete $worksymlink
}
return 0
}
proc portclean::clean_logs {args} {
global portpath subport
set logpath [getportlogpath $portpath]
set subdir [file join $logpath $subport]
if {[file isdirectory $subdir]} {
ui_debug "Removing directory: ${subdir}"
if {[catch {delete $subdir} result]} {
ui_debug "$::errorInfo"
ui_error "$result"
}
catch {file delete $logpath}
} else {
ui_debug "No log directory found to remove at ${logpath}"
}
return 0
}
proc portclean::clean_archive {args} {
global subport ports_version_glob portdbpath
# Define archive destination directory, target filename, regex for archive name
set archivepath [file join $portdbpath incoming]
if {[info exists ports_version_glob]} {
# Match all possible archive variants that match the version
# glob specified by the user.
set fileglob "$subport-${ports_version_glob}*.*.*.*"
} else {
# Match all possible archives for this port.
set fileglob "$subport-*_*.*.*.*"
}
# Remove the archive files
set count 0
foreach dir [list $archivepath ${archivepath}/verified] {
set archivelist [glob -nocomplain -directory $dir $fileglob]
foreach path $archivelist {
# Make sure file is truly an archive file for this port, and not
# an accidental match with some other file that might exist. Also
# delete anything ending in .TMP since those are incomplete and
# thus can't be checked and aren't useful anyway.
set archivetype [string range [file extension $path] 1 end]
if {[file isfile $path] && ($archivetype eq "TMP"
|| [dict get [extract_archive_metadata $path $archivetype portname] portname] eq $subport)} {
ui_debug "Removing archive: $path"
if {[catch {delete $path} result]} {
ui_debug "$::errorInfo"
ui_error "$result"
}
if {$archivetype eq "TMP"} {
set path [file rootname $path]
}
foreach sigtype {rmd160 sig} {
if {[file isfile ${path}.${sigtype}]} {
ui_debug "Removing archive signature: ${path}.${sigtype}"
if {[catch {delete ${path}.${sigtype}} result]} {
ui_debug "$::errorInfo"
ui_error "$result"
}
}
}
incr count
}
}
}
if {$count > 0} {
ui_debug "$count archive(s) removed."
} else {
ui_debug "No archives found to remove at $archivepath"
}
return 0
}
target_runpkg ${org.macports.clean} portclean_run
+288
View File
@@ -0,0 +1,288 @@
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
#
# Copyright (c) 2005-2007, 2009-2011, 2013 The MacPorts Project
# Copyright (c) 2004 Robert Shaw <rshaw@opendarwin.org>
# Copyright (c) 2002 - 2003 Apple Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of Apple Inc. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
package provide portclean_run 1.0
package require portutil 1.0
package require Pextlib 1.0
namespace eval portclean {
proc clean_start {args} {
global UI_PREFIX
ui_notice "$UI_PREFIX [format [msgcat::mc "Cleaning %s"] [option subport]]"
if {[getuid] == 0 && [geteuid] != 0} {
elevateToRoot "clean"
}
}
proc clean_main {args} {
global UI_PREFIX ports_clean_dist ports_clean_work ports_clean_logs \
ports_clean_archive ports_clean_all keeplogs
if {[info exists ports_clean_all] && $ports_clean_all eq "yes" || \
[info exists ports_clean_dist] && $ports_clean_dist eq "yes"} {
ui_info "$UI_PREFIX [format [msgcat::mc "Removing distfiles for %s"] [option subport]]"
clean_dist
}
if {[info exists ports_clean_all] && $ports_clean_all eq "yes" || \
[info exists ports_clean_archive] && $ports_clean_archive eq "yes"} {
ui_info "$UI_PREFIX [format [msgcat::mc "Removing temporary archives for %s"] [option subport]]"
clean_archive
}
if {[info exists ports_clean_all] && $ports_clean_all eq "yes" || \
[info exists ports_clean_work] && $ports_clean_work eq "yes" || \
[info exists ports_clean_archive] && $ports_clean_archive eq "yes" || \
[info exists ports_clean_dist] && $ports_clean_dist eq "yes" || \
!([info exists ports_clean_logs] && $ports_clean_logs eq "yes")} {
ui_info "$UI_PREFIX [format [msgcat::mc "Removing work directory for %s"] [option subport]]"
clean_work
}
if {([info exists ports_clean_logs] && $ports_clean_logs eq "yes") || ($keeplogs eq "no")} {
clean_logs
}
return 0
}
#
# Remove the directory where the distfiles reside.
# This is crude, but works.
#
proc clean_dist {args} {
global name ports_force distpath dist_subdir distfiles patchfiles portdbpath
# remove known distfiles for sure (if they exist)
set count 0
foreach file $distfiles {
set distfile [getdistname $file]
ui_debug "Looking for $distfile"
set distfile [file join $distpath $distfile]
if {[file isfile $distfile]} {
ui_debug "Removing file: $distfile"
if {[catch {delete $distfile} result]} {
ui_debug "$::errorInfo"
ui_error "$result"
}
incr count
}
}
if {$count > 0} {
ui_debug "$count distfile(s) removed."
} else {
ui_debug "No distfiles found to remove at $distpath"
}
set count 0
if {![info exists patchfiles]} {
set patchfiles [list]
}
foreach file $patchfiles {
set patchfile [getdistname $file]
ui_debug "Looking for $patchfile"
set patchfile [file join $distpath $patchfile]
if {[file isfile $patchfile]} {
ui_debug "Removing file: $patchfile"
if {[catch {delete $patchfile} result]} {
ui_debug "$::errorInfo"
ui_error "$result"
}
incr count
}
}
if {$count > 0} {
ui_debug "$count patchfile(s) removed."
} else {
ui_debug "No patchfiles found to remove at $distpath"
}
# next remove dist_subdir if only needed for this port,
# or if user forces us to
set dirlist [list]
if {$dist_subdir ne $name} {
if {!([info exists ports_force] && $ports_force eq "yes")
&& [file isdirectory $distpath]
&& ![dirempty $distpath]} {
ui_warn [format [msgcat::mc "Distfiles directory '%s' may contain distfiles needed for other ports, use the -f flag to force removal" ] $distpath]
} else {
lappend dirlist $dist_subdir
lappend dirlist $name
}
} else {
lappend dirlist $name
}
# loop through directories
set count 0
foreach dir $dirlist {
set distdir [file join ${portdbpath} distfiles $dir]
if {[file isdirectory $distdir]} {
ui_debug "Removing directory: ${distdir}"
if {[catch {delete $distdir} result]} {
ui_debug "$::errorInfo"
ui_error "$result"
}
incr count
}
}
if {$count > 0} {
ui_debug "$count distfile directory(s) removed."
} else {
ui_debug "No distfile directory found to remove."
}
return 0
}
proc clean_work {args} {
global portbuildpath subbuildpath worksymlink subport
if {[file isdirectory $subbuildpath]} {
ui_debug "Removing directory: ${subbuildpath}"
macports_try -pass_signal {
delete $subbuildpath
} on error {eMessage} {
ui_debug "$::errorInfo"
ui_error "$eMessage"
}
} else {
ui_debug "No work directory found to remove at ${subbuildpath}"
}
set old_buildpath [portutil::get_oldbuildpath]
set old_subbbuildpath [file join $old_buildpath $subport]
if {[catch {set old_subbbuildpath_norm [realpath $old_subbbuildpath]}]} {
set old_subbbuildpath_norm [file normalize $old_subbbuildpath]
}
if {$old_subbbuildpath_norm ne $old_subbbuildpath && [file isdirectory $old_subbbuildpath_norm]} {
ui_debug "Removing directory: ${old_subbbuildpath_norm}"
macports_try -pass_signal {
delete $old_subbbuildpath_norm
} on error {eMessage} {
ui_debug "$::errorInfo"
ui_error "$eMessage"
}
}
if {![catch {file type $old_subbbuildpath}]} {
ui_debug "Removing symlink: ${old_subbbuildpath}"
macports_try -pass_signal {
delete $old_subbbuildpath
} on error {eMessage} {
ui_debug "$::errorInfo"
ui_error "$eMessage"
}
}
# silently fail if non-empty (other subports might be using old_buildpath)
catch {file delete $old_buildpath}
# Clean symlink, if necessary
if {![catch {file type $worksymlink} result] && $result eq "link"} {
ui_debug "Removing symlink: $worksymlink"
delete $worksymlink
}
return 0
}
proc clean_logs {args} {
global portpath subport
set logpath [getportlogpath $portpath]
set subdir [file join $logpath $subport]
if {[file isdirectory $subdir]} {
ui_debug "Removing directory: ${subdir}"
if {[catch {delete $subdir} result]} {
ui_debug "$::errorInfo"
ui_error "$result"
}
catch {file delete $logpath}
} else {
ui_debug "No log directory found to remove at ${logpath}"
}
return 0
}
proc clean_archive {args} {
global subport ports_version_glob portdbpath
# Define archive destination directory, target filename, regex for archive name
set archivepath [file join $portdbpath incoming]
if {[info exists ports_version_glob]} {
# Match all possible archive variants that match the version
# glob specified by the user.
set fileglob "$subport-${ports_version_glob}*.*.*.*"
} else {
# Match all possible archives for this port.
set fileglob "$subport-*_*.*.*.*"
}
# Remove the archive files
set count 0
foreach dir [list $archivepath ${archivepath}/verified] {
set archivelist [glob -nocomplain -directory $dir $fileglob]
foreach path $archivelist {
# Make sure file is truly an archive file for this port, and not
# an accidental match with some other file that might exist. Also
# delete anything ending in .TMP since those are incomplete and
# thus can't be checked and aren't useful anyway.
set archivetype [string range [file extension $path] 1 end]
if {[file isfile $path] && ($archivetype eq "TMP"
|| [dict get [extract_archive_metadata $path $archivetype portname] portname] eq $subport)} {
ui_debug "Removing archive: $path"
if {[catch {delete $path} result]} {
ui_debug "$::errorInfo"
ui_error "$result"
}
if {$archivetype eq "TMP"} {
set path [file rootname $path]
}
foreach sigtype {rmd160 sig} {
if {[file isfile ${path}.${sigtype}]} {
ui_debug "Removing archive signature: ${path}.${sigtype}"
if {[catch {delete ${path}.${sigtype}} result]} {
ui_debug "$::errorInfo"
ui_error "$result"
}
}
}
incr count
}
}
}
if {$count > 0} {
ui_debug "$count archive(s) removed."
} else {
ui_debug "No archives found to remove at $archivepath"
}
return 0
}
}
+7 -332
View File
@@ -31,14 +31,13 @@
#
package provide portconfigure 1.0
package require portutil 1.0
package require portprogress 1.0
set org.macports.configure [target_new org.macports.configure portconfigure::configure_main]
target_provides ${org.macports.configure} configure
target_requires ${org.macports.configure} main fetch checksum extract patch
target_prerun ${org.macports.configure} portconfigure::configure_start
target_postrun ${org.macports.configure} portconfigure::configure_finish
target_runpkg ${org.macports.configure} portconfigure_run
namespace eval portconfigure {
# configure_get_default_compiler is fairly expensive, so cache the result
@@ -359,79 +358,6 @@ default compiler.openmp_version {}
default compiler.mpi {}
default compiler.thread_local_storage no
set_ui_prefix
proc portconfigure::configure_start {args} {
global UI_PREFIX subport configure.compiler compiler.fallback configure.ccache
ui_notice "$UI_PREFIX [format [msgcat::mc "Configuring %s"] $subport]"
set compiler ${configure.compiler}
set valid_compilers {
{^apple-gcc-(4\.[02])$} {MacPorts Apple GCC %s}
{^cc$} {System cc}
{^clang$} {Xcode Clang}
{^gcc$} {System GCC}
{^gcc-(3\.3|4\.[02])$} {Xcode GCC %s}
{^llvm-gcc-4\.2$} {Xcode LLVM-GCC 4.2}
{^macports-clang$} {MacPorts Clang (port select)}
{^macports-clang-(\d+(?:\.\d+)?)$} {MacPorts Clang %s}
{^macports-gcc$} {MacPorts GCC (port select)}
{^macports-gcc-(\d+(?:\.\d+)?)$} {MacPorts GCC %s}
{^macports-llvm-gcc-4\.2$} {MacPorts LLVM-GCC 4.2}
{^macports-g95$} {MacPorts G95}
{^macports-mpich-default$} {MacPorts MPICH Wrapper for MacPorts' Default C/C++ Compiler}
{^macports-openmpi-default$} {MacPorts Open MPI Wrapper for MacPorts' Default C/C++ Compiler}
{^macports-mpich-clang$} {MacPorts MPICH Wrapper for Xcode Clang}
{^macports-openmpi-clang$} {MacPorts Open MPI Wrapper for Xcode Clang}
{^macports-mpich-clang-(\d+(?:\.\d+)?)$} {MacPorts MPICH Wrapper for Clang %s}
{^macports-openmpi-clang-(\d+(?:\.\d+)?)$} {MacPorts Open MPI Wrapper for Clang %s}
{^macports-mpich-gcc-(\d+(?:\.\d+)?)$} {MacPorts MPICH Wrapper for GCC %s}
{^macports-openmpi-gcc-(\d+(?:\.\d+)?)$} {MacPorts Open MPI Wrapper for GCC %s}
{^macports-(clang|gcc)-devel$} {MacPorts %s Development}
}
foreach {re fmt} $valid_compilers {
if {[set matches [regexp -inline $re $compiler]] ne ""} {
set compiler_name [format $fmt {*}[lrange $matches 1 end]]
break
}
}
if {![info exists compiler_name]} {
return -code error "Invalid value for configure.compiler: $compiler"
}
ui_debug "Preferred compilers: ${compiler.fallback}"
ui_debug "Using compiler '$compiler_name'"
variable no_default_compiler_allowed
if {$no_default_compiler_allowed} {
ui_warn_once no_default_compiler_allowed "All compilers are either blacklisted or unavailable; defaulting to first fallback option"
}
# Additional ccache directory setup
if {${configure.ccache}} {
global ccache_dir ccache_size macportsuser
# Create ccache directory with correct permissions with root privileges
elevateToRoot "configure ccache"
if {[catch {
file mkdir ${ccache_dir}
file attributes ${ccache_dir} -owner ${macportsuser} -permissions 0755
} result]} {
ui_warn "ccache_dir ${ccache_dir} could not be created; disabling ccache: $result"
set configure.ccache no
}
dropPrivileges
# Initialize ccache directory with the given maximum size
if {${configure.ccache}} {
if {[catch {
exec ccache -M ${ccache_size} >/dev/null
} result]} {
ui_warn "ccache_dir ${ccache_dir} could not be initialized; disabling ccache: $result"
set configure.ccache no
}
}
}
}
# internal function to choose the default configure.build_arch and
# configure.universal_archs based on supported_archs and build_arch or
# universal_archs, plus the SDK being used
@@ -1780,247 +1706,16 @@ proc portconfigure::add_compiler_port_dependencies {compiler} {
}
}
proc portconfigure::configure_main {args} {
global worksrcpath use_configure use_autoreconf use_autoconf use_automake use_xmkmf \
configure.pipe configure.libs configure.classpath configure.universal_args \
configure.perl configure.python configure.ruby configure.install configure.awk configure.bison \
configure.pkg_config configure.pkg_config_path \
configure.ccache configure.distcc configure.javac configure.sdkroot \
configure.march configure.mtune os.platform os.major \
compiler.limit_flags
foreach tool {cc cxx objc objcxx f77 f90 fc ld} {
global configure.${tool} configure.${tool}_archflags
}
foreach flags {cflags cppflags cxxflags objcflags objcxxflags ldflags fflags f90flags fcflags} {
global configure.${flags} configure.universal_${flags}
}
set callback [list "-callback" portprogress::target_progress_callback]
if {[tbool use_autoreconf]} {
if {[catch {command_exec {*}${callback} autoreconf} result]} {
return -code error "[format [msgcat::mc "%s failure: %s"] autoreconf $result]"
}
}
if {[tbool use_automake]} {
if {[catch {command_exec {*}${callback} automake} result]} {
return -code error "[format [msgcat::mc "%s failure: %s"] automake $result]"
}
}
if {[tbool use_autoconf]} {
if {[catch {command_exec {*}${callback} autoconf} result]} {
return -code error "[format [msgcat::mc "%s failure: %s"] autoconf $result]"
}
}
if {[tbool use_xmkmf]} {
parse_environment xmkmf
if {[catch {command_exec {*}${callback} xmkmf} result]} {
return -code error "[format [msgcat::mc "%s failure: %s"] xmkmf $result]"
}
parse_environment xmkmf
if {[catch {command_exec {*}${callback} -varprefix xmkmf "cd ${worksrcpath} && make Makefiles"} result]} {
return -code error "[format [msgcat::mc "%s failure: %s"] "make Makefiles" $result]"
}
} elseif {[tbool use_configure]} {
# Merge (ld|c|cpp|cxx)flags into the environment variable.
parse_environment configure
# Set pre-compiler filter to use (ccache/distcc), if any.
if {[tbool configure.ccache] && [tbool configure.distcc]} {
set filter ccache
append_to_environment_value configure "CCACHE_PREFIX" "distcc"
} elseif {[tbool configure.ccache]} {
set filter ccache
} elseif {[tbool configure.distcc]} {
set filter distcc
} else {
set filter ""
}
foreach env_var {CC CXX OBJC OBJCXX} {
append_to_environment_value configure $env_var $filter
}
# Set flags controlling the kind of compiler output.
if {[tbool configure.pipe]} {
set output -pipe
} else {
set output ""
}
foreach env_var {CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS FFLAGS F90FLAGS FCFLAGS} {
append_to_environment_value configure $env_var $output
}
# Append configure flags.
foreach env_var { \
CC CXX OBJC OBJCXX FC F77 F90 JAVAC \
CFLAGS CPPFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS \
FFLAGS F90FLAGS FCFLAGS LDFLAGS LIBS CLASSPATH \
PERL PYTHON RUBY INSTALL AWK BISON PKG_CONFIG \
DEVELOPER_DIR \
} {
set value [option configure.[string tolower $env_var]]
append_to_environment_value configure $env_var {*}$value
}
foreach env_var { \
PKG_CONFIG_PATH \
} {
set value [option configure.[string tolower $env_var]]
append_to_environment_value configure $env_var [join $value ":"]
}
# https://trac.macports.org/ticket/34221
if {${os.platform} eq "darwin" && ${os.major} == 12} {
append_to_environment_value configure "__CFPREFERENCES_AVOID_DAEMON" 1
}
# add SDK flags if needed
if {${configure.sdkroot} ne "" && !${compiler.limit_flags}} {
foreach env_var {CPPFLAGS CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS} {
append_to_environment_value configure $env_var -isysroot${configure.sdkroot}
}
append_to_environment_value configure "LDFLAGS" -Wl,-syslibroot,${configure.sdkroot}
}
# add extra flags that are conditional on whether we're building universal
append_to_environment_value configure CFLAGS {*}[get_canonical_archflags cc]
if {![catch {get_canonical_archflags f77} flags]} {
append_to_environment_value configure FFLAGS {*}$flags
}
foreach tool {cxx objc objcxx cpp f90 fc ld} {
if {[catch {get_canonical_archflags $tool} flags]} {
continue
}
set env_var [string toupper $tool]FLAGS
append_to_environment_value configure $env_var {*}$flags
}
if {[variant_exists universal] && [variant_isset universal]} {
configure.pre_args-append {*}${configure.universal_args}
} else {
foreach env_var {CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS FFLAGS F90FLAGS FCFLAGS LDFLAGS} {
if {${configure.march} ne ""} {
append_to_environment_value configure $env_var -march=${configure.march}
}
if {${configure.mtune} ne ""} {
append_to_environment_value configure $env_var -mtune=${configure.mtune}
}
}
}
# Execute the command (with the new environment).
if {[catch {command_exec {*}${callback} configure} result]} {
global configure.dir build.dir
foreach error_log [list ${configure.dir}/config.log ${configure.dir}/CMakeFiles/CMakeError.log ${build.dir}/meson-logs/meson-log.txt] {
if {[file exists ${error_log}]} {
ui_error "[format [msgcat::mc "Failed to configure %s: consult %s"] [option subport] ${error_log}]"
}
}
return -code error "[format [msgcat::mc "%s failure: %s"] configure $result]"
}
}
return 0
}
proc portconfigure::check_warnings {warning_flag} {
global \
workpath
set files [list]
fs-traverse -tails file [list ${workpath}] {
if {[file tail $file] in [list config.log CMakeError.log meson-log.txt] && [file isfile [file join ${workpath} $file]]} {
# We could do the searching ourselves, but using a tool optimized for this purpose is likely much faster
# than using Tcl.
#
# Using /usr/bin/grep here so we don't accidentally pick up a MacPorts-installed grep which might
# currently not be runnable due to a missing library.
set args [list "/usr/bin/grep" "-El" "--" "-W[quotemeta $warning_flag]\\\]\$"]
lappend args [file join ${workpath} $file]
if {![catch {exec -- {*}$args}]} {
lappend files $file
}
}
}
if {[llength $files] > 0} {
ui_warn [format [msgcat::mc "Configuration logfiles contain indications of %s; check that features were not accidentally disabled:"] "-W$warning_flag"]
foreach file $files {
ui_msg [format " found in %s" $file]
}
}
}
options configure.checks.implicit_int
default configure.checks.implicit_int yes
proc portconfigure::check_implicit_int {} {
portconfigure::check_warnings {implicit-int}
}
options configure.checks.incompatible_function_pointer_types
default configure.checks.incompatible_function_pointer_types yes
proc portconfigure::check_incompatible_function_pointer_types {} {
portconfigure::check_warnings {incompatible-function-pointer-types}
}
options configure.checks.implicit_function_declaration \
options configure.checks.implicit_int \
configure.checks.incompatible_function_pointer_types \
configure.checks.implicit_function_declaration \
configure.checks.implicit_function_declaration.whitelist
default configure.checks.implicit_int yes
default configure.checks.incompatible_function_pointer_types yes
default configure.checks.implicit_function_declaration yes
default configure.checks.implicit_function_declaration.whitelist {[portconfigure::load_implicit_function_declaration_whitelist ${configure.sdk_version}]}
proc portconfigure::check_implicit_function_declarations {} {
global \
workpath \
configure.checks.implicit_function_declaration.whitelist
# Map from function name to config.log that used it without declaration
set undeclared_functions [dict create]
fs-traverse -tails file [list ${workpath}] {
if {[file tail $file] in [list config.log CMakeError.log meson-log.txt] && [file isfile [file join ${workpath} $file]]} {
# We could do the searching ourselves, but using a tool optimized for this purpose is likely much faster
# than using Tcl.
#
# Using /usr/bin/grep here so we don't accidentally pick up a MacPorts-installed grep which might
# currently not be runnable due to a missing library.
set args [list "/usr/bin/grep" "-E" "--" "-Wimplicit-function-declaration\\\]\$"]
lappend args [file join ${workpath} $file]
if {![catch {set result [exec -- {*}$args]}]} {
foreach line [split $result "\n"] {
if {[regexp -- "(?:implicit declaration of function|implicitly declaring library function|call to undeclared function|call to undeclared library function) '(\[^']+)'" $line -> function]} {
set is_whitelisted no
foreach whitelisted ${configure.checks.implicit_function_declaration.whitelist} {
if {[string match -nocase $whitelisted $function]} {
set is_whitelisted yes
break
}
}
if {!$is_whitelisted} {
dict set undeclared_functions $function $file 1
} else {
ui_debug [format "Ignoring implicit declaration of function '%s' because it is whitelisted" $function]
}
}
}
}
}
}
if {[dict size $undeclared_functions] > 0} {
ui_warn [format [msgcat::mc "Configuration logfiles contain indications of %s; check that features were not accidentally disabled:"] "-Wimplicit-function-declaration"]
dict for {function files} $undeclared_functions {
ui_msg [format " %s: found in %s" $function [join [dict keys $files] ", "]]
}
}
}
proc portconfigure::load_implicit_function_declaration_whitelist {sdk_version} {
set whitelist [list]
@@ -2035,23 +1730,3 @@ proc portconfigure::load_implicit_function_declaration_whitelist {sdk_version} {
return $whitelist
}
proc portconfigure::configure_finish {args} {
global \
configure.dir \
configure.checks.implicit_function_declaration \
configure.checks.implicit_int \
configure.checks.incompatible_function_pointer_types
if {[file isdirectory ${configure.dir}]} {
if {${configure.checks.implicit_function_declaration}} {
portconfigure::check_implicit_function_declarations
}
if {${configure.checks.implicit_int}} {
portconfigure::check_implicit_int
}
if {${configure.checks.incompatible_function_pointer_types}} {
portconfigure::check_incompatible_function_pointer_types
}
}
}
+330
View File
@@ -0,0 +1,330 @@
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
package provide portconfigure_run 1.0
package require portutil 1.0
package require portprogress 1.0
namespace eval portconfigure {
proc configure_start {args} {
global UI_PREFIX subport configure.compiler compiler.fallback configure.ccache
ui_notice "$UI_PREFIX [format [msgcat::mc "Configuring %s"] $subport]"
set compiler ${configure.compiler}
set valid_compilers {
{^apple-gcc-(4\.[02])$} {MacPorts Apple GCC %s}
{^cc$} {System cc}
{^clang$} {Xcode Clang}
{^gcc$} {System GCC}
{^gcc-(3\.3|4\.[02])$} {Xcode GCC %s}
{^llvm-gcc-4\.2$} {Xcode LLVM-GCC 4.2}
{^macports-clang$} {MacPorts Clang (port select)}
{^macports-clang-(\d+(?:\.\d+)?)$} {MacPorts Clang %s}
{^macports-gcc$} {MacPorts GCC (port select)}
{^macports-gcc-(\d+(?:\.\d+)?)$} {MacPorts GCC %s}
{^macports-llvm-gcc-4\.2$} {MacPorts LLVM-GCC 4.2}
{^macports-g95$} {MacPorts G95}
{^macports-mpich-default$} {MacPorts MPICH Wrapper for MacPorts' Default C/C++ Compiler}
{^macports-openmpi-default$} {MacPorts Open MPI Wrapper for MacPorts' Default C/C++ Compiler}
{^macports-mpich-clang$} {MacPorts MPICH Wrapper for Xcode Clang}
{^macports-openmpi-clang$} {MacPorts Open MPI Wrapper for Xcode Clang}
{^macports-mpich-clang-(\d+(?:\.\d+)?)$} {MacPorts MPICH Wrapper for Clang %s}
{^macports-openmpi-clang-(\d+(?:\.\d+)?)$} {MacPorts Open MPI Wrapper for Clang %s}
{^macports-mpich-gcc-(\d+(?:\.\d+)?)$} {MacPorts MPICH Wrapper for GCC %s}
{^macports-openmpi-gcc-(\d+(?:\.\d+)?)$} {MacPorts Open MPI Wrapper for GCC %s}
{^macports-(clang|gcc)-devel$} {MacPorts %s Development}
}
foreach {re fmt} $valid_compilers {
if {[set matches [regexp -inline $re $compiler]] ne ""} {
set compiler_name [format $fmt {*}[lrange $matches 1 end]]
break
}
}
if {![info exists compiler_name]} {
return -code error "Invalid value for configure.compiler: $compiler"
}
ui_debug "Preferred compilers: ${compiler.fallback}"
ui_debug "Using compiler '$compiler_name'"
variable no_default_compiler_allowed
if {$no_default_compiler_allowed} {
ui_warn_once no_default_compiler_allowed "All compilers are either blacklisted or unavailable; defaulting to first fallback option"
}
# Additional ccache directory setup
if {${configure.ccache}} {
global ccache_dir ccache_size macportsuser
# Create ccache directory with correct permissions with root privileges
elevateToRoot "configure ccache"
if {[catch {
file mkdir ${ccache_dir}
file attributes ${ccache_dir} -owner ${macportsuser} -permissions 0755
} result]} {
ui_warn "ccache_dir ${ccache_dir} could not be created; disabling ccache: $result"
set configure.ccache no
}
dropPrivileges
# Initialize ccache directory with the given maximum size
if {${configure.ccache}} {
if {[catch {
exec ccache -M ${ccache_size} >/dev/null
} result]} {
ui_warn "ccache_dir ${ccache_dir} could not be initialized; disabling ccache: $result"
set configure.ccache no
}
}
}
}
proc configure_main {args} {
global worksrcpath use_configure use_autoreconf use_autoconf use_automake use_xmkmf \
configure.pipe configure.libs configure.classpath configure.universal_args \
configure.perl configure.python configure.ruby configure.install configure.awk configure.bison \
configure.pkg_config configure.pkg_config_path \
configure.ccache configure.distcc configure.javac configure.sdkroot \
configure.march configure.mtune os.platform os.major \
compiler.limit_flags
foreach tool {cc cxx objc objcxx f77 f90 fc ld} {
global configure.${tool} configure.${tool}_archflags
}
foreach flags {cflags cppflags cxxflags objcflags objcxxflags ldflags fflags f90flags fcflags} {
global configure.${flags} configure.universal_${flags}
}
set callback [list "-callback" portprogress::target_progress_callback]
if {[tbool use_autoreconf]} {
if {[catch {command_exec {*}${callback} autoreconf} result]} {
return -code error "[format [msgcat::mc "%s failure: %s"] autoreconf $result]"
}
}
if {[tbool use_automake]} {
if {[catch {command_exec {*}${callback} automake} result]} {
return -code error "[format [msgcat::mc "%s failure: %s"] automake $result]"
}
}
if {[tbool use_autoconf]} {
if {[catch {command_exec {*}${callback} autoconf} result]} {
return -code error "[format [msgcat::mc "%s failure: %s"] autoconf $result]"
}
}
if {[tbool use_xmkmf]} {
parse_environment xmkmf
if {[catch {command_exec {*}${callback} xmkmf} result]} {
return -code error "[format [msgcat::mc "%s failure: %s"] xmkmf $result]"
}
parse_environment xmkmf
if {[catch {command_exec {*}${callback} -varprefix xmkmf "cd ${worksrcpath} && make Makefiles"} result]} {
return -code error "[format [msgcat::mc "%s failure: %s"] "make Makefiles" $result]"
}
} elseif {[tbool use_configure]} {
# Merge (ld|c|cpp|cxx)flags into the environment variable.
parse_environment configure
# Set pre-compiler filter to use (ccache/distcc), if any.
if {[tbool configure.ccache] && [tbool configure.distcc]} {
set filter ccache
append_to_environment_value configure "CCACHE_PREFIX" "distcc"
} elseif {[tbool configure.ccache]} {
set filter ccache
} elseif {[tbool configure.distcc]} {
set filter distcc
} else {
set filter ""
}
foreach env_var {CC CXX OBJC OBJCXX} {
append_to_environment_value configure $env_var $filter
}
# Set flags controlling the kind of compiler output.
if {[tbool configure.pipe]} {
set output -pipe
} else {
set output ""
}
foreach env_var {CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS FFLAGS F90FLAGS FCFLAGS} {
append_to_environment_value configure $env_var $output
}
# Append configure flags.
foreach env_var { \
CC CXX OBJC OBJCXX FC F77 F90 JAVAC \
CFLAGS CPPFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS \
FFLAGS F90FLAGS FCFLAGS LDFLAGS LIBS CLASSPATH \
PERL PYTHON RUBY INSTALL AWK BISON PKG_CONFIG \
DEVELOPER_DIR \
} {
set value [option configure.[string tolower $env_var]]
append_to_environment_value configure $env_var {*}$value
}
foreach env_var { \
PKG_CONFIG_PATH \
} {
set value [option configure.[string tolower $env_var]]
append_to_environment_value configure $env_var [join $value ":"]
}
# https://trac.macports.org/ticket/34221
if {${os.platform} eq "darwin" && ${os.major} == 12} {
append_to_environment_value configure "__CFPREFERENCES_AVOID_DAEMON" 1
}
# add SDK flags if needed
if {${configure.sdkroot} ne "" && !${compiler.limit_flags}} {
foreach env_var {CPPFLAGS CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS} {
append_to_environment_value configure $env_var -isysroot${configure.sdkroot}
}
append_to_environment_value configure "LDFLAGS" -Wl,-syslibroot,${configure.sdkroot}
}
# add extra flags that are conditional on whether we're building universal
append_to_environment_value configure CFLAGS {*}[get_canonical_archflags cc]
if {![catch {get_canonical_archflags f77} flags]} {
append_to_environment_value configure FFLAGS {*}$flags
}
foreach tool {cxx objc objcxx cpp f90 fc ld} {
if {[catch {get_canonical_archflags $tool} flags]} {
continue
}
set env_var [string toupper $tool]FLAGS
append_to_environment_value configure $env_var {*}$flags
}
if {[variant_exists universal] && [variant_isset universal]} {
configure.pre_args-append {*}${configure.universal_args}
} else {
foreach env_var {CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS FFLAGS F90FLAGS FCFLAGS LDFLAGS} {
if {${configure.march} ne ""} {
append_to_environment_value configure $env_var -march=${configure.march}
}
if {${configure.mtune} ne ""} {
append_to_environment_value configure $env_var -mtune=${configure.mtune}
}
}
}
# Execute the command (with the new environment).
if {[catch {command_exec {*}${callback} configure} result]} {
global configure.dir build.dir
foreach error_log [list ${configure.dir}/config.log ${configure.dir}/CMakeFiles/CMakeError.log ${build.dir}/meson-logs/meson-log.txt] {
if {[file exists ${error_log}]} {
ui_error "[format [msgcat::mc "Failed to configure %s: consult %s"] [option subport] ${error_log}]"
}
}
return -code error "[format [msgcat::mc "%s failure: %s"] configure $result]"
}
}
return 0
}
proc check_warnings {warning_flag} {
global \
workpath
set files [list]
fs-traverse -tails file [list ${workpath}] {
if {[file tail $file] in [list config.log CMakeError.log meson-log.txt] && [file isfile [file join ${workpath} $file]]} {
# We could do the searching ourselves, but using a tool optimized for this purpose is likely much faster
# than using Tcl.
#
# Using /usr/bin/grep here so we don't accidentally pick up a MacPorts-installed grep which might
# currently not be runnable due to a missing library.
set args [list "/usr/bin/grep" "-El" "--" "-W[quotemeta $warning_flag]\\\]\$"]
lappend args [file join ${workpath} $file]
if {![catch {exec -- {*}$args}]} {
lappend files $file
}
}
}
if {[llength $files] > 0} {
ui_warn [format [msgcat::mc "Configuration logfiles contain indications of %s; check that features were not accidentally disabled:"] "-W$warning_flag"]
foreach file $files {
ui_msg [format " found in %s" $file]
}
}
}
proc check_implicit_int {} {
check_warnings {implicit-int}
}
proc check_incompatible_function_pointer_types {} {
check_warnings {incompatible-function-pointer-types}
}
proc check_implicit_function_declarations {} {
global \
workpath \
configure.checks.implicit_function_declaration.whitelist
# Map from function name to config.log that used it without declaration
set undeclared_functions [dict create]
fs-traverse -tails file [list ${workpath}] {
if {[file tail $file] in [list config.log CMakeError.log meson-log.txt] && [file isfile [file join ${workpath} $file]]} {
# We could do the searching ourselves, but using a tool optimized for this purpose is likely much faster
# than using Tcl.
#
# Using /usr/bin/grep here so we don't accidentally pick up a MacPorts-installed grep which might
# currently not be runnable due to a missing library.
set args [list "/usr/bin/grep" "-E" "--" "-Wimplicit-function-declaration\\\]\$"]
lappend args [file join ${workpath} $file]
if {![catch {set result [exec -- {*}$args]}]} {
foreach line [split $result "\n"] {
if {[regexp -- "(?:implicit declaration of function|implicitly declaring library function|call to undeclared function|call to undeclared library function) '(\[^']+)'" $line -> function]} {
set is_whitelisted no
foreach whitelisted ${configure.checks.implicit_function_declaration.whitelist} {
if {[string match -nocase $whitelisted $function]} {
set is_whitelisted yes
break
}
}
if {!$is_whitelisted} {
dict set undeclared_functions $function $file 1
} else {
ui_debug [format "Ignoring implicit declaration of function '%s' because it is whitelisted" $function]
}
}
}
}
}
}
if {[dict size $undeclared_functions] > 0} {
ui_warn [format [msgcat::mc "Configuration logfiles contain indications of %s; check that features were not accidentally disabled:"] "-Wimplicit-function-declaration"]
dict for {function files} $undeclared_functions {
ui_msg [format " %s: found in %s" $function [join [dict keys $files] ", "]]
}
}
}
proc configure_finish {args} {
global \
configure.dir \
configure.checks.implicit_function_declaration \
configure.checks.implicit_int \
configure.checks.incompatible_function_pointer_types
if {[file isdirectory ${configure.dir}]} {
if {${configure.checks.implicit_function_declaration}} {
check_implicit_function_declarations
}
if {${configure.checks.implicit_int}} {
check_implicit_int
}
if {${configure.checks.incompatible_function_pointer_types}} {
check_incompatible_function_pointer_types
}
}
}
}
+2 -60
View File
@@ -1,38 +1,8 @@
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
# portdeactivate.tcl
#
# Copyright (c) 2010-2011 The MacPorts Project
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of The MacPorts Project nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# the 'deactivate' target is provided by this package
package provide portdeactivate 1.0
package require portutil 1.0
set org.macports.deactivate [target_new org.macports.deactivate portdeactivate::deactivate_main]
target_runtype ${org.macports.deactivate} always
@@ -40,35 +10,7 @@ target_state ${org.macports.deactivate} no
target_provides ${org.macports.deactivate} deactivate
target_requires ${org.macports.deactivate} main
target_prerun ${org.macports.deactivate} portdeactivate::deactivate_start
namespace eval portdeactivate {
}
target_runpkg ${org.macports.deactivate} portdeactivate_run
options deactivate.asroot
set deactivate.asroot no
proc portdeactivate::deactivate_start {args} {
global prefix
if {![file writable $prefix] || ([getuid] == 0 && [geteuid] != 0)} {
# if install location is not writable, need root privileges
elevateToRoot "deactivate"
}
}
proc portdeactivate::deactivate_main {args} {
global subport _inregistry_version _inregistry_revision _inregistry_variants user_options
foreach {var backup} {_inregistry_version version _inregistry_revision revision _inregistry_variants portvariants} {
if {![info exists $var]} {
set $var [option $backup]
}
}
if {[portstartupitem::loaded] ne ""} {
if {[eval_targets "unload"]} {
ui_warn [format [msgcat::mc "Failed to unload startupitem(s) for %s (continuing anyway)"] $subport]
}
}
registry_deactivate $subport $_inregistry_version $_inregistry_revision $_inregistry_variants [array get user_options]
return 0
}
default deactivate.asroot no
+61
View File
@@ -0,0 +1,61 @@
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
#
# Copyright (c) 2010-2011 The MacPorts Project
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of The MacPorts Project nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
package provide portdeactivate_run 1.0
package require portutil 1.0
namespace eval portdeactivate {
proc deactivate_start {args} {
global prefix
if {![file writable $prefix] || ([getuid] == 0 && [geteuid] != 0)} {
# if install location is not writable, need root privileges
elevateToRoot "deactivate"
}
}
proc deactivate_main {args} {
global subport _inregistry_version _inregistry_revision _inregistry_variants user_options
foreach {var backup} {_inregistry_version version _inregistry_revision revision _inregistry_variants portvariants} {
if {![info exists $var]} {
set $var [option $backup]
}
}
if {[portstartupitem::loaded] ne ""} {
if {[eval_targets "unload"]} {
ui_warn [format [msgcat::mc "Failed to unload startupitem(s) for %s (continuing anyway)"] $subport]
}
}
registry_deactivate $subport $_inregistry_version $_inregistry_revision $_inregistry_variants [array get user_options]
return 0
}
}
+6 -10
View File
@@ -1,5 +1,4 @@
# et:ts=4
# portdepends.tcl
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
#
# Copyright (c) 2005, 2007-2009 The MacPorts Project
# Copyright (c) 2002 - 2003 Apple Inc.
@@ -28,13 +27,8 @@
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
package provide portdepends 1.0
package require portutil 1.0
namespace eval portdepends {
}
# define options
options depends_fetch depends_extract depends_patch depends_build depends_run depends_lib depends_test depends
@@ -52,9 +46,9 @@ option_proc depends_test portdepends::validate_depends_options
# New option for the new dependency. We generate a warning because we don't handle this yet.
option_proc depends portdepends::validate_depends_options_new
set_ui_prefix
namespace eval portdepends {
proc portdepends::validate_depends_options {option action {value ""}} {
proc validate_depends_options {option action {value ""}} {
switch $action {
set {
foreach depspec $value {
@@ -69,6 +63,8 @@ proc portdepends::validate_depends_options {option action {value ""}} {
}
}
proc portdepends::validate_depends_options_new {option action {value ""}} {
proc validate_depends_options_new {option action {value ""}} {
ui_warn [msgcat::mc "depends option is not handled yet"]
}
}
+3 -412
View File
@@ -1,49 +1,13 @@
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:filetype=tcl:et:sw=4:ts=4:sts=4
# portdestroot.tcl
#
# Copyright (c) 2002 - 2003 Apple Inc.
# Copyright (c) 2004 - 2005 Robert Shaw <rshaw@opendarwin.org>
# Copyright (c) 2004-2005, 2007-2013 The MacPorts Project
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of Apple Inc. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
package provide portdestroot 1.0
package require portutil 1.0
set org.macports.destroot [target_new org.macports.destroot portdestroot::destroot_main]
target_provides ${org.macports.destroot} destroot
target_requires ${org.macports.destroot} main fetch checksum extract patch configure build
target_prerun ${org.macports.destroot} portdestroot::destroot_start
target_postrun ${org.macports.destroot} portdestroot::destroot_finish
namespace eval portdestroot {
# Save old umask
variable oldmask
}
target_runpkg ${org.macports.destroot} portdestroot_run
# define options
options destroot.target destroot.destdir destroot.clean destroot.keepdirs destroot.umask \
@@ -65,9 +29,8 @@ default destroot.keepdirs {}
default destroot.violate_mtree no
default destroot.delete_la_files {${delete_la_files}}
set_ui_prefix
proc portdestroot::destroot_getargs {args} {
namespace eval portdestroot {
proc destroot_getargs {args} {
global build.type os.platform destroot.cmd destroot.target
if {((${build.type} eq "default" && ${os.platform} ne "freebsd") ||
(${build.type} eq "gnu"))
@@ -78,376 +41,4 @@ proc portdestroot::destroot_getargs {args} {
return ${destroot.target}
}
proc portdestroot::destroot_start {args} {
global UI_PREFIX prefix subport destroot os.platform destroot.clean portsharepath \
destroot.umask destroot.asroot euid egid \
applications_dir frameworks_dir
variable oldmask
ui_notice "$UI_PREFIX [format [msgcat::mc "Staging %s into destroot"] ${subport}]"
# start gsoc08-privileges
if { [getuid] == 0 && [geteuid] != 0 } {
# if started with sudo but have dropped the privileges
ui_debug "Can't run destroot under sudo without elevated privileges (due to mtree)."
ui_debug "Run destroot without sudo to avoid root privileges."
ui_debug "Going to escalate privileges back to root."
seteuid $euid
setegid $egid
ui_debug "euid changed to: [geteuid]. egid changed to: [getegid]."
}
if { [tbool destroot.asroot] && [getuid] != 0 } {
return -code error "You cannot run this port without root privileges. You need to re-run with 'sudo port'.";
}
# end gsoc08-privileges
set oldmask [umask ${destroot.umask}]
set mtree [findBinary mtree ${::portutil::autoconf::mtree_path}]
if { ${destroot.clean} eq "yes" } {
delete "${destroot}"
}
file mkdir "${destroot}"
if { ${os.platform} eq "darwin" } {
system -W ${destroot} "${mtree} -e -U -f [shellescape [file join ${portsharepath} install macosx.mtree]]"
file mkdir "${destroot}${applications_dir}"
file mkdir "${destroot}${frameworks_dir}"
}
file mkdir "${destroot}${prefix}"
system -W ${destroot}${prefix} "${mtree} -e -U -f [shellescape [file join ${portsharepath} install prefix.mtree]]"
# Create startup-scripts/items
portstartupitem::startupitem_create
}
proc portdestroot::destroot_main {args} {
global system_options
if {$system_options(clonebin_path) ne ""} {
global env
set saved_path $env(PATH)
set env(PATH) $system_options(clonebin_path):$env(PATH)
}
try {
command_exec -callback portprogress::target_progress_callback destroot
} finally {
if {[info exists saved_path]} {
set env(PATH) $saved_path
}
}
return 0
}
proc portdestroot::destroot_finish {args} {
global UI_PREFIX destroot prefix subport destroot.violate_mtree \
applications_dir frameworks_dir destroot.keepdirs \
destroot.delete_la_files install.user install.group \
macportsuser
variable oldmask
foreach fileToDelete {share/info/dir lib/charset.alias} {
if {[file exists "${destroot}${prefix}/${fileToDelete}"]} {
ui_debug "Deleting stray ${fileToDelete} file."
file delete "${destroot}${prefix}/${fileToDelete}"
}
}
# Prevent overlinking due to glibtool .la files: https://trac.macports.org/ticket/38010
ui_debug "Fixing glibtool .la files in destroot for ${subport}"
if {[getuid] == 0} {
set macports_uid [name_to_uid $macportsuser]
set macports_gid [uname_to_gid $macportsuser]
set fix_ownership 1
} else {
set fix_ownership 0
}
fs-traverse -depth fullpath [list $destroot] {
file lstat $fullpath statinfo
# Ensure installed files are not owned by the unprivileged account
if {$fix_ownership && ($statinfo(uid) == $macports_uid || $statinfo(gid) == $macports_gid)} {
if {$statinfo(uid) == $macports_uid} {
ui_debug "Changing owner to ${install.user} for $fullpath"
set new_owner ${install.user}
} else {
# only group needs to be changed
set new_owner -1
}
if {$statinfo(gid) == $macports_gid} {
ui_debug "Changing group to ${install.group} for $fullpath"
set new_group ${install.group}
} else {
# only owner needs to be changed
set new_group -1
}
# Changing owner may also change permissions, so we restore
# them afterwards. 'file attributes' doesn't work on links
# (it operates on the link target instead) but links should
# not have setuid/setgid bits set anyway.
if {$statinfo(type) ne "link"} {
set saved_perms [file attributes $fullpath -permissions]
}
lchown $fullpath $new_owner $new_group
if {$statinfo(type) ne "link"} {
file attributes $fullpath -permissions $saved_perms
}
}
if {[file extension $fullpath] eq ".la" && $statinfo(type) in {file link}} {
if {$statinfo(type) eq "link" && [file pathtype [file link $fullpath]] ne "relative"} {
# prepend $destroot to target of absolute symlinks
set checkpath ${destroot}[file link $fullpath]
} else {
set checkpath $fullpath
}
# Make sure it is from glibtool ... "a libtool library file" will appear in the first line
set is_la_file 0
if {![catch {open $checkpath} fp]} {
if {[gets $fp line] > 0 && [string first "a libtool library file" $line] != -1} {
set is_la_file 1
}
catch {close $fp}
} else {
ui_debug "Failed to open $checkpath"
}
if {$is_la_file} {
if {${destroot.delete_la_files}} {
ui_debug "Removing [file tail $fullpath]"
file delete ${fullpath}
} elseif {$statinfo(type) eq "file"} {
ui_debug "Clearing dependency_libs in [file tail $fullpath]"
reinplace -q "/dependency_libs/ s/'.*'/''/" ${fullpath}
}
}
}
}
# Prune empty directories in ${destroot}
package require fileutil
foreach path ${destroot.keepdirs} {
# Prepend $destroot if $path isn't already inside it
set path [::fileutil::jail $destroot $path]
if {![file isdirectory ${path}]} {
xinstall -m 0755 -d ${path}
}
if {![file exists ${path}/.turd_${subport}]} {
xinstall -c -m 0644 /dev/null ${path}/.turd_${subport}
}
}
fs-traverse -depth dir [list ${destroot}] {
if {[file type $dir] eq "directory"} {
catch {file delete $dir}
}
}
if {![file isdirectory ${destroot}]} {
ui_error "No files have been installed in the destroot directory!"
ui_error "Please make sure that this software supports\
'make install DESTDIR=\${destroot}' or implement an\
alternative destroot mechanism in the Portfile."
ui_error "Files might have been installed directly into your system,\
check before proceeding."
return -code error "Staging $subport into destroot failed"
}
# Compress all manpages with gzip (instead)
set manpath ${destroot}${prefix}/share/man
if {[file isdirectory ${manpath}] && [file type ${manpath}] eq "directory"} {
ui_info "$UI_PREFIX [format [msgcat::mc "Compressing man pages for %s"] ${subport}]"
set gzip [findBinary gzip ${::portutil::autoconf::gzip_path}]
set gunzip "$gzip -d"
set bunzip2 "[findBinary bzip2 ${::portutil::autoconf::bzip2_path}] -d"
set found 0
set manlinks [list]
set mandir_re {^(cat|man)(.)$}
foreach mandir [readdir "${manpath}"] {
if {![regexp ${mandir_re} ${mandir} match ignore manindex]} { continue }
set gzfile_re "^(.*\[.\]${manindex}\[a-z\]*)\[.\]gz\$"
set bz2file_re "^(.*\[.\]${manindex}\[a-z\]*)\[.\]bz2\$"
set normalfile_re "\[.\]${manindex}\[a-z\]*\$"
set mandirpath [file join ${manpath} ${mandir}]
if {[file isdirectory ${mandirpath}] && [file type ${mandirpath}] eq "directory"} {
ui_debug "Scanning ${mandir}"
foreach manfile [readdir ${mandirpath}] {
set manfilepath [file join ${mandirpath} ${manfile}]
if {[file isfile ${manfilepath}] && [file type ${manfilepath}] eq "file"} {
if {[regexp ${gzfile_re} ${manfile} gzfile manfile]} {
set found 1
system -W ${manpath} \
"$gunzip -f [shellescape [file join ${mandir} ${gzfile}]] && \
$gzip -9vnf [shellescape [file join ${mandir} ${manfile}]]"
} elseif {[regexp ${bz2file_re} ${manfile} bz2file manfile]} {
set found 1
system -W ${manpath} \
"$bunzip2 -f [shellescape [file join ${mandir} ${bz2file}]] && \
$gzip -9vnf [shellescape [file join ${mandir} ${manfile}]]"
} elseif {[regexp ${normalfile_re} ${manfile}]} {
set found 1
system -W ${manpath} \
"$gzip -9vnf [shellescape [file join ${mandir} ${manfile}]]"
}
set gzmanfile ${manfile}.gz
set gzmanfilepath [file join ${mandirpath} ${gzmanfile}]
if {[file exists ${gzmanfilepath}]} {
set desired 00444
set current [file attributes ${gzmanfilepath} -permissions]
if {$current != $desired} {
ui_info "[file join ${mandir} ${gzmanfile}]: changing permissions from $current to $desired"
file attributes ${gzmanfilepath} -permissions $desired
}
}
} elseif {[file type ${manfilepath}] eq "link"} {
lappend manlinks [file join ${mandir} ${manfile}]
}
}
}
}
if {$found == 1} {
# check man page links and rename/repoint them if necessary
set gzext_re "\[.\]gz\$"
foreach manlink $manlinks {
set manlinkpath [file join $manpath $manlink]
# if link destination is not gzipped, check it
set manlinksrc [file readlink $manlinkpath]
if {![regexp ${gzext_re} ${manlinksrc}]} {
set mandir [file dirname $manlink]
set mandirpath [file join $manpath $mandir]
if {[catch {pwd} oldpwd]} {
set oldpwd {}
}
if {[catch {_cd $mandirpath} err]} {
puts $err
return
}
# if link source is an absolute path, check for it under destroot
set mls_check "$manlinksrc"
if {[file pathtype $mls_check] eq "absolute"} {
set mls_check "${destroot}${mls_check}"
}
# if gzipped destination exists, fix link
if {[file isfile ${mls_check}.gz]} {
# if actual link name does not end with gz, rename it
if {![regexp ${gzext_re} ${manlink}]} {
ui_debug "renaming link: $manlink to ${manlink}.gz"
file rename $manlinkpath ${manlinkpath}.gz
set manlink ${manlink}.gz
set manlinkpath [file join $manpath $manlink]
}
# repoint the link
ui_debug "repointing link: $manlink from $manlinksrc to ${manlinksrc}.gz"
file delete $manlinkpath
ln -s "${manlinksrc}.gz" "${manlinkpath}"
}
if {$oldpwd ne {}} {
_cd $oldpwd
}
}
}
} else {
ui_debug "No man pages found to compress."
}
}
# test for violations of mtree
if { ${destroot.violate_mtree} ne "yes" } {
ui_debug "checking for mtree violations"
set mtree_violation "no"
set prefixPaths [list bin etc include lib libexec sbin share src var www Applications Developer Library]
set pathsToCheck [list /]
while {[llength $pathsToCheck] > 0} {
set pathToCheck [lpop pathsToCheck 0]
foreach file [glob -nocomplain -directory $destroot$pathToCheck .* *] {
if {[file tail $file] eq "." || [file tail $file] eq ".."} {
continue
}
if {[string equal -length [string length $destroot] $destroot $file]} {
# just double-checking that $destroot is a prefix, as is appropriate
set dfile [file join / [string range $file [string length $destroot] end]]
} else {
throw MACPORTS "Unexpected filepath `${file}' while checking for mtree violations"
}
if {$dfile eq $prefix} {
# we've found our prefix
foreach pfile [glob -nocomplain -tails -directory $file .* *] {
if {$pfile eq "." || $pfile eq ".."} {
continue
}
if {$pfile ni $prefixPaths} {
ui_warn "violation by [file join $dfile $pfile]"
set mtree_violation "yes"
}
}
} elseif {[string equal -length [expr {[string length $dfile] + 1}] $dfile/ $prefix]} {
# we've found a subpath of our prefix
lappend pathsToCheck $dfile
} else {
set dir_allowed no
# these files are (at least potentially) outside of the prefix
foreach dir [list $applications_dir $frameworks_dir /Library/LaunchAgents /Library/LaunchDaemons /Library/StartupItems] {
if {[string equal -length [expr {[string length $dfile] + 1}] $dfile/ $dir]} {
# it's a prefix of one of the allowed paths
set dir_allowed yes
break
}
}
if {$dir_allowed} {
lappend pathsToCheck $dfile
} else {
# not a prefix of an allowed path, so it's either the path itself or a violation
switch -- $dfile \
$applications_dir - \
$frameworks_dir - \
/Library/LaunchAgents - \
/Library/LaunchDaemons - \
/Library/StartupItems { ui_debug "port installs files in $dfile" } \
default {
ui_warn "violation by $dfile"
set mtree_violation "yes"
}
}
}
}
}
# abort here only so all violations can be observed
if { ${mtree_violation} ne "no" } {
ui_warn "[format [msgcat::mc "%s violates the layout of the ports-filesystems!"] $subport]"
ui_warn "Please fix or indicate this misbehavior (if it is intended), it will be an error in future releases!"
# error "mtree violation!"
}
} else {
ui_warn "[format [msgcat::mc "%s installs files outside the common directory structure."] $subport]"
}
# Work around apparent filesystem bug.
# https://trac.macports.org/ticket/67336
if {![catch {fs_clone_capable $destroot} result] && $result} {
global workpath
ui_debug "Applying sparse file lseek bug workaround"
try {
fs-traverse -depth fullpath [list $destroot] {
if {[file type $fullpath] eq "file" && [fileIsSparse $fullpath]} {
ui_debug "Cloning $fullpath for workaround"
clonefile $fullpath ${workpath}/.macports-sparse-workaround
file delete ${workpath}/.macports-sparse-workaround
if {![fileIsSparse $fullpath]} {
ui_debug "$fullpath is no longer sparse"
}
}
}
} on error {eMessage} {
ui_debug "Error while applying sparse file workaround: $eMessage"
}
}
# Restore umask
umask $oldmask
return 0
}
+413
View File
@@ -0,0 +1,413 @@
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
#
# Copyright (c) 2002 - 2003 Apple Inc.
# Copyright (c) 2004 - 2005 Robert Shaw <rshaw@opendarwin.org>
# Copyright (c) 2004-2005, 2007-2013 The MacPorts Project
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of Apple Inc. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
package provide portdestroot_run 1.0
package require portutil 1.0
namespace eval portdestroot {
# Save old umask
variable oldmask
proc destroot_start {args} {
global UI_PREFIX prefix subport destroot os.platform destroot.clean portsharepath \
destroot.umask destroot.asroot euid egid \
applications_dir frameworks_dir
variable oldmask
ui_notice "$UI_PREFIX [format [msgcat::mc "Staging %s into destroot"] ${subport}]"
# start gsoc08-privileges
if { [getuid] == 0 && [geteuid] != 0 } {
# if started with sudo but have dropped the privileges
ui_debug "Can't run destroot under sudo without elevated privileges (due to mtree)."
ui_debug "Run destroot without sudo to avoid root privileges."
ui_debug "Going to escalate privileges back to root."
seteuid $euid
setegid $egid
ui_debug "euid changed to: [geteuid]. egid changed to: [getegid]."
}
if { [tbool destroot.asroot] && [getuid] != 0 } {
return -code error "You cannot run this port without root privileges. You need to re-run with 'sudo port'.";
}
# end gsoc08-privileges
set oldmask [umask ${destroot.umask}]
set mtree [findBinary mtree ${::portutil::autoconf::mtree_path}]
if { ${destroot.clean} eq "yes" } {
delete "${destroot}"
}
file mkdir "${destroot}"
if { ${os.platform} eq "darwin" } {
system -W ${destroot} "${mtree} -e -U -f [shellescape [file join ${portsharepath} install macosx.mtree]]"
file mkdir "${destroot}${applications_dir}"
file mkdir "${destroot}${frameworks_dir}"
}
file mkdir "${destroot}${prefix}"
system -W ${destroot}${prefix} "${mtree} -e -U -f [shellescape [file join ${portsharepath} install prefix.mtree]]"
# Create startup-scripts/items
portstartupitem::startupitem_create
}
proc destroot_main {args} {
global system_options
if {$system_options(clonebin_path) ne ""} {
global env
set saved_path $env(PATH)
set env(PATH) $system_options(clonebin_path):$env(PATH)
}
try {
command_exec -callback portprogress::target_progress_callback destroot
} finally {
if {[info exists saved_path]} {
set env(PATH) $saved_path
}
}
return 0
}
proc destroot_finish {args} {
global UI_PREFIX destroot prefix subport destroot.violate_mtree \
applications_dir frameworks_dir destroot.keepdirs \
destroot.delete_la_files install.user install.group \
macportsuser
variable oldmask
foreach fileToDelete {share/info/dir lib/charset.alias} {
if {[file exists "${destroot}${prefix}/${fileToDelete}"]} {
ui_debug "Deleting stray ${fileToDelete} file."
file delete "${destroot}${prefix}/${fileToDelete}"
}
}
# Prevent overlinking due to glibtool .la files: https://trac.macports.org/ticket/38010
ui_debug "Fixing glibtool .la files in destroot for ${subport}"
if {[getuid] == 0} {
set macports_uid [name_to_uid $macportsuser]
set macports_gid [uname_to_gid $macportsuser]
set fix_ownership 1
} else {
set fix_ownership 0
}
fs-traverse -depth fullpath [list $destroot] {
file lstat $fullpath statinfo
# Ensure installed files are not owned by the unprivileged account
if {$fix_ownership && ($statinfo(uid) == $macports_uid || $statinfo(gid) == $macports_gid)} {
if {$statinfo(uid) == $macports_uid} {
ui_debug "Changing owner to ${install.user} for $fullpath"
set new_owner ${install.user}
} else {
# only group needs to be changed
set new_owner -1
}
if {$statinfo(gid) == $macports_gid} {
ui_debug "Changing group to ${install.group} for $fullpath"
set new_group ${install.group}
} else {
# only owner needs to be changed
set new_group -1
}
# Changing owner may also change permissions, so we restore
# them afterwards. 'file attributes' doesn't work on links
# (it operates on the link target instead) but links should
# not have setuid/setgid bits set anyway.
if {$statinfo(type) ne "link"} {
set saved_perms [file attributes $fullpath -permissions]
}
lchown $fullpath $new_owner $new_group
if {$statinfo(type) ne "link"} {
file attributes $fullpath -permissions $saved_perms
}
}
if {[file extension $fullpath] eq ".la" && $statinfo(type) in {file link}} {
if {$statinfo(type) eq "link" && [file pathtype [file link $fullpath]] ne "relative"} {
# prepend $destroot to target of absolute symlinks
set checkpath ${destroot}[file link $fullpath]
} else {
set checkpath $fullpath
}
# Make sure it is from glibtool ... "a libtool library file" will appear in the first line
set is_la_file 0
if {![catch {open $checkpath} fp]} {
if {[gets $fp line] > 0 && [string first "a libtool library file" $line] != -1} {
set is_la_file 1
}
catch {close $fp}
} else {
ui_debug "Failed to open $checkpath"
}
if {$is_la_file} {
if {${destroot.delete_la_files}} {
ui_debug "Removing [file tail $fullpath]"
file delete ${fullpath}
} elseif {$statinfo(type) eq "file"} {
ui_debug "Clearing dependency_libs in [file tail $fullpath]"
reinplace -q "/dependency_libs/ s/'.*'/''/" ${fullpath}
}
}
}
}
# Prune empty directories in ${destroot}
package require fileutil
foreach path ${destroot.keepdirs} {
# Prepend $destroot if $path isn't already inside it
set path [::fileutil::jail $destroot $path]
if {![file isdirectory ${path}]} {
xinstall -m 0755 -d ${path}
}
if {![file exists ${path}/.turd_${subport}]} {
xinstall -c -m 0644 /dev/null ${path}/.turd_${subport}
}
}
fs-traverse -depth dir [list ${destroot}] {
if {[file type $dir] eq "directory"} {
catch {file delete $dir}
}
}
if {![file isdirectory ${destroot}]} {
ui_error "No files have been installed in the destroot directory!"
ui_error "Please make sure that this software supports\
'make install DESTDIR=\${destroot}' or implement an\
alternative destroot mechanism in the Portfile."
ui_error "Files might have been installed directly into your system,\
check before proceeding."
return -code error "Staging $subport into destroot failed"
}
# Compress all manpages with gzip (instead)
set manpath ${destroot}${prefix}/share/man
if {[file isdirectory ${manpath}] && [file type ${manpath}] eq "directory"} {
ui_info "$UI_PREFIX [format [msgcat::mc "Compressing man pages for %s"] ${subport}]"
set gzip [findBinary gzip ${::portutil::autoconf::gzip_path}]
set gunzip "$gzip -d"
set bunzip2 "[findBinary bzip2 ${::portutil::autoconf::bzip2_path}] -d"
set found 0
set manlinks [list]
set mandir_re {^(cat|man)(.)$}
foreach mandir [readdir "${manpath}"] {
if {![regexp ${mandir_re} ${mandir} match ignore manindex]} { continue }
set gzfile_re "^(.*\[.\]${manindex}\[a-z\]*)\[.\]gz\$"
set bz2file_re "^(.*\[.\]${manindex}\[a-z\]*)\[.\]bz2\$"
set normalfile_re "\[.\]${manindex}\[a-z\]*\$"
set mandirpath [file join ${manpath} ${mandir}]
if {[file isdirectory ${mandirpath}] && [file type ${mandirpath}] eq "directory"} {
ui_debug "Scanning ${mandir}"
foreach manfile [readdir ${mandirpath}] {
set manfilepath [file join ${mandirpath} ${manfile}]
if {[file isfile ${manfilepath}] && [file type ${manfilepath}] eq "file"} {
if {[regexp ${gzfile_re} ${manfile} gzfile manfile]} {
set found 1
system -W ${manpath} \
"$gunzip -f [shellescape [file join ${mandir} ${gzfile}]] && \
$gzip -9vnf [shellescape [file join ${mandir} ${manfile}]]"
} elseif {[regexp ${bz2file_re} ${manfile} bz2file manfile]} {
set found 1
system -W ${manpath} \
"$bunzip2 -f [shellescape [file join ${mandir} ${bz2file}]] && \
$gzip -9vnf [shellescape [file join ${mandir} ${manfile}]]"
} elseif {[regexp ${normalfile_re} ${manfile}]} {
set found 1
system -W ${manpath} \
"$gzip -9vnf [shellescape [file join ${mandir} ${manfile}]]"
}
set gzmanfile ${manfile}.gz
set gzmanfilepath [file join ${mandirpath} ${gzmanfile}]
if {[file exists ${gzmanfilepath}]} {
set desired 00444
set current [file attributes ${gzmanfilepath} -permissions]
if {$current != $desired} {
ui_info "[file join ${mandir} ${gzmanfile}]: changing permissions from $current to $desired"
file attributes ${gzmanfilepath} -permissions $desired
}
}
} elseif {[file type ${manfilepath}] eq "link"} {
lappend manlinks [file join ${mandir} ${manfile}]
}
}
}
}
if {$found == 1} {
# check man page links and rename/repoint them if necessary
set gzext_re "\[.\]gz\$"
foreach manlink $manlinks {
set manlinkpath [file join $manpath $manlink]
# if link destination is not gzipped, check it
set manlinksrc [file readlink $manlinkpath]
if {![regexp ${gzext_re} ${manlinksrc}]} {
set mandir [file dirname $manlink]
set mandirpath [file join $manpath $mandir]
if {[catch {pwd} oldpwd]} {
set oldpwd {}
}
if {[catch {_cd $mandirpath} err]} {
puts $err
return
}
# if link source is an absolute path, check for it under destroot
set mls_check "$manlinksrc"
if {[file pathtype $mls_check] eq "absolute"} {
set mls_check "${destroot}${mls_check}"
}
# if gzipped destination exists, fix link
if {[file isfile ${mls_check}.gz]} {
# if actual link name does not end with gz, rename it
if {![regexp ${gzext_re} ${manlink}]} {
ui_debug "renaming link: $manlink to ${manlink}.gz"
file rename $manlinkpath ${manlinkpath}.gz
set manlink ${manlink}.gz
set manlinkpath [file join $manpath $manlink]
}
# repoint the link
ui_debug "repointing link: $manlink from $manlinksrc to ${manlinksrc}.gz"
file delete $manlinkpath
ln -s "${manlinksrc}.gz" "${manlinkpath}"
}
if {$oldpwd ne {}} {
_cd $oldpwd
}
}
}
} else {
ui_debug "No man pages found to compress."
}
}
# test for violations of mtree
if { ${destroot.violate_mtree} ne "yes" } {
ui_debug "checking for mtree violations"
set mtree_violation "no"
set prefixPaths [list bin etc include lib libexec sbin share src var www Applications Developer Library]
set pathsToCheck [list /]
while {[llength $pathsToCheck] > 0} {
set pathToCheck [lpop pathsToCheck 0]
foreach file [glob -nocomplain -directory $destroot$pathToCheck .* *] {
if {[file tail $file] eq "." || [file tail $file] eq ".."} {
continue
}
if {[string equal -length [string length $destroot] $destroot $file]} {
# just double-checking that $destroot is a prefix, as is appropriate
set dfile [file join / [string range $file [string length $destroot] end]]
} else {
throw MACPORTS "Unexpected filepath `${file}' while checking for mtree violations"
}
if {$dfile eq $prefix} {
# we've found our prefix
foreach pfile [glob -nocomplain -tails -directory $file .* *] {
if {$pfile eq "." || $pfile eq ".."} {
continue
}
if {$pfile ni $prefixPaths} {
ui_warn "violation by [file join $dfile $pfile]"
set mtree_violation "yes"
}
}
} elseif {[string equal -length [expr {[string length $dfile] + 1}] $dfile/ $prefix]} {
# we've found a subpath of our prefix
lappend pathsToCheck $dfile
} else {
set dir_allowed no
# these files are (at least potentially) outside of the prefix
foreach dir [list $applications_dir $frameworks_dir /Library/LaunchAgents /Library/LaunchDaemons /Library/StartupItems] {
if {[string equal -length [expr {[string length $dfile] + 1}] $dfile/ $dir]} {
# it's a prefix of one of the allowed paths
set dir_allowed yes
break
}
}
if {$dir_allowed} {
lappend pathsToCheck $dfile
} else {
# not a prefix of an allowed path, so it's either the path itself or a violation
switch -- $dfile \
$applications_dir - \
$frameworks_dir - \
/Library/LaunchAgents - \
/Library/LaunchDaemons - \
/Library/StartupItems { ui_debug "port installs files in $dfile" } \
default {
ui_warn "violation by $dfile"
set mtree_violation "yes"
}
}
}
}
}
# abort here only so all violations can be observed
if { ${mtree_violation} ne "no" } {
ui_warn "[format [msgcat::mc "%s violates the layout of the ports-filesystems!"] $subport]"
ui_warn "Please fix or indicate this misbehavior (if it is intended), it will be an error in future releases!"
# error "mtree violation!"
}
} else {
ui_warn "[format [msgcat::mc "%s installs files outside the common directory structure."] $subport]"
}
# Work around apparent filesystem bug.
# https://trac.macports.org/ticket/67336
if {![catch {fs_clone_capable $destroot} result] && $result} {
global workpath
ui_debug "Applying sparse file lseek bug workaround"
try {
fs-traverse -depth fullpath [list $destroot] {
if {[file type $fullpath] eq "file" && [fileIsSparse $fullpath]} {
ui_debug "Cloning $fullpath for workaround"
clonefile $fullpath ${workpath}/.macports-sparse-workaround
file delete ${workpath}/.macports-sparse-workaround
if {![fileIsSparse $fullpath]} {
ui_debug "$fullpath is no longer sparse"
}
}
}
} on error {eMessage} {
ui_debug "Error while applying sparse file workaround: $eMessage"
}
}
# Restore umask
umask $oldmask
return 0
}
}
+2 -128
View File
@@ -1,142 +1,16 @@
# et:ts=4
# portdistcheck.tcl
#
# Copyright (c) 2007-2011, 2014, 2016 The MacPorts Project
# Copyright (c) 2005-2006 Paul Guyot <pguyot@kallisys.net>,
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of The MacPorts Project nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
package provide portdistcheck 1.0
package require portutil 1.0
package require portfetch 1.0
set org.macports.distcheck [target_new org.macports.distcheck portdistcheck::distcheck_main]
target_runtype ${org.macports.distcheck} always
target_state ${org.macports.distcheck} no
target_provides ${org.macports.distcheck} distcheck
target_requires ${org.macports.distcheck} main
namespace eval portdistcheck {
}
target_runpkg ${org.macports.distcheck} portdistcheck_run
# define options
options distcheck.type
# defaults
default distcheck.type moddate
proc portdistcheck::distcheck_main {args} {
global distcheck.type fetch.type fetch.ignore_sslcert \
subport portpath
set port_moddate [file mtime ${portpath}/Portfile]
ui_debug "Portfile modification date is [clock format $port_moddate]"
set curl_options [list]
if {[tbool fetch.ignore_sslcert]} {
lappend curl_options "--ignore-ssl-cert"
}
# Check the distfiles if it's a regular fetch phase.
if {${distcheck.type} ne "none"
&& ${fetch.type} eq "standard"} {
# portfetch 1.0::checkfiles sets fetch_urls list.
set fetch_urls [list]
portfetch::checkfiles fetch_urls
set totalsize 0
global portfetch::urlmap
# Check all the files.
foreach {url_var distfile} $fetch_urls {
if {![info exists urlmap($url_var)]} {
ui_error [format [msgcat::mc "No defined site for tag: %s, using master_sites"] $url_var]
set urlmap($url_var) $master_sites
}
if {${distcheck.type} eq "moddate"} {
set count 0
foreach site $urlmap($url_var) {
ui_debug [format [msgcat::mc "Checking %s from %s"] $distfile $site]
set file_url [portfetch::assemble_url $site $distfile]
macports_try -pass_signal {
set urlnewer [curl isnewer {*}$curl_options $file_url $port_moddate]
if {$urlnewer} {
ui_warn "port $subport: $file_url is newer than Portfile"
}
incr count
} on error {eMessage} {
ui_debug [msgcat::mc "couldn't fetch %s for %s (%s)" $file_url $subport $eMessage]
}
}
if {$count == 0} {
ui_error "no mirror had $distfile for $subport"
}
} elseif {${distcheck.type} eq "filesize"} {
set count 0
foreach site $urlmap($url_var) {
ui_debug [format [msgcat::mc "Checking %s from %s"] $distfile $site]
set file_url [portfetch::assemble_url $site $distfile]
macports_try -pass_signal {
set urlsize [curl getsize {*}$curl_options $file_url]
incr count
if {$urlsize > 0} {
ui_info "port $subport: $distfile $urlsize bytes"
incr totalsize $urlsize
break
}
} on error {eMessage} {
ui_debug [msgcat::mc "couldn't fetch %s for %s (%s)" $file_url $subport $eMessage]
}
}
if {$count == 0} {
ui_error "no mirror had $distfile for $subport"
}
} else {
ui_error "unknown distcheck.type ${distcheck.type}"
break
}
}
if {${distcheck.type} eq "filesize" && $totalsize > 0} {
if {$totalsize < 1024} {
set size $totalsize
set humansize "${size}"
} elseif {$totalsize < 1024*1024} {
set size [expr {$totalsize / 1024.0}]
set humansize [format "%.1fK" $size]
} elseif {$totalsize < 1024*1024*1024} {
set size [expr {$totalsize / (1024.0*1024.0)}]
set humansize [format "%.1fM" $size]
} else {
set size [expr {$totalsize / (1024.0*1024.0*1024.0)}]
set humansize [format "%.1fG" $size]
}
ui_msg "$subport: $humansize"
}
}
}
+130
View File
@@ -0,0 +1,130 @@
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
#
# Copyright (c) 2007-2011, 2014, 2016 The MacPorts Project
# Copyright (c) 2005-2006 Paul Guyot <pguyot@kallisys.net>,
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of The MacPorts Project nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package provide portdistcheck_run 1.0
package require portutil 1.0
package require portfetch 1.0
package require portfetch_run 1.0
namespace eval portdistcheck {
proc distcheck_main {args} {
global distcheck.type fetch.type fetch.ignore_sslcert \
subport portpath
set port_moddate [file mtime ${portpath}/Portfile]
ui_debug "Portfile modification date is [clock format $port_moddate]"
set curl_options [list]
if {[tbool fetch.ignore_sslcert]} {
lappend curl_options "--ignore-ssl-cert"
}
# Check the distfiles if it's a regular fetch phase.
if {${distcheck.type} ne "none"
&& ${fetch.type} eq "standard"} {
# portfetch 1.0::checkfiles sets fetch_urls list.
set fetch_urls [list]
portfetch::checkfiles fetch_urls
set totalsize 0
global portfetch::urlmap
# Check all the files.
foreach {url_var distfile} $fetch_urls {
if {![info exists urlmap($url_var)]} {
ui_error [format [msgcat::mc "No defined site for tag: %s, using master_sites"] $url_var]
set urlmap($url_var) $master_sites
}
if {${distcheck.type} eq "moddate"} {
set count 0
foreach site $urlmap($url_var) {
ui_debug [format [msgcat::mc "Checking %s from %s"] $distfile $site]
set file_url [portfetch::assemble_url $site $distfile]
macports_try -pass_signal {
set urlnewer [curl isnewer {*}$curl_options $file_url $port_moddate]
if {$urlnewer} {
ui_warn "port $subport: $file_url is newer than Portfile"
}
incr count
} on error {eMessage} {
ui_debug [msgcat::mc "couldn't fetch %s for %s (%s)" $file_url $subport $eMessage]
}
}
if {$count == 0} {
ui_error "no mirror had $distfile for $subport"
}
} elseif {${distcheck.type} eq "filesize"} {
set count 0
foreach site $urlmap($url_var) {
ui_debug [format [msgcat::mc "Checking %s from %s"] $distfile $site]
set file_url [portfetch::assemble_url $site $distfile]
macports_try -pass_signal {
set urlsize [curl getsize {*}$curl_options $file_url]
incr count
if {$urlsize > 0} {
ui_info "port $subport: $distfile $urlsize bytes"
incr totalsize $urlsize
break
}
} on error {eMessage} {
ui_debug [msgcat::mc "couldn't fetch %s for %s (%s)" $file_url $subport $eMessage]
}
}
if {$count == 0} {
ui_error "no mirror had $distfile for $subport"
}
} else {
ui_error "unknown distcheck.type ${distcheck.type}"
break
}
}
if {${distcheck.type} eq "filesize" && $totalsize > 0} {
if {$totalsize < 1024} {
set size $totalsize
set humansize "${size}"
} elseif {$totalsize < 1024*1024} {
set size [expr {$totalsize / 1024.0}]
set humansize [format "%.1fK" $size]
} elseif {$totalsize < 1024*1024*1024} {
set size [expr {$totalsize / (1024.0*1024.0)}]
set humansize [format "%.1fM" $size]
} else {
set size [expr {$totalsize / (1024.0*1024.0*1024.0)}]
set humansize [format "%.1fG" $size]
}
ui_msg "$subport: $humansize"
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More