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