#!/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 } link_dir() { local dir=$1 local dest_dir=$2 local dotfiles_dir=$3 local dotted=$4 local exclude_file_globs="$5" local include_file_globs="$6" local dest_path=`build_path $dest_dir $dir $dotted` $DEBUG "link_dir $1 $2 $3 $4 $5 $6" $VERBOSE "recurring on $dest_path" pushdir $dir for f in *; do $DEBUG "handling the file $f" handle_file $f $dest_path $dotfiles_dir/$dir 1 "$exclude_file_globs" "$include_file_globs" done popdir } link_file() { local file=$1 local dest_dir=$2 local dotfiles_dir=$3 local dotted=$4 local dest_file=`build_path $dest_dir $file $dotted` if echo $DEST_STACK | grep -vq ":$dest_file"; then DEST_STACK="$DEST_STACK:$dest_file" $PRINT $dest_file:$dotfiles_dir/$file fi } handle_file() { local file=$1 local dest_dir=$2 local dotfiles_dir=$3 local dotted=$4 local exclude_file_globs="$5" local include_file_globs="$6" $DEBUG "handle_file $1 $2 $3 $4 $5 $6" 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 link_dir $file $dest_dir $dotfiles_dir $dotted "$exclude_file_globs" "$include_file_globs" else link_file $file $dest_dir $dotfiles_dir $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-' ] } 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 dotfiles_dirs= local excludes= local includes= while getopts VqvI:x:t:d: opt; do case "$opt" in 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 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" 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