aboutsummaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/design/external_special_remote_protocol.mdwn22
-rw-r--r--doc/devblog/day_238__extending_addurl_further.mdwn67
-rw-r--r--doc/related_software.mdwn4
-rw-r--r--doc/special_remotes/external.mdwn8
-rwxr-xr-xdoc/special_remotes/external/git-annex-remote-torrent191
5 files changed, 281 insertions, 11 deletions
diff --git a/doc/design/external_special_remote_protocol.mdwn b/doc/design/external_special_remote_protocol.mdwn
index 072c5a1a2..cc3bfce96 100644
--- a/doc/design/external_special_remote_protocol.mdwn
+++ b/doc/design/external_special_remote_protocol.mdwn
@@ -131,10 +131,8 @@ replying with `UNSUPPORTED-REQUEST` is acceptable.
If not, it can send `CLAIMURL-FAILURE`.
* `CHECKURL Url`
Asks the remote to check if the url's content can currently be downloaded
- (without downloading it). If the url is not accessible, send
- `CHECKURL-FAILURE`. If the url is accessible and the size is known,
- send the size in `CHECKURL-SIZE`. If the url is accessible, but the size
- is unknown, send `CHECKURL-SIZEUNKOWN`.
+ (without downloading it). The remote replies with one of `CHECKURL-FAILURE`,
+ `CHECKURL-CONTENTS`, or `CHECKURL-MULTI`.
More optional requests may be added, without changing the protocol version,
so if an unknown request is seen, reply with `UNSUPPORTED-REQUEST`.
@@ -181,12 +179,18 @@ while it's handling a request.
Indicates that the CLAIMURL url will be handled by this remote.
* `CLAIMURL-FAILURE`
Indicates that the CLAIMURL url wil not be handled by this remote.
-* `CHECKURL-SIZE Size`
+* `CHECKURL-CONTENTS Size|UNKNOWN Filename`
+ Indicates that the requested url has been verified to exist.
+ The Size is the size in bytes, or use "UNKNOWN" if the size could not be
+ determined.
+ The Filename can be empty (in which case a default is used),
+ or can specify a filename that is suggested to be used for this url.
+* `CHECKURL-MULTI Url Size|UNKNOWN Filename ...`
Indicates that the requested url has been verified to exist,
- and its size is known. The size is in bytes.
-* `CHECKURL-SIZEUNKNOWN`
- Indicates that the requested url has been verified to exist,
- but its size could not be determined.
+ and contains multiple files, which can each be accessed using
+ their own url.
+ Note that since a list is returned, neither the Url nor the Filename
+ can contain spaces.
* `CHECKURL-FAILURE`
Indicates that the requested url could not be accessed.
* `UNSUPPORTED-REQUEST`
diff --git a/doc/devblog/day_238__extending_addurl_further.mdwn b/doc/devblog/day_238__extending_addurl_further.mdwn
new file mode 100644
index 000000000..f58bee6a5
--- /dev/null
+++ b/doc/devblog/day_238__extending_addurl_further.mdwn
@@ -0,0 +1,67 @@
+Some more work on the interface that lets remotes claim urls for `git annex
+addurl`. Added support for remotes suggesting a filename to use when
+adding an url. Also, added support for urls that result in multiple files
+when downloaded. The obvious use case for that is an url to a torrent that
+contains multiple files.
+
+Then, got `git annex importfeed` to also check if a remote claims an url.
+
+Finally, I put together a quick demo external remote using this new
+interface. [[special_remotes/external/git-annex-remote-torrent]]
+adds support for torrent files to git-annex, using aria2c to download them.
+It supports multi-file torrents, but not magnet links. (I'll probably
+rewrite this more robustly and efficiently in haskell sometime soon.)
+
+Here's a demo:
+
+<pre>
+# git annex initremote torrent type=external encryption=none externaltype=torrent
+initremote torrent ok
+(Recording state in git...)
+# ls
+# git annex addurl --fast file:///home/joey/my.torrent
+ % Total % Received % Xferd Average Speed Time Time Time Current
+ Dload Upload Total Spent Left Speed
+100 198 100 198 0 0 3946k 0 --:--:-- --:--:-- --:--:-- 3946k
+addurl _home_joey_my.torrent/bar (using torrent) ok
+addurl _home_joey_my.torrent/baz (using torrent) ok
+addurl _home_joey_my.torrent/foo (using torrent) ok
+(Recording state in git...)
+# ls _home_joey_my.torrent/
+bar@ baz@ foo@
+# git annex get _home_joey_my.torrent/baz
+get _home_joey_my.torrent/baz (from torrent...)
+ % Total % Received % Xferd Average Speed Time Time Time Current
+ Dload Upload Total Spent Left Speed
+ 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-100 198 100 198 0 0 3580k 0 --:--:-- --:--:-- --:--:-- 3580k
+
+12/11 18:14:56 [NOTICE] IPv4 DHT: listening on UDP port 6946
+
+12/11 18:14:56 [NOTICE] IPv4 BitTorrent: listening on TCP port 6961
+
+12/11 18:14:56 [NOTICE] IPv6 BitTorrent: listening on TCP port 6961
+
+12/11 18:14:56 [NOTICE] Seeding is over.
+12/11 18:14:57 [NOTICE] Download complete: /home/joey/tmp/tmp.Le89hJSXyh/tor
+
+12/11 18:14:57 [NOTICE] Your share ratio was 0.0, uploaded/downloaded=0B/0B
+
+Download Results:
+gid |stat|avg speed |path/URI
+======+====+===========+=======================================================
+71f6b6|OK | 0B/s|/home/joey/tmp/tmp.Le89hJSXyh/tor/baz
+
+Status Legend:
+(OK):download completed.
+ok
+(Recording state in git...)
+# git annex find
+_home_joey_my.torrent/baz
+# git annex whereis _home_joey_my.torrent/baz
+whereis _home_joey_my.torrent/baz (2 copies)
+ 1878241d-ee49-446d-8cce-041c46442d94 -- [torrent]
+ 52412020-2bb3-4aa4-ae16-0da22ba48875 -- joey@darkstar:~/tmp/repo [here]
+
+ torrent: file:///home/joey/my.torrent#2
+ok
+</pre>
diff --git a/doc/related_software.mdwn b/doc/related_software.mdwn
index 1e5c0f6b0..f2b8e601b 100644
--- a/doc/related_software.mdwn
+++ b/doc/related_software.mdwn
@@ -15,3 +15,7 @@ designed to interoperate with it.
[an extension](https://github.com/magit/magit-annex) for git annex.
* [DataLad](http://datalad.org/) uses git-annex to provide access to
scientific data available from various sources.
+* The [Baobáxia](https://github.com/RedeMocambos/baobaxia) project
+ built by the Brazilian [Mocambos network](http://www.mocambos.net/)
+ is [using git-annex to connect isolated communities](http://www.modspil.dk/itpolitik/baob_xia.html).
+ Repositories sync over satellite internet and/or sneakernet.
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