From 3700be9ce6802653df30c413179d93316bf0b291 Mon Sep 17 00:00:00 2001 From: Pablo Olmos de Aguilera Corradini and Mike Burns Date: Sun, 27 Oct 2013 17:16:30 -0300 Subject: Force some directories to be symlinks Typically a directory structure is copied instead of symlinked, while files are symlinked. However, some cases require symlinked dirs: git submodules, vim plugins, and so on. This introduces a `SYMLINK_DIRS` option for rcrc(5) that takes a space-separated list of "exclude patterns". Any directory matching these patterns is symlinked. This also introduces a `-S` argument for lsrc(1), rcup(1), and rcdn(1). This argument takes a pattern, for one-off directory symlinking. It can be repeated. This also introduces `-S` and `-s` for mkrc(1). `-S` will re-install the files as symlinks, and `-s` will not. This does work with `-C`, though perhaps unintuitively - we don't know what the user means in this case. However, it will not crash. Bug: `-s` does not work right if `SYMLINK_DIRS` is set. Bug #36 addresses this. --- bin/lsrc | 30 ++++++++++++++++++++++-------- bin/mkrc | 14 ++++++++++++-- bin/rcdn | 7 ++++++- bin/rcup | 7 ++++++- man/lsrc.1 | 8 +++++++- man/mkrc.1 | 11 +++++++++++ man/rcdn.1 | 5 +++++ man/rcrc.5 | 9 +++++++++ man/rcup.1 | 5 +++++ share/rcm.sh.in | 8 +++++++- 10 files changed, 90 insertions(+), 14 deletions(-) diff --git a/bin/lsrc b/bin/lsrc index 3496a17..d8a36b5 100755 --- a/bin/lsrc +++ b/bin/lsrc @@ -53,16 +53,18 @@ show_dir() { 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" + $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" + handle_file $f $dest_path $dotfiles_dir $next_dir 1 "$exclude_file_globs" "$include_file_globs" "$symlink_dirs_file_globs" done popdir } @@ -96,6 +98,7 @@ show_file() { 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 @@ -122,15 +125,18 @@ handle_file() { 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" + $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" + 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 @@ -198,7 +204,7 @@ is_excluded() { show_help() { local exit_code=${1:-0} - $PRINT "Usage: lsrc [-FVqvh] [-I EXCL_PAT] [-x EXCL_PAT] [-t TAG] [-d DOT_DIR]" + $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 @@ -212,8 +218,9 @@ handle_command_line() { local dotfiles_dirs= local excludes= local includes= + local symlink_dirs= - while getopts FVqvhI:x:t:d: opt; do + while getopts FVqvhI:x:S:t:d: opt; do case "$opt" in F) show_sigils=1;; h) show_help ;; @@ -224,6 +231,7 @@ handle_command_line() { d) dotfiles_dirs="$dotfiles_dirs $OPTARG";; V) version=1;; x) excludes="$excludes $OPTARG";; + S) symlink_dirs="$symlink_dirs $OPTARG";; esac done shift $(($OPTIND-1)) @@ -234,6 +242,7 @@ handle_command_line() { DOTFILES_DIRS=${dotfiles_dirs:-$DOTFILES_DIRS} EXCLUDES=${excludes:-$EXCLUDES} INCLUDES=${includes:-$INCLUDES} + SYMLINK_DIRS=${symlink_dirs:-$SYMLINK_DIRS} FILES=$@ $DEBUG "TAGS: $TAGS" @@ -250,19 +259,24 @@ $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" + $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" @@ -272,7 +286,7 @@ for DOTFILES_DIR in $DOTFILES_DIRS; do continue fi - handle_file $file $DEST_DIR $DOTFILES_DIR . 0 "$exclude_file_globs" "$include_file_globs" + handle_file $file $DEST_DIR $DOTFILES_DIR . 0 "$exclude_file_globs" "$include_file_globs" "$symlink_dirs_file_globs" done cd $DOTFILES_DIR diff --git a/bin/mkrc b/bin/mkrc index c78d10b..f44cadb 100755 --- a/bin/mkrc +++ b/bin/mkrc @@ -40,8 +40,9 @@ verbosity=0 in_host=0 version=0 always_copy=0 +force_symlink=0 -while getopts ChVvqot:d: opt; do +while getopts ChSsVvqot:d: opt; do case "$opt" in C) always_copy=1 ;; h) show_help ;; @@ -51,6 +52,8 @@ while getopts ChVvqot:d: opt; do o) in_host=1 ;; d) DOTFILES_DIR=$OPTARG ;; V) version=1 ;; + S) force_symlink=1 ;; + s) force_symlink=0 ;; esac done shift $(($OPTIND-1)) @@ -67,8 +70,15 @@ fi files=$@ +if [ $force_symlink -eq 1 ]; then + for file in $files; do + dedotted=`de_dot $file` + INSTALL="$INSTALL -S $dedotted" + done +fi + for file in $files; do - dotless=`echo $file | sed -e "s|$DEST_DIR/||" | sed -e 's/^\.//'` + dotless=`de_dot $file` dest=`destination $DOTFILES_DIR $dotless $in_host $tag` mkdir -p $dest/`dirname $dotless` $PRINT "Moving..." diff --git a/bin/rcdn b/bin/rcdn index ebd5dea..064a541 100755 --- a/bin/rcdn +++ b/bin/rcdn @@ -36,14 +36,16 @@ handle_command_line() { local files= local excludes= local includes= + local symlink_dirs= - while getopts VqvhI:x:t:d: opt; do + while getopts VqvhI:x:S:t:d: opt; do case "$opt" in h) show_help ;; I) includes="$includes $OPTARG";; k) run_hooks=1 ;; K) run_hooks=0 ;; t) arg_tags="$arg_tags $OPTARG" ;; + S) symlink_dirs="$symlink_dirs $OPTARG";; v) verbosity=$(($verbosity + 1));; q) verbosity=$(($verbosity - 1));; d) dotfiles_dirs="$dotfiles_dirs $OPTARG" ;; @@ -72,6 +74,9 @@ handle_command_line() { for include in $includes; do LS_ARGS="$LS_ARGS -I $include" done + for symlink_dir in $symlink_dirs; do + LS_ARGS="$LS_ARGS -S $symlink_dir" + done LS_ARGS="$LS_ARGS $files" $DEBUG "LS_ARGS: $LS_ARGS" diff --git a/bin/rcup b/bin/rcup index f5c9459..5ba4822 100755 --- a/bin/rcup +++ b/bin/rcup @@ -104,9 +104,10 @@ handle_command_line() { local excludes= local includes= local always_copy=0 + local symlink_dirs= REPLACE_ALL=0 - while getopts CVqvfhikKI:x:t:d: opt; do + while getopts CVqvfhikKI:x:S:t:d: opt; do case "$opt" in C) always_copy=1 ;; d) dotfiles_dirs="$dotfiles_dirs $OPTARG" ;; @@ -118,6 +119,7 @@ handle_command_line() { K) run_hooks=0 ;; q) verbosity=$(($verbosity - 1)) ;; t) arg_tags="$arg_tags $OPTARG" ;; + S) symlink_dirs="$symlink_dirs $OPTARG";; v) verbosity=$(($verbosity + 1)) ;; V) version=1 ;; x) excludes="$excludes $OPTARG" ;; @@ -148,6 +150,9 @@ handle_command_line() { for include in $includes; do LS_ARGS="$LS_ARGS -I $include" done + for symlink_dir in $symlink_dirs; do + LS_ARGS="$LS_ARGS -S $symlink_dir" + done LS_ARGS="$LS_ARGS $files" $DEBUG "LS_ARGS: $LS_ARGS" diff --git a/man/lsrc.1 b/man/lsrc.1 index 6070428..984a378 100644 --- a/man/lsrc.1 +++ b/man/lsrc.1 @@ -1,4 +1,4 @@ -.Dd July 28, 2013 +.Dd February 7, 2014 .Dt LSRC 1 .Os .Sh NAME @@ -11,6 +11,7 @@ .Op Fl I Ar excl_pat .Op Fl t Ar tag .Op Fl x Ar excl_pat +.Op Fl N Ar excl_pat .Op files ... .Sh DESCRIPTION This program lists all configuration files, both the sources in the @@ -50,6 +51,11 @@ more details are in the .Sx EXCLUDE PATTERN section. . +.It Fl S Ar excl_pat +symlink the directory that match the given pattern. See +.Sx EXCLUDE PATTERN +for more details. This option can be repeated. +. .It Fl t Ar TAG list dotfiles according to TAG . diff --git a/man/mkrc.1 b/man/mkrc.1 index 384b485..adc4089 100644 --- a/man/mkrc.1 +++ b/man/mkrc.1 @@ -28,6 +28,16 @@ multiple times. install dotfiles into the host-specific directory .It Fl q decrease verbosity +.It Fl s +if the rc file is a file, symlink it; otherwise, make a directory +structure as described in +.Xr rcup 1 +in the section +.Sx ALGORITHM . +This is the default. +.It Fl S +treat the specified rc files as files to be symlinked, even if they are +directories .It Fl t Ar TAG install dotfiles according to tag .It Fl v @@ -47,6 +57,7 @@ User configuration file. Defaults to .Dl mkrc -t zsh -d company-dotfiles ~/.zshrc ~/.zlogin .Dl mkrc -o ~/.rcrc .Dl mkrc -C .ssh +.Dl mkrc -S .zpretzo .Sh SEE ALSO .Xr lsrc 1 , .Xr rcdn 1 , diff --git a/man/rcdn.1 b/man/rcdn.1 index 43780ca..a276b76 100644 --- a/man/rcdn.1 +++ b/man/rcdn.1 @@ -64,6 +64,11 @@ run pre- and post-hooks. This is the default. skip pre- and post-hooks .It Fl q decrease verbosity +.It Fl S Ar EXCL_PAT +when removing dotfiles, any file that matches +.Ar EXCL_PAT +should be treated as a file that was symlinked, even if it is a +directory. This can be repeated. .It Fl t Ar TAG remove dotfiles according to .Ar TAG diff --git a/man/rcrc.5 b/man/rcrc.5 index ec6ef9a..ca6e22e 100644 --- a/man/rcrc.5 +++ b/man/rcrc.5 @@ -46,6 +46,14 @@ under the section . .It Va TAGS the default tags. +. +.It Va SYMLINK_DIRS +a space-separated list of patterns. Directories matching a pattern are +symlinked instead of descended. Patterns are explained in detail in +.Xr lsrc 1 +under the section +.Sx EXCLUDE PATTERN . +. .El .Sh FILES .Pa ~/.rcrc @@ -55,6 +63,7 @@ the default tags. .Dl DOTFILES_DIRS="/home/mike/.dotfiles /usr/share/dotfiles" .Dl EXCLUDES="irbrc *:*emacs* dotfiles:python*" .Dl TAGS="freebsd development email git laptop gmail notmuch" +.Dl SYMLINK_DIRS="zprezto" .Sh SEE ALSO .Xr lsrc 1 , .Xr mkrc 1 , diff --git a/man/rcup.1 b/man/rcup.1 index 3304436..41e25fd 100644 --- a/man/rcup.1 +++ b/man/rcup.1 @@ -56,6 +56,11 @@ run pre- and post-hooks (see for more details on hooks). This is the default. .It Fl K skip pre- and post-hooks +.It Fl S Ar EXCL_PAT +any rc file that matches +.Ar EXCL_PAT +is installed as if it were a file (using a symlink) instead of as if it +were a directory (by making a directory). This option can be repeated. .It Fl t Ar TAG install dotfiles according to .Ar TAG diff --git a/share/rcm.sh.in b/share/rcm.sh.in index c9a98b3..f4ee212 100644 --- a/share/rcm.sh.in +++ b/share/rcm.sh.in @@ -10,7 +10,7 @@ ERROR=echo_error VERBOSE=: MKDIR=mkdir LN="ln -s" -CP=cp +CP="cp -R" RM=rm DEFAULT_DOTFILES_DIR=$HOME/.dotfiles MV=mv @@ -117,6 +117,12 @@ run_hooks() { fi } +de_dot() { + $DEBUG "de_dot $1" + $DEBUG " with DEST_DIR: $DEST_DIR" + echo $1 | sed -e "s|$DEST_DIR/||" | sed -e 's/^\.//' +} + : ${RCRC:=$HOME/.rcrc} if [ -r "$RCRC" ]; then -- cgit v1.2.3