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