]> arthur.barton.de Git - pt.git/blob - bin/pt
Update copyright year to "2007-2009".
[pt.git] / bin / pt
1 #!/bin/bash
2 #
3 # pt -- the MacPorts port tool"
4 # Copyright (c)2007-2009 Alexander Barton, alex@barton.de
5 #
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.
11 #
12
13 NAME=`basename "$0"`
14 VERSION="0.2.0"
15 DATE="2008-12-14"
16
17 QUIET=
18 PORT_VERBOSE=
19 VERBOSE=
20 DEBUG=
21
22 UPGRADE_REMOVE_INACTIVE=1
23 CLEAN_WORKDIR=1
24
25 declare -i WIDTH=${COLUMNS:-80}
26
27 LINE="-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
28
29 Version() {
30         # Display version information.
31
32         echo "$NAME $VERSION ($DATE) -- the MacPorts port tool"
33         echo "Copyright (c)2007-2009 Alexander Barton, alex@barton.de"
34         echo
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."
37         echo
38 }
39
40 Usage() {
41         # Display some usage information and exit.
42
43         Version
44         echo "Usage: $0 <options> <command> [<args> ...]"
45         echo
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"
59         echo
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"
65         echo
66         Clean_Exit 1
67 }
68
69 Init() {
70         # Initialize "state machine", clear temporary files.
71
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"
82
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`
86
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."
91 }
92
93 Reset() {
94         # Reset "required" and "missing" package lists, move saved
95         # packages to "required.all"/"missing.all" lists for later
96         # processing.
97
98         Debug_Msg "Resetting internal state ..."
99         rm -f "$TMPDIR/tmp"*
100         
101         [ -r "$TMPDIR/required" ] \
102                 && cat "$TMPDIR/required" >>"$TMPDIR/required.all"
103         echo -n '' >"$TMPDIR/required"
104         
105         [ -r "$TMPDIR/missing" ] \
106                 && cat "$TMPDIR/missing" >>"$TMPDIR/missing.all"
107         echo -n '' >"$TMPDIR/missing"
108 }
109
110 Check_Root_Perm() {
111         # Check, if this script is running with root privileges.
112
113         [ "$UID" -eq 0 -o "$EUID" -eq 0 ] && return 0
114         Error_Msg "This function must be executed with root privileges!"
115         Clean_Exit 1
116 }
117
118 Debug_Tmpdir() {
119         # List contents of temporary directory to console.
120         echo "--- $TMPDIR ---"; ls -al "$TMPDIR"; echo "---"
121 }
122
123 Debug_Dump_File() {
124         # Dump contents of a file to console.
125         echo "--- $1 ---"; cat "$1"; echo "---"
126 }
127
128 Clean_Exit() {
129         # Exit this scripts after cleaning up.
130         # $1: exit code
131
132         Debug_Msg "Cleaning up ..."
133         [ -n "$TMPDIR" ] && rm -rf "$TMPDIR"
134         Debug_Msg "Done. Exit code: $1"
135         exit $1
136 }
137
138 Clean_Exit_Signal() {
139         # Exit this script with exit code 127, used when an interup signal
140         # (SIGINT) has been catched.
141
142         echo
143         Clean_Exit 127
144 }
145
146 Msg() {
147         # Display message, if not running in "quiet" mode.
148         # $*: message to display.
149
150         [ -n "$QUIET" ] && return
151         if [ "$1" = "-n" ]; then
152                 shift
153                 echo -n "$*"
154         else
155                 echo "$*"
156         fi
157 }
158
159 Msg_NoQuiet() {
160         # Display message, even when running in "quiet" mode.
161         # $*: message to display.
162
163         if [ "$1" = "-n" ]; then
164                 shift
165                 echo -n "$*"
166         else
167                 echo "$*"
168         fi
169 }
170
171 Verbose_Msg() {
172         # Display message when running in "debug" or "verbose" mode.
173         # $*: message to display.
174
175         [ -z "$QUIET" -a -n "$VERBOSE" ] && echo $*
176 }
177
178 Debug_Msg() {
179         # Display message when running in "debug" mode.
180         # $*: message to display.
181
182         [ -n "$DEBUG" ] && echo $*
183 }
184
185 Warn_Msg() {
186         # Display warning message.
187         # $*: message to display.
188
189         echo "Warning: $*"
190 }
191
192 Error_Msg() {
193         # Display error message.
194         # $*: message to display.
195
196         echo "Error: $*"
197 }
198
199 Prompt() {
200         tty >/dev/null 2>&1
201         [ $? -ne 0 ] && return 0
202         
203         x="_"
204         Msg_NoQuiet -n "$* [Y/n] "
205         while [ "$x" != "" -a "$x" != "n" -a "$x" != "N" -a "$x" != "y" -a "$x" != "Y" ]; do
206                 read -s -n 1 x
207         done
208         [ -z "$x" ] && x="yes"
209         [ "$x" = "n" ] && x="no"
210         [ "$x" = "y" ] && x="yes"
211         Msg_NoQuiet "- $x"
212         [ "$x" = "no" ] && return 1 || return 0
213 }
214
215 PortCmd()  {
216         # Call the real "port(1)" command, show and hide output as configured.
217         # $*: arguments for port(1).
218
219         local args="-q "
220         [ -n "$VERBOSE" ] && args=""
221         [ -n "$PORT_VERBOSE" ] && args="-v "
222         [ -n "$DEBUG" ] && args="-v -d "
223         local cmd="port $args$*"
224
225         declare -i a=${#cmd}+4; a=$WIDTH-$a; a=$a/2
226         local bottom="$LINE"
227         local top="${LINE:0:$a}[ $cmd ]${LINE}"
228
229         local r=1
230         if [ "$args" = "" ]; then
231                 $cmd | while read x; do
232                         msg=$(echo "$x"|sed -e 's/--->//g'|sed -e 's/^  //g')
233                         msg=" - $msg"
234                         if [ ${#msg} -ge $WIDTH ]; then
235                                 declare -i w=$WIDTH-3
236                                 echo "${msg:0:$w}..."
237                         else
238                                 echo "$msg"
239                         fi
240                 done; r=$?
241         elif [ "$args" = "-v " -o "$args" = "-v -d " ]; then
242                 Msg_NoQuiet "${top:0:$WIDTH}"
243                 $cmd; r=$?
244                 Msg_NoQuiet "${bottom:0:$WIDTH}"
245         else
246                 $cmd >/dev/null 2>&1 ; r=$?
247         fi
248
249         return $r
250 }
251
252 Port_Exists() {
253         # Check, if the given port exists
254         # $1: port
255
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!"
259                 return $r
260         fi
261         Debug_Msg "Port \"$1\" exists. Ok."
262         return 0
263 }
264
265 Port_Installed() {
266         # Check, if the given port is installed
267         # $1: port
268
269         Port_Exists "$1"
270         [ $? -eq 0 ] || return 1
271
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!"
275                 return $r
276         fi
277         Debug_Msg "Port \"$1\" is installed. Ok."
278         return 0
279 }
280
281 Dump_Package_File() {
282         # Display contents of a "pt package-list file", like "required[.all]".
283         # $1: title text
284         # $2: package-list file name
285         # $3: "u": show only un-installed ports
286
287         pkgs=$(cat "$2" | sort -u)
288         [ -z "$pkgs" ] && return 0
289
290         Msg_NoQuiet "$1"
291         Msg_NoQuiet -n "  "
292         declare -i x=2
293         declare -i count=0
294         for d in $pkgs; do
295                 grep "^  $d " "$TMPDIR/installed" >/dev/null 2>&1; local r=$?
296                 if [ "$3" = "u" ]; then
297                         [ $r -eq 0 ] && continue
298                 else
299                         [ $r -eq 0 ] && d="$d[i]"
300                 fi
301                 x=$x+${#d}+1
302                 if [ $x -gt $WIDTH ]; then
303                         Msg_NoQuiet; Msg_NoQuiet -n "  "
304                         x=${#d}+3
305                 fi
306                 Msg_NoQuiet -n "$d "
307                 count=$count+1
308         done
309         Msg_NoQuiet
310         return $count
311 }
312
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
317
318         pkgs=$(cat "$1" | sort -u)
319         declare -i count=0
320         for d in $pkgs; do
321                 grep "^  $d " "$TMPDIR/installed" >/dev/null 2>&1; local r=$?
322                 if [ "$2" = "u" ]; then
323                         [ $r -eq 0 ] && continue
324                 fi
325                 count=$count+1
326         done
327         return $count
328 }
329
330 Deps_r() {
331         local phase=""
332         grep "^$1\$" "$TMP4" >/dev/null 2>&1
333         if [ $? -eq 0 ]; then
334                 Debug_Msg "Dependencies for \"$1\" already checked. Skipping."
335                 return
336         fi
337         Debug_Msg "Checking dependencies for \"$1\" ..."
338         echo "$1" >>"$TMP4"
339         port deps "$1" | while read x; do
340                 if [ "$x" = "$1 has no dependencies" ]; then
341                         phase=""; continue;
342                 fi
343                 if [ "$x" = "$1 has build dependencies on:" ]; then
344                         phase="build"; continue
345                 fi
346                 if [ "$x" = "$1 has library dependencies on:" ]; then
347                         phase="lib"; continue
348                 fi
349                 if [ "$x" = "$1 has runtime dependencies on:" ]; then
350                         phase="runtime"; continue
351                 fi
352
353                 case "$phase" in
354                         "build")
355                                 echo "$1:$x" >>"$TMP1"
356                                 Deps_r "$x"
357                                 ;;
358                         "lib")
359                                 echo "$1:$x" >>"$TMP2"
360                                 Deps_r "$x"
361                                 ;;
362                         "runtime")
363                                 echo "$1:$x" >>"$TMP3"
364                                 Deps_r "$x"
365                                 ;;
366                         *)
367                                 Warn_Msg "Unknown phase, token \"$x\"!?"
368                 esac
369         done
370 }
371
372 Deps_a() {
373         # 1: level
374         # 2: file
375         # 3: type
376         # 4: root-element
377
378         declare -i level=$1
379         local deps=""
380         local t=""
381         
382         [ -z "$4" ] && t=$(head -n 1 "$2" | cut -d':' -f1) || t="$4"
383
384         while [ -n "$t" ]; do
385                 deps=$(grep "^$t:" "$2" 2>/dev/null | sort -u)
386                 grep -v "^$t:" "$2" >"$TMP" 2>/dev/null
387                 cat "$TMP" >"$2"
388
389                 for d in $deps; do
390                         port=$(echo "$d" | cut -d':' -f1)
391                         req=$(echo "$d" | cut -d':' -f2)
392         
393                         declare -i x=0
394                         while [ $x -lt $level ]; do
395                                 [ -n "$VERBOSE" -a -z "$QUIET" ] && echo -n '  '
396                                 x=$x+1
397                         done
398         
399                         Verbose_Msg "Port \"$t\" depends on $req"
400                         echo "$req" >>"$TMPDIR/required"
401         
402                         Deps_a $level+1 "$2" "$3" "$req"
403                 done
404
405                 [ "$level" -le 1 ] && t=$(head -n 1 "$2" | cut -d':' -f1) || t=""
406         done
407 }
408
409 Deps() {
410         # Display dependancies of a port
411         # $1: port
412
413         Port_Exists "$1"; local r=$?
414         [ $r -ne 0 ] && return $r
415
416         touch "$TMP1" "$TMP2" "$TMP3" "$TMP4"
417
418         Msg "Analyzing port \"$1\" ..."
419         Deps_r "$1"
420
421         build_deps=$(cat "$TMP1")
422         lib_deps=$(cat "$TMP2")
423         runtime_deps=$(cat "$TMP3")
424
425         if [ -z "$build_deps" -a -z "$lib_deps" -a -z "$runtime_deps" ]; then
426                 Msg "Port \"$1\" has no dependencies."
427                 return 0
428         fi
429
430         if [ -n "$build_deps" ]; then
431                 Verbose_Msg; Verbose_Msg "Build dependencies:"
432                 Deps_a 1 "$TMP1" build
433         fi
434         if [ -n "$lib_deps" ]; then
435                 Verbose_Msg; Verbose_Msg "Library dependencies:"
436                 Deps_a 1 "$TMP2" lib
437         fi
438         if [ -n "$runtime_deps" ]; then
439                 Verbose_Msg; Verbose_Msg "Runtime dependencies:"
440                 Deps_a 1 "$TMP3" runtime
441         fi
442         Msg
443
444         deps=$(cat "$TMPDIR/required" | sort -u)
445         declare -i count=$(cat "$TMPDIR/required" | sort -u | wc -l )
446         not_inst=""
447
448         [ "$count" -eq 1 ] \
449                 && Msg_NoQuiet "The following port is required by \"$1\":" \
450                 || Msg_NoQuiet "The following $count ports are required by \"$1\":"
451         Msg_NoQuiet -n "  "
452         declare -i count=0
453         declare -i x=2
454         for d in $deps; do
455                 grep "^  $d " "$TMPDIR/installed" >/dev/null 2>&1; local r=$?
456                 if [ $r -eq 0 ]; then
457                          d="$d[i]"
458                 else
459                         count=$count+1
460                         not_inst="$not_inst $d"
461                 fi
462                 x=$x+${#d}+1
463                 if [ $x -gt $WIDTH ]; then
464                         Msg_NoQuiet; Msg_NoQuiet -n "  "
465                         declare -i x=${#d}+3
466                 fi
467                 Msg_NoQuiet -n "$d "
468         done
469         Msg_NoQuiet
470
471         if [ -n "$not_inst" ]; then
472                 [ "$count" -eq 1 ] \
473                         && Msg_NoQuiet "The following port (probably) needs to be installed:" \
474                         || Msg_NoQuiet "The following $count ports (probably!) need to be installed:"
475                 Msg_NoQuiet -n "  "
476                 declare -i x=2
477                 for d in $not_inst; do
478                         x=$x+${#d}+1
479                         if [ $x -gt $WIDTH ]; then
480                                 Msg_NoQuiet; Msg_NoQuiet -n "  "
481                                 declare -i x=${#d}+3
482                         fi
483                         Msg_NoQuiet -n "$d "
484                         echo "$d" >>"$TMPDIR/missing"
485                 done
486                 Msg_NoQuiet
487         else
488                 Msg_NoQuiet "All required ports are already installed."
489         fi
490
491         Msg
492         return 0
493 }
494
495 Port_Install() {
496         # Install a given port, and its dependencies.
497         # $*: port, including version number, variant(s), ...
498
499         Msg_NoQuiet "Installing port \"$p\" (and dependencies) ..."
500
501         local args=""
502         [ -n "$CLEAN_WORKDIR" ] && args="$args -c"
503
504         PortCmd $args install $*
505         if [ $? -ne 0 ]; then
506                 Error_Msg "Installation of \"$1\" failed!"
507                 return 1
508         fi
509         return 0
510 }
511
512 Port_Upgrade() {
513         # Clean build directory of a port
514         # $1: port
515         # $2: old version
516         # $3: new version
517
518         Msg_NoQuiet "Upgrading port \"$1\" (and dependencies): $2 -> $3 ..."
519
520         local args=""
521         [ -n "$CLEAN_WORKDIR" ] && args="$args -c"
522         [ -n "$UPGRADE_REMOVE_INACTIVE" ] && args="$args -fu"
523
524         PortCmd $args upgrade -n $port
525         if [ $? -ne 0 ]; then
526                 Error_Msg "Failed to upgrade port \"$1\"!"
527                 return 1
528         fi
529         return 0
530 }
531
532 Port_Clean() {
533         # Clean build directory of a port
534         # $1: port
535
536         Msg_NoQuiet "Cleaning build directory of port \"$1\" ..."
537
538         PortCmd clean --all "$1"
539         if [ $? -ne 0 ]; then
540                 Error_Msg "Failed to clean port \"$1\"!"
541                 return 1
542         fi
543         return 0
544 }
545
546 Port_Remove() {
547         # Remove a given port
548         # $1: port
549
550         Msg_NoQuiet "Removing port \"$1\" ..."
551
552         PortCmd uninstall "$1"
553         if [ $? -ne 0 ]; then
554                 Error_Msg "Failed to remove port \"$1\"!"
555                 return 1
556         fi
557         return 0
558 }
559
560 Install() {
561         if [ $# -lt 1 ]; then
562                 Error_Msg "No ports requested!?"
563                 return 1
564         fi
565
566         deps=$(cat "$TMPDIR/required.all" | sort -u)
567         not_inst=""
568         
569         cat "$TMPDIR/missing.all" >"$TMPDIR/install.all"
570         for p in $*; do
571                 echo "$p" >>"$TMPDIR/install.all"
572         done
573         
574         for p in $*; do
575                 echo "$p" >>"$TMPDIR/requested.all"
576         done
577         
578         Verbose_Msg
579
580         if [ -z "$QUIET" ]; then
581                 Count_Package_File "$TMPDIR/requested.all"; c=$?
582                 [ $c -eq 1 ] && s=" has" || s="s have"
583                 Dump_Package_File \
584                         "The following $c port$s been requested:" \
585                         "$TMPDIR/requested.all"
586         fi
587         Count_Package_File "$TMPDIR/required.all"; c_req=$?
588         [ $c_req -eq 1 ] && s=" is" || s="s are"
589         Dump_Package_File \
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"
594         Dump_Package_File \
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
600                 return 0
601         fi
602         [ $c_all -eq 1 ] && s="" || s="s"
603         Dump_Package_File \
604                 "The following $c_all NEW port$s will be installed (if required):" \
605                 "$TMPDIR/install.all" "u"
606         c_inst=$?
607
608         ports=$(tail -r "$TMPDIR/missing.all" | uniq )
609         ports="$ports $*"
610         if [ -n "$DEBUG" ]; then
611                 Debug_Msg "Order of installation:"
612                 Debug_Msg "  " $ports
613         fi
614
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
621                         Msg "Aborting."; Msg
622                         return 1
623                 fi
624         fi
625         Msg
626
627         declare -i errors=0
628         declare -i count=0
629
630         for p in $*; do
631                 Port_Install "$p"
632                 [ $? -eq 0 ] || errors=$errors+1
633
634                 count=$count+1
635         done
636         Msg
637
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!";
643                 Msg
644                 local r=1
645         else
646                 local r=0
647         fi
648
649         Init
650         return $r
651 }
652
653 Init_Outdated() {
654         Msg "Searching for outdated ports ..."
655         echo -n "" >"$TMPDIR/outdated"
656         echo -n "" >"$TMPDIR/outdated.info"
657         port outdated | \
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"
663         done
664 }
665
666 List_Outdated() {
667         Init_Outdated
668         Count_Package_File "$TMPDIR/outdated"
669         if [ $? -lt 1 ]; then
670                 Msg "No installed ports are outdated."
671                 return 0
672         fi
673         Dump_Package_File \
674                 "The following installed ports are outdated and will be UPGRADED:" \
675                 "$TMPDIR/outdated"
676         c_out=$?
677
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"
682                 done
683         fi
684         
685         [ $c_out -gt 100 ] && c_out=100
686         return $c_out;
687 }
688
689 Upgrade() {
690         List_Outdated && return 0
691
692         Prompt "Do you want to continue?"
693         if [ $? -ne 0 ]; then
694                 Msg "Aborting."; Msg
695                 return 1
696         fi
697         Msg
698
699         declare -i errors=0
700         cat "$TMPDIR/outdated.info" | while read port v1 a v2; do
701                 Port_Upgrade "$port" "$v1" "$v2"
702                 [ $? -eq 0 ] || errors=$errors+1
703         done
704         Msg
705
706         if [ $errors -gt 0 ]; then
707                 [ $errors -gt 1 ] && s="s" || s=""
708                 Warn_Msg "$errors error$s occured during upgrading!"
709                 Msg
710                 local r=1
711         else
712                 local r=0
713         fi
714
715         Init_Outdated
716         Count_Package_File "$TMPDIR/outdated"; c=$?
717         if [ $c -gt 0 ]; then
718                 if [ $c -eq 1 ]; then
719                         s1="is"; s2=""
720                 else
721                         s1="are"; s2="s"
722                 fi
723                 Warn_Msg "There $s1 still $c outdated port$s2 installed!"
724         fi
725
726         Init
727         return $r
728 }
729
730 Update() {
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"
736         else
737                 Error_Msg "Failed to update port archive!"
738         fi
739         return $r
740 }
741
742 Clean() {
743         local r=0
744         declare -i errors=0
745         for p in $*; do
746                 Port_Exists "$p"
747                 if [ $? -eq 0 ]; then
748                         Port_Clean "$p"
749                         [ $? -ne 0 ] && errors=$errors+1
750                 else
751                         errors=$errors+1
752                 fi
753         done
754         if [ $errors -gt 0 ]; then
755                 Msg_NoQuiet
756                 [ $errors -ne 1 ] && s="s" || s=""
757                 Error_Msg "$errors failure$s while cleaning ports!"
758                 r=1
759         fi
760         return $r
761 }
762
763 Remove() {
764         local r=0
765         declare -i errors=0
766         for p in $*; do
767                 Port_Installed "$p"
768                 if [ $? -eq 0 ]; then
769                         Port_Remove "$p"
770                         [ $? -ne 0 ] && errors=$errors+1
771                 else
772                         errors=$errors+1
773                 fi
774         done
775         if [ $errors -gt 0 ]; then
776                 [ $errors -ne 1 ] && s="s" || s=""
777                 Error_Msg "$errors failure$s while removing ports!"
778                 r=1
779         fi
780         return $r
781 }
782
783 Status() {
784         local r=0
785         Init; r=$?
786         q=$QUIET; [ "$2" != '-q' ] && QUIET=
787         [ "$1" = "" ] \
788                 && Msg -n "Ports base version: " \
789                 || Msg -n "$1: "
790         version=$( port --version 2>/dev/null | grep "MacPorts" )
791         [ $? -eq 0 ] || version=$( port version | cut -d' ' -f2 )
792         Msg "$version"
793         QUIET=$q
794         return $r
795 }
796
797 trap Clean_Exit_Signal SIGINT
798
799 # read in defaults, if available
800 [ -r "/etc/$NAME.conf" ] && . "/etc/$NAME.conf"
801
802 while true; do
803         case "$1" in
804                 "-v")
805                         VERBOSE=1; QUIET=
806                         shift
807                         ;;
808                 "+v")
809                         VERBOSE=
810                         shift
811                         ;;
812                 "-V")
813                         PORT_VERBOSE=1; VERBOSE=1
814                         shift
815                         ;;
816                 "+V")
817                         PORT_VERBOSE=
818                         shift
819                         ;;
820                 "-q")
821                         QUIET=1; VERBOSE=; DEBUG=
822                         shift
823                         ;;
824                 "+q")
825                         QUIET=
826                         shift
827                         ;;
828                 "-d")
829                         DEBUG=1; VERBOSE=1; QUIET=
830                         shift
831                         ;;
832                 "+d")
833                         DEBUG=
834                         shift
835                         ;;
836                 "--usage"|"--help"|"-*"|"+*")
837                         Usage
838                         ;;
839                 "--version")
840                         Version
841                         Clean_Exit 0
842                         ;;
843                 *)
844                         break;
845         esac
846 done
847
848 TMPDIR=`mktemp -d /tmp/${NAME}.XXXXXX` || exit 2
849 Debug_Msg "Temporary directory is \"$TMPDIR\"."
850
851 TMP="$TMPDIR/tmp"
852 TMP1="$TMPDIR/tmp.1"
853 TMP2="$TMPDIR/tmp.2"
854 TMP3="$TMPDIR/tmp.3"
855 TMP4="$TMPDIR/tmp.4"
856
857 r=0
858 case "$1" in
859         "clean")
860                 shift
861                 Check_Root_Perm
862                 [ $# -lt 1 ] && Usage
863                 Init
864                 Clean $*
865                 Clean_Exit $?
866                 ;;
867         "deps")
868                 shift
869                 [ $# -lt 1 ] && Usage
870                 Init
871                 for p in $*; do
872                         Reset
873                         Deps "$p"; r=$?
874                         [ $r -ne 0 ] && Clean_Exit $r
875                 done
876                 Clean_Exit $r
877                 ;;
878         "install")
879                 shift
880                 Check_Root_Perm
881                 [ $# -lt 1 ] && Usage
882                 Init
883                 Verbose_Msg "Building port dependencies ..."
884                 for p in $*; do
885                         Port_Exists "$p"
886                         [ $? -ne 0 ] && Clean_Exit 1
887                         Reset
888                         Deps "$p" >/dev/null; r=$?
889                         [ $r -ne 0 ] && Clean_Exit $r
890                 done
891                 Reset
892                 Install $*
893                 Clean_Exit $?
894                 ;;
895         "list")
896                 shift
897                 [ $# -lt 1 ] && Usage
898                 port list $*
899                 Clean_Exit $?
900                 ;;
901         "outdated"|"list-outdated")
902                 List_Outdated
903                 Clean_Exit $?
904                 ;;
905         "update"|"selfupdate")
906                 shift
907                 Check_Root_Perm
908                 [ $# -ne 0 ] && Usage
909                 Update
910                 Clean_Exit $?
911                 ;;
912         "upgrade"|"dist-upgrade")
913                 shift
914                 Check_Root_Perm
915                 [ $# -gt 0 ] && Usage
916                 Init
917                 Upgrade
918                 Clean_Exit $?
919                 ;;
920         "freshup"|"fresh")
921                 shift
922                 Check_Root_Perm
923                 [ $# -ne 0 ] && Usage
924                 Update
925                 List_Outdated
926                 Clean_Exit $?
927                 ;;
928         "go"|"up")
929                 shift
930                 Check_Root_Perm
931                 [ $# -ne 0 ] && Usage
932                 Update
933                 Upgrade
934                 Clean_Exit $?
935                 ;;
936         "remove"|"uninstall")
937                 shift
938                 Check_Root_Perm
939                 [ $# -lt 1 ] && Usage
940                 Init
941                 Remove $*
942                 Clean_Exit $?
943                 ;;
944         "search")
945                 shift
946                 [ $# -lt 1 ] && Usage
947                 port search $*
948                 Clean_Exit $?
949                 ;;
950         "info")
951                 shift
952                 [ $# -lt 1 ] && Usage
953                 port info $*
954                 Clean_Exit $?
955                 ;;
956         "status")
957                 shift
958                 [ $# -ne 0 ] && Usage
959                 VERBOSE=1; Status
960                 Clean_Exit $?
961                 ;;
962         *)
963                 Usage
964 esac
965
966 # -eof-