From 30e09856846e482d1bc805645956d2cfe202e0cc Mon Sep 17 00:00:00 2001 From: Mike Burns Date: Wed, 10 Jul 2013 23:50:11 +0200 Subject: Add lsrc The `lsrc` command works just like the `rcup` command but instead of making symlinks and directories, it just lists all the files that would be symlinks. It prints the destination (e.g. `~/.foo`) and the source (`~/.dotfiles/foo`), separated by a colon. Re-write `rcup` in terms of `lsrc`. --- Makefile | 2 + README.md | 4 +- bin/lsrc | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++ bin/rcup | 206 ++++++++++++++++++-------------------------------------- man/man1/lsrc.1 | 50 ++++++++++++++ man/man1/mkrc.1 | 2 +- man/man1/rcup.1 | 2 +- man/man5/rcrc.5 | 2 +- 8 files changed, 309 insertions(+), 145 deletions(-) create mode 100755 bin/lsrc create mode 100644 man/man1/lsrc.1 diff --git a/Makefile b/Makefile index f4c2b5c..5a05334 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,10 @@ install: install -dm 0755 $(PREFIX)/libexec/rcm install -m 0755 bin/mkrc $(PREFIX)/bin install -m 0755 bin/rcup $(PREFIX)/bin + install -m 0755 bin/lsrc $(PREFIX)/bin install -m 0644 man/man1/rcup.1 $(PREFIX)/share/man/man1 install -m 0644 man/man1/mkrc.1 $(PREFIX)/share/man/man1 + install -m 0644 man/man1/lsrc.1 $(PREFIX)/share/man/man1 install -m 0644 man/man5/rcrc.5 $(PREFIX)/share/man/man5 install -m 0644 libexec/rcm/rcm.sh $(PREFIX)/libexec/rcm diff --git a/README.md b/README.md index 5d5e61b..f75f57b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This is a management suite for dotfiles. It assumes that you have a separate dotfiles directory, or are interested in creating one. -The programs provided are `rcup` and `mkrc`. +The programs provided are `rcup`, `mkrc`, and `lsrc`. Installation ------------ @@ -27,6 +27,8 @@ Programs directories. * `mkrc` is for introducing a dotfile into your dotfiles directory, with support for tags and multiple source directories. +* `lsrc` shows you all your dotfiles and where they would be symlinked + to. It is used by `rcup` but is provided for your own use, too. Support ------- diff --git a/bin/lsrc b/bin/lsrc new file mode 100755 index 0000000..2a1a9e0 --- /dev/null +++ b/bin/lsrc @@ -0,0 +1,186 @@ +#!/bin/sh + +#set -x + +DEST_DIR=$HOME +DEFAULT_DOTFILES_DIR=$HOME/.dotfiles +HOSTNAME=`hostname -s` +DEBUG=: +PRINT=echo +VERBOSE=: + +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 dest_path=`build_path $dest_dir $dir $dotted` + + $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 + 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` + + $PRINT $dest_file:$dotfiles_dir/$file +} + +handle_file() { + local file=$1 + local dest_dir=$2 + local dotfiles_dir=$3 + local dotted=$4 + + $DEBUG handle_file $1 $2 $3 $4 + + if [ ! -e $file ]; then + $VERBOSE "skipping non-existent file $file" + elif [ -d $file ]; then + link_dir $file $dest_dir $dotfiles_dir $dotted + else + dest_file=`build_path $dest_dir $file $dotted` + link_file $file $dest_dir $dotfiles_dir $dotted + fi +} + +metafile() { + [ x$2 = 'xhost-' -o x$3 = 'xtag-' -o x$1 = "xRakefile" -o x$1 = "xinstall" ] +} + +handle_command_line() { + arg_tags="" + verbosity=0 + version=0 + dotfiles_dirs= + while getopts Vqvt:d: opt; do + case "$opt" in + t) arg_tags="$arg_tags $OPTARG";; + v) verbosity=$(($verbosity + 1));; + q) verbosity=$(($verbosity - 1));; + d) dotfiles_dirs="$dotfiles_dirs $OPTARG";; + V) version=1 + esac + done + shift $(($OPTIND-1)) + + if [ $version -eq 1 ]; then + version rcup + exit 0 + elif [ $verbosity -ge 2 ]; then + DEBUG=echo + VERBOSE=echo + PRINT=echo + elif [ $verbosity -eq 1 ]; then + DEBUG=: + VERBOSE=echo + PRINT=echo + elif [ $verbosity -eq 0 ]; then + DEBUG=: + VERBOSE=: + PRINT=echo + else + DEBUG=: + VERBOSE=: + PRINT=: + fi + + if [ "x$arg_tags" != "x" ]; then + TAGS=$arg_tags + fi + + if [ "x$dotfiles_dirs" != "x" ]; then + DOTFILES_DIRS=$dotfiles_dirs + fi + + FILES=$@ +} + +if [ -e $HOME/.rcrc ]; then + . $HOME/.rcrc +fi + +. `dirname $0`/../libexec/rcm/rcm.sh +handle_command_line $* + +if [ "x$DOTFILES_DIRS" = "x" ]; then + DOTFILES_DIRS="$DOTFILES_DIRS $DEFAULT_DOTFILES_DIR" +fi + +for DOTFILES_DIR in $DOTFILES_DIRS; do + + if [ ! -d $DOTFILES_DIR ]; then + $VERBOSE "skipping non-existent directory: $DOTFILES_DIR" + continue + fi + + cd $DOTFILES_DIR + DIR_STACK=":$DOTFILES_DIR" + + for file in ${FILES:-*}; do + host_portion=`echo $file | sed -e 's/host-.*/host-/'` + tag_portion=`echo $file | sed -e 's/tag-.*/tag-/'` + if ! metafile $file $host_portion $tag_portion; then + handle_file $file $DEST_DIR $DOTFILES_DIR 0 + fi + 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 + 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 + handle_file $file $DEST_DIR $DOTFILES_DIR/tag-$tag 0 + done + popdir + fi + done + +done diff --git a/bin/rcup b/bin/rcup index 64626b3..22f699d 100755 --- a/bin/rcup +++ b/bin/rcup @@ -5,144 +5,103 @@ REPLACE_ALL=0 DEST_DIR=$HOME -DEFAULT_DOTFILES_DIR=$HOME/.dotfiles -HOSTNAME=`hostname -s` DEBUG=: PRINT=echo +PROMPT=echo_n VERBOSE=: -PROMPT=echo MKDIR=mkdir LN=ln RM=rm -pushdir() { - DIR_STACK="$DIR_STACK:$PWD/$1" - $DEBUG "cd'ing to $1 from `pwd` with stack $DIR_STACK" - cd $1 +echo_n() { + printf "%s " "$*" } -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 +link_file() { + local src=$1 + local dest=$2 - if [ $dotted -eq 1 ]; then - echo $dest/$file - else - echo $dest/.$file + $PRINT "linking $dest" + if [ -h $dest ]; then + rm -f $dest fi -} - -link_dir() { - local dir=$1 - local dest_dir=$2 - local dotfiles_dir=$3 - local dotted=$4 - local dest_path=`build_path $dest_dir $dir $dotted` - - $VERBOSE "recurring on $dest_path" - $MKDIR -p $dest_path - pushdir $dir - for f in *; do - $DEBUG "handling the file $f" - handle_file $f $dest_path $3/$1 1 - 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` - - $PRINT "linking $dest_file" - if [ -h $dest_file ]; then - rm -f $dest_file - fi - $LN -s $dotfiles_dir/$file $dest_file + $LN -s $src $dest } replace_file() { - local file=$1 - local dest_dir=$2 - local dotfiles_dir=$3 - local dotted=$4 - local dest_file=`build_path $dest_dir $file $dotted` + local src=$1 + local dest=$2 + + $DEBUG replace_file $1 $2 - $RM -rf $dest_file - link_file $file $dest_dir $dotfiles_dir $dotted + $RM -rf $dest + link_file $src $dest +} + +is_nested() { + echo $1 | sed "s:$DEST_DIR/::" | grep -q / + return $? } is_identical() { diff -q -s $1 $2 > /dev/null } +handle_dir() { + local dest=$1 + + $DEBUG handle_dir $1 + + dirname $dest | xargs $MKDIR -p +} + handle_file() { - local file=$1 - local dest_dir=$2 - local dotfiles_dir=$3 - local dotted=$4 + local src=$1 + local dest=$2 - $DEBUG handle_file $1 $2 $3 $4 + $DEBUG handle_file $1 $2 - if [ ! -e $file ]; then - $VERBOSE "skipping non-existent file $file" - elif [ -d $file ]; then - link_dir $file $dest_dir $dotfiles_dir $dotted - else - dest_file=`build_path $dest_dir $file $dotted` - if [ -e "$dest_file" ]; then - if is_identical $file $dest_file; then - $VERBOSE "identical $dest_file" - elif [ $REPLACE_ALL -eq 1 ]; then - replace_file $file $dest_dir $dotfiles_dir $dotted - else - $PROMPT "overwrite ${dest_file}? [ynaq]" - read overwrite - case $overwrite in - a) - REPLACE_ALL=1 - replace_file $file $dest_dir $dotfiles_dir $dotted - ;; - y) replace_file $file $dest_dir $dotfiles_dir $dotted - ;; - q) exit 1 - ;; - *) $VERBOSE "skipping $dest_file" - ;; - esac - fi + if [ -e "$dest" ]; then + if is_identical $src $dest; then + $VERBOSE "identical $dest" + elif [ $REPLACE_ALL -eq 1 ]; then + replace_file $src $dest else - link_file $file $dest_dir $dotfiles_dir $dotted + $PROMPT "overwrite ${dest}? [ynaq]" + read overwrite + case $overwrite in + a) REPLACE_ALL=1 + replace_file $src $dest + ;; + y) replace_file $src $dest ;; + q) exit 1 ;; + *) $VERBOSE "skipping $dest" ;; + esac fi + else + link_file $src $dest fi } -metafile() { - [ x$2 = 'xhost-' -o x$3 = 'xtag-' -o x$1 = "xRakefile" -o x$1 = "xinstall" ] -} - handle_command_line() { arg_tags="" verbosity=0 version=0 dotfiles_dirs= + LS_ARGS= while getopts Vqvt:d: opt; do case "$opt" in - t) arg_tags="$arg_tags $OPTARG";; + t) + arg_tags="$arg_tags $OPTARG" + LS_ARGS="$LS_ARGS -t $OPTARG" + ;; v) verbosity=$(($verbosity + 1));; q) verbosity=$(($verbosity - 1));; - d) dotfiles_dirs="$dotfiles_dirs $OPTARG";; + d) + dotfiles_dirs="$dotfiles_dirs $OPTARG" + LS_ARGS="$LS_ARGS -d $OPTARG" + ;; V) version=1 esac done @@ -178,6 +137,7 @@ handle_command_line() { fi FILES=$@ + LS_ARGS="$LS_ARGS $FILES" } if [ -e $HOME/.rcrc ]; then @@ -187,49 +147,13 @@ fi . `dirname $0`/../libexec/rcm/rcm.sh handle_command_line $* -if [ "x$DOTFILES_DIRS" = "x" ]; then - DOTFILES_DIRS="$DOTFILES_DIRS $DEFAULT_DOTFILES_DIR" -fi - -for DOTFILES_DIR in $DOTFILES_DIRS; do - - if [ ! -d $DOTFILES_DIR ]; then - $VERBOSE "skipping non-existent directory: $DOTFILES_DIR" - continue - fi - - cd $DOTFILES_DIR - DIR_STACK=":$DOTFILES_DIR" - - for file in ${FILES:-*}; do - host_portion=`echo $file | sed -e 's/host-.*/host-/'` - tag_portion=`echo $file | sed -e 's/tag-.*/tag-/'` - if ! metafile $file $host_portion $tag_portion; then - handle_file $file $DEST_DIR $DOTFILES_DIR 0 - fi - done - - cd $DOTFILES_DIR +for dest_and_src in `lsrc $LS_ARGS`; do + dest=`echo $dest_and_src | sed 's/:.*//'` + src=`echo $dest_and_src | sed 's/.*://'` - 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 - done - popdir + if is_nested $dest; then + handle_dir $dest fi - cd $DOTFILES_DIR - - for tag in $TAGS; do - if [ -d tag-$tag ]; then - pushdir `basename tag-$tag` - for file in ${FILES:-*}; do - handle_file $file $DEST_DIR $DOTFILES_DIR/tag-$tag 0 - done - popdir - fi - done - + handle_file $src $dest done diff --git a/man/man1/lsrc.1 b/man/man1/lsrc.1 new file mode 100644 index 0000000..50642a6 --- /dev/null +++ b/man/man1/lsrc.1 @@ -0,0 +1,50 @@ +.TH lsrc "1" "July 2013" "rcm" + +.SH NAME +lsrc \- show configuration files + +.SH SYNOPSIS +.B lsrc [-v] [-q] [-t \fItag\fR] [-d \fIdir\fR] [\fIfiles...\fR] + +.SH DESCRIPTION + +This program lists all configuration files, both the sources in the +dotfiles directories and the destinations in your home directory. + +See \fIrcup\fR\|(1), the \fBDIRECTORY LAYOUT\fR section, for details on +the directory layout. + +It supports these options: + +.TP +\fB-v\fR +increase verbosity. This can be repeated for extra verbosity. + +.TP +\fB-q\fR +decrease verbosity + +.TP +\fB-t\fR \fITAG\fR +list dotfiles according to TAG + +.TP +\fB-d\fR \fIDIR\fR +list dotfiles from the DIR. This can be specified multiple times. + +.TP +\fIfiles...\fR +only list the specified file(s) + + +.SH AUTHOR + +Written by Mike Burns. + +.SH FILES +.I ~/.dotfiles +.I ~/.rcrc + +.SH SEE ALSO + +\&\fIrcrc\fR\|(5), \fImkrc\fR\|(1), \fIrcup\fR\|(1) diff --git a/man/man1/mkrc.1 b/man/man1/mkrc.1 index b241e6b..b8b555f 100644 --- a/man/man1/mkrc.1 +++ b/man/man1/mkrc.1 @@ -42,4 +42,4 @@ Written by Mike Burns. .SH SEE ALSO -\&\fIrcrc\fR\|(5), \fIrcup\fR\|(1) +\&\fIrcrc\fR\|(5), \fIrcup\fR\|(1), \fIlsrc\fR\|(1) diff --git a/man/man1/rcup.1 b/man/man1/rcup.1 index f68cc87..c24753c 100644 --- a/man/man1/rcup.1 +++ b/man/man1/rcup.1 @@ -67,4 +67,4 @@ Written by Mike Burns. .SH SEE ALSO -\&\fIrcrc\fR\|(5), \fImkrc\fR\|(1) +\&\fIrcrc\fR\|(5), \fImkrc\fR\|(1), \fIlsrc\fR\|(1) diff --git a/man/man5/rcrc.5 b/man/man5/rcrc.5 index 67dc2a3..6f28e06 100644 --- a/man/man5/rcrc.5 +++ b/man/man5/rcrc.5 @@ -37,4 +37,4 @@ Written by Mike Burns. .SH SEE ALSO -\&\fImkrc\fR\|(5), \fIrcup\fR\|(1) +\&\fImkrc\fR\|(5), \fIrcup\fR\|(1), \fIlsrc\fR\|(1) -- cgit v1.2.3