#!/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 symlink_dirs_file_globs="$8" local dest_path=`build_path "$dest_dir" "$dir" $dotted` $DEBUG "show_dir $1 $2 $3 $4 $5 $6 $7 $8" $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" "$symlink_dirs_file_globs" done popdir } sigil_for() { local file=$1 local symlink_dirs_file_globs=$2 local copy_always=0 local symlink_dirs=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 [ -n "$symlink_dirs_file_globs" ]; then symlink_dirs=1 fi if [ $copy_always -eq 1 ]; then echo 'X' elif [ $symlink_dirs -eq 1 ]; then echo '$' else echo '@' fi } show_file() { local file="$1" local dest_dir="$2" local dotfiles_dir="$3" local dotfiles_subdir="$4" local dotted=$5 local symlink_dirs_file_globs="$6" 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" "$symlink_dirs_file_globs"` 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" local symlink_dirs_file_globs="$8" $DEBUG "handle_file $1 $2 $3 $4 $5 $6 $7 $8" 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" ] && is_excluded $file "$symlink_dirs_file_globs"; then show_file "$file" "$dest_dir" "$dotfiles_dir" "$dotfiles_subdir" $dotted "$symlink_dirs_file_globs" elif [ -d "$file" ]; then show_dir "$file" "$dest_dir" "$dotfiles_dir" "$dotfiles_subdir" $dotted "$exclude_file_globs" "$include_file_globs" "$symlink_dirs_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 } show_help() { local exit_code=${1:-0} $PRINT "Usage: lsrc [-FVqvh] [-I EXCL_PAT] [-x EXCL_PAT] [-N EXCL_PAT ] [-t TAG] [-d DOT_DIR]" $PRINT "see lsrc(1) and rcm(5) for more details" exit $exit_code } handle_command_line() { local arg_tags= local verbosity=0 local version=0 local show_sigils=0 local dotfiles_dirs= local excludes= local includes= local symlink_dirs= while getopts FVqvhI:x:S:t:d: opt; do case "$opt" in F) show_sigils=1;; h) show_help ;; 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";; S) symlink_dirs="$symlink_dirs $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} SYMLINK_DIRS=${symlink_dirs:-$SYMLINK_DIRS} FILES=$@ $DEBUG "TAGS: $TAGS" $DEBUG "DOTFILES_DIRS: $DOTFILES_DIRS" } DEST_STACK= handle_command_line $* : ${DOTFILES_DIRS:=$DOTFILES_DIRS $DEFAULT_DOTFILES_DIR} $DEBUG "DOTFILES_DIRS: $DOTFILES_DIRS" : ${COPY_ALWAYS:=""} $DEBUG "COPY_ALWAYS: $COPY_ALWAYS" : ${SYMLINK_DIRS:=""} $DEBUG "SYMLINK_DIRS: $SYMLINK_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"` symlink_dirs_file_globs=`dotfiles_dir_excludes $DOTFILES_DIR "$SYMLINK_DIRS"` $DEBUG "symlink_dirs_file_globs: $symlink_dirs_file_globs" 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" "$symlink_dirs_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