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