CRUX-ARM : Home

Home :: Documentation :: Download :: Development :: Community :: Ports :: Packages :: Bugs :: Links :: About :: Donors
9fdf768e3a10de5101ba4fec7dcf43ecf4123c43
[pkgutils-cross.git] / pkgmk.in
1 #!/bin/bash
2 #
3 # pkgutils
4 #
5 # Copyright (c) 2000-2005 Per Liden
6 # Copyright (c) 2006-2007 by CRUX team (http://crux.nu)
7 #
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21 # USA.
22 #
23
24 info() {
25 echo "=======> $1"
26 }
27
28 warning() {
29 info "WARNING: $1" >&2
30 }
31
32 error() {
33 info "ERROR: $1" >&2
34 }
35
36 get_filename() {
37 if [[ $1 =~ ^(http|https|ftp|file)://.*/(.+) ]]; then
38 echo "$PKGMK_SOURCE_DIR/${BASH_REMATCH[2]}"
39 else
40 echo $1
41 fi
42 }
43
44 get_basename() {
45 local FILE="`echo $1 | sed 's|^.*://.*/||g'`"
46 echo $FILE
47 }
48
49 check_pkgfile() {
50 if [ ! "$name" ]; then
51 error "Variable 'name' not specified in $PKGMK_PKGFILE."
52 exit 1
53 elif [ ! "$version" ]; then
54 error "Variable 'version' not specified in $PKGMK_PKGFILE."
55 exit 1
56 elif [ ! "$release" ]; then
57 error "Variable 'release' not specified in $PKGMK_PKGFILE."
58 exit 1
59 elif [ "`type -t build`" != "function" ]; then
60 error "Function 'build' not specified in $PKGMK_PKGFILE."
61 exit 1
62 fi
63 }
64
65 check_directory() {
66 if [ ! -d $1 ]; then
67 error "Directory '$1' does not exist."
68 exit 1
69 elif [ ! -w $1 ]; then
70 error "Directory '$1' not writable."
71 exit 1
72 elif [ ! -x $1 ] || [ ! -r $1 ]; then
73 error "Directory '$1' not readable."
74 exit 1
75 fi
76 }
77
78 download_file() {
79 info "Downloading '$1'."
80
81 if [ ! "`type -p wget`" ]; then
82 error "Command 'wget' not found."
83 exit 1
84 fi
85
86 LOCAL_FILENAME=`get_filename $1`
87 LOCAL_FILENAME_PARTIAL="$LOCAL_FILENAME.partial"
88 DOWNLOAD_OPTS="--passive-ftp --no-directories --tries=3 --waitretry=3 \
89 --directory-prefix=$PKGMK_SOURCE_DIR \
90 --output-document=$LOCAL_FILENAME_PARTIAL --no-check-certificate"
91
92 if [ -f "$LOCAL_FILENAME_PARTIAL" ]; then
93 info "Partial download found, trying to resume"
94 RESUME_CMD="-c"
95 fi
96
97 error=1
98
99 BASENAME=`get_basename $1`
100 for REPO in ${PKGMK_SOURCE_MIRRORS[@]}; do
101 REPO="`echo $REPO | sed 's|/$||'`"
102 wget $RESUME_CMD $DOWNLOAD_OPTS $PKGMK_WGET_OPTS $REPO/$BASENAME
103 error=$?
104 if [ $error == 0 ]; then
105 break
106 fi
107 done
108
109 if [ $error != 0 ]; then
110 while true; do
111 wget $RESUME_CMD $DOWNLOAD_OPTS $PKGMK_WGET_OPTS $1
112 error=$?
113 if [ $error != 0 ] && [ "$RESUME_CMD" ]; then
114 info "Partial download failed, restarting"
115 rm -f "$LOCAL_FILENAME_PARTIAL"
116 RESUME_CMD=""
117 else
118 break
119 fi
120 done
121 fi
122
123 if [ $error != 0 ]; then
124 error "Downloading '$1' failed."
125 exit 1
126 fi
127
128 mv -f "$LOCAL_FILENAME_PARTIAL" "$LOCAL_FILENAME"
129 }
130
131 download_source() {
132 local FILE LOCAL_FILENAME
133
134 for FILE in ${source[@]}; do
135 LOCAL_FILENAME=`get_filename $FILE`
136 if [ ! -e $LOCAL_FILENAME ]; then
137 if [ "$LOCAL_FILENAME" = "$FILE" ]; then
138 error "Source file '$LOCAL_FILENAME' not found (can not be downloaded, URL not specified)."
139 exit 1
140 else
141 if [ "$PKGMK_DOWNLOAD" = "yes" ]; then
142 download_file $FILE
143 else
144 error "Source file '$LOCAL_FILENAME' not found (use option -d to download)."
145 exit 1
146 fi
147 fi
148 fi
149 done
150 }
151
152 unpack_source() {
153 local FILE LOCAL_FILENAME COMMAND
154
155 for FILE in ${source[@]}; do
156 LOCAL_FILENAME=`get_filename $FILE`
157 case $LOCAL_FILENAME in
158 *.tar.gz|*.tar.Z|*.tgz)
159 COMMAND="tar -C $SRC --use-compress-program=gzip -xf $LOCAL_FILENAME" ;;
160 *.tar.bz2)
161 COMMAND="tar -C $SRC --use-compress-program=bzip2 -xf $LOCAL_FILENAME" ;;
162 *.zip)
163 COMMAND="unzip -qq -o -d $SRC $LOCAL_FILENAME" ;;
164 *)
165 COMMAND="cp $LOCAL_FILENAME $SRC" ;;
166 esac
167
168 echo "$COMMAND"
169
170 $COMMAND
171
172 if [ $? != 0 ]; then
173 if [ "$PKGMK_KEEP_WORK" = "no" ]; then
174 rm -rf $PKGMK_WORK_DIR
175 fi
176 error "Building '$TARGET' failed."
177 exit 1
178 fi
179 done
180 }
181
182 make_md5sum() {
183 local FILE LOCAL_FILENAMES
184
185 if [ "$source" ]; then
186 for FILE in ${source[@]}; do
187 LOCAL_FILENAMES="$LOCAL_FILENAMES `get_filename $FILE`"
188 done
189
190 md5sum $LOCAL_FILENAMES | sed -e 's| .*/| |' | sort -k 2
191 fi
192 }
193
194 make_footprint() {
195 pkginfo --footprint $TARGET | \
196 sed "s|\tlib/modules/`uname -r`/|\tlib/modules/<kernel-version>/|g" | \
197 sort -k 3
198 }
199
200 check_md5sum() {
201 local FILE="$PKGMK_WORK_DIR/.tmp"
202
203 cd $PKGMK_ROOT
204
205 if [ -f $PKGMK_MD5SUM ]; then
206 make_md5sum > $FILE.md5sum
207 sort -k 2 $PKGMK_MD5SUM > $FILE.md5sum.orig
208 diff -w -t -U 0 $FILE.md5sum.orig $FILE.md5sum | \
209 sed '/^@@/d' | \
210 sed '/^+++/d' | \
211 sed '/^---/d' | \
212 sed 's/^+/NEW /g' | \
213 sed 's/^-/MISSING /g' > $FILE.md5sum.diff
214 if [ -s $FILE.md5sum.diff ]; then
215 error "Md5sum mismatch found:"
216 cat $FILE.md5sum.diff >&2
217
218 if [ "$PKGMK_KEEP_WORK" = "no" ]; then
219 rm -rf $PKGMK_WORK_DIR
220 fi
221
222 if [ "$PKGMK_CHECK_MD5SUM" = "yes" ]; then
223 error "Md5sum not ok."
224 exit 1
225 fi
226
227 error "Building '$TARGET' failed."
228 exit 1
229 fi
230 else
231 if [ "$PKGMK_CHECK_MD5SUM" = "yes" ]; then
232 if [ "$PKGMK_KEEP_WORK" = "no" ]; then
233 rm -rf $PKGMK_WORK_DIR
234 fi
235 info "Md5sum not found."
236 exit 1
237 fi
238
239 warning "Md5sum not found, creating new."
240 make_md5sum > $PKGMK_MD5SUM
241 fi
242
243 if [ "$PKGMK_CHECK_MD5SUM" = "yes" ]; then
244 if [ "$PKGMK_KEEP_WORK" = "no" ]; then
245 rm -rf $PKGMK_WORK_DIR
246 fi
247 info "Md5sum ok."
248 exit 0
249 fi
250 }
251
252 strip_files() {
253 local FILE FILTER
254
255 cd $PKG
256
257 if [ -f $PKGMK_ROOT/$PKGMK_NOSTRIP ]; then
258 FILTER="grep -v -f $PKGMK_ROOT/$PKGMK_NOSTRIP"
259 else
260 FILTER="cat"
261 fi
262
263 find . -type f -printf "%P\n" | $FILTER | while read FILE; do
264 case $(file -b "$FILE") in
265 *ELF*executable*not\ stripped)
266 strip --strip-all "$FILE"
267 ;;
268 *ELF*shared\ object*not\ stripped)
269 strip --strip-unneeded "$FILE"
270 ;;
271 current\ ar\ archive)
272 strip --strip-debug "$FILE"
273 esac
274 done
275 }
276
277 compress_manpages() {
278 local FILE DIR TARGET
279
280 cd $PKG
281
282 find . -type f -path "*/man/man*/*" | while read FILE; do
283 if [ "$FILE" = "${FILE%%.gz}" ]; then
284 gzip -9 "$FILE"
285 fi
286 done
287
288 find . -type l -path "*/man/man*/*" | while read FILE; do
289 TARGET=`readlink -n "$FILE"`
290 TARGET="${TARGET##*/}"
291 TARGET="${TARGET%%.gz}.gz"
292 rm -f "$FILE"
293 FILE="${FILE%%.gz}.gz"
294 DIR=`dirname "$FILE"`
295
296 if [ -e "$DIR/$TARGET" ]; then
297 ln -sf "$TARGET" "$FILE"
298 fi
299 done
300 }
301
302 check_footprint() {
303 local FILE="$PKGMK_WORK_DIR/.tmp"
304
305 cd $PKGMK_ROOT
306
307 if [ -f $TARGET ]; then
308 make_footprint > $FILE.footprint
309 if [ -f $PKGMK_FOOTPRINT ]; then
310 sort -k 3 $PKGMK_FOOTPRINT > $FILE.footprint.orig
311 diff -w -t -U 0 $FILE.footprint.orig $FILE.footprint | \
312 sed '/^@@/d' | \
313 sed '/^+++/d' | \
314 sed '/^---/d' | \
315 sed 's/^+/NEW /g' | \
316 sed 's/^-/MISSING /g' > $FILE.footprint.diff
317 if [ -s $FILE.footprint.diff ]; then
318 error "Footprint mismatch found:"
319 cat $FILE.footprint.diff >&2
320 BUILD_SUCCESSFUL="no"
321 fi
322 else
323 warning "Footprint not found, creating new."
324 mv $FILE.footprint $PKGMK_FOOTPRINT
325 fi
326 else
327 error "Package '$TARGET' was not found."
328 BUILD_SUCCESSFUL="no"
329 fi
330 }
331
332 make_work_dir() {
333 export PKG="$PKGMK_WORK_DIR/pkg"
334 export SRC="$PKGMK_WORK_DIR/src"
335 umask 022
336
337 cd $PKGMK_ROOT
338 remove_work_dir
339 mkdir -p $SRC $PKG
340
341 if [ "$PKGMK_IGNORE_MD5SUM" = "no" ]; then
342 check_md5sum
343 fi
344 }
345
346 remove_work_dir() {
347 rm -rf $PKGMK_WORK_DIR
348 }
349
350
351 build_package() {
352 local BUILD_SUCCESSFUL="no"
353
354 make_work_dir
355
356 if [ "$UID" != "0" ]; then
357 warning "Packages should be built as root."
358 fi
359
360 info "Building '$TARGET'."
361
362 unpack_source
363
364 cd $SRC
365 (set -e -x ; build)
366
367 if [ $? = 0 ]; then
368 if [ "$PKGMK_NO_STRIP" = "no" ]; then
369 strip_files
370 fi
371
372 compress_manpages
373
374 cd $PKG
375 info "Build result:"
376 tar czvvf $TARGET *
377
378 if [ $? = 0 ]; then
379 BUILD_SUCCESSFUL="yes"
380
381 if [ "$PKGMK_IGNORE_FOOTPRINT" = "yes" ]; then
382 warning "Footprint ignored."
383 else
384 check_footprint
385 fi
386 fi
387 fi
388
389 if [ "$PKGMK_KEEP_WORK" = "no" ]; then
390 remove_work_dir
391 fi
392
393 if [ "$BUILD_SUCCESSFUL" = "yes" ]; then
394 info "Building '$TARGET' succeeded."
395 else
396 if [ -f $TARGET ]; then
397 touch -r $PKGMK_ROOT/$PKGMK_PKGFILE $TARGET &> /dev/null
398 fi
399 error "Building '$TARGET' failed."
400 exit 1
401 fi
402 }
403
404 install_package() {
405 local COMMAND
406
407 info "Installing '$TARGET'."
408
409 if [ "$PKGMK_INSTALL" = "install" ]; then
410 COMMAND="pkgadd $TARGET"
411 else
412 COMMAND="pkgadd -u $TARGET"
413 fi
414
415 cd $PKGMK_ROOT
416 echo "$COMMAND"
417 $COMMAND
418
419 if [ $? = 0 ]; then
420 info "Installing '$TARGET' succeeded."
421 else
422 error "Installing '$TARGET' failed."
423 exit 1
424 fi
425 }
426
427 recursive() {
428 local ARGS FILE DIR
429
430 ARGS=`echo "$@" | sed -e "s/--recursive//g" -e "s/-r//g"`
431
432 for FILE in `find $PKGMK_ROOT -name $PKGMK_PKGFILE | sort`; do
433 DIR="`dirname $FILE`/"
434 if [ -d $DIR ]; then
435 info "Entering directory '$DIR'."
436 (cd $DIR && $PKGMK_COMMAND $ARGS)
437 info "Leaving directory '$DIR'."
438 fi
439 done
440 }
441
442 clean() {
443 local FILE LOCAL_FILENAME
444
445 if [ -f $TARGET ]; then
446 info "Removing $TARGET"
447 rm -f $TARGET
448 fi
449
450 for FILE in ${source[@]}; do
451 LOCAL_FILENAME=`get_filename $FILE`
452 if [ -e $LOCAL_FILENAME ] && [ "$LOCAL_FILENAME" != "$FILE" ]; then
453 info "Removing $LOCAL_FILENAME"
454 rm -f $LOCAL_FILENAME
455 fi
456 done
457 }
458
459 update_footprint() {
460 if [ ! -f $TARGET ]; then
461 error "Unable to update footprint. File '$TARGET' not found."
462 exit 1
463 fi
464
465 make_footprint > $PKGMK_FOOTPRINT
466 touch $TARGET
467
468 info "Footprint updated."
469 }
470
471 build_needed() {
472 local FILE RESULT
473
474 RESULT="yes"
475 if [ -f $TARGET ]; then
476 RESULT="no"
477 for FILE in $PKGMK_PKGFILE ${source[@]}; do
478 FILE=`get_filename $FILE`
479 if [ ! -e $FILE ] || [ ! $TARGET -nt $FILE ]; then
480 RESULT="yes"
481 break
482 fi
483 done
484 fi
485
486 echo $RESULT
487 }
488
489 interrupted() {
490 echo ""
491 error "Interrupted."
492
493 if [ "$PKGMK_KEEP_WORK" = "no" ]; then
494 rm -rf $PKGMK_WORK_DIR
495 fi
496
497 exit 1
498 }
499
500 print_help() {
501 echo "usage: `basename $PKGMK_COMMAND` [options]"
502 echo "options:"
503 echo " -i, --install build and install package"
504 echo " -u, --upgrade build and install package (as upgrade)"
505 echo " -r, --recursive search for and build packages recursively"
506 echo " -d, --download download missing source file(s)"
507 echo " -do, --download-only do not build, only download missing source file(s)"
508 echo " -eo, --extract-only do not build, only extract source file(s)"
509 echo " -utd, --up-to-date do not build, only check if package is up to date"
510 echo " -uf, --update-footprint update footprint using result from last build"
511 echo " -if, --ignore-footprint build package without checking footprint"
512 echo " -um, --update-md5sum update md5sum"
513 echo " -im, --ignore-md5sum build package without checking md5sum"
514 echo " -cm, --check-md5sum do not build, only check md5sum"
515 echo " -ns, --no-strip do not strip executable binaries or libraries"
516 echo " -f, --force build package even if it appears to be up to date"
517 echo " -c, --clean remove package and downloaded files"
518 echo " -kw, --keep-work keep temporary working directory"
519 echo " -cf, --config-file <file> use alternative configuration file"
520 echo " -v, --version print version and exit "
521 echo " -h, --help print help and exit"
522 }
523
524 parse_options() {
525 while [ "$1" ]; do
526 case $1 in
527 -i|--install)
528 PKGMK_INSTALL="install" ;;
529 -u|--upgrade)
530 PKGMK_INSTALL="upgrade" ;;
531 -r|--recursive)
532 PKGMK_RECURSIVE="yes" ;;
533 -d|--download)
534 PKGMK_DOWNLOAD="yes" ;;
535 -do|--download-only)
536 PKGMK_DOWNLOAD="yes"
537 PKGMK_DOWNLOAD_ONLY="yes" ;;
538 -eo|--extract-only)
539 PKGMK_EXTRACT_ONLY="yes" ;;
540 -utd|--up-to-date)
541 PKGMK_UP_TO_DATE="yes" ;;
542 -uf|--update-footprint)
543 PKGMK_UPDATE_FOOTPRINT="yes" ;;
544 -if|--ignore-footprint)
545 PKGMK_IGNORE_FOOTPRINT="yes" ;;
546 -um|--update-md5sum)
547 PKGMK_UPDATE_MD5SUM="yes" ;;
548 -im|--ignore-md5sum)
549 PKGMK_IGNORE_MD5SUM="yes" ;;
550 -cm|--check-md5sum)
551 PKGMK_CHECK_MD5SUM="yes" ;;
552 -ns|--no-strip)
553 PKGMK_NO_STRIP="yes" ;;
554 -f|--force)
555 PKGMK_FORCE="yes" ;;
556 -c|--clean)
557 PKGMK_CLEAN="yes" ;;
558 -kw|--keep-work)
559 PKGMK_KEEP_WORK="yes" ;;
560 -cf|--config-file)
561 if [ ! "$2" ]; then
562 echo "`basename $PKGMK_COMMAND`: option $1 requires an argument"
563 exit 1
564 fi
565 PKGMK_CONFFILE="$2"
566 shift ;;
567 -v|--version)
568 echo "`basename $PKGMK_COMMAND` (pkgutils) $PKGMK_VERSION"
569 exit 0 ;;
570 -h|--help)
571 print_help
572 exit 0 ;;
573 *)
574 echo "`basename $PKGMK_COMMAND`: invalid option $1"
575 exit 1 ;;
576 esac
577 shift
578 done
579 }
580
581 main() {
582 local FILE TARGET
583
584 parse_options "$@"
585
586 if [ "$PKGMK_RECURSIVE" = "yes" ]; then
587 recursive "$@"
588 exit 0
589 fi
590
591 for FILE in $PKGMK_PKGFILE $PKGMK_CONFFILE; do
592 if [ ! -f $FILE ]; then
593 error "File '$FILE' not found."
594 exit 1
595 fi
596 . $FILE
597 done
598
599 check_directory "$PKGMK_SOURCE_DIR"
600 check_directory "$PKGMK_PACKAGE_DIR"
601 check_directory "`dirname $PKGMK_WORK_DIR`"
602
603 check_pkgfile
604
605 TARGET="$PKGMK_PACKAGE_DIR/$name#$version-$release.pkg.tar.gz"
606
607 if [ "$PKGMK_CLEAN" = "yes" ]; then
608 clean
609 exit 0
610 fi
611
612 if [ "$PKGMK_UPDATE_FOOTPRINT" = "yes" ]; then
613 update_footprint
614 exit 0
615 fi
616
617 if [ "$PKGMK_UPDATE_MD5SUM" = "yes" ]; then
618 download_source
619 make_md5sum > $PKGMK_MD5SUM
620 info "Md5sum updated."
621 exit 0
622 fi
623
624 if [ "$PKGMK_DOWNLOAD_ONLY" = "yes" ]; then
625 download_source
626 exit 0
627 fi
628
629 if [ "$PKGMK_EXTRACT_ONLY" = "yes" ]; then
630 download_source
631 make_work_dir
632 info "Extracting sources of package '$name-$version'."
633 unpack_source
634 exit 0
635 fi
636
637 if [ "$PKGMK_UP_TO_DATE" = "yes" ]; then
638 if [ "`build_needed`" = "yes" ]; then
639 info "Package '$TARGET' is not up to date."
640 else
641 info "Package '$TARGET' is up to date."
642 fi
643 exit 0
644 fi
645
646 if [ "`build_needed`" = "no" ] && [ "$PKGMK_FORCE" = "no" ] && [ "$PKGMK_CHECK_MD5SUM" = "no" ]; then
647 info "Package '$TARGET' is up to date."
648 else
649 download_source
650 build_package
651 fi
652
653 if [ "$PKGMK_INSTALL" != "no" ]; then
654 install_package
655 fi
656
657 exit 0
658 }
659
660 trap "interrupted" SIGHUP SIGINT SIGQUIT SIGTERM
661
662 export LC_ALL=POSIX
663
664 readonly PKGMK_VERSION="#VERSION#"
665 readonly PKGMK_COMMAND="$0"
666 readonly PKGMK_ROOT="$PWD"
667
668 PKGMK_CONFFILE="/etc/pkgmk.conf"
669 PKGMK_PKGFILE="Pkgfile"
670 PKGMK_FOOTPRINT=".footprint"
671 PKGMK_MD5SUM=".md5sum"
672 PKGMK_NOSTRIP=".nostrip"
673
674 PKGMK_SOURCE_MIRRORS=()
675 PKGMK_SOURCE_DIR="$PWD"
676 PKGMK_PACKAGE_DIR="$PWD"
677 PKGMK_WORK_DIR="$PWD/work"
678
679 PKGMK_INSTALL="no"
680 PKGMK_RECURSIVE="no"
681 PKGMK_DOWNLOAD="no"
682 PKGMK_DOWNLOAD_ONLY="no"
683 PKGMK_EXTRACT_ONLY="no"
684 PKGMK_UP_TO_DATE="no"
685 PKGMK_UPDATE_FOOTPRINT="no"
686 PKGMK_IGNORE_FOOTPRINT="no"
687 PKGMK_FORCE="no"
688 PKGMK_KEEP_WORK="no"
689 PKGMK_UPDATE_MD5SUM="no"
690 PKGMK_IGNORE_MD5SUM="no"
691 PKGMK_CHECK_MD5SUM="no"
692 PKGMK_NO_STRIP="no"
693 PKGMK_CLEAN="no"
694
695 main "$@"
696
697 # End of file