From 3c6cbc343d19e221756be024ba8d5bf2632c38d7 Mon Sep 17 00:00:00 2001 From: Mike Burns Date: Fri, 7 Jun 2013 10:49:17 +0200 Subject: Initial commit This adds mkrc and rcup, along with a Makefile to handle installation. `rcup` is for installing files from the `~/.dotfiles` repo. It allows for tagged files and host-specific files, and can install/update one-off files. `mkrc` is for moving a normal file into the dotfiles repo. --- Makefile | 7 +++ bin/mkrc | 60 ++++++++++++++++++ bin/rcup | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 277 insertions(+) create mode 100644 Makefile create mode 100755 bin/mkrc create mode 100755 bin/rcup diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..df46731 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +PREFIX=/usr/local + +install: + install -m 0755 bin/mkrc $(PREFIX)/bin + install -m 0755 bin/rcup $(PREFIX)/bin + +.PHONY: install diff --git a/bin/mkrc b/bin/mkrc new file mode 100755 index 0000000..39714ec --- /dev/null +++ b/bin/mkrc @@ -0,0 +1,60 @@ +#!/bin/sh + +set -x + +DOTFILES=$HOME/.dotfiles +MV=mv +INSTALL=./install +ROOT_DIR=$HOME + + +destination() { + if [ $# -eq 1 ]; then + echo $DOTFILES/$1 + else + echo $DOTFILES/tag-$2/$1 + fi +} + +install_dotfile() { + prior_wd=`pwd` + cd $DOTFILES + $INSTALL -t ${2:--} $1 + cd $prior_wd +} + +if [ $# -eq 0 ]; then + echo "Usage: dotfiles-add [-t tag] filename ..." + exit 1 +fi + +tag= +verbosity=0 +while getopts vqt: opt; do + case "$opt" in + t) tag=$OPTARG;; + v) verbosity=$(($verbosity + 1));; + q) verbosity=$(($verbosity - 1));; + esac +done +shift $(($OPTIND-1)) + +if [ $verbosity -ge 2 ]; then + MV="$MV -v" + INSTALL="$INSTALL -vv" +elif [ $verbosity -eq 1 ]; then + MV="$MV -v" + INSTALL="$INSTALL -v" +elif [ $verbosity -eq 0 ]; then + MV="$MV -v" +else + INSTALL="$INSTALL -q" +fi + +files=$@ + +for file in $files; do + dotless=`echo $file | sed -e "s|$ROOT_DIR/||" | sed -e 's/^\.//'` + $MV $file `destination $dotless $tag` + install_dotfile $dotless $tag +done diff --git a/bin/rcup b/bin/rcup new file mode 100755 index 0000000..65a2d0e --- /dev/null +++ b/bin/rcup @@ -0,0 +1,210 @@ +#!/bin/sh + +#set -x + +REPLACE_ALL=0 + +DEST_DIR=$HOME +DOTFILES_DIR=$HOME/.dotfiles +HOSTNAME=`hostname -s` +HOST_FILES=$DOTFILES_DIR/host-$HOSTNAME +DEBUG=: +PRINT=echo +VERBOSE=: +PROMPT=echo +DIRSTACK=":$DOTFILES_DIR" +MKDIR=mkdir +LN=ln +RM=rm + +pushdir() { + DIRSTACK="$DIRSTACK:$PWD/$1" + $DEBUG "cd'ing to $1 from `pwd` with stack $DIRSTACK" + cd $1 +} + +popdir() { + current=`echo $DIRSTACK | sed -e 's/.*://g'` + prior=`echo $DIRSTACK | sed -e "s|:$current$||" | sed -e 's/.*://g'` + DIRSTACK=`echo $DIRSTACK | sed -e 's/:[^:]*$//'` + $DEBUG "cd'ing to $prior from `pwd` with stack $DIRSTACK" + 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" + $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 +} + +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` + + $RM -rf $dest_file + link_file $file $dest_dir $dotfiles_dir $dotted +} + +is_identical() { + diff -q -s $1 $2 > /dev/null +} + +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` + 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 + else + link_file $file $dest_dir $dotfiles_dir $dotted + fi + fi +} + +metafile() { + [ x$2 = 'xhost-' -o x$3 = 'xtag-' -o x$1 = "xRakefile" -o x$1 = "xinstall" ] +} + +handle_command_line() { + arg_tags="" + verbosity=0 + while getopts qvt: opt; do + case "$opt" in + t) arg_tags="$arg_tags $OPTARG";; + v) verbosity=$(($verbosity + 1));; + q) verbosity=$(($verbosity - 1));; + esac + done + shift $(($OPTIND-1)) + + if [ $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 + + FILES=$@ +} + +if [ -e $HOME/.rcrc ]; then + . $HOME/.rcrc +fi + +handle_command_line $* + +cd $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 + +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 -- cgit v1.2.3