diff --git a/src/port1.0/Makefile.in b/src/port1.0/Makefile.in index 8bf7669ce..b837362d5 100644 --- a/src/port1.0/Makefile.in +++ b/src/port1.0/Makefile.in @@ -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 diff --git a/src/port1.0/portactivate.tcl b/src/port1.0/portactivate.tcl index c1c5167f7..191ea73a6 100644 --- a/src/port1.0/portactivate.tcl +++ b/src/port1.0/portactivate.tcl @@ -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 -# 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 -} diff --git a/src/port1.0/portactivate_run.tcl b/src/port1.0/portactivate_run.tcl new file mode 100644 index 000000000..586eb7dde --- /dev/null +++ b/src/port1.0/portactivate_run.tcl @@ -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 +# 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 +} + +} diff --git a/src/port1.0/portbuild.tcl b/src/port1.0/portbuild.tcl index b565a1d1a..709487866 100644 --- a/src/port1.0/portbuild.tcl +++ b/src/port1.0/portbuild.tcl @@ -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 -} diff --git a/src/port1.0/portbuild_run.tcl b/src/port1.0/portbuild_run.tcl new file mode 100644 index 000000000..a627aa997 --- /dev/null +++ b/src/port1.0/portbuild_run.tcl @@ -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 +} + +} diff --git a/src/port1.0/portbump.tcl b/src/port1.0/portbump.tcl index 9b3aefd3d..2cad1cae5 100644 --- a/src/port1.0/portbump.tcl +++ b/src/port1.0/portbump.tcl @@ -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 "" - 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 diff --git a/src/port1.0/portbump_run.tcl b/src/port1.0/portbump_run.tcl new file mode 100644 index 000000000..0b6fc0182 --- /dev/null +++ b/src/port1.0/portbump_run.tcl @@ -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 "" + 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 + } +} + + +} diff --git a/src/port1.0/portchecksum.tcl b/src/port1.0/portchecksum.tcl index f4a4e5105..919031e0b 100644 --- a/src/port1.0/portchecksum.tcl +++ b/src/port1.0/portchecksum.tcl @@ -1,43 +1,12 @@ -# et:ts=4 -# portchecksum.tcl -# -# Copyright (c) 2002 - 2004 Apple Inc. -# Copyright (c) 2004 - 2005 Paul Guyot -# 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 "" - 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 -} diff --git a/src/port1.0/portchecksum_run.tcl b/src/port1.0/portchecksum_run.tcl new file mode 100644 index 000000000..3967bc6a5 --- /dev/null +++ b/src/port1.0/portchecksum_run.tcl @@ -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 +# 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 "" + 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 +} + +} diff --git a/src/port1.0/portclean.tcl b/src/port1.0/portclean.tcl index 3c04ac7d2..4b4a3b7c7 100644 --- a/src/port1.0/portclean.tcl +++ b/src/port1.0/portclean.tcl @@ -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 -# 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 diff --git a/src/port1.0/portclean_run.tcl b/src/port1.0/portclean_run.tcl new file mode 100644 index 000000000..330b04c69 --- /dev/null +++ b/src/port1.0/portclean_run.tcl @@ -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 +# 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 +} + +} diff --git a/src/port1.0/portconfigure.tcl b/src/port1.0/portconfigure.tcl index f93273ee2..7bc5e6687 100644 --- a/src/port1.0/portconfigure.tcl +++ b/src/port1.0/portconfigure.tcl @@ -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 - } - } -} diff --git a/src/port1.0/portconfigure_run.tcl b/src/port1.0/portconfigure_run.tcl new file mode 100644 index 000000000..aadc9acbf --- /dev/null +++ b/src/port1.0/portconfigure_run.tcl @@ -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 + } + } +} + +} diff --git a/src/port1.0/portdeactivate.tcl b/src/port1.0/portdeactivate.tcl index 2cedb5704..b54086061 100644 --- a/src/port1.0/portdeactivate.tcl +++ b/src/port1.0/portdeactivate.tcl @@ -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 diff --git a/src/port1.0/portdeactivate_run.tcl b/src/port1.0/portdeactivate_run.tcl new file mode 100644 index 000000000..59ce2d1b9 --- /dev/null +++ b/src/port1.0/portdeactivate_run.tcl @@ -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 +} + +} diff --git a/src/port1.0/portdepends.tcl b/src/port1.0/portdepends.tcl index 82dc09dad..811ed6396 100644 --- a/src/port1.0/portdepends.tcl +++ b/src/port1.0/portdepends.tcl @@ -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"] } + +} diff --git a/src/port1.0/portdestroot.tcl b/src/port1.0/portdestroot.tcl index 0537de6af..644fbc4cf 100644 --- a/src/port1.0/portdestroot.tcl +++ b/src/port1.0/portdestroot.tcl @@ -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 -# 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 } diff --git a/src/port1.0/portdestroot_run.tcl b/src/port1.0/portdestroot_run.tcl new file mode 100644 index 000000000..4a6aa37ba --- /dev/null +++ b/src/port1.0/portdestroot_run.tcl @@ -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 +# 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 +} + +} diff --git a/src/port1.0/portdistcheck.tcl b/src/port1.0/portdistcheck.tcl index 0321bc068..0185dd5f2 100644 --- a/src/port1.0/portdistcheck.tcl +++ b/src/port1.0/portdistcheck.tcl @@ -1,142 +1,16 @@ -# et:ts=4 -# portdistcheck.tcl -# -# Copyright (c) 2007-2011, 2014, 2016 The MacPorts Project -# Copyright (c) 2005-2006 Paul Guyot , -# 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" - } - } -} diff --git a/src/port1.0/portdistcheck_run.tcl b/src/port1.0/portdistcheck_run.tcl new file mode 100644 index 000000000..8462c3cad --- /dev/null +++ b/src/port1.0/portdistcheck_run.tcl @@ -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 , +# 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" + } + } +} + +} diff --git a/src/port1.0/portdistfiles.tcl b/src/port1.0/portdistfiles.tcl index 025e5fc9f..88c73be1b 100644 --- a/src/port1.0/portdistfiles.tcl +++ b/src/port1.0/portdistfiles.tcl @@ -1,38 +1,6 @@ -# -*- 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 -# portdistfiles.tcl -# -# Copyright (c) 2008-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. -# +# -*- 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 portdistfiles 1.0 -package require portutil 1.0 -package require portfetch 1.0 -package require portchecksum 1.0 set org.macports.distfiles [target_new org.macports.distfiles portdistfiles::distfiles_main] target_runtype ${org.macports.distfiles} always @@ -40,62 +8,4 @@ target_state ${org.macports.distfiles} no target_provides ${org.macports.distfiles} distfiles target_requires ${org.macports.distfiles} main target_prerun ${org.macports.distfiles} portdistfiles::distfiles_start - -namespace eval portdistfiles { -} - -set_ui_prefix - -proc portdistfiles::distfiles_start {args} { - global UI_PREFIX subport - ui_notice "$UI_PREFIX [format [msgcat::mc "Distfiles for %s"] ${subport}]" -} - -proc portdistfiles::distfiles_main {args} { - global master_sites patch_sites patchfiles checksums_array \ - portdbpath dist_subdir all_dist_files - - # give up on ports that do not provide URLs - if {(![info exists master_sites] || $master_sites eq "{}") - && (![info exists patchfiles] || ![info exists patch_sites] || $patch_sites eq "{}")} { - return 0 - } - - # from portfetch... process the sites, files and patches - set fetch_urls [list] - portfetch::checkfiles fetch_urls - - # also give up on ports that don't have any distfiles - if {![info exists all_dist_files]} { - return 0 - } - - # get checksum data from the portfile and parse it - set result [portchecksum::parse_checksums [option checksums]] - - global portfetch::urlmap - foreach {url_var distfile} $fetch_urls { - ui_msg "\[$distfile\] [file join $portdbpath distfiles $dist_subdir $distfile]" - - # print checksums if available - if {$result eq "yes" && [info exists checksums_array($distfile)]} { - foreach {type sum} $checksums_array($distfile) { - ui_msg " $type: $sum" - } - } - - # determine sites to download from - if {![info exists urlmap($url_var)]} { - set urlmap($url_var) $urlmap(master_sites) - } - - # determine URLs to download - foreach site $urlmap($url_var) { - set file_url [portfetch::assemble_url $site $distfile] - ui_msg " $file_url" - } - - ui_msg " " - - } -} +target_runpkg ${org.macports.distfiles} portdistfiles_run diff --git a/src/port1.0/portdistfiles_run.tcl b/src/port1.0/portdistfiles_run.tcl new file mode 100644 index 000000000..440b87656 --- /dev/null +++ b/src/port1.0/portdistfiles_run.tcl @@ -0,0 +1,91 @@ +# -*- 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) 2008-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 portdistfiles_run 1.0 +package require portutil 1.0 +package require portfetch_run 1.0 +package require portchecksum_run 1.0 + +namespace eval portdistfiles { + +proc distfiles_start {args} { + global UI_PREFIX subport + ui_notice "$UI_PREFIX [format [msgcat::mc "Distfiles for %s"] ${subport}]" +} + +proc distfiles_main {args} { + global master_sites patch_sites patchfiles checksums_array \ + portdbpath dist_subdir all_dist_files + + # give up on ports that do not provide URLs + if {(![info exists master_sites] || $master_sites eq "{}") + && (![info exists patchfiles] || ![info exists patch_sites] || $patch_sites eq "{}")} { + return 0 + } + + # from portfetch... process the sites, files and patches + set fetch_urls [list] + portfetch::checkfiles fetch_urls + + # also give up on ports that don't have any distfiles + if {![info exists all_dist_files]} { + return 0 + } + + # get checksum data from the portfile and parse it + set result [portchecksum::parse_checksums [option checksums]] + + global portfetch::urlmap + foreach {url_var distfile} $fetch_urls { + ui_msg "\[$distfile\] [file join $portdbpath distfiles $dist_subdir $distfile]" + + # print checksums if available + if {$result eq "yes" && [info exists checksums_array($distfile)]} { + foreach {type sum} $checksums_array($distfile) { + ui_msg " $type: $sum" + } + } + + # determine sites to download from + if {![info exists urlmap($url_var)]} { + set urlmap($url_var) $urlmap(master_sites) + } + + # determine URLs to download + foreach site $urlmap($url_var) { + set file_url [portfetch::assemble_url $site $distfile] + ui_msg " $file_url" + } + + ui_msg " " + + } +} + +} diff --git a/src/port1.0/portlint.tcl b/src/port1.0/portlint.tcl index adc172ad4..1af24f709 100644 --- a/src/port1.0/portlint.tcl +++ b/src/port1.0/portlint.tcl @@ -82,8 +82,6 @@ namespace eval portlint { ] } -set_ui_prefix - # lint_checksum_types # # Given a list of checksum types, return a list of strings which are warnings @@ -115,6 +113,36 @@ proc portlint::lint_checksum_type_list {types} { return $issues } +# 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 portlint::verify_checksum_format {type value} { + switch [string tolower $type] { + sha256 - + blake3 { + return [regexp {^[0-9a-f]{64}$} $value] + } + rmd160 - + sha1 { + return [regexp {^[0-9a-f]{40}$} $value] + } + md5 { + return [regexp {^[0-9a-f]{32}$} $value] + } + size { + return [regexp {^\d+$} $value] + } + default { + # unrecognized checksum type + return -1 + } + } +} + # lint_checksum # # Checks a given Portfile checksum string. Returns a list of lists. @@ -152,7 +180,7 @@ proc portlint::lint_checksum {checksum_string} { set c_type $current set c_value [lindex $checksum_tokens $ctr+1] - switch [portchecksum::verify_checksum_format $c_type $c_value] { + switch [portlint::verify_checksum_format $c_type $c_value] { 1 { # checksum type recognized, and checksum looks good incr ctr 2 @@ -183,7 +211,7 @@ proc portlint::lint_checksum {checksum_string} { if {$ctr == $ctr_start} { set has_filenames true } elseif {($ctr == ([llength $checksum_tokens] - 1)) || \ - ([portchecksum::verify_checksum_format \ + ([portlint::verify_checksum_format \ [lindex $checksum_tokens $ctr-2] \ [lindex $checksum_tokens $ctr-1] \ ] != 1)} { diff --git a/src/port1.0/tests/portactivate.test b/src/port1.0/tests/portactivate.test index 4b48a6936..e566c4f3e 100644 --- a/src/port1.0/tests/portactivate.test +++ b/src/port1.0/tests/portactivate.test @@ -8,7 +8,10 @@ set pwd [file dirname [file normalize $argv0]] source ../port_test_autoconf.tcl source $macports::autoconf::top_srcdir/src/macports1.0/tests/test_setup.tcl +package require port 1.0 +package require portutil 1.0 package require portactivate 1.0 +package require portactivate_run 1.0 package require registry 1.0 macports_worker_init diff --git a/src/port1.0/tests/portbuild.test b/src/port1.0/tests/portbuild.test index ba539e221..7d941136a 100644 --- a/src/port1.0/tests/portbuild.test +++ b/src/port1.0/tests/portbuild.test @@ -14,6 +14,7 @@ namespace eval port { proc run_callbacks {args} {} } +package require portutil 1.0 package require portbuild 1.0 set build_getjobs_fixture_setup { diff --git a/src/port1.0/tests/portbump.test b/src/port1.0/tests/portbump.test index 984b87021..9e682fd85 100644 --- a/src/port1.0/tests/portbump.test +++ b/src/port1.0/tests/portbump.test @@ -14,7 +14,9 @@ namespace eval port { proc run_callbacks {args} {} } +package require portutil 1.0 package require portbump 1.0 +package require portbump_run 1.0 # ============================================================ # Tests for portbump::replace_checksums diff --git a/src/port1.0/tests/portchecksum.test b/src/port1.0/tests/portchecksum.test index 60c636d2c..d0bc058dc 100644 --- a/src/port1.0/tests/portchecksum.test +++ b/src/port1.0/tests/portchecksum.test @@ -8,7 +8,10 @@ set pwd [file dirname [file normalize $argv0]] source ../port_test_autoconf.tcl source $macports::autoconf::top_srcdir/src/macports1.0/tests/test_setup.tcl +package require portutil 1.0 package require portchecksum 1.0 +package require portchecksum_run +set_ui_prefix proc make_blake3_test_vector_file {path length} { set fd [open $path w] @@ -145,91 +148,8 @@ test calc_blake3_multichunk { } -result "Calc multi-chunk blake3 successful." -test verify_checksum_format_md5 { - Test that we properly verify an MD5 checksum -} -body { - set checksum "9f70ecc1095ff10df81be6b5f218328d" - if {[portchecksum::verify_checksum_format "md5" $checksum] != 1} { - return "FAIL: did not verify $checksum as MD5" - } - return "Verify MD5 successful" -} -result "Verify MD5 successful" - -test verify_checksum_format_sha1 { - Test that we properly verify an SHA1 checksum -} -body { - set checksum "5560df60ff202ca8b8c3dcf51ad650b78e859261" - if {[portchecksum::verify_checksum_format "sha1" $checksum] != 1} { - return "FAIL: did not verify $checksum as SHA1" - } - return "Verify SHA1 successful" -} -result "Verify SHA1 successful" - -test verify_checksum_format_rmd160 { - Test that we properly verify an rmd160 checksum -} -body { - set checksum "5aee5d12fe536e2e288e9f1daafd84f1bc17c3e6" - if {[portchecksum::verify_checksum_format "rmd160" $checksum] != 1} { - return "FAIL: did not verify $checksum as rmd160" - } - return "Verify rmd160 successful" -} -result "Verify rmd160 successful" - -test verify_checksum_format_sha256 { - Test that we properly verify an SHA256 checksum -} -body { - set checksum "2f686816f2a80e8efcc4ef40ac4e898d27ce4205a61ee422d56f8c5e8b46612e" - if {[portchecksum::verify_checksum_format "sha256" $checksum] != 1} { - return "FAIL: did not verify $checksum as sha256" - } - return "Verify sha256 successful" -} -result "Verify sha256 successful" - -test verify_checksum_format_blake3 { - Test that we properly verify a BLAKE3 checksum -} -body { - set checksum "bb25f9a3571c6a1580e33ea64b34124c93fed104092497a91450c21a66ee57e3" - if {[portchecksum::verify_checksum_format "blake3" $checksum] != 1} { - return "FAIL: did not verify $checksum as blake3" - } - return "Verify blake3 successful" -} -result "Verify blake3 successful" - -test verify_checksum_format_blake3_too_short { - Test that we reject a BLAKE3 checksum that is too short -} -body { - set checksum "bb25f9a3571c6a1580e33ea64b34124c93fed104092497a91450c21a66ee57" - if {[portchecksum::verify_checksum_format "blake3" $checksum] != 0} { - return "FAIL: did not reject short blake3 checksum" - } - return "Reject short blake3 successful" -} -result "Reject short blake3 successful" - -test verify_checksum_format_blake3_non_hex { - Test that we reject a BLAKE3 checksum containing non-hex characters -} -body { - set checksum "bb25f9a3571c6a1580e33ea64b34124c93fed104092497a91450c21a66ee57zz" - if {[portchecksum::verify_checksum_format "blake3" $checksum] != 0} { - return "FAIL: did not reject non-hex blake3 checksum" - } - return "Reject non-hex blake3 successful" -} -result "Reject non-hex blake3 successful" - -test verify_unknown_checksum_format { - Test that we respond as expected to an unknown checksum format -} -body { - set checksum "thisisnotread" - if {[portchecksum::verify_checksum_format "lol22" $checksum] != -1} { - return "FAIL: did not respond as expected to an unknown checksum" - } - return "Verify unknown successful" -} -result "Verify unknown successful" - - - # test checksum_start - test checksum_main { Checksum main unit test. Checks for empty files. } -body { diff --git a/src/port1.0/tests/portclean.test b/src/port1.0/tests/portclean.test index 4ff02ad98..2b8f00d64 100644 --- a/src/port1.0/tests/portclean.test +++ b/src/port1.0/tests/portclean.test @@ -8,7 +8,9 @@ set pwd [file dirname [file normalize $argv0]] source ../port_test_autoconf.tcl source $macports::autoconf::top_srcdir/src/macports1.0/tests/test_setup.tcl +package require portutil 1.0 package require portclean 1.0 +package require portclean_run 1.0 source ../port_autoconf.tcl macports_worker_init diff --git a/src/port1.0/tests/portdeactivate.test b/src/port1.0/tests/portdeactivate.test index 2f6074f25..7a16ba396 100644 --- a/src/port1.0/tests/portdeactivate.test +++ b/src/port1.0/tests/portdeactivate.test @@ -8,6 +8,7 @@ set pwd [file dirname [file normalize $argv0]] source ../port_test_autoconf.tcl source $macports::autoconf::top_srcdir/src/macports1.0/tests/test_setup.tcl +package require portutil 1.0 package require portdeactivate 1.0 package require registry 1.0 macports_worker_init diff --git a/src/port1.0/tests/portdepends.test b/src/port1.0/tests/portdepends.test index 19f8633d1..b99f38a90 100644 --- a/src/port1.0/tests/portdepends.test +++ b/src/port1.0/tests/portdepends.test @@ -8,9 +8,9 @@ set pwd [file dirname [file normalize $argv0]] source ../port_test_autoconf.tcl source $macports::autoconf::top_srcdir/src/macports1.0/tests/test_setup.tcl +package require portutil 1.0 package require portdepends 1.0 - test validate_depends_options { Validate depends unit test. } -body { diff --git a/src/port1.0/tests/portdistcheck.test b/src/port1.0/tests/portdistcheck.test index 8c4695048..12d8de915 100644 --- a/src/port1.0/tests/portdistcheck.test +++ b/src/port1.0/tests/portdistcheck.test @@ -8,7 +8,9 @@ set pwd [file dirname [file normalize $argv0]] source ../port_test_autoconf.tcl source $macports::autoconf::top_srcdir/src/macports1.0/tests/test_setup.tcl +package require portutil 1.0 package require portdistcheck 1.0 +package require portdistcheck_run 1.0 macports_worker_init diff --git a/src/port1.0/tests/portlint.test b/src/port1.0/tests/portlint.test index 7a074dad6..9162c51d4 100644 --- a/src/port1.0/tests/portlint.test +++ b/src/port1.0/tests/portlint.test @@ -10,6 +10,86 @@ source $macports::autoconf::top_srcdir/src/macports1.0/tests/test_setup.tcl package require portlint 1.0 +test verify_checksum_format_md5 { + Test that we properly verify an MD5 checksum +} -body { + set checksum "9f70ecc1095ff10df81be6b5f218328d" + if {[portlint::verify_checksum_format "md5" $checksum] != 1} { + return "FAIL: did not verify $checksum as MD5" + } + return "Verify MD5 successful" +} -result "Verify MD5 successful" + +test verify_checksum_format_sha1 { + Test that we properly verify an SHA1 checksum +} -body { + set checksum "5560df60ff202ca8b8c3dcf51ad650b78e859261" + if {[portlint::verify_checksum_format "sha1" $checksum] != 1} { + return "FAIL: did not verify $checksum as SHA1" + } + return "Verify SHA1 successful" +} -result "Verify SHA1 successful" + +test verify_checksum_format_rmd160 { + Test that we properly verify an rmd160 checksum +} -body { + set checksum "5aee5d12fe536e2e288e9f1daafd84f1bc17c3e6" + if {[portlint::verify_checksum_format "rmd160" $checksum] != 1} { + return "FAIL: did not verify $checksum as rmd160" + } + return "Verify rmd160 successful" +} -result "Verify rmd160 successful" + +test verify_checksum_format_sha256 { + Test that we properly verify an SHA256 checksum +} -body { + set checksum "2f686816f2a80e8efcc4ef40ac4e898d27ce4205a61ee422d56f8c5e8b46612e" + if {[portlint::verify_checksum_format "sha256" $checksum] != 1} { + return "FAIL: did not verify $checksum as sha256" + } + return "Verify sha256 successful" +} -result "Verify sha256 successful" + +test verify_checksum_format_blake3 { + Test that we properly verify a BLAKE3 checksum +} -body { + set checksum "bb25f9a3571c6a1580e33ea64b34124c93fed104092497a91450c21a66ee57e3" + if {[portlint::verify_checksum_format "blake3" $checksum] != 1} { + return "FAIL: did not verify $checksum as blake3" + } + return "Verify blake3 successful" +} -result "Verify blake3 successful" + +test verify_checksum_format_blake3_too_short { + Test that we reject a BLAKE3 checksum that is too short +} -body { + set checksum "bb25f9a3571c6a1580e33ea64b34124c93fed104092497a91450c21a66ee57" + if {[portlint::verify_checksum_format "blake3" $checksum] != 0} { + return "FAIL: did not reject short blake3 checksum" + } + return "Reject short blake3 successful" +} -result "Reject short blake3 successful" + +test verify_checksum_format_blake3_non_hex { + Test that we reject a BLAKE3 checksum containing non-hex characters +} -body { + set checksum "bb25f9a3571c6a1580e33ea64b34124c93fed104092497a91450c21a66ee57zz" + if {[portlint::verify_checksum_format "blake3" $checksum] != 0} { + return "FAIL: did not reject non-hex blake3 checksum" + } + return "Reject non-hex blake3 successful" +} -result "Reject non-hex blake3 successful" + +test verify_unknown_checksum_format { + Test that we respond as expected to an unknown checksum format +} -body { + set checksum "thisisnotread" + if {[portlint::verify_checksum_format "lol22" $checksum] != -1} { + return "FAIL: did not respond as expected to an unknown checksum" + } + return "Verify unknown successful" +} -result "Verify unknown successful" + test test_lint_checksum_type_list { Verify that we get no warnings if we pass in the list of recommended checksum types to lint_checksum_type_list.