206 lines
5.1 KiB
Bash
Executable file
206 lines
5.1 KiB
Bash
Executable file
#!/bin/sh
|
|
# git-annex external special remote program
|
|
#
|
|
# This is basically the same as git-annex's built-in directory special remote.
|
|
#
|
|
# Install in PATH as git-annex-remote-directory
|
|
#
|
|
# Copyright 2013 Joey Hess; licenced under the GNU GPL version 3 or higher.
|
|
|
|
set -e
|
|
|
|
# This program speaks a line-based protocol on stdin and stdout.
|
|
# When running any commands, their stdout should be redirected to stderr
|
|
# (or /dev/null) to avoid messing up the protocol.
|
|
runcmd () {
|
|
"$@" >&2
|
|
}
|
|
|
|
# Gets a value from the remote's configuration, and stores it in RET
|
|
getconfig () {
|
|
ask GETCONFIG "$1"
|
|
}
|
|
|
|
# Stores a value in the remote's configuration.
|
|
setconfig () {
|
|
echo SETCONFIG "$1" "$2"
|
|
}
|
|
|
|
# Sets LOC to the location to use to store a key.
|
|
calclocation () {
|
|
ask DIRHASH "$1"
|
|
LOC="$mydirectory/$RET/$1"
|
|
}
|
|
|
|
# Asks for some value, and stores it in RET
|
|
ask () {
|
|
echo "$1" "$2"
|
|
read resp
|
|
# Tricky POSIX shell code to split first word of the resp,
|
|
# preserving all other whitespace
|
|
case "${resp%% *}" in
|
|
VALUE)
|
|
RET="$(echo "$resp" | sed 's/^VALUE \?//')"
|
|
;;
|
|
*)
|
|
RET=""
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# This remote doesn't need credentials to access it,
|
|
# but many of them will. Here's how to handle requiring the user
|
|
# set MYPASSWORD and MYLOGIN when running initremote. The creds
|
|
# will be stored securely for later use, so the user only needs
|
|
# to provide them once.
|
|
setupcreds () {
|
|
if [ -z "$MYPASSWORD" ] || [ -z "$MYLOGIN" ]; then
|
|
echo INITREMOTE-FAILURE "You need to set MYPASSWORD and MYLOGIN environment variables when running initremote."
|
|
else
|
|
echo SETCREDS mycreds "$MYLOGIN" "$MYPASSWORD"
|
|
echo INITREMOTE-SUCCESS
|
|
fi
|
|
}
|
|
|
|
getcreds () {
|
|
echo GETCREDS mycreds
|
|
read resp
|
|
case "${resp%% *}" in
|
|
CREDS)
|
|
MYLOGIN="$(echo "$resp" | sed 's/^CREDS \([^ ]*\) .*/\1/')"
|
|
MYPASSWORD="$(echo "$resp" | sed 's/^CREDS [^ ]* //')"
|
|
;;
|
|
esac
|
|
|
|
}
|
|
|
|
# This has to come first, to get the protocol started.
|
|
echo VERSION 1
|
|
|
|
while read line; do
|
|
set -- $line
|
|
case "$1" in
|
|
INITREMOTE)
|
|
# Do anything necessary to create resources
|
|
# used by the remote. Try to be idempotent.
|
|
#
|
|
# Use GETCONFIG to get any needed configuration
|
|
# settings, and SETCONFIG to set any persistent
|
|
# configuration settings.
|
|
#
|
|
# (Note that this is not run every time, only when
|
|
# git annex initremote or git annex enableremote is
|
|
# run.)
|
|
|
|
# The directory provided by the user
|
|
# could be relative; make it absolute,
|
|
# and store that.
|
|
getconfig directory
|
|
mydirectory="$(readlink -f "$RET")" || true
|
|
setconfig directory "$mydirectory"
|
|
if [ -z "$mydirectory" ]; then
|
|
echo INITREMOTE-FAILURE "You need to set directory="
|
|
else
|
|
if mkdir -p "$mydirectory"; then
|
|
setupcreds
|
|
else
|
|
echo INITREMOTE-FAILURE "Failed to write to $mydirectory"
|
|
fi
|
|
fi
|
|
;;
|
|
PREPARE)
|
|
# Use GETCONFIG to get configuration settings,
|
|
# and do anything needed to get ready for using the
|
|
# special remote here.
|
|
getcreds
|
|
getconfig directory
|
|
mydirectory="$RET"
|
|
if [ -d "$mydirectory" ]; then
|
|
echo PREPARE-SUCCESS
|
|
else
|
|
echo PREPARE-FAILURE "$mydirectory not found"
|
|
fi
|
|
;;
|
|
TRANSFER)
|
|
key="$3"
|
|
file="$4"
|
|
case "$2" in
|
|
STORE)
|
|
# Store the file to a location
|
|
# based on the key.
|
|
# XXX when at all possible, send PROGRESS
|
|
calclocation "$key"
|
|
mkdir -p "$(dirname "$LOC")"
|
|
# Store in temp file first, so that
|
|
# CHECKPRESENT does not see it
|
|
# until it is all stored.
|
|
mkdir -p "$mydirectory/tmp"
|
|
tmp="$mydirectory/tmp/$key"
|
|
if runcmd cp "$file" "$tmp" \
|
|
&& runcmd mv -f "$tmp" "$LOC"; then
|
|
echo TRANSFER-SUCCESS STORE "$key"
|
|
else
|
|
echo TRANSFER-FAILURE STORE "$key"
|
|
fi
|
|
|
|
mkdir -p "$(dirname "$LOC")"
|
|
# The file may already exist, so
|
|
# make sure we can overwrite it.
|
|
chmod 644 "$LOC" 2>/dev/null || true
|
|
;;
|
|
RETRIEVE)
|
|
# Retrieve from a location based on
|
|
# the key, outputting to the file.
|
|
# XXX when easy to do, send PROGRESS
|
|
calclocation "$key"
|
|
if runcmd cp "$LOC" "$file"; then
|
|
echo TRANSFER-SUCCESS RETRIEVE "$key"
|
|
else
|
|
echo TRANSFER-FAILURE RETRIEVE "$key"
|
|
fi
|
|
;;
|
|
esac
|
|
;;
|
|
CHECKPRESENT)
|
|
key="$2"
|
|
calclocation "$key"
|
|
if [ -e "$LOC" ]; then
|
|
echo CHECKPRESENT-SUCCESS "$key"
|
|
else
|
|
if [ -d "$mydirectory" ]; then
|
|
echo CHECKPRESENT-FAILURE "$key"
|
|
else
|
|
# When the directory does not exist,
|
|
# the remote is not available.
|
|
# (A network remote would similarly
|
|
# fail with CHECKPRESENT-UNKNOWN
|
|
# if it couldn't be contacted).
|
|
echo CHECKPRESENT-UNKNOWN "$key" "this remote is not currently available"
|
|
fi
|
|
fi
|
|
;;
|
|
REMOVE)
|
|
key="$2"
|
|
calclocation "$key"
|
|
# Note that it's not a failure to remove a
|
|
# key that is not present.
|
|
if [ -e "$LOC" ]; then
|
|
if runcmd rm -f "$LOC"; then
|
|
echo REMOVE-SUCCESS "$key"
|
|
else
|
|
echo REMOVE-FAILURE "$key"
|
|
fi
|
|
else
|
|
echo REMOVE-SUCCESS "$key"
|
|
fi
|
|
;;
|
|
*)
|
|
# The requests listed above are all the ones
|
|
# that are required to be supported, so it's fine
|
|
# to say that any other request is unsupported.
|
|
echo UNSUPPORTED-REQUEST
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# XXX anything that needs to be done at shutdown can be done here
|