Skip to content
2b07403 Jul 29, 2015
234 lines (227 sloc) 7.75 KB
# stow plug-in for Joey Hess' excellent mr tool.
#
# This allows using GNU Stow as a symlink manager with mr.
#
# Author: Adam Spiers <mr@adamspiers.org>
# INSTRUCTIONS
#
# To make mr use this file, add a line like this inside the [DEFAULT]
# section of your ~/.mrconfig:
#
# include = cat /usr/share/mr/stow
#
# and then inside each [repo] section of your ~/.mrconfig for
# which you want the contents to be stowed, add this line:
#
# stowable = true
#
# Obviously you also need Stow installed. This plug-in assumes that
# the stow script is somewhere on your $PATH, but you can export
# STOW_COMMAND to override this if it's somewhere else.
#
# At least version 2.1.0 is required[1], but you can easily build the
# latest from git using the following recipe:
#
# --------- 8< --- copy into your ~/.mrconfig ---- 8< ---------
# [stow]
# checkout = git_clone git://git.savannah.gnu.org/stow.git
# fixups =
# cd "$MR_REPO"
# ./configure --prefix=$HOME
# make install
# --------- 8< --------- 8< --------- 8< --------- 8< ---------
#
# The default behaviour is to stow on checkout, and restow on update.
# The manual actions 'stow', 'restow', and 'unstow' are also
# available.
#
# By default, ~/.STOW is used as the stow directory, and ~ as the
# target directory. You can export STOW_DIR and STOW_TARGET to
# override these defaults.
#
# stowing is automatically performed via post_checkout, and restowing
# via post_update, as can be seen from below (search for 'Automatic
# actions'). Note that these run before fixups, which allows fixups
# to refer to stowed files, but isn't ideal if the fixups are
# responsible for creating the stow package's installation image,
# e.g. via a typical './configure && make install' sequence. Here's a
# suggested mrconfig chunk to handle this particular use case:
#
# stowable = true
# lib =
# STOW_PKG_TYPE=directory
# STOW_NO_AUTOMATIC_ACTIONS=yes
# mr_pre_unstow () {
# install-info --delete --info-dir=$HOME/share/info $STOW_PKG_PATH/share/info/*.info
# }
# mr_post_stow () {
# install-info --info-dir=$HOME/share/info $STOW_PKG_PATH/share/info/*.info
# }
# fixups =
# if ! [ -e configure ]; then
# bash ./autogen.sh
# fi
# set_stow_common_opts
# ./configure --prefix=$STOW_PKG_PATH
# make install prefix=$STOW_PKG_PATH
# rm $STOW_PKG_PATH/share/info/dir
# mr_restow_regardless
#
# [1] Older versions could create a frankenstein ~/.git/ directory
# containing symlinks to multiple .git/ sub-directories in different
# stow packages! 2.1.0 onwards does not have this problem - it
# supports local per-directory .stow-local-ignore and global
# ~/.stow-global-ignore files, and even without configuration of
# these, it chooses sensible default ignore lists which prevent
# stowing of a package's .git/ sub-directory. These ignore lists are
# also ideal if you only want to stow a subset of a stow package's
# contents.
lib =
: ${STOW_DIR:=$HOME/.STOW}
: ${STOW_TARGET:=$HOME}
#
if ! [ -d "$STOW_TARGET" ]; then mkdir -p "$STOW_TARGET"; fi
if ! [ -d "$STOW_DIR" ]; then mkdir -p "$STOW_DIR" ; fi
if ! [ -f "$STOW_DIR/.stow" ]; then touch "$STOW_DIR/.stow"; fi
#
#MR_STOWABLE=no
is_stowable () {
[ -z "$MR_DISABLE_STOW" ] &&
( cd "$MR_REPO" && mr stowable >/dev/null 2>&1 )
#[ "$MR_STOWABLE" = yes ]
}
stowable_then_continue () {
if is_stowable; then
return 0
else
if [ -n "$1" ]; then
info "$MR_NAME isn't stowable; skipping $MR_ACTION"
fi
return 1
fi
}
#
set_stow_common_opts () {
: ${STOW_PKG_TYPE:=symlink}
STOW_PKG_PATH="$STOW_DIR/$MR_NAME"
stow_common_opts="-t $STOW_TARGET -d $STOW_DIR"
STOW="${STOW_COMMAND:-stow}"
case "`$STOW --version`" in
'version 1.*')
stow_common_opts="$stow_common_opts -p"
;;
*)
;;
esac
if [ -n "$MR_STOW_OPTIONS" ]; then
stow_common_opts="$stow_common_opts $MR_STOW_OPTIONS"
fi
if [ -n "$MR_STOW_OVER" ]; then
stow_common_opts="$stow_common_opts --override=$MR_STOW_OVER"
fi
}
#
mr_stow () {
stowable_then_continue || return 0
set_stow_common_opts
ensure_package_exists
command "$STOW" $stow_common_opts "$@" "$MR_NAME"
mr_post_stow
info "Stowed $MR_NAME"
}
mr_restow_if_already_stowed () {
stowable_then_continue || return 0
if ! [ -L "$STOW_PKG_PATH" ]; then
info "$MR_REPO wasn't stowed yet; won't restow."
return
fi
mr_restow_regardless "$@"
}
mr_restow_regardless () {
stowable_then_continue || return 0
set_stow_common_opts
ensure_package_exists
mr_pre_unstow
command "$STOW" -R $stow_common_opts "$@" "$MR_NAME"
mr_post_stow
info "Restowed $MR_NAME"
}
mr_pre_unstow () {
: # This can be "overridden" by the lib section of a repo definition
#info "no mr_pre_unstow hook"
}
mr_post_stow () {
: # This can be "overridden" by the lib section of a repo definition
#info "no mr_post_stow hook"
}
mr_unstow () {
stowable_then_continue || return 0
set_stow_common_opts
if ! [ -d "$STOW_PKG_PATH" ]; then
info "$MR_REPO wasn't stowed yet in $STOW_PKG_PATH; can't unstow."
return
fi
mr_pre_unstow
command "$STOW" -D $stow_common_opts "$@" "$MR_NAME"
if [ "$STOW_PKG_TYPE" = 'symlink' ]; then
rm -f "$STOW_PKG_PATH"
fi
info "Unstowed $MR_NAME"
}
#
ensure_symlink_exists () {
[ $# = 2 ] || error "CONFIG BUG: Usage: ensure_symlink_exists SYMLINK TARGET"
symlink="$1"
required_target="$2"
if [ -L "$symlink" ]; then
actual_target="`readlink $symlink`"
if [ "$actual_target" = "$required_target" ]; then
return
else
error "Symlink $symlink already points to $actual_target, cannot point to $required_target; aborting."
fi
fi
if [ -e "$symlink" ]; then
error "Cannot create symlink $symlink - already exists; aborting."
fi
ln -s "$required_target" "$symlink"
}
#
ensure_package_exists () {
case "$STOW_PKG_TYPE" in
symlink)
ensure_symlink_exists "$STOW_PKG_PATH" "$MR_REPO"
;;
directory)
[ -e "$STOW_PKG_PATH" ] || mkdir "$STOW_PKG_PATH"
[ -d "$STOW_PKG_PATH" ] || error "Expected $STOW_PKG_PATH to be a directory; aborting."
if [ -L "$STOW_PKG_PATH" ]; then
error "Didn't expect $STOW_PKG_PATH to be a symlink; aborting."
fi
;;
*)
error "Unrecognised value '$STOW_PKG_TYPE' for \$STOW_PKG_TYPE; aborting."
;;
esac
}
#stowable = is_stowable
stowable = false
showstowable =
if is_stowable; then
echo "$MR_NAME is stowable"
else
echo "$MR_NAME is not stowable"
fi
# Automatic actions
post_checkout_append = [ -n "$STOW_NO_AUTOMATIC_ACTIONS" ] || mr_stow
#post_update_append = mr_restow_if_already_stowed
post_update_append = [ -n "$STOW_NO_AUTOMATIC_ACTIONS" ] || mr_restow_regardless
# Manual actions
stow = mr_stow "$@"
stowover = MR_STOW_OVER=. mr_stow "$@"
unstow = mr_unstow "$@"
restow = mr_restow_regardless "$@"
restowover = MR_STOW_OVER=. mr_restow_regardless "$@"
# Local variables:
# mode: sh
# End:
Something went wrong with that request. Please try again.