| # Copyright (C) 2009 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| |
| # A collection of shell function definitions used by various build scripts |
| # in the Android NDK (Native Development Kit) |
| # |
| |
| # Get current script name into PROGNAME |
| PROGNAME=`basename $0` |
| |
| # Find the Android NDK root, assuming we are invoked from a script |
| # within its directory structure. |
| # |
| # $1: Variable name that will receive the path |
| # $2: Path of invoking script |
| find_ndk_root () |
| { |
| # Try to auto-detect the NDK root by walking up the directory |
| # path to the current script. |
| local PROGDIR="`dirname \"$2\"`" |
| while [ -n "1" ] ; do |
| if [ -d "$PROGDIR/build/core" ] ; then |
| break |
| fi |
| if [ -z "$PROGDIR" -o "$PROGDIR" = '/' ] ; then |
| return 1 |
| fi |
| PROGDIR="`cd \"$PROGDIR/..\" && pwd`" |
| done |
| eval $1="$PROGDIR" |
| } |
| |
| # Put location of Android NDK into ANDROID_NDK_ROOT and |
| # perform a tiny amount of sanity check |
| # |
| if [ -z "$ANDROID_NDK_ROOT" ] ; then |
| find_ndk_root ANDROID_NDK_ROOT "$0" |
| if [ $? != 0 ]; then |
| echo "Please define ANDROID_NDK_ROOT to point to the root of your" |
| echo "Android NDK installation." |
| exit 1 |
| fi |
| fi |
| |
| echo "$ANDROID_NDK_ROOT" | grep -q -e " " |
| if [ $? = 0 ] ; then |
| echo "ERROR: The Android NDK installation path contains a space !" |
| echo "Please install to a different location." |
| exit 1 |
| fi |
| |
| if [ ! -d $ANDROID_NDK_ROOT ] ; then |
| echo "ERROR: Your ANDROID_NDK_ROOT variable does not point to a directory." |
| exit 1 |
| fi |
| |
| if [ ! -f $ANDROID_NDK_ROOT/build/core/ndk-common.sh ] ; then |
| echo "ERROR: Your ANDROID_NDK_ROOT variable does not point to a valid directory." |
| exit 1 |
| fi |
| |
| ## Logging support |
| ## |
| VERBOSE=${VERBOSE-yes} |
| VERBOSE2=${VERBOSE2-no} |
| |
| |
| # If NDK_LOGFILE is defined in the environment, use this as the log file |
| TMPLOG= |
| if [ -n "$NDK_LOGFILE" ] ; then |
| mkdir -p `dirname "$NDK_LOGFILE"` && touch "$NDK_LOGFILE" |
| TMPLOG="$NDK_LOGFILE" |
| fi |
| |
| # Setup a log file where all log() and log2() output will be sent |
| # |
| # $1: log file path (optional) |
| # |
| setup_default_log_file () |
| { |
| if [ -n "$NDK_LOGFILE" ] ; then |
| return |
| fi |
| if [ -n "$1" ] ; then |
| NDK_LOGFILE="$1" |
| else |
| NDK_LOGFILE=/tmp/ndk-log-$$.txt |
| fi |
| export NDK_LOGFILE |
| TMPLOG="$NDK_LOGFILE" |
| rm -rf "$TMPLOG" && mkdir -p `dirname "$TMPLOG"` && touch "$TMPLOG" |
| echo "To follow build in another terminal, please use: tail -F $TMPLOG" |
| } |
| |
| dump () |
| { |
| if [ -n "$TMPLOG" ] ; then |
| echo "$@" >> $TMPLOG |
| fi |
| echo "$@" |
| } |
| |
| dump_n () |
| { |
| if [ -n "$TMPLOG" ] ; then |
| printf %s "$@" >> $TMPLOG |
| fi |
| printf %s "$@" |
| } |
| |
| log () |
| { |
| if [ "$VERBOSE" = "yes" ] ; then |
| echo "$@" |
| else |
| if [ -n "$TMPLOG" ] ; then |
| echo "$@" >> $TMPLOG |
| fi |
| fi |
| } |
| |
| log_n () |
| { |
| if [ "$VERBOSE" = "yes" ] ; then |
| printf %s "$@" |
| else |
| if [ -n "$TMPLOG" ] ; then |
| printf %s "$@" >> $TMPLOG |
| fi |
| fi |
| } |
| |
| log2 () |
| { |
| if [ "$VERBOSE2" = "yes" ] ; then |
| echo "$@" |
| else |
| if [ -n "$TMPLOG" ] ; then |
| echo "$@" >> $TMPLOG |
| fi |
| fi |
| } |
| |
| run () |
| { |
| if [ "$VERBOSE" = "yes" ] ; then |
| echo "## COMMAND: $@" |
| "$@" 2>&1 |
| else |
| if [ -n "$TMPLOG" ] ; then |
| echo "## COMMAND: $@" >> $TMPLOG |
| "$@" >>$TMPLOG 2>&1 |
| else |
| "$@" > /dev/null 2>&1 |
| fi |
| fi |
| } |
| |
| run2 () |
| { |
| if [ "$VERBOSE2" = "yes" ] ; then |
| echo "## COMMAND: $@" |
| "$@" 2>&1 |
| elif [ "$VERBOSE" = "yes" ]; then |
| echo "## COMMAND: $@" |
| if [ -n "$TMPLOG" ]; then |
| echo "## COMMAND: $@" >> $TMPLOG |
| "$@" >>$TMPLOG 2>&1 |
| else |
| "$@" > /dev/null 2>&1 |
| fi |
| else |
| if [ -n "$TMPLOG" ]; then |
| "$@" >>$TMPLOG 2>&1 |
| else |
| "$@" > /dev/null 2>&1 |
| fi |
| fi |
| } |
| |
| panic () |
| { |
| dump "ERROR: $@" |
| exit 1 |
| } |
| |
| fail_panic () |
| { |
| if [ $? != 0 ] ; then |
| dump "ERROR: $@" |
| exit 1 |
| fi |
| } |
| |
| fail_warning () |
| { |
| if [ $? != 0 ] ; then |
| dump "WARNING: $@" |
| fi |
| } |
| |
| |
| ## Utilities |
| ## |
| |
| # Return the value of a given named variable |
| # $1: variable name |
| # |
| # example: |
| # FOO=BAR |
| # BAR=ZOO |
| # echo `var_value $FOO` |
| # will print 'ZOO' |
| # |
| var_value () |
| { |
| # find a better way to do that ? |
| eval echo "$`echo $1`" |
| } |
| |
| # convert to uppercase |
| # assumes tr is installed on the platform ? |
| # |
| to_uppercase () |
| { |
| echo $1 | tr "[:lower:]" "[:upper:]" |
| } |
| |
| ## First, we need to detect the HOST CPU, because proper HOST_ARCH detection |
| ## requires platform-specific tricks. |
| ## |
| HOST_EXE="" |
| HOST_OS=`uname -s` |
| case "$HOST_OS" in |
| Darwin) |
| HOST_OS=darwin |
| ;; |
| Linux) |
| # note that building 32-bit binaries on x86_64 is handled later |
| HOST_OS=linux |
| ;; |
| FreeBsd) # note: this is not tested |
| HOST_OS=freebsd |
| ;; |
| CYGWIN*|*_NT-*) |
| HOST_OS=windows |
| HOST_EXE=.exe |
| if [ "x$OSTYPE" = xcygwin ] ; then |
| HOST_OS=cygwin |
| fi |
| ;; |
| esac |
| |
| log2 "HOST_OS=$HOST_OS" |
| log2 "HOST_EXE=$HOST_EXE" |
| |
| ## Now find the host architecture. This must correspond to the bitness of |
| ## the binaries we're going to run with this NDK. Certain platforms allow |
| ## you to use a 64-bit kernel with a 32-bit userland, and unfortunately |
| ## commands like 'uname -m' only report the kernel bitness. |
| ## |
| HOST_ARCH=`uname -m` |
| case "$HOST_ARCH" in |
| i?86) HOST_ARCH=x86 |
| # "uname -m" reports i386 on Snow Leopard even though its architecture is |
| # 64-bit. In order to use it to build 64-bit toolchains we need to fix the |
| # reporting anomoly here. |
| if [ "$HOST_OS" = darwin ] ; then |
| if ! echo __LP64__ | (CCOPTS= gcc -E - 2>/dev/null) | grep -q __LP64__ ; then |
| # or if gcc -dM -E - < /dev/null | grep -q __LP64__; then |
| HOST_ARCH=x86_64 |
| fi |
| fi |
| ;; |
| amd64) HOST_ARCH=x86_64 |
| ;; |
| powerpc) HOST_ARCH=ppc |
| ;; |
| esac |
| |
| case "$HOST_OS-$HOST_ARCH" in |
| linux-x86_64|darwin-x86_64) |
| ## On Linux or Darwin, a 64-bit kernel doesn't mean that the user-land |
| ## is always 32-bit, so use "file" to determine the bitness of the shell |
| ## that invoked us. The -L option is used to de-reference symlinks. |
| ## |
| ## Note that on Darwin, a single executable can contain both x86 and |
| ## x86_64 machine code, so just look for x86_64 (darwin) or x86-64 (Linux) |
| ## in the output. |
| ## |
| file -L "$SHELL" | grep -q "x86[_-]64" |
| if [ $? != 0 ]; then |
| # $SHELL is not a 64-bit executable, so assume our userland is too. |
| log2 "Detected 32-bit userland on 64-bit kernel system!" |
| HOST_ARCH=x86 |
| fi |
| ;; |
| esac |
| |
| log2 "HOST_ARCH=$HOST_ARCH" |
| |
| # at this point, the supported values for HOST_ARCH are: |
| # x86 |
| # x86_64 |
| # ppc |
| # |
| # other values may be possible but haven't been tested |
| # |
| # at this point, the value of HOST_OS should be one of the following: |
| # linux |
| # darwin |
| # windows (MSys) |
| # cygwin |
| # |
| # Note that cygwin is treated as a special case because it behaves very differently |
| # for a few things. Other values may be possible but have not been tested |
| # |
| |
| # define HOST_TAG as a unique tag used to identify both the host OS and CPU |
| # supported values are: |
| # |
| # linux-x86 |
| # linux-x86_64 |
| # darwin-x86 |
| # darwin-x86_64 |
| # darwin-ppc |
| # windows |
| # windows-x86_64 |
| # |
| # other values are possible but were not tested. |
| # |
| compute_host_tag () |
| { |
| HOST_TAG=${HOST_OS}-${HOST_ARCH} |
| # Special case for windows-x86 => windows |
| case $HOST_TAG in |
| windows-x86|cygwin-x86) |
| HOST_TAG="windows" |
| ;; |
| esac |
| log2 "HOST_TAG=$HOST_TAG" |
| } |
| |
| compute_host_tag |
| |
| # Compute the number of host CPU cores an HOST_NUM_CPUS |
| # |
| case "$HOST_OS" in |
| linux) |
| HOST_NUM_CPUS=`cat /proc/cpuinfo | grep processor | wc -l` |
| ;; |
| darwin|freebsd) |
| HOST_NUM_CPUS=`sysctl -n hw.ncpu` |
| ;; |
| windows|cygwin) |
| HOST_NUM_CPUS=$NUMBER_OF_PROCESSORS |
| ;; |
| *) # let's play safe here |
| HOST_NUM_CPUS=1 |
| esac |
| |
| log2 "HOST_NUM_CPUS=$HOST_NUM_CPUS" |
| |
| # If BUILD_NUM_CPUS is not already defined in your environment, |
| # define it as the double of HOST_NUM_CPUS. This is used to |
| # run Make commands in parralles, as in 'make -j$BUILD_NUM_CPUS' |
| # |
| if [ -z "$BUILD_NUM_CPUS" ] ; then |
| BUILD_NUM_CPUS=`expr $HOST_NUM_CPUS \* 2` |
| fi |
| |
| log2 "BUILD_NUM_CPUS=$BUILD_NUM_CPUS" |
| |
| |
| ## HOST TOOLCHAIN SUPPORT |
| ## |
| |
| # force the generation of 32-bit binaries on 64-bit systems |
| # |
| FORCE_32BIT=no |
| force_32bit_binaries () |
| { |
| if [ "$HOST_ARCH" = x86_64 ] ; then |
| log2 "Forcing generation of 32-bit host binaries on $HOST_ARCH" |
| FORCE_32BIT=yes |
| HOST_ARCH=x86 |
| log2 "HOST_ARCH=$HOST_ARCH" |
| compute_host_tag |
| fi |
| } |
| |
| # On Windows, cygwin binaries will be generated by default, but |
| # you can force mingw ones that do not link to cygwin.dll if you |
| # call this function. |
| # |
| disable_cygwin () |
| { |
| if [ $HOST_OS = cygwin ] ; then |
| log2 "Disabling cygwin binaries generation" |
| CFLAGS="$CFLAGS -mno-cygwin" |
| LDFLAGS="$LDFLAGS -mno-cygwin" |
| HOST_OS=windows |
| compute_host_tag |
| fi |
| } |
| |
| # Various probes are going to need to run a small C program |
| mkdir -p /tmp/ndk-$USER/tmp/tests |
| |
| TMPC=/tmp/ndk-$USER/tmp/tests/test-$$.c |
| TMPO=/tmp/ndk-$USER/tmp/tests/test-$$.o |
| TMPE=/tmp/ndk-$USER/tmp/tests/test-$$$EXE |
| TMPL=/tmp/ndk-$USER/tmp/tests/test-$$.log |
| |
| # cleanup temporary files |
| clean_temp () |
| { |
| rm -f $TMPC $TMPO $TMPL $TMPE |
| } |
| |
| # cleanup temp files then exit with an error |
| clean_exit () |
| { |
| clean_temp |
| exit 1 |
| } |
| |
| # this function will setup the compiler and linker and check that they work as advertised |
| # note that you should call 'force_32bit_binaries' before this one if you want it to |
| # generate 32-bit binaries on 64-bit systems (that support it). |
| # |
| setup_toolchain () |
| { |
| if [ -z "$CC" ] ; then |
| CC=gcc |
| fi |
| if [ -z "$CXX" ] ; then |
| CXX=g++ |
| fi |
| if [ -z "$CXXFLAGS" ] ; then |
| CXXFLAGS="$CFLAGS" |
| fi |
| if [ -z "$LD" ] ; then |
| LD="$CC" |
| fi |
| |
| log2 "Using '$CC' as the C compiler" |
| |
| # check that we can compile a trivial C program with this compiler |
| mkdir -p $(dirname "$TMPC") |
| cat > $TMPC <<EOF |
| int main(void) {} |
| EOF |
| |
| if [ "$FORCE_32BIT" = yes ] ; then |
| CC="$CC -m32" |
| CXX="$CXX -m32" |
| LD="$LD -m32" |
| compile |
| if [ $? != 0 ] ; then |
| # sometimes, we need to also tell the assembler to generate 32-bit binaries |
| # this is highly dependent on your GCC installation (and no, we can't set |
| # this flag all the time) |
| CFLAGS="$CFLAGS -Wa,--32" |
| compile |
| fi |
| fi |
| |
| compile |
| if [ $? != 0 ] ; then |
| echo "your C compiler doesn't seem to work:" |
| cat $TMPL |
| clean_exit |
| fi |
| log "CC : compiler check ok ($CC)" |
| |
| # check that we can link the trivial program into an executable |
| link |
| if [ $? != 0 ] ; then |
| OLD_LD="$LD" |
| LD="$CC" |
| compile |
| link |
| if [ $? != 0 ] ; then |
| LD="$OLD_LD" |
| echo "your linker doesn't seem to work:" |
| cat $TMPL |
| clean_exit |
| fi |
| fi |
| log2 "Using '$LD' as the linker" |
| log "LD : linker check ok ($LD)" |
| |
| # check the C++ compiler |
| log2 "Using '$CXX' as the C++ compiler" |
| |
| cat > $TMPC <<EOF |
| #include <iostream> |
| using namespace std; |
| int main() |
| { |
| cout << "Hello World!" << endl; |
| return 0; |
| } |
| EOF |
| |
| compile_cpp |
| if [ $? != 0 ] ; then |
| echo "your C++ compiler doesn't seem to work" |
| cat $TMPL |
| clean_exit |
| fi |
| |
| log "CXX : C++ compiler check ok ($CXX)" |
| |
| # XXX: TODO perform AR checks |
| AR=ar |
| ARFLAGS= |
| } |
| |
| # try to compile the current source file in $TMPC into an object |
| # stores the error log into $TMPL |
| # |
| compile () |
| { |
| log2 "Object : $CC -o $TMPO -c $CFLAGS $TMPC" |
| $CC -o $TMPO -c $CFLAGS $TMPC 2> $TMPL |
| } |
| |
| compile_cpp () |
| { |
| log2 "Object : $CXX -o $TMPO -c $CXXFLAGS $TMPC" |
| $CXX -o $TMPO -c $CXXFLAGS $TMPC 2> $TMPL |
| } |
| |
| # try to link the recently built file into an executable. error log in $TMPL |
| # |
| link() |
| { |
| log2 "Link : $LD -o $TMPE $TMPO $LDFLAGS" |
| $LD -o $TMPE $TMPO $LDFLAGS 2> $TMPL |
| } |
| |
| # run a command |
| # |
| execute() |
| { |
| log2 "Running: $*" |
| $* |
| } |
| |
| # perform a simple compile / link / run of the source file in $TMPC |
| compile_exec_run() |
| { |
| log2 "RunExec : $CC -o $TMPE $CFLAGS $TMPC" |
| compile |
| if [ $? != 0 ] ; then |
| echo "Failure to compile test program" |
| cat $TMPC |
| cat $TMPL |
| clean_exit |
| fi |
| link |
| if [ $? != 0 ] ; then |
| echo "Failure to link test program" |
| cat $TMPC |
| echo "------" |
| cat $TMPL |
| clean_exit |
| fi |
| $TMPE |
| } |
| |
| pattern_match () |
| { |
| echo "$2" | grep -q -E -e "$1" |
| } |
| |
| # Let's check that we have a working md5sum here |
| check_md5sum () |
| { |
| A_MD5=`echo "A" | md5sum | cut -d' ' -f1` |
| if [ "$A_MD5" != "bf072e9119077b4e76437a93986787ef" ] ; then |
| echo "Please install md5sum on this machine" |
| exit 2 |
| fi |
| } |
| |
| # Find if a given shell program is available. |
| # We need to take care of the fact that the 'which <foo>' command |
| # may return either an empty string (Linux) or something like |
| # "no <foo> in ..." (Darwin). Also, we need to redirect stderr |
| # to /dev/null for Cygwin |
| # |
| # $1: variable name |
| # $2: program name |
| # |
| # Result: set $1 to the full path of the corresponding command |
| # or to the empty/undefined string if not available |
| # |
| find_program () |
| { |
| local PROG RET |
| PROG=`which $2 2>/dev/null` |
| RET=$? |
| if [ $RET != 0 ]; then |
| PROG= |
| fi |
| eval $1=\"$PROG\" |
| return $RET |
| } |
| |
| prepare_download () |
| { |
| find_program CMD_WGET wget |
| find_program CMD_CURL curl |
| find_program CMD_SCRP scp |
| } |
| |
| find_pbzip2 () |
| { |
| if [ -z "$_PBZIP2_initialized" ] ; then |
| find_program PBZIP2 pbzip2 |
| _PBZIP2_initialized="yes" |
| fi |
| } |
| |
| # Download a file with either 'curl', 'wget' or 'scp' |
| # |
| # $1: source URL (e.g. http://foo.com, ssh://blah, /some/path) |
| # $2: target file |
| download_file () |
| { |
| # Is this HTTP, HTTPS or FTP ? |
| if pattern_match "^(http|https|ftp):.*" "$1"; then |
| if [ -n "$CMD_WGET" ] ; then |
| run $CMD_WGET -O $2 $1 |
| elif [ -n "$CMD_CURL" ] ; then |
| run $CMD_CURL -o $2 $1 |
| else |
| echo "Please install wget or curl on this machine" |
| exit 1 |
| fi |
| return |
| fi |
| |
| # Is this SSH ? |
| # Accept both ssh://<path> or <machine>:<path> |
| # |
| if pattern_match "^(ssh|[^:]+):.*" "$1"; then |
| if [ -n "$CMD_SCP" ] ; then |
| scp_src=`echo $1 | sed -e s%ssh://%%g` |
| run $CMD_SCP $scp_src $2 |
| else |
| echo "Please install scp on this machine" |
| exit 1 |
| fi |
| return |
| fi |
| |
| # Is this a file copy ? |
| # Accept both file://<path> or /<path> |
| # |
| if pattern_match "^(file://|/).*" "$1"; then |
| cp_src=`echo $1 | sed -e s%^file://%%g` |
| run cp -f $cp_src $2 |
| return |
| fi |
| } |
| |
| |
| # Unpack a given archive |
| # |
| # $1: archive file path |
| # $2: optional target directory (current one if omitted) |
| # |
| unpack_archive () |
| { |
| local ARCHIVE="$1" |
| local DIR=${2-.} |
| local RESULT TARFLAGS ZIPFLAGS |
| mkdir -p "$DIR" |
| if [ "$VERBOSE2" = "yes" ] ; then |
| TARFLAGS="vxpf" |
| ZIPFLAGS="" |
| else |
| TARFLAGS="xpf" |
| ZIPFLAGS="q" |
| fi |
| case "$ARCHIVE" in |
| *.zip) |
| (cd $DIR && run unzip $ZIPFLAGS "$ARCHIVE") |
| ;; |
| *.tar) |
| run tar $TARFLAGS "$ARCHIVE" -C $DIR |
| ;; |
| *.tar.gz) |
| run tar z$TARFLAGS "$ARCHIVE" -C $DIR |
| ;; |
| *.tar.bz2) |
| find_pbzip2 |
| if [ -n "$PBZIP2" ] ; then |
| run tar --use-compress-prog=pbzip2 -$TARFLAGS "$ARCHIVE" -C $DIR |
| else |
| run tar j$TARFLAGS "$ARCHIVE" -C $DIR |
| fi |
| # remove ._* files by MacOSX to preserve resource forks we don't need |
| find $DIR -name "\._*" -exec rm {} \; |
| ;; |
| *) |
| panic "Cannot unpack archive with unknown extension: $ARCHIVE" |
| ;; |
| esac |
| } |
| |
| # Pack a given archive |
| # |
| # $1: archive file path (including extension) |
| # $2: source directory for archive content |
| # $3+: list of files (including patterns), all if empty |
| pack_archive () |
| { |
| local ARCHIVE="$1" |
| local SRCDIR="$2" |
| local SRCFILES |
| local TARFLAGS ZIPFLAGS |
| shift; shift; |
| if [ -z "$1" ] ; then |
| SRCFILES="*" |
| else |
| SRCFILES="$@" |
| fi |
| if [ "`basename $ARCHIVE`" = "$ARCHIVE" ] ; then |
| ARCHIVE="`pwd`/$ARCHIVE" |
| fi |
| mkdir -p `dirname $ARCHIVE` |
| if [ "$VERBOSE2" = "yes" ] ; then |
| TARFLAGS="vcf" |
| ZIPFLAGS="-9r" |
| else |
| TARFLAGS="cf" |
| ZIPFLAGS="-9qr" |
| fi |
| case "$ARCHIVE" in |
| *.zip) |
| (cd $SRCDIR && run zip $ZIPFLAGS "$ARCHIVE" $SRCFILES) |
| ;; |
| *.tar) |
| (cd $SRCDIR && run tar $TARFLAGS "$ARCHIVE" $SRCFILES) |
| ;; |
| *.tar.gz) |
| (cd $SRCDIR && run tar z$TARFLAGS "$ARCHIVE" $SRCFILES) |
| ;; |
| *.tar.bz2) |
| find_pbzip2 |
| if [ -n "$PBZIP2" ] ; then |
| (cd $SRCDIR && run tar --use-compress-prog=pbzip2 -$TARFLAGS "$ARCHIVE" $SRCFILES) |
| else |
| (cd $SRCDIR && run tar j$TARFLAGS "$ARCHIVE" $SRCFILES) |
| fi |
| ;; |
| *) |
| panic "Unsupported archive format: $ARCHIVE" |
| ;; |
| esac |
| } |
| |
| # Copy a directory, create target location if needed |
| # |
| # $1: source directory |
| # $2: target directory location |
| # |
| copy_directory () |
| { |
| local SRCDIR="$1" |
| local DSTDIR="$2" |
| if [ ! -d "$SRCDIR" ] ; then |
| panic "Can't copy from non-directory: $SRCDIR" |
| fi |
| log "Copying directory: " |
| log " from $SRCDIR" |
| log " to $DSTDIR" |
| mkdir -p "$DSTDIR" && (cd "$SRCDIR" && 2>/dev/null tar cf - *) | (tar xf - -C "$DSTDIR") |
| fail_panic "Cannot copy to directory: $DSTDIR" |
| } |
| |
| # This is the same than copy_directory(), but symlinks will be replaced |
| # by the file they actually point to instead. |
| copy_directory_nolinks () |
| { |
| local SRCDIR="$1" |
| local DSTDIR="$2" |
| if [ ! -d "$SRCDIR" ] ; then |
| panic "Can't copy from non-directory: $SRCDIR" |
| fi |
| log "Copying directory (without symlinks): " |
| log " from $SRCDIR" |
| log " to $DSTDIR" |
| mkdir -p "$DSTDIR" && (cd "$SRCDIR" && tar chf - *) | (tar xf - -C "$DSTDIR") |
| fail_panic "Cannot copy to directory: $DSTDIR" |
| } |
| |
| # Copy certain files from one directory to another one |
| # $1: source directory |
| # $2: target directory |
| # $3+: file list (including patterns) |
| copy_file_list () |
| { |
| local SRCDIR="$1" |
| local DSTDIR="$2" |
| shift; shift; |
| if [ ! -d "$SRCDIR" ] ; then |
| panic "Cant' copy from non-directory: $SRCDIR" |
| fi |
| log "Copying file: $@" |
| log " from $SRCDIR" |
| log " to $DSTDIR" |
| mkdir -p "$DSTDIR" && (cd "$SRCDIR" && tar cf - "$@") | (tar xf - -C "$DSTDIR") |
| fail_panic "Cannot copy files to directory: $DSTDIR" |
| } |
| |
| # Rotate a log file |
| # If the given log file exist, add a -1 to the end of the file. |
| # If older log files exist, rename them to -<n+1> |
| # $1: log file |
| # $2: maximum version to retain [optional] |
| rotate_log () |
| { |
| # Default Maximum versions to retain |
| local MAXVER="5" |
| local LOGFILE="$1" |
| shift; |
| if [ ! -z "$1" ] ; then |
| local tmpmax="$1" |
| shift; |
| tmpmax=`expr $tmpmax + 0` |
| if [ $tmpmax -lt 1 ] ; then |
| panic "Invalid maximum log file versions '$tmpmax' invalid; defaulting to $MAXVER" |
| else |
| MAXVER=$tmpmax; |
| fi |
| fi |
| |
| # Do Nothing if the log file does not exist |
| if [ ! -f "${LOGFILE}" ] ; then |
| return |
| fi |
| |
| # Rename existing older versions |
| ver=$MAXVER |
| while [ $ver -ge 1 ] |
| do |
| local prev=$(( $ver - 1 )) |
| local old="-$prev" |
| |
| # Instead of old version 0; use the original filename |
| if [ $ver -eq 1 ] ; then |
| old="" |
| fi |
| |
| if [ -f "${LOGFILE}${old}" ] ; then |
| mv -f "${LOGFILE}${old}" "${LOGFILE}-${ver}" |
| fi |
| |
| ver=$prev |
| done |
| } |