1# Copyright (C) 2009 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# 15 16# A collection of shell function definitions used by various build scripts 17# in the Android NDK (Native Development Kit) 18# 19 20# Get current script name into PROGNAME 21PROGNAME=`basename $0` 22 23# Find the Android NDK root, assuming we are invoked from a script 24# within its directory structure. 25# 26# $1: Variable name that will receive the path 27# $2: Path of invoking script 28find_ndk_root () 29{ 30 # Try to auto-detect the NDK root by walking up the directory 31 # path to the current script. 32 local PROGDIR="`dirname \"$2\"`" 33 while [ -n "1" ] ; do 34 if [ -d "$PROGDIR/build/core" ] ; then 35 break 36 fi 37 if [ -z "$PROGDIR" -o "$PROGDIR" = '/' ] ; then 38 return 1 39 fi 40 PROGDIR="`cd \"$PROGDIR/..\" && pwd`" 41 done 42 eval $1="$PROGDIR" 43} 44 45# Put location of Android NDK into ANDROID_NDK_ROOT and 46# perform a tiny amount of sanity check 47# 48if [ -z "$ANDROID_NDK_ROOT" ] ; then 49 find_ndk_root ANDROID_NDK_ROOT "$0" 50 if [ $? != 0 ]; then 51 echo "Please define ANDROID_NDK_ROOT to point to the root of your" 52 echo "Android NDK installation." 53 exit 1 54 fi 55fi 56 57echo "$ANDROID_NDK_ROOT" | grep -q -e " " 58if [ $? = 0 ] ; then 59 echo "ERROR: The Android NDK installation path contains a space !" 60 echo "Please install to a different location." 61 exit 1 62fi 63 64if [ ! -d $ANDROID_NDK_ROOT ] ; then 65 echo "ERROR: Your ANDROID_NDK_ROOT variable does not point to a directory." 66 exit 1 67fi 68 69if [ ! -f $ANDROID_NDK_ROOT/build/tools/ndk-common.sh ] ; then 70 echo "ERROR: Your ANDROID_NDK_ROOT variable does not point to a valid directory." 71 exit 1 72fi 73 74## Use DRYRUN to find out top-level commands. 75DRYRUN=${DRYRUN-no} 76 77## Logging support 78## 79VERBOSE=${VERBOSE-yes} 80VERBOSE2=${VERBOSE2-no} 81 82 83# If NDK_LOGFILE is defined in the environment, use this as the log file 84TMPLOG= 85if [ -n "$NDK_LOGFILE" ] ; then 86 mkdir -p `dirname "$NDK_LOGFILE"` && touch "$NDK_LOGFILE" 87 TMPLOG="$NDK_LOGFILE" 88fi 89 90# Setup a log file where all log() and log2() output will be sent 91# 92# $1: log file path (optional) 93# 94setup_default_log_file () 95{ 96 if [ -n "$NDK_LOGFILE" ] ; then 97 return 98 fi 99 if [ -n "$1" ] ; then 100 NDK_LOGFILE="$1" 101 else 102 NDK_LOGFILE=/tmp/ndk-log-$$.txt 103 fi 104 export NDK_LOGFILE 105 TMPLOG="$NDK_LOGFILE" 106 rm -rf "$TMPLOG" && mkdir -p `dirname "$TMPLOG"` && touch "$TMPLOG" 107 echo "To follow build in another terminal, please use: tail -F $TMPLOG" 108} 109 110dump () 111{ 112 if [ -n "$TMPLOG" ] ; then 113 echo "$@" >> $TMPLOG 114 fi 115 echo "$@" 116} 117 118dump_n () 119{ 120 if [ -n "$TMPLOG" ] ; then 121 printf %s "$@" >> $TMPLOG 122 fi 123 printf %s "$@" 124} 125 126log () 127{ 128 if [ "$VERBOSE" = "yes" ] ; then 129 echo "$@" 130 else 131 if [ -n "$TMPLOG" ] ; then 132 echo "$@" >> $TMPLOG 133 fi 134 fi 135} 136 137log_n () 138{ 139 if [ "$VERBOSE" = "yes" ] ; then 140 printf %s "$@" 141 else 142 if [ -n "$TMPLOG" ] ; then 143 printf %s "$@" >> $TMPLOG 144 fi 145 fi 146} 147 148log2 () 149{ 150 if [ "$VERBOSE2" = "yes" ] ; then 151 echo "$@" 152 else 153 if [ -n "$TMPLOG" ] ; then 154 echo "$@" >> $TMPLOG 155 fi 156 fi 157} 158 159run () 160{ 161 if [ "$DRYRUN" = "yes" ] ; then 162 echo "## SKIP COMMAND: $@" 163 elif [ "$VERBOSE" = "yes" ] ; then 164 echo "## COMMAND: $@" 165 "$@" 2>&1 166 else 167 if [ -n "$TMPLOG" ] ; then 168 echo "## COMMAND: $@" >> $TMPLOG 169 "$@" >>$TMPLOG 2>&1 170 else 171 "$@" > /dev/null 2>&1 172 fi 173 fi 174} 175 176run2 () 177{ 178 if [ "$DRYRUN" = "yes" ] ; then 179 echo "## SKIP COMMAND: $@" 180 elif [ "$VERBOSE2" = "yes" ] ; then 181 echo "## COMMAND: $@" 182 "$@" 2>&1 183 elif [ "$VERBOSE" = "yes" ]; then 184 echo "## COMMAND: $@" 185 if [ -n "$TMPLOG" ]; then 186 echo "## COMMAND: $@" >> $TMPLOG 187 "$@" >>$TMPLOG 2>&1 188 else 189 "$@" > /dev/null 2>&1 190 fi 191 else 192 if [ -n "$TMPLOG" ]; then 193 "$@" >>$TMPLOG 2>&1 194 else 195 "$@" > /dev/null 2>&1 196 fi 197 fi 198} 199 200panic () 201{ 202 dump "ERROR: $@" 203 exit 1 204} 205 206fail_panic () 207{ 208 if [ $? != 0 ] ; then 209 dump "ERROR: $@" 210 exit 1 211 fi 212} 213 214fail_warning () 215{ 216 if [ $? != 0 ] ; then 217 dump "WARNING: $@" 218 fi 219} 220 221 222## Utilities 223## 224 225# Return the value of a given named variable 226# $1: variable name 227# 228# example: 229# FOO=BAR 230# BAR=ZOO 231# echo `var_value $FOO` 232# will print 'ZOO' 233# 234var_value () 235{ 236 # find a better way to do that ? 237 eval echo "$`echo $1`" 238} 239 240# convert to uppercase 241# assumes tr is installed on the platform ? 242# 243to_uppercase () 244{ 245 echo $1 | tr "[:lower:]" "[:upper:]" 246} 247 248## First, we need to detect the HOST CPU, because proper HOST_ARCH detection 249## requires platform-specific tricks. 250## 251HOST_EXE="" 252HOST_OS=`uname -s` 253case "$HOST_OS" in 254 Darwin) 255 HOST_OS=darwin 256 ;; 257 Linux) 258 # note that building 32-bit binaries on x86_64 is handled later 259 HOST_OS=linux 260 ;; 261 FreeBsd) # note: this is not tested 262 HOST_OS=freebsd 263 ;; 264 CYGWIN*|*_NT-*) 265 HOST_OS=windows 266 HOST_EXE=.exe 267 if [ "x$OSTYPE" = xcygwin ] ; then 268 HOST_OS=cygwin 269 fi 270 ;; 271esac 272 273log2 "HOST_OS=$HOST_OS" 274log2 "HOST_EXE=$HOST_EXE" 275 276## Now find the host architecture. This must correspond to the bitness of 277## the binaries we're going to run with this NDK. Certain platforms allow 278## you to use a 64-bit kernel with a 32-bit userland, and unfortunately 279## commands like 'uname -m' only report the kernel bitness. 280## 281HOST_ARCH=`uname -m` 282case "$HOST_ARCH" in 283 i?86) HOST_ARCH=x86 284 # "uname -m" reports i386 on Snow Leopard even though its architecture is 285 # 64-bit. In order to use it to build 64-bit toolchains we need to fix the 286 # reporting anomoly here. 287 if [ "$HOST_OS" = darwin ] ; then 288 if ! echo __LP64__ | (CCOPTS= gcc -E - 2>/dev/null) | grep -q __LP64__ ; then 289 # or if gcc -dM -E - < /dev/null | grep -q __LP64__; then 290 HOST_ARCH=x86_64 291 fi 292 fi 293 ;; 294 amd64) HOST_ARCH=x86_64 295 ;; 296 powerpc) HOST_ARCH=ppc 297 ;; 298esac 299 300HOST_FILE_PROGRAM="file" 301case "$HOST_OS-$HOST_ARCH" in 302 linux-x86_64|darwin-x86_64) 303 ## On Linux or Darwin, a 64-bit kernel doesn't mean that the user-land 304 ## is always 32-bit, so use "file" to determine the bitness of the shell 305 ## that invoked us. The -L option is used to de-reference symlinks. 306 ## 307 ## Note that on Darwin, a single executable can contain both x86 and 308 ## x86_64 machine code, so just look for x86_64 (darwin) or x86-64 (Linux) 309 ## in the output. 310 ## 311 ## Also note that some versions of 'file' in MacPort may report erroneous 312 ## result. See http://b.android.com/53769. Use /usr/bin/file if exists. 313 if [ "$HOST_OS" = "darwin" ]; then 314 SYSTEM_FILE_PROGRAM="/usr/bin/file" 315 test -x "$SYSTEM_FILE_PROGRAM" && HOST_FILE_PROGRAM="$SYSTEM_FILE_PROGRAM" 316 fi 317 "$HOST_FILE_PROGRAM" -L "$SHELL" | grep -q "x86[_-]64" 318 if [ $? != 0 ]; then 319 # $SHELL is not a 64-bit executable, so assume our userland is too. 320 log2 "Detected 32-bit userland on 64-bit kernel system!" 321 HOST_ARCH=x86 322 fi 323 ;; 324esac 325 326log2 "HOST_ARCH=$HOST_ARCH" 327 328# at this point, the supported values for HOST_ARCH are: 329# x86 330# x86_64 331# ppc 332# 333# other values may be possible but haven't been tested 334# 335# at this point, the value of HOST_OS should be one of the following: 336# linux 337# darwin 338# windows (MSys) 339# cygwin 340# 341# Note that cygwin is treated as a special case because it behaves very differently 342# for a few things. Other values may be possible but have not been tested 343# 344 345# define HOST_TAG as a unique tag used to identify both the host OS and CPU 346# supported values are: 347# 348# linux-x86 349# linux-x86_64 350# darwin-x86 351# darwin-x86_64 352# darwin-ppc 353# windows 354# windows-x86_64 355# 356# other values are possible but were not tested. 357# 358compute_host_tag () 359{ 360 HOST_TAG=${HOST_OS}-${HOST_ARCH} 361 # Special case for windows-x86 => windows 362 case $HOST_TAG in 363 windows-x86|cygwin-x86) 364 HOST_TAG="windows" 365 ;; 366 esac 367 log2 "HOST_TAG=$HOST_TAG" 368} 369 370compute_host_tag 371 372# Compute the number of host CPU cores an HOST_NUM_CPUS 373# 374case "$HOST_OS" in 375 linux) 376 HOST_NUM_CPUS=`cat /proc/cpuinfo | grep processor | wc -l` 377 ;; 378 darwin|freebsd) 379 HOST_NUM_CPUS=`sysctl -n hw.ncpu` 380 ;; 381 windows|cygwin) 382 HOST_NUM_CPUS=$NUMBER_OF_PROCESSORS 383 ;; 384 *) # let's play safe here 385 HOST_NUM_CPUS=1 386esac 387 388log2 "HOST_NUM_CPUS=$HOST_NUM_CPUS" 389 390# If BUILD_NUM_CPUS is not already defined in your environment, 391# define it as the double of HOST_NUM_CPUS. This is used to 392# run Make commands in parralles, as in 'make -j$BUILD_NUM_CPUS' 393# 394if [ -z "$BUILD_NUM_CPUS" ] ; then 395 BUILD_NUM_CPUS=`expr $HOST_NUM_CPUS \* 2` 396fi 397 398log2 "BUILD_NUM_CPUS=$BUILD_NUM_CPUS" 399 400 401## HOST TOOLCHAIN SUPPORT 402## 403 404# force the generation of 32-bit binaries on 64-bit systems 405# 406FORCE_32BIT=no 407force_32bit_binaries () 408{ 409 if [ "$HOST_ARCH" = x86_64 ] ; then 410 log2 "Forcing generation of 32-bit host binaries on $HOST_ARCH" 411 FORCE_32BIT=yes 412 HOST_ARCH=x86 413 log2 "HOST_ARCH=$HOST_ARCH" 414 compute_host_tag 415 fi 416} 417 418# On Windows, cygwin binaries will be generated by default, but 419# you can force mingw ones that do not link to cygwin.dll if you 420# call this function. 421# 422disable_cygwin () 423{ 424 if [ $HOST_OS = cygwin ] ; then 425 log2 "Disabling cygwin binaries generation" 426 CFLAGS="$CFLAGS -mno-cygwin" 427 LDFLAGS="$LDFLAGS -mno-cygwin" 428 HOST_OS=windows 429 compute_host_tag 430 fi 431} 432 433# Various probes are going to need to run a small C program 434mkdir -p /tmp/ndk-$USER/tmp/tests 435 436TMPC=/tmp/ndk-$USER/tmp/tests/test-$$.c 437TMPO=/tmp/ndk-$USER/tmp/tests/test-$$.o 438TMPE=/tmp/ndk-$USER/tmp/tests/test-$$$EXE 439TMPL=/tmp/ndk-$USER/tmp/tests/test-$$.log 440 441# cleanup temporary files 442clean_temp () 443{ 444 rm -f $TMPC $TMPO $TMPL $TMPE 445} 446 447# cleanup temp files then exit with an error 448clean_exit () 449{ 450 clean_temp 451 exit 1 452} 453 454# this function will setup the compiler and linker and check that they work as advertised 455# note that you should call 'force_32bit_binaries' before this one if you want it to 456# generate 32-bit binaries on 64-bit systems (that support it). 457# 458setup_toolchain () 459{ 460 if [ -z "$CC" ] ; then 461 CC=gcc 462 fi 463 if [ -z "$CXX" ] ; then 464 CXX=g++ 465 fi 466 if [ -z "$CXXFLAGS" ] ; then 467 CXXFLAGS="$CFLAGS" 468 fi 469 if [ -z "$LD" ] ; then 470 LD="$CC" 471 fi 472 473 log2 "Using '$CC' as the C compiler" 474 475 # check that we can compile a trivial C program with this compiler 476 mkdir -p $(dirname "$TMPC") 477 cat > $TMPC <<EOF 478int main(void) {} 479EOF 480 481 if [ "$FORCE_32BIT" = yes ] ; then 482 CC="$CC -m32" 483 CXX="$CXX -m32" 484 LD="$LD -m32" 485 compile 486 if [ $? != 0 ] ; then 487 # sometimes, we need to also tell the assembler to generate 32-bit binaries 488 # this is highly dependent on your GCC installation (and no, we can't set 489 # this flag all the time) 490 CFLAGS="$CFLAGS -Wa,--32" 491 compile 492 fi 493 fi 494 495 compile 496 if [ $? != 0 ] ; then 497 echo "your C compiler doesn't seem to work:" 498 cat $TMPL 499 clean_exit 500 fi 501 log "CC : compiler check ok ($CC)" 502 503 # check that we can link the trivial program into an executable 504 link 505 if [ $? != 0 ] ; then 506 OLD_LD="$LD" 507 LD="$CC" 508 compile 509 link 510 if [ $? != 0 ] ; then 511 LD="$OLD_LD" 512 echo "your linker doesn't seem to work:" 513 cat $TMPL 514 clean_exit 515 fi 516 fi 517 log2 "Using '$LD' as the linker" 518 log "LD : linker check ok ($LD)" 519 520 # check the C++ compiler 521 log2 "Using '$CXX' as the C++ compiler" 522 523 cat > $TMPC <<EOF 524#include <iostream> 525using namespace std; 526int main() 527{ 528 cout << "Hello World!" << endl; 529 return 0; 530} 531EOF 532 533 compile_cpp 534 if [ $? != 0 ] ; then 535 echo "your C++ compiler doesn't seem to work" 536 cat $TMPL 537 clean_exit 538 fi 539 540 log "CXX : C++ compiler check ok ($CXX)" 541 542 # XXX: TODO perform AR checks 543 AR=ar 544 ARFLAGS= 545} 546 547# try to compile the current source file in $TMPC into an object 548# stores the error log into $TMPL 549# 550compile () 551{ 552 log2 "Object : $CC -o $TMPO -c $CFLAGS $TMPC" 553 $CC -o $TMPO -c $CFLAGS $TMPC 2> $TMPL 554} 555 556compile_cpp () 557{ 558 log2 "Object : $CXX -o $TMPO -c $CXXFLAGS $TMPC" 559 $CXX -o $TMPO -c $CXXFLAGS $TMPC 2> $TMPL 560} 561 562# try to link the recently built file into an executable. error log in $TMPL 563# 564link() 565{ 566 log2 "Link : $LD -o $TMPE $TMPO $LDFLAGS" 567 $LD -o $TMPE $TMPO $LDFLAGS 2> $TMPL 568} 569 570# run a command 571# 572execute() 573{ 574 log2 "Running: $*" 575 $* 576} 577 578# perform a simple compile / link / run of the source file in $TMPC 579compile_exec_run() 580{ 581 log2 "RunExec : $CC -o $TMPE $CFLAGS $TMPC" 582 compile 583 if [ $? != 0 ] ; then 584 echo "Failure to compile test program" 585 cat $TMPC 586 cat $TMPL 587 clean_exit 588 fi 589 link 590 if [ $? != 0 ] ; then 591 echo "Failure to link test program" 592 cat $TMPC 593 echo "------" 594 cat $TMPL 595 clean_exit 596 fi 597 $TMPE 598} 599 600pattern_match () 601{ 602 echo "$2" | grep -q -E -e "$1" 603} 604 605# Let's check that we have a working md5sum here 606check_md5sum () 607{ 608 A_MD5=`echo "A" | md5sum | cut -d' ' -f1` 609 if [ "$A_MD5" != "bf072e9119077b4e76437a93986787ef" ] ; then 610 echo "Please install md5sum on this machine" 611 exit 2 612 fi 613} 614 615# Find if a given shell program is available. 616# We need to take care of the fact that the 'which <foo>' command 617# may return either an empty string (Linux) or something like 618# "no <foo> in ..." (Darwin). Also, we need to redirect stderr 619# to /dev/null for Cygwin 620# 621# $1: variable name 622# $2: program name 623# 624# Result: set $1 to the full path of the corresponding command 625# or to the empty/undefined string if not available 626# 627find_program () 628{ 629 local PROG RET 630 PROG=`which $2 2>/dev/null` 631 RET=$? 632 if [ $RET != 0 ]; then 633 PROG= 634 fi 635 eval $1=\"$PROG\" 636 return $RET 637} 638 639prepare_download () 640{ 641 find_program CMD_WGET wget 642 find_program CMD_CURL curl 643 find_program CMD_SCRP scp 644} 645 646find_pbzip2 () 647{ 648 if [ -z "$_PBZIP2_initialized" ] ; then 649 find_program PBZIP2 pbzip2 650 _PBZIP2_initialized="yes" 651 fi 652} 653 654# Download a file with either 'curl', 'wget' or 'scp' 655# 656# $1: source URL (e.g. http://foo.com, ssh://blah, /some/path) 657# $2: target file 658download_file () 659{ 660 # Is this HTTP, HTTPS or FTP ? 661 if pattern_match "^(http|https|ftp):.*" "$1"; then 662 if [ -n "$CMD_WGET" ] ; then 663 run $CMD_WGET -O $2 $1 664 elif [ -n "$CMD_CURL" ] ; then 665 run $CMD_CURL -o $2 $1 666 else 667 echo "Please install wget or curl on this machine" 668 exit 1 669 fi 670 return 671 fi 672 673 # Is this SSH ? 674 # Accept both ssh://<path> or <machine>:<path> 675 # 676 if pattern_match "^(ssh|[^:]+):.*" "$1"; then 677 if [ -n "$CMD_SCP" ] ; then 678 scp_src=`echo $1 | sed -e s%ssh://%%g` 679 run $CMD_SCP $scp_src $2 680 else 681 echo "Please install scp on this machine" 682 exit 1 683 fi 684 return 685 fi 686 687 # Is this a file copy ? 688 # Accept both file://<path> or /<path> 689 # 690 if pattern_match "^(file://|/).*" "$1"; then 691 cp_src=`echo $1 | sed -e s%^file://%%g` 692 run cp -f $cp_src $2 693 return 694 fi 695} 696 697# Form the relative path between from one abs path to another 698# 699# $1 : start path 700# $2 : end path 701# 702# From: 703# http://stackoverflow.com/questions/2564634/bash-convert-absolute-path-into-relative-path-given-a-current-directory 704relpath () 705{ 706 [ $# -ge 1 ] && [ $# -le 2 ] || return 1 707 current="${2:+"$1"}" 708 target="${2:-"$1"}" 709 [ "$target" != . ] || target=/ 710 target="/${target##/}" 711 [ "$current" != . ] || current=/ 712 current="${current:="/"}" 713 current="/${current##/}" 714 appendix="${target##/}" 715 relative='' 716 while appendix="${target#"$current"/}" 717 [ "$current" != '/' ] && [ "$appendix" = "$target" ]; do 718 if [ "$current" = "$appendix" ]; then 719 relative="${relative:-.}" 720 echo "${relative#/}" 721 return 0 722 fi 723 current="${current%/*}" 724 relative="$relative${relative:+/}.." 725 done 726 relative="$relative${relative:+${appendix:+/}}${appendix#/}" 727 echo "$relative" 728} 729 730# Unpack a given archive 731# 732# $1: archive file path 733# $2: optional target directory (current one if omitted) 734# 735unpack_archive () 736{ 737 local ARCHIVE="$1" 738 local DIR=${2-.} 739 local RESULT TARFLAGS ZIPFLAGS 740 mkdir -p "$DIR" 741 if [ "$VERBOSE2" = "yes" ] ; then 742 TARFLAGS="vxpf" 743 ZIPFLAGS="" 744 else 745 TARFLAGS="xpf" 746 ZIPFLAGS="q" 747 fi 748 case "$ARCHIVE" in 749 *.zip) 750 (cd $DIR && run unzip $ZIPFLAGS "$ARCHIVE") 751 ;; 752 *.tar) 753 run tar $TARFLAGS "$ARCHIVE" -C $DIR 754 ;; 755 *.tar.gz) 756 run tar z$TARFLAGS "$ARCHIVE" -C $DIR 757 ;; 758 *.tar.bz2) 759 find_pbzip2 760 if [ -n "$PBZIP2" ] ; then 761 run tar --use-compress-prog=pbzip2 -$TARFLAGS "$ARCHIVE" -C $DIR 762 else 763 run tar j$TARFLAGS "$ARCHIVE" -C $DIR 764 fi 765 # remove ._* files by MacOSX to preserve resource forks we don't need 766 find $DIR -name "\._*" -exec rm {} \; 767 ;; 768 *) 769 panic "Cannot unpack archive with unknown extension: $ARCHIVE" 770 ;; 771 esac 772} 773 774# Pack a given archive 775# 776# $1: archive file path (including extension) 777# $2: source directory for archive content 778# $3+: list of files (including patterns), all if empty 779pack_archive () 780{ 781 local ARCHIVE="$1" 782 local SRCDIR="$2" 783 local SRCFILES 784 local TARFLAGS ZIPFLAGS 785 shift; shift; 786 if [ -z "$1" ] ; then 787 SRCFILES="*" 788 else 789 SRCFILES="$@" 790 fi 791 if [ "`basename $ARCHIVE`" = "$ARCHIVE" ] ; then 792 ARCHIVE="`pwd`/$ARCHIVE" 793 fi 794 mkdir -p `dirname $ARCHIVE` 795 if [ "$VERBOSE2" = "yes" ] ; then 796 TARFLAGS="vcf" 797 ZIPFLAGS="-9r" 798 else 799 TARFLAGS="cf" 800 ZIPFLAGS="-9qr" 801 fi 802 # Ensure symlinks are stored as is in zip files. for toolchains 803 # this can save up to 7 MB in the size of the final archive 804 #ZIPFLAGS="$ZIPFLAGS --symlinks" 805 case "$ARCHIVE" in 806 *.zip) 807 (cd $SRCDIR && run zip $ZIPFLAGS "$ARCHIVE" $SRCFILES) 808 ;; 809 *.tar) 810 (cd $SRCDIR && run tar $TARFLAGS "$ARCHIVE" $SRCFILES) 811 ;; 812 *.tar.gz) 813 (cd $SRCDIR && run tar z$TARFLAGS "$ARCHIVE" $SRCFILES) 814 ;; 815 *.tar.bz2) 816 find_pbzip2 817 if [ -n "$PBZIP2" ] ; then 818 (cd $SRCDIR && run tar --use-compress-prog=pbzip2 -$TARFLAGS "$ARCHIVE" $SRCFILES) 819 else 820 (cd $SRCDIR && run tar j$TARFLAGS "$ARCHIVE" $SRCFILES) 821 fi 822 ;; 823 *) 824 panic "Unsupported archive format: $ARCHIVE" 825 ;; 826 esac 827} 828 829# Copy a directory, create target location if needed 830# 831# $1: source directory 832# $2: target directory location 833# 834copy_directory () 835{ 836 local SRCDIR="$1" 837 local DSTDIR="$2" 838 if [ ! -d "$SRCDIR" ] ; then 839 panic "Can't copy from non-directory: $SRCDIR" 840 fi 841 log "Copying directory: " 842 log " from $SRCDIR" 843 log " to $DSTDIR" 844 mkdir -p "$DSTDIR" && (cd "$SRCDIR" && 2>/dev/null tar cf - *) | (tar xf - -C "$DSTDIR") 845 fail_panic "Cannot copy to directory: $DSTDIR" 846} 847 848# Move a directory, create target location if needed 849# 850# $1: source directory 851# $2: target directory location 852# 853move_directory () 854{ 855 local SRCDIR="$1" 856 local DSTDIR="$2" 857 if [ ! -d "$SRCDIR" ] ; then 858 panic "Can't move from non-directory: $SRCDIR" 859 fi 860 log "Move directory: " 861 log " from $SRCDIR" 862 log " to $DSTDIR" 863 mkdir -p "$DSTDIR" && (mv "$SRCDIR"/* "$DSTDIR") 864 fail_panic "Cannot move to directory: $DSTDIR" 865} 866 867# This is the same than copy_directory(), but symlinks will be replaced 868# by the file they actually point to instead. 869copy_directory_nolinks () 870{ 871 local SRCDIR="$1" 872 local DSTDIR="$2" 873 if [ ! -d "$SRCDIR" ] ; then 874 panic "Can't copy from non-directory: $SRCDIR" 875 fi 876 log "Copying directory (without symlinks): " 877 log " from $SRCDIR" 878 log " to $DSTDIR" 879 mkdir -p "$DSTDIR" && (cd "$SRCDIR" && tar chf - *) | (tar xf - -C "$DSTDIR") 880 fail_panic "Cannot copy to directory: $DSTDIR" 881} 882 883# Copy certain files from one directory to another one 884# $1: source directory 885# $2: target directory 886# $3+: file list (including patterns) 887copy_file_list () 888{ 889 local SRCDIR="$1" 890 local DSTDIR="$2" 891 shift; shift; 892 if [ ! -d "$SRCDIR" ] ; then 893 panic "Cant' copy from non-directory: $SRCDIR" 894 fi 895 log "Copying file: $@" 896 log " from $SRCDIR" 897 log " to $DSTDIR" 898 mkdir -p "$DSTDIR" && (cd "$SRCDIR" && (echo $@ | tr ' ' '\n' | tar cf - -T -)) | (tar xf - -C "$DSTDIR") 899 fail_panic "Cannot copy files to directory: $DSTDIR" 900} 901 902# Rotate a log file 903# If the given log file exist, add a -1 to the end of the file. 904# If older log files exist, rename them to -<n+1> 905# $1: log file 906# $2: maximum version to retain [optional] 907rotate_log () 908{ 909 # Default Maximum versions to retain 910 local MAXVER="5" 911 local LOGFILE="$1" 912 shift; 913 if [ ! -z "$1" ] ; then 914 local tmpmax="$1" 915 shift; 916 tmpmax=`expr $tmpmax + 0` 917 if [ $tmpmax -lt 1 ] ; then 918 panic "Invalid maximum log file versions '$tmpmax' invalid; defaulting to $MAXVER" 919 else 920 MAXVER=$tmpmax; 921 fi 922 fi 923 924 # Do Nothing if the log file does not exist 925 if [ ! -f "${LOGFILE}" ] ; then 926 return 927 fi 928 929 # Rename existing older versions 930 ver=$MAXVER 931 while [ $ver -ge 1 ] 932 do 933 local prev=$(( $ver - 1 )) 934 local old="-$prev" 935 936 # Instead of old version 0; use the original filename 937 if [ $ver -eq 1 ] ; then 938 old="" 939 fi 940 941 if [ -f "${LOGFILE}${old}" ] ; then 942 mv -f "${LOGFILE}${old}" "${LOGFILE}-${ver}" 943 fi 944 945 ver=$prev 946 done 947} 948 949# Dereference symlink 950# $1+: directories 951dereference_symlink () 952{ 953 local DIRECTORY SYMLINKS DIR FILE LINK 954 for DIRECTORY in "$@"; do 955 if [ -d "$DIRECTORY" ]; then 956 while true; do 957 # Find all symlinks in this directory. 958 SYMLINKS=`find $DIRECTORY -type l` 959 if [ -z "$SYMLINKS" ]; then 960 break; 961 fi 962 # Iterate symlinks 963 for SYMLINK in $SYMLINKS; do 964 if [ -L "$SYMLINK" ]; then 965 DIR=`dirname "$SYMLINK"` 966 FILE=`basename "$SYMLINK"` 967 # Note that if `readlink $FILE` is also a link, we want to deal 968 # with it in the next iteration. There is potential infinite-loop 969 # situation for cicular link doesn't exist in our case, though. 970 (cd "$DIR" && \ 971 LINK=`readlink "$FILE"` && \ 972 test ! -L "$LINK" && \ 973 rm -f "$FILE" && \ 974 cp -a "$LINK" "$FILE") 975 fi 976 done 977 done 978 fi 979 done 980} 981