1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
|
#!/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
|