3 # pt -- the MacPorts port tool"
4 # Copyright (c)2007-2009 Alexander Barton, alex@barton.de
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 # Please read the file COPYING, README and AUTHORS for more information.
22 UPGRADE_REMOVE_INACTIVE=1
25 declare -i WIDTH=${COLUMNS:-80}
27 LINE="-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
30 # Display version information.
32 echo "$NAME $VERSION ($DATE) -- the MacPorts port tool"
33 echo "Copyright (c)2007-2009 Alexander Barton, alex@barton.de"
35 echo "This is free software; see the source for copying conditions. There is NO"
36 echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
41 # Display some usage information and exit.
44 echo "Usage: $0 <options> <command> [<args> ...]"
46 echo "Available commands:"
47 echo " deps <port> [<port> [...]] -- examine dependencies"
48 echo " install <port> [<port> [...]] -- install port(s)"
49 echo " remove <port> [<port> [...]] -- remove port(s)"
50 echo " clean <port> [<port> [...]] -- clean port build files"
51 echo " update -- update port database"
52 echo " outdated -- list all outdated ports"
53 echo " upgrade -- upgrade outdated port(s)"
54 echo " freshup -- update port database & list outdated ports"
55 echo " search <term> -- search for port(s)"
56 echo " list <term> -- list port(s)"
57 echo " info <port> -- display details of a port"
58 echo " status -- show MacPorts status"
60 echo "The following global options are available:"
61 echo " -q: quiet mode, little output +q: no quiet mode, normal output"
62 echo " -v: enable verbose mode +v: disable verbose mode"
63 echo " -V: verbose port(1) messages +V: no verbose port(1) messages"
64 echo " -d: enable debug mode +d: disable verbose mode"
70 # Initialize "state machine", clear temporary files.
72 Verbose_Msg "Initializing port states ..."
73 port list >"$TMPDIR/available"
74 Debug_Msg "Listing installed ports ..."
75 port installed | grep "^ " >"$TMPDIR/installed"
76 Debug_Msg "Listing inactive ports ..."
77 port list inactive >"$TMPDIR/inactive"
78 echo -n '' >"$TMPDIR/required.all"
79 echo -n '' >"$TMPDIR/missing.all"
80 echo -n "" >"$TMPDIR/outdated"
81 echo -n "" >"$TMPDIR/outdated.info"
83 declare -i c_avail=`cat "$TMPDIR/available" | wc -l`
84 declare -i c_inst=`cat "$TMPDIR/installed" | wc -l`
85 declare -i c_inact=`cat "$TMPDIR/inactive" | wc -l`
87 [ $c_inst -eq $c_avail ] && c_inst=0
88 [ $c_inact -eq $c_avail ] && c_inact=0
89 [ $c_inact -eq 0 ] && s="" || s=" ($c_inact inactive)"
90 Verbose_Msg "$c_avail ports available, $c_inst installed$s."
94 # Reset "required" and "missing" package lists, move saved
95 # packages to "required.all"/"missing.all" lists for later
98 Debug_Msg "Resetting internal state ..."
101 [ -r "$TMPDIR/required" ] \
102 && cat "$TMPDIR/required" >>"$TMPDIR/required.all"
103 echo -n '' >"$TMPDIR/required"
105 [ -r "$TMPDIR/missing" ] \
106 && cat "$TMPDIR/missing" >>"$TMPDIR/missing.all"
107 echo -n '' >"$TMPDIR/missing"
111 # Check, if this script is running with root privileges.
113 [ "$UID" -eq 0 -o "$EUID" -eq 0 ] && return 0
114 Error_Msg "This function must be executed with root privileges!"
119 # List contents of temporary directory to console.
120 echo "--- $TMPDIR ---"; ls -al "$TMPDIR"; echo "---"
124 # Dump contents of a file to console.
125 echo "--- $1 ---"; cat "$1"; echo "---"
129 # Exit this scripts after cleaning up.
132 Debug_Msg "Cleaning up ..."
133 [ -n "$TMPDIR" ] && rm -rf "$TMPDIR"
134 Debug_Msg "Done. Exit code: $1"
138 Clean_Exit_Signal() {
139 # Exit this script with exit code 127, used when an interup signal
140 # (SIGINT) has been catched.
147 # Display message, if not running in "quiet" mode.
148 # $*: message to display.
150 [ -n "$QUIET" ] && return
151 if [ "$1" = "-n" ]; then
160 # Display message, even when running in "quiet" mode.
161 # $*: message to display.
163 if [ "$1" = "-n" ]; then
172 # Display message when running in "debug" or "verbose" mode.
173 # $*: message to display.
175 [ -z "$QUIET" -a -n "$VERBOSE" ] && echo $*
179 # Display message when running in "debug" mode.
180 # $*: message to display.
182 [ -n "$DEBUG" ] && echo $*
186 # Display warning message.
187 # $*: message to display.
193 # Display error message.
194 # $*: message to display.
201 [ $? -ne 0 ] && return 0
204 Msg_NoQuiet -n "$* [Y/n] "
205 while [ "$x" != "" -a "$x" != "n" -a "$x" != "N" -a "$x" != "y" -a "$x" != "Y" ]; do
208 [ -z "$x" ] && x="yes"
209 [ "$x" = "n" ] && x="no"
210 [ "$x" = "y" ] && x="yes"
212 [ "$x" = "no" ] && return 1 || return 0
216 # Call the real "port(1)" command, show and hide output as configured.
217 # $*: arguments for port(1).
220 [ -n "$VERBOSE" ] && args=""
221 [ -n "$PORT_VERBOSE" ] && args="-v "
222 [ -n "$DEBUG" ] && args="-v -d "
223 local cmd="port $args$*"
225 declare -i a=${#cmd}+4; a=$WIDTH-$a; a=$a/2
227 local top="${LINE:0:$a}[ $cmd ]${LINE}"
230 if [ "$args" = "" ]; then
231 $cmd | while read x; do
232 msg=$(echo "$x"|sed -e 's/--->//g'|sed -e 's/^ //g')
234 if [ ${#msg} -ge $WIDTH ]; then
235 declare -i w=$WIDTH-3
236 echo "${msg:0:$w}..."
241 elif [ "$args" = "-v " -o "$args" = "-v -d " ]; then
242 Msg_NoQuiet "${top:0:$WIDTH}"
244 Msg_NoQuiet "${bottom:0:$WIDTH}"
246 $cmd >/dev/null 2>&1 ; r=$?
253 # Check, if the given port exists
256 port info "$1" 2>/dev/null | grep 'Maintainers: ' >/dev/null; local r=$?
257 if [ $r -ne 0 ]; then
258 Error_Msg "Port \"$1\" does not exist!"
261 Debug_Msg "Port \"$1\" exists. Ok."
266 # Check, if the given port is installed
270 [ $? -eq 0 ] || return 1
272 grep "^ $1 " "$TMPDIR/installed" >/dev/null 2>&1; local r=$?
273 if [ $r -ne 0 ]; then
274 Error_Msg "Port \"$1\" is not installed!"
277 Debug_Msg "Port \"$1\" is installed. Ok."
281 Dump_Package_File() {
282 # Display contents of a "pt package-list file", like "required[.all]".
284 # $2: package-list file name
285 # $3: "u": show only un-installed ports
287 pkgs=$(cat "$2" | sort -u)
288 [ -z "$pkgs" ] && return 0
295 grep "^ $d " "$TMPDIR/installed" >/dev/null 2>&1; local r=$?
296 if [ "$3" = "u" ]; then
297 [ $r -eq 0 ] && continue
299 [ $r -eq 0 ] && d="$d[i]"
302 if [ $x -gt $WIDTH ]; then
303 Msg_NoQuiet; Msg_NoQuiet -n " "
313 Count_Package_File() {
314 # Return number of packages listed in a "pt package-list file".
315 # $1: package-list file name
316 # $2: "u": show only un-installed ports
318 pkgs=$(cat "$1" | sort -u)
321 grep "^ $d " "$TMPDIR/installed" >/dev/null 2>&1; local r=$?
322 if [ "$2" = "u" ]; then
323 [ $r -eq 0 ] && continue
332 grep "^$1\$" "$TMP4" >/dev/null 2>&1
333 if [ $? -eq 0 ]; then
334 Debug_Msg "Dependencies for \"$1\" already checked. Skipping."
337 Debug_Msg "Checking dependencies for \"$1\" ..."
339 port deps "$1" | while read x; do
340 if [ "$x" = "$1 has no dependencies" ]; then
343 if [ "$x" = "$1 has build dependencies on:" ]; then
344 phase="build"; continue
346 if [ "$x" = "$1 has library dependencies on:" ]; then
347 phase="lib"; continue
349 if [ "$x" = "$1 has runtime dependencies on:" ]; then
350 phase="runtime"; continue
355 echo "$1:$x" >>"$TMP1"
359 echo "$1:$x" >>"$TMP2"
363 echo "$1:$x" >>"$TMP3"
367 Warn_Msg "Unknown phase, token \"$x\"!?"
382 [ -z "$4" ] && t=$(head -n 1 "$2" | cut -d':' -f1) || t="$4"
384 while [ -n "$t" ]; do
385 deps=$(grep "^$t:" "$2" 2>/dev/null | sort -u)
386 grep -v "^$t:" "$2" >"$TMP" 2>/dev/null
390 port=$(echo "$d" | cut -d':' -f1)
391 req=$(echo "$d" | cut -d':' -f2)
394 while [ $x -lt $level ]; do
395 [ -n "$VERBOSE" -a -z "$QUIET" ] && echo -n ' '
399 Verbose_Msg "Port \"$t\" depends on $req"
400 echo "$req" >>"$TMPDIR/required"
402 Deps_a $level+1 "$2" "$3" "$req"
405 [ "$level" -le 1 ] && t=$(head -n 1 "$2" | cut -d':' -f1) || t=""
410 # Display dependancies of a port
413 Port_Exists "$1"; local r=$?
414 [ $r -ne 0 ] && return $r
416 touch "$TMP1" "$TMP2" "$TMP3" "$TMP4"
418 Msg "Analyzing port \"$1\" ..."
421 build_deps=$(cat "$TMP1")
422 lib_deps=$(cat "$TMP2")
423 runtime_deps=$(cat "$TMP3")
425 if [ -z "$build_deps" -a -z "$lib_deps" -a -z "$runtime_deps" ]; then
426 Msg "Port \"$1\" has no dependencies."
430 if [ -n "$build_deps" ]; then
431 Verbose_Msg; Verbose_Msg "Build dependencies:"
432 Deps_a 1 "$TMP1" build
434 if [ -n "$lib_deps" ]; then
435 Verbose_Msg; Verbose_Msg "Library dependencies:"
438 if [ -n "$runtime_deps" ]; then
439 Verbose_Msg; Verbose_Msg "Runtime dependencies:"
440 Deps_a 1 "$TMP3" runtime
444 deps=$(cat "$TMPDIR/required" | sort -u)
445 declare -i count=$(cat "$TMPDIR/required" | sort -u | wc -l )
449 && Msg_NoQuiet "The following port is required by \"$1\":" \
450 || Msg_NoQuiet "The following $count ports are required by \"$1\":"
455 grep "^ $d " "$TMPDIR/installed" >/dev/null 2>&1; local r=$?
456 if [ $r -eq 0 ]; then
460 not_inst="$not_inst $d"
463 if [ $x -gt $WIDTH ]; then
464 Msg_NoQuiet; Msg_NoQuiet -n " "
471 if [ -n "$not_inst" ]; then
473 && Msg_NoQuiet "The following port (probably) needs to be installed:" \
474 || Msg_NoQuiet "The following $count ports (probably!) need to be installed:"
477 for d in $not_inst; do
479 if [ $x -gt $WIDTH ]; then
480 Msg_NoQuiet; Msg_NoQuiet -n " "
484 echo "$d" >>"$TMPDIR/missing"
488 Msg_NoQuiet "All required ports are already installed."
496 # Install a given port, and its dependencies.
497 # $*: port, including version number, variant(s), ...
499 Msg_NoQuiet "Installing port \"$p\" (and dependencies) ..."
502 [ -n "$CLEAN_WORKDIR" ] && args="$args -c"
504 PortCmd $args install $*
505 if [ $? -ne 0 ]; then
506 Error_Msg "Installation of \"$1\" failed!"
513 # Clean build directory of a port
518 Msg_NoQuiet "Upgrading port \"$1\" (and dependencies): $2 -> $3 ..."
521 [ -n "$CLEAN_WORKDIR" ] && args="$args -c"
522 [ -n "$UPGRADE_REMOVE_INACTIVE" ] && args="$args -fu"
524 PortCmd $args upgrade -n $port
525 if [ $? -ne 0 ]; then
526 Error_Msg "Failed to upgrade port \"$1\"!"
533 # Clean build directory of a port
536 Msg_NoQuiet "Cleaning build directory of port \"$1\" ..."
538 PortCmd clean --all "$1"
539 if [ $? -ne 0 ]; then
540 Error_Msg "Failed to clean port \"$1\"!"
547 # Remove a given port
550 Msg_NoQuiet "Removing port \"$1\" ..."
552 PortCmd uninstall "$1"
553 if [ $? -ne 0 ]; then
554 Error_Msg "Failed to remove port \"$1\"!"
561 if [ $# -lt 1 ]; then
562 Error_Msg "No ports requested!?"
566 deps=$(cat "$TMPDIR/required.all" | sort -u)
569 cat "$TMPDIR/missing.all" >"$TMPDIR/install.all"
571 echo "$p" >>"$TMPDIR/install.all"
575 echo "$p" >>"$TMPDIR/requested.all"
580 if [ -z "$QUIET" ]; then
581 Count_Package_File "$TMPDIR/requested.all"; c=$?
582 [ $c -eq 1 ] && s=" has" || s="s have"
584 "The following $c port$s been requested:" \
585 "$TMPDIR/requested.all"
587 Count_Package_File "$TMPDIR/required.all"; c_req=$?
588 [ $c_req -eq 1 ] && s=" is" || s="s are"
590 "The following $c_req port$s required to fulfil dependencies:" \
591 "$TMPDIR/required.all"
592 Count_Package_File "$TMPDIR/missing.all"; c_add=$?
593 [ $c_add -eq 1 ] && s=" (probably!) needs" || s="s (probably!) need"
595 "The following $c_add additional port$s to be installed:" \
596 "$TMPDIR/missing.all"
597 Count_Package_File "$TMPDIR/install.all" "u"; c_all=$?
598 if [ $c_all -lt 1 ]; then
599 Msg_NoQuiet "No new ports to install."; Msg
602 [ $c_all -eq 1 ] && s="" || s="s"
604 "The following $c_all NEW port$s will be installed (if required):" \
605 "$TMPDIR/install.all" "u"
608 ports=$(tail -r "$TMPDIR/missing.all" | uniq )
610 if [ -n "$DEBUG" ]; then
611 Debug_Msg "Order of installation:"
615 [ "$#" -eq 1 ] && s1=" has" || s1="s have"
616 [ "$c_inst" -eq 1 ] && s2="" || s2="s"
617 Msg_NoQuiet "$# port$s1 been requested, $c_inst port$s2 will be installed."
618 if [ $# -ne $c_inst ]; then
619 Prompt "Do you want to continue?"
620 if [ $? -ne 0 ]; then
632 [ $? -eq 0 ] || errors=$errors+1
638 [ $count -eq 1 ] && s=" has" || s="s have"
639 Msg "$count requested port$s been installed."
640 if [ $errors -gt 0 ]; then
641 [ $errors -gt 1 ] && s="s" || s=""
642 Error_Msg "There have been failures, see above!";
654 Msg "Searching for outdated ports ..."
655 echo -n "" >"$TMPDIR/outdated"
656 echo -n "" >"$TMPDIR/outdated.info"
658 grep -v "No installed ports are outdated" | \
659 grep -v "The following installed ports are outdated" | \
660 awk "{ print \$1, \$2, \$3, \$4 }" | while read port v1 a v2; do
661 echo "$port" >>"$TMPDIR/outdated"
662 echo "$port $v1 $a $v2" >>"$TMPDIR/outdated.info"
668 Count_Package_File "$TMPDIR/outdated"
669 if [ $? -lt 1 ]; then
670 Msg "No installed ports are outdated."
674 "The following installed ports are outdated and will be UPGRADED:" \
678 if [ -n "$VERBOSE" ]; then
679 echo "Upgrade details:"
680 cat "$TMPDIR/outdated.info" | while read port v1 a v2; do
681 echo " $port $v1 -> $v2"
685 [ $c_out -gt 100 ] && c_out=100
690 List_Outdated && return 0
692 Prompt "Do you want to continue?"
693 if [ $? -ne 0 ]; then
700 cat "$TMPDIR/outdated.info" | while read port v1 a v2; do
701 Port_Upgrade "$port" "$v1" "$v2"
702 [ $? -eq 0 ] || errors=$errors+1
706 if [ $errors -gt 0 ]; then
707 [ $errors -gt 1 ] && s="s" || s=""
708 Warn_Msg "$errors error$s occured during upgrading!"
716 Count_Package_File "$TMPDIR/outdated"; c=$?
717 if [ $c -gt 0 ]; then
718 if [ $c -eq 1 ]; then
723 Warn_Msg "There $s1 still $c outdated port$s2 installed!"
731 Status "Actual ports base version" -q
732 Msg "Updating installed port software and database ..."
733 port -q selfupdate; local r=$?
734 if [ $r -eq 0 ]; then
735 Status "New ports base version"
737 Error_Msg "Failed to update port archive!"
747 if [ $? -eq 0 ]; then
749 [ $? -ne 0 ] && errors=$errors+1
754 if [ $errors -gt 0 ]; then
756 [ $errors -ne 1 ] && s="s" || s=""
757 Error_Msg "$errors failure$s while cleaning ports!"
768 if [ $? -eq 0 ]; then
770 [ $? -ne 0 ] && errors=$errors+1
775 if [ $errors -gt 0 ]; then
776 [ $errors -ne 1 ] && s="s" || s=""
777 Error_Msg "$errors failure$s while removing ports!"
786 q=$QUIET; [ "$2" != '-q' ] && QUIET=
788 && Msg -n "Ports base version: " \
790 version=$( port --version 2>/dev/null | grep "MacPorts" )
791 [ $? -eq 0 ] || version=$( port version | cut -d' ' -f2 )
797 trap Clean_Exit_Signal SIGINT
799 # read in defaults, if available
800 [ -r "/etc/$NAME.conf" ] && . "/etc/$NAME.conf"
813 PORT_VERBOSE=1; VERBOSE=1
821 QUIET=1; VERBOSE=; DEBUG=
829 DEBUG=1; VERBOSE=1; QUIET=
836 "--usage"|"--help"|"-*"|"+*")
848 TMPDIR=`mktemp -d /tmp/${NAME}.XXXXXX` || exit 2
849 Debug_Msg "Temporary directory is \"$TMPDIR\"."
862 [ $# -lt 1 ] && Usage
869 [ $# -lt 1 ] && Usage
874 [ $r -ne 0 ] && Clean_Exit $r
881 [ $# -lt 1 ] && Usage
883 Verbose_Msg "Building port dependencies ..."
886 [ $? -ne 0 ] && Clean_Exit 1
888 Deps "$p" >/dev/null; r=$?
889 [ $r -ne 0 ] && Clean_Exit $r
897 [ $# -lt 1 ] && Usage
901 "outdated"|"list-outdated")
905 "update"|"selfupdate")
908 [ $# -ne 0 ] && Usage
912 "upgrade"|"dist-upgrade")
915 [ $# -gt 0 ] && Usage
923 [ $# -ne 0 ] && Usage
931 [ $# -ne 0 ] && Usage
936 "remove"|"uninstall")
939 [ $# -lt 1 ] && Usage
946 [ $# -lt 1 ] && Usage
952 [ $# -lt 1 ] && Usage
958 [ $# -ne 0 ] && Usage