#!/bin/sh : ${RCM_LIB:=`dirname $0`/../share/rcm} . $RCM_LIB/rcm.sh pushdir() { DIR_STACK="$DIR_STACK:$PWD/$1" $DEBUG "cd'ing to $1 from `pwd` with stack $DIR_STACK" cd $1 } popdir() { current=`echo $DIR_STACK | sed -e 's/.*://g'` prior=`echo $DIR_STACK | sed -e "s|:$current$||" | sed -e 's/.*://g'` DIR_STACK=`echo $DIR_STACK | sed -e 's/:[^:]*$//'` $DEBUG "cd'ing to $prior from `pwd` with stack $DIR_STACK" cd $prior } build_path() { local dest=$1 local file=$2 local dotted=$3 if [ $dotted -eq 1 ]; then echo $dest/$file else echo $dest/.$file fi } file_join() { local result= for file; do if [ "x$file" != "x." ]; then if [ "x$result" = "x" ]; then result=$file else result="$result/$file" fi fi done echo $result } show_dir() { local dir=$1 local dest_dir=$2 local dotfiles_dir=$3 local dotfiles_subdir=$4 local dotted=$5 local exclude_file_globs="$6" local include_file_globs="$7" local dest_path=`build_path $dest_dir $dir $dotted` $DEBUG "show_dir $1 $2 $3 $4 $5 $6 $7" $VERBOSE "recurring on $dest_path" pushdir $dir for f in *; do $DEBUG "handling the file $f" next_dir=`file_join $dotfiles_subdir $dir` handle_file $f $dest_path $dotfiles_dir $next_dir 1 "$exclude_file_globs" "$include_file_globs" done popdir } sigil_for() { local file=$1 local copy_always=0 for copy_file in $COPY_ALWAYS; do $DEBUG "copy_file: $copy_file" $DEBUG "file: $file" case $file in $copy_file) copy_always=1 break ;; esac done if [ $copy_always -eq 1 ]; then echo 'X' else echo '@' fi } show_file() { local file=$1 local dest_dir=$2 local dotfiles_dir=$3 local dotfiles_subdir=$4 local dotted=$5 local dest_file=`build_path $dest_dir $file $dotted` if echo $DEST_STACK | grep -vq ":$dest_file"; then DEST_STACK="$DEST_STACK:$dest_file" src_file=`file_join $dotfiles_subdir $file` abs_src_file=`file_join $dotfiles_dir $src_file` output=$dest_file:$abs_src_file if [ $SHOW_SIGILS -eq 1 ]; then sigil=`sigil_for $src_file` output="$output:$sigil" fi $PRINT $output fi } handle_file() { local file=$1 local dest_dir=$2 local dotfiles_dir=$3 local dotfiles_subdir=$4 local dotted=$5 local exclude_file_globs="$6" local include_file_globs="$7" $DEBUG "handle_file $1 $2 $3 $4 $5 $6 $7" if [ ! -e $file ]; then $VERBOSE "skipping non-existent file $file" elif is_excluded $file "$exclude_file_globs" "$include_file_globs"; then $VERBOSE "skipping excluded file $file" elif [ -d $file ]; then show_dir $file $dest_dir $dotfiles_dir $dotfiles_subdir $dotted "$exclude_file_globs" "$include_file_globs" else show_file $file $dest_dir $dotfiles_dir $dotfiles_subdir $dotted fi } is_metafile() { host_portion=`echo $1 | sed -e 's/host-.*/host-/'` tag_portion=`echo $1 | sed -e 's/tag-.*/tag-/'` [ x$host_portion = 'xhost-' -o x$tag_portion = 'xtag-' -o "x$1" = "xhooks" ] } dotfiles_dir_excludes() { local dotfiles_dir=$1 local excludes="$2" $DEBUG "dotfiles_dir_excludes $dotfiles_dir" $DEBUG " with excludes: $excludes" for exclude in $excludes; do if echo $exclude | grep -q :; then dotfiles_dir_pat=`echo $exclude | sed 's/:.*//'` file_glob=`echo $exclude | sed 's/.*://'` if [ "x$dotfiles_dir_pat" != "x*" ] && is_relative $dotfiles_dir_pat; then dotfiles_dir_pat=$PWD/$dotfiles_dir_pat fi if [ "x$dotfiles_dir_pat" = "x*" -o "x$dotfiles_dir_pat" = "x$dotfiles_dir" ]; then echo $file_glob fi else echo $exclude fi done } is_excluded() { local file=$1 local exclude_file_globs="$2" local include_file_globs="$3" $DEBUG "is_excluded $file $exclude_file_globs $include_file_globs" for exclude_file_glob in $exclude_file_globs; do $DEBUG "file: $file" $DEBUG "exclude_file_glob: $exclude_file_glob" case $file in $exclude_file_glob) for include_file_glob in $include_file_globs; do case $file in $include_file_glob) return 1;; esac done return 0 ;; esac done return 1 } handle_command_line() { local arg_tags= local verbosity=0 local version=0 local show_sigils=0 local dotfiles_dirs= local excludes= local includes= while getopts FVqvI:x:t:d: opt; do case "$opt" in F) show_sigils=1;; I) includes="$includes $OPTARG";; t) arg_tags="$arg_tags $OPTARG";; v) verbosity=$(($verbosity + 1));; q) verbosity=$(($verbosity - 1));; d) dotfiles_dirs="$dotfiles_dirs $OPTARG";; V) version=1;; x) excludes="$excludes $OPTARG";; esac done shift $(($OPTIND-1)) handle_common_flags lsrc $version $verbosity SHOW_SIGILS=$show_sigils TAGS=${arg_tags:-$TAGS} DOTFILES_DIRS=${dotfiles_dirs:-$DOTFILES_DIRS} EXCLUDES=${excludes:-$EXCLUDES} INCLUDES=${includes:-$INCLUDES} FILES=$@ $DEBUG "TAGS: $TAGS" $DEBUG "DOTFILES_DIRS: $DOTFILES_DIRS" } DEST_STACK= if [ -e $HOME/.rcrc ]; then . $HOME/.rcrc fi handle_command_line $* : ${DOTFILES_DIRS:=$DOTFILES_DIRS $DEFAULT_DOTFILES_DIR} $DEBUG "DOTFILES_DIRS: $DOTFILES_DIRS" : ${COPY_ALWAYS:=""} $DEBUG "COPY_ALWAYS: $COPY_ALWAYS" for DOTFILES_DIR in $DOTFILES_DIRS; do if is_relative $DOTFILES_DIR; then DOTFILES_DIR=$PWD/$DOTFILES_DIR fi if [ ! -d $DOTFILES_DIR ]; then $VERBOSE "skipping non-existent directory: $DOTFILES_DIR" continue fi exclude_file_globs=`dotfiles_dir_excludes $DOTFILES_DIR "$EXCLUDES"` $DEBUG "exclude_file_globs: $exclude_file_globs" include_file_globs=`dotfiles_dir_excludes $DOTFILES_DIR "$INCLUDES"` cd $DOTFILES_DIR DIR_STACK=":$DOTFILES_DIR" for file in ${FILES:-*}; do if is_metafile $file; then continue fi handle_file $file $DEST_DIR $DOTFILES_DIR . 0 "$exclude_file_globs" "$include_file_globs" done cd $DOTFILES_DIR host_files=$DOTFILES_DIR/host-$HOSTNAME if [ -d $host_files ]; then pushdir `basename $host_files` for file in ${FILES:-*}; do handle_file $file $DEST_DIR $host_files . 0 "$exclude_file_globs" "$include_file_globs" done popdir fi cd $DOTFILES_DIR for tag in $TAGS; do if [ -d tag-$tag ]; then pushdir `basename tag-$tag` for file in ${FILES:-*}; do $DEBUG "TAG: $tag, exclude_file_globs: $exclude_file_globs" handle_file $file $DEST_DIR $DOTFILES_DIR/tag-$tag . 0 "$exclude_file_globs" "$include_file_globs" done popdir fi done done