summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Joey Hess <joeyh@joeyh.name>2014-12-11 18:09:44 -0400
committerGravatar Joey Hess <joeyh@joeyh.name>2014-12-11 18:09:44 -0400
commit0a26abf0ea0f19deb2e318e574bcbdc2f2f4d79d (patch)
tree531fcbf789b3d67fd43a372f851c0c76db7388ed
parent7efc177f1a75cfdccb08cc195cbca3f880de59ad (diff)
add working external special remote for torrents
Not IMHO good enough quality to be more than an example, but it does work!
-rw-r--r--doc/special_remotes/external.mdwn8
-rwxr-xr-xdoc/special_remotes/external/git-annex-remote-torrent191
2 files changed, 197 insertions, 2 deletions
diff --git a/doc/special_remotes/external.mdwn b/doc/special_remotes/external.mdwn
index d96999693..010f2a17b 100644
--- a/doc/special_remotes/external.mdwn
+++ b/doc/special_remotes/external.mdwn
@@ -14,14 +14,18 @@ It's not hard!
* Install it in PATH.
* When the user runs `git annex initremote foo type=external externaltype=$bar`,
it will use your program.
+* See [[design/external_special_remote_protocol]] for what the program
+ needs to do. There's an example at the end of this page.
* If things don't seem to work, pass `--debug` and you'll see, amoung other
things, a transcript of git-annex's communication with your program.
* If you build a new special remote, please add it to the list
of [[special_remotes]].
+Here's an example of using an external special remote to add torrent
+support to git-annex: [[external/git-annex-remote-torrent]]
+
Here's a simple shell script example, which can easily be adapted
to run whatever commands you need. Or better, re-written in some better
-language of your choice. See [[design/external_special_remote_protocol]]
-for the details.
+language of your choice.
[[!inline pages="special_remotes/external/example.sh" feeds=no]]
diff --git a/doc/special_remotes/external/git-annex-remote-torrent b/doc/special_remotes/external/git-annex-remote-torrent
new file mode 100755
index 000000000..4f5e62a90
--- /dev/null
+++ b/doc/special_remotes/external/git-annex-remote-torrent
@@ -0,0 +1,191 @@
+#!/bin/sh
+# This is a demo git-annex external special remote program,
+# which adds basic torrent download support to git-annex.
+#
+# Uses aria2c. Also needs the original bittorrent (or bittornado) for the
+# btshowmetainfo command.
+#
+# Install in PATH as git-annex-remote-torrent
+#
+# Enable remote by running:
+# git annex initremote torrent type=external encryption=none externaltype=torrent
+# git annex untrust torrent
+#
+# Copyright 2014 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 response and stores it in $RET
+getvalue () {
+ 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
+}
+
+# Get a list of all known torrent urls for a key,
+# storing it in a temp file.
+geturls () {
+ key="$1"
+ tmp="$2"
+
+ echo GETURLS "$key"
+ getvalue
+ while [ -n "$RET" ]; do
+ if istorrent "$RET"; then
+ echo "$RET" >> "$tmp"
+ fi
+ getvalue
+ done
+}
+
+# Does the url end in .torrent?
+# Note that we use #N on the url to indicate which file
+# from a multi-file torrent is wanted.
+istorrent () {
+ echo "$1" | egrep -q "\.torrent(#.*)?$"
+}
+
+# Download a single file from a torrent.
+#
+# Note: Does not support resuming interrupted transfers.
+# Note: Does not feed progress info back to git-annex, and since
+# the destination file is only populated at the end, git-annex will fail
+# to display a progress bar for this download.
+downloadtorrent () {
+ torrent="$1"
+ n="$2"
+ dest="$3"
+
+ tmpdir="$(mktemp -d)"
+ if ! runcmd aria2c --select-file="$n" "$torrent" -d "$tmpdir"; then
+ false
+ fi
+
+ # aria2c will create part of the directory structure
+ # contained in the torrent. It may download parts of other files
+ # in addition to the one we asked for. So, we need to find
+ # out the filename we want, and look for it.
+ wantdir="$(btshowmetainfo "$torrent" | grep "^directory name: " | sed "s/^directory name: //")"
+ wantfile="$(btshowmetainfo "$tmp" | grep '^ ' | sed 's/^ //' | head -n "$n" | tail -n 1 | sed 's/ ([0-9]*)$//')"
+ if [ -e "$tmpdir/$wantdir/$wantfile" ]; then
+ mv "$tmpdir/$wantdir/$wantfile" "$dest"
+ rm -rf "$tmpdir"
+ else
+ rm -rf "$tmpdir"
+ false
+ fi
+}
+
+# This has to come first, to get the protocol started.
+echo VERSION 1
+
+while read line; do
+ set -- $line
+ case "$1" in
+ INITREMOTE)
+ echo INITREMOTE-SUCCESS
+ ;;
+ PREPARE)
+ echo PREPARE-SUCCESS
+ ;;
+ CLAIMURL)
+ url="$2"
+ if istorrent "$url"; then
+ echo CLAIMURL-SUCCESS
+ else
+ echo CLAIMURL-FAILURE
+ fi
+ ;;
+ CHECKURL)
+ url="$2"
+ # List contents of torrent.
+ tmp=$(mktemp)
+ if ! runcmd curl -o "$tmp" "$url"; then
+ echo CHECKURL-FAILURE
+ else
+ oldIFS="$IFS"
+ IFS="
+"
+ printf "CHECKURL-MULTI"
+ n=0
+ for l in $(btshowmetainfo "$tmp" | grep '^ ' | sed 's/^ //'); do
+ # Note that the file cannot contain spaces.
+ file="$(echo "$l" | sed 's/ ([0-9]*)$//' | sed 's/ /_/g')"
+ size="$(echo "$l" | sed 's/.* (\([0-9]*\))$/\1/')"
+ n=$(expr $n + 1)
+ printf " $url#$n $size $file"
+ done
+ printf "\n"
+ IFS="$oldIFS"
+ fi
+ rm -f "$tmp"
+ ;;
+ TRANSFER)
+ key="$3"
+ file="$4"
+ case "$2" in
+ STORE)
+ runcmd echo "upload not supported"
+ echo TRANSFER-FAILURE STORE "$key"
+ ;;
+ RETRIEVE)
+ urltmp=$(mktemp)
+ geturls "$key" "$urltmp"
+ url="$(head "$urltmp")" || true
+ rm -f "$urltmp"
+ if [ -z "$url" ]; then
+ echo TRANSFER-FAILURE RETRIEVE "$key" "no known torrent urls for this key"
+ else
+ tmp=$(mktemp)
+ if ! runcmd curl -o "$tmp" "$url"; then
+ echo TRANSFER-FAILURE RETRIEVE "$key" "failed downloading torrent file from $url"
+ else
+ filenum="$(echo "$url" | sed 's/.*#\(\d*\)/\1/')"
+ if downloadtorrent "$tmp" "$filenum" "$file"; then
+ echo TRANSFER-SUCCESS RETRIEVE "$key"
+ else
+ echo TRANSFER-FAILURE RETRIEVE "$key" "failed to download torrent contents from $url"
+ fi
+ fi
+ rm -f "$tmp"
+ fi
+ ;;
+ esac
+ ;;
+ CHECKPRESENT)
+ key="$2"
+ # Let's just assume that torrents are always present
+ # for simplicity.
+ echo CHECKPRESENT-SUCCESS "$key"
+ ;;
+ REMOVE)
+ key="$2"
+ # Remove all torrent urls for the key.
+ tmp=$(mktemp)
+ geturls "$key" "$tmp"
+ for url in $(cat "$tmp"); do
+ echo SETURLMISSING "$key" "$url"
+ done
+ rm -f "$tmp"
+ echo REMOVE-SUCCESS "$key"
+ ;;
+ *)
+ echo UNSUPPORTED-REQUEST
+ ;;
+ esac
+done