Codebase list git-annex-remote-rclone / f2df1c8
Import upstream version 0.7 Debian Janitor 9 months ago
6 changed file(s) with 236 addition(s) and 64 deletion(s). Raw diff Collapse all Expand all
0 name: Shellcheck
1
2 on:
3 push:
4 pull_request:
5 schedule:
6 - cron: '0 6 * * *'
7
8 jobs:
9 shellcheck:
10 runs-on: ubuntu-18.04
11
12 steps:
13 - name: Set up environment
14 uses: actions/checkout@v1
15
16 - name: Install dependencies
17 run: |
18 sudo apt update && sudo apt install shellcheck
19
20 - name: shellcheck
21 run: |
22 shellcheck git-annex-remote-rclone
0 name: Tests
1
2 on:
3 push:
4 pull_request:
5 schedule:
6 - cron: '0 6 * * *'
7
8 jobs:
9 test:
10 runs-on: ${{ matrix.os }}
11
12 strategy:
13 fail-fast: false
14 matrix:
15 os:
16 - ubuntu-18.04
17 #- windows-2019
18 - macos-latest
19 rclone:
20 - current
21 - v1.58.1 # current "current" -- the baseline
22 - v1.53.3 # Debian bullseye (current stable)
23 - v1.45 # Debian buster (current oldstable)
24 # older versions for which there is internal logic
25 - v1.33
26 - v1.30
27 # - v1.29 TODO: seems to need rclone config run -- must be done in test script
28 exclude:
29 # 1.30 - --version exits non-0
30 - os: macos-latest
31 rclone: v1.30
32 # 1.45 - has some odd handling of HOME on OSX - does not use overloaded $HOME
33 - os: macos-latest
34 rclone: v1.45
35
36 steps:
37 - name: Set up environment
38 uses: actions/checkout@v1
39
40 - name: Install Python
41 uses: actions/setup-python@v4
42 with:
43 python-version: '>=3.7'
44
45 - name: Install datalad-installer
46 run: pip install datalad-installer
47
48 - name: Install git-annex (Ubuntu)
49 if: startsWith(matrix.os, 'ubuntu-')
50 run: datalad-installer --sudo ok git-annex -m datalad/git-annex:release
51
52 - name: Install git-annex (macOS)
53 if: startsWith(matrix.os, 'macos-')
54 run: datalad-installer git-annex -m brew
55
56 - name: Install latest rclone
57 if: matrix.rclone == 'current'
58 run: datalad-installer --sudo ok rclone -m downloads.rclone.org
59
60 - name: Install specific version of rclone
61 if: matrix.rclone != 'current'
62 run: datalad-installer --sudo ok rclone=${{ matrix.rclone }} -m downloads.rclone.org
63
64 - name: ${{ matrix.module }} tests
65 run: |
66 PATH=$PWD:$PATH tests/all-in-one.sh
67 # Test without encryption so we do get 0-sized files in rclone remote store
68 PATH=$PWD:$PATH GARR_TEST_ENCRYPTION=none tests/all-in-one.sh
1111 - curl 'https://downloads.rclone.org/rclone-current-linux-amd64.zip' > rclone.zip
1212 - unzip rclone.zip
1313 - mv rclone-*-linux-amd64/rclone /usr/local/bin
14 - echo -e '[local]\ntype = local\nnounc =' > ~/.rclone.conf
15 - git-annex version
16 - mkdir testrepo
17 - cd testrepo
18 - git init .
19 - git-annex init
20 - git-annex initremote GA-rclone-CI type=external externaltype=rclone target=local prefix=/tmp/GA-rclone-CI chunk=100MiB encryption=shared mac=HMACSHA512
21 - touch test
22 - git-annex add test
23 - git-annex copy test --to GA-rclone-CI
24 - git-annex testremote GA-rclone-CI --fast
14 - tests/all-in-one.sh
33 Some ways of using earlier versions could result in data loss. [more information here](https://github.com/DanielDent/git-annex-remote-rclone/issues/8)__
44
55
6 [![build status](https://gitlab.com/DanielDent/git-annex-remote-rclone/badges/master/build.svg)](https://gitlab.com/DanielDent/git-annex-remote-rclone/commits/master)
6 [![Tests](https://github.com/DanielDent/git-annex-remote-rclone/actions/workflows/test.yml/badge.svg)](https://github.com/DanielDent/git-annex-remote-rclone/actions/workflows/test.yml)
7 [![Shellcheck](https://github.com/DanielDent/git-annex-remote-rclone/actions/workflows/shellcheck.yml/badge.svg)](https://github.com/DanielDent/git-annex-remote-rclone/actions/workflows/shellcheck.yml)
78
89 This wrapper around [rclone](http://rclone.org/) makes any destination supported by rclone usable with git-annex.
910
122123
123124 ## License
124125
125 Copyright 2016-2017 [Daniel Dent](https://www.danieldent.com/). Licensed under the GPLv3.
126 Copyright 2016-2022 [Daniel Dent](https://www.danieldent.com/), 2022 [git-annex-remote-rclone contributors](https://github.com/DanielDent/git-annex-remote-rclone/graphs/contributors). Licensed under the GPLv3.
00 #!/bin/bash
1 # emacs: -*- mode: python; tab-width: 4; indent-tabs-mode: t -*-
2 # ex: set sts=4 ts=4 sw=4 noet:
3 #
14 # git-annex-remote-rclone - wrapper to enable use of rclone-supported cloud providers as git-annex special remotes.
25 #
36 # Install in PATH as git-annex-remote-rclone
47 #
5 # Copyright (C) 2016-2017 Daniel Dent
8 # Copyright (C) 2016-2022 Daniel Dent
9 # 2022 git-annex-remote-rclone contributors
610 #
711 # This program is free software: you can redistribute it and/or modify it under the terms of version 3 of the GNU
812 # General Public License as published by the Free Software Foundation.
4347 echo "INITREMOTE-FAILURE rclone_layout setting not recognized"
4448 exit 1
4549 ;;
46 esac
50 esac
4751 }
4852
4953 # Sets LOC to the location to use to store a key.
5963 ;;
6064 nodir)
6165 LOC="$REMOTE_TARGET:$REMOTE_PREFIX/"
62 ;;
66 ;;
6367 mixed)
6468 ask DIRHASH "$1"
6569 LOC="$REMOTE_TARGET:$REMOTE_PREFIX/$RET"
6670 ;;
6771 frankencase)
6872 ask DIRHASH "$1"
69 lret=$(echo $RET|tr A-Z a-z)
73 lret=$(echo "$RET" | tr '[:upper:]' '[:lower:]')
7074 LOC="$REMOTE_TARGET:$REMOTE_PREFIX/$lret"
7175 ;;
7276 esac
7680 ask () {
7781 echo "$1" "$2"
7882 read -r resp
79 # Strip trailing carriage return, if present
80 resp="${resp%$'\r'}"
81 if echo $resp|grep '^VALUE '>/dev/null; then
82 RET=$(echo "$resp" | cut -f2- -d' ')
83 else
84 RET=""
83 # Strip trailing carriage return, if present
84 resp="${resp%$'\r'}"
85 if echo "$resp" | grep '^VALUE '>/dev/null; then
86 RET=$(echo "$resp" | cut -f2- -d' ')
87 else
88 RET=""
8589 fi
8690 }
8791
92 GREP () {
93 set +e
94 out=$(grep "$@")
95 rc=$?
96 set -e
97 # Replace explicit newline since we must provide 1 line DEBUG
98 # Fancy sed is from Example 5 of https://linuxhint.com/newline_replace_sed
99 # which worked on Linux and OSX.
100 # shellcheck disable=SC2016
101 out_safe=$(echo "$out" | sed -ne 'H;${x;s/\n/\\n/g;s/^,//;p;}')
102 echo "DEBUG 'grep \"$*\"' exited with rc=$rc and stdout=${out_safe}"
103 exit $rc
104 }
88105
89106 # This has to come first, to get the protocol started.
90107 echo VERSION 1
91108
92109 while read -r line; do
93 # Strip trailing carriage return, if present
94 line="${line%$'\r'}"
110 # Strip trailing carriage return, if present
111 line="${line%$'\r'}"
112 # shellcheck disable=SC2086
95113 set -- $line
96114 case "$1" in
97115 INITREMOTE)
98116 # Do anything necessary to create resources
99117 # used by the remote. Try to be idempotent.
100 #
118 #
101119 # Use GETCONFIG to get any needed configuration
102120 # settings, and SETCONFIG to set any persistent
103121 # configuration settings.
104 #
122 #
105123 # (Note that this is not run every time, only when
106124 # git annex initremote or git annex enableremote is
107125 # run.)
109127 getconfig prefix
110128 REMOTE_PREFIX=$RET
111129 if [ -z "$REMOTE_PREFIX" ]; then
112 REMOTE_PREFIX="git-annex"
130 REMOTE_PREFIX="git-annex"
113131 fi
114132 if [ "$REMOTE_PREFIX" == "/" ]; then
115 echo INITREMOTE-FAILURE "storing objects directly in the root (/) is not supported"
133 echo INITREMOTE-FAILURE "storing objects directly in the root (/) is not supported"
116134 fi
117135 setconfig prefix $REMOTE_PREFIX
118136
119137 getconfig target
120138 REMOTE_TARGET=$RET
121 setconfig target $REMOTE_TARGET
122
139 setconfig target "$REMOTE_TARGET"
140
123141 getconfig rclone_layout
124142 RCLONE_LAYOUT=$RET
125143 validate_layout
126 setconfig rclone_layout $RCLONE_LAYOUT
144 setconfig rclone_layout "$RCLONE_LAYOUT"
127145
128146 if [ -z "$REMOTE_TARGET" ]; then
129 echo INITREMOTE-FAILURE "rclone remote target must be specified (use target= parameter)"
130 fi
131
132 if runcmd rclone mkdir $REMOTE_TARGET:$REMOTE_PREFIX; then
133 echo INITREMOTE-SUCCESS
134 else
135 echo INITREMOTE-FAILURE "Failed to create directory on remote. Ensure that 'rclone config' has been run."
136 fi
147 echo INITREMOTE-FAILURE "rclone remote target must be specified (use target= parameter)"
148 fi
149
150 if runcmd rclone mkdir "$REMOTE_TARGET:$REMOTE_PREFIX"; then
151 echo INITREMOTE-SUCCESS
152 else
153 echo INITREMOTE-FAILURE "Failed to create directory on remote. Ensure that 'rclone config' has been run."
154 fi
137155 ;;
138156 PREPARE)
139157 # Use GETCONFIG to get configuration settings,
142160
143161 getconfig prefix
144162 REMOTE_PREFIX="$RET"
145
163
146164 getconfig target
147165 REMOTE_TARGET="$RET"
148
166
149167 getconfig rclone_layout
150168 RCLONE_LAYOUT="$RET"
151169 validate_layout
152170
153 echo PREPARE-SUCCESS
171 echo PREPARE-SUCCESS
154172 ;;
155173 TRANSFER)
174 op="$2"
156175 key="$3"
157 file="$4"
158 case "$2" in
176 shift 3
177 file="$*"
178 case "$op" in
159179 STORE)
160180 # Store the file to a location
161181 # based on the key.
163183 calclocation "$key"
164184 if [ ! -e "$file" ]; then
165185 echo TRANSFER-FAILURE STORE "$key" "asked to store non-existent file $file"
166 else
186 else
167187 if runcmd rclone copy "$file" "$LOC"; then
168188 echo TRANSFER-SUCCESS STORE "$key"
169189 else
170190 echo TRANSFER-FAILURE STORE "$key"
171191 fi
172 fi
192 fi
173193 ;;
174194 RETRIEVE)
175195 # Retrieve from a location based on
178198 calclocation "$key"
179199 # http://stackoverflow.com/questions/31396985/why-is-mktemp-on-os-x-broken-with-a-command-that-worked-on-linux
180200 if GA_RC_TEMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/rclone-annex-tmp.XXXXXXXXX") &&
181 runcmd rclone copy "$LOC$key" $GA_RC_TEMP_DIR &&
182 mv $GA_RC_TEMP_DIR/$key $file &&
183 rmdir $GA_RC_TEMP_DIR; then
201 runcmd rclone copy "$LOC$key" "$GA_RC_TEMP_DIR" &&
202 mv "$GA_RC_TEMP_DIR/$key" "$file" &&
203 rmdir "$GA_RC_TEMP_DIR"; then
184204 echo TRANSFER-SUCCESS RETRIEVE "$key"
185205 else
186206 echo TRANSFER-FAILURE RETRIEVE "$key"
196216 # Some rclone backends support multiple
197217 # files under one name.
198218 if check_result=$(rclone size "$LOC$key" 2>&1) &&
199 echo $check_result|grep -E 'Total objects: [1-9][0-9]* Total size' >&2 &&
200 ! echo $check_result|grep 'Total size: 0 (0 bytes)' >&2; then
219 echo "$check_result" | GREP -E 'Total objects: [1-9][0-9]*\>'; then
201220 echo CHECKPRESENT-SUCCESS "$key"
202221 else
203222 # rclone 1.29 used 'Total objects: 0'
204223 # rclone 1.30 uses 'directory not found'
205 if echo $check_result|grep 'Total objects: 0' >&2 ||
206 echo $check_result|grep ' directory not found' >&2; then
224 if echo "$check_result" | GREP 'Total objects: 0' ||
225 echo "$check_result" | GREP ' directory not found'; then
207226 echo CHECKPRESENT-FAILURE "$key"
208227 else
209228 # When the directory does not exist,
221240 # Note that it's not a failure to remove a
222241 # key that is not present.
223242 if remove_result=$(rclone delete --retries 1 "$LOC$key" 2>&1); then
224 echo REMOVE-SUCCESS "$key"
225 else
226 # rclone 1.29 used Failed to purge: Couldn't find directory:
243 echo REMOVE-SUCCESS "$key"
244 else
245 # rclone 1.29 used Failed to purge: Couldn't find directory:
227246 # rclone 1.30 used no such file or directory
228247 # rclone 1.33 uses directory not found
229 if echo $remove_result | grep " Failed to purge: Couldn't find directory: " >&2 ||
230 echo $remove_result | grep ' no such file or directory' ||
231 echo $remove_result | grep ' directory not found' >&2
232 then
248 if echo "$remove_result" | GREP " Failed to purge: Couldn't find directory: " ||
249 echo "$remove_result" | GREP ' no such file or directory' ||
250 echo "$remove_result" | GREP ' directory not found'
251 then
233252 echo REMOVE-SUCCESS "$key"
234 else
235 echo REMOVE-FAILURE "$key"
253 else
254 echo REMOVE-FAILURE "$key"
236255 fi
237256 fi
238257 ;;
242261 # to say that any other request is unsupported.
243262 echo UNSUPPORTED-REQUEST
244263 ;;
245 esac
264 esac
246265 done
247266
248267
0 #!/bin/bash
1
2 cd "$(mktemp -d "${TMPDIR:-/tmp}/garr-XXXXXXX")"
3
4 # recipe from https://stackoverflow.com/a/4024263/1265472
5 # sort -V seems to work on OSX yoh has access to.
6 verlte() {
7 [ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]
8 }
9
10 verlt() {
11 [ "$1" = "$2" ] && return 1 || verlte $1 $2
12 }
13
14
15 set -eux
16
17 # provide versioning information to possibly ease troubleshooting
18 git annex version
19 rclone --version
20
21 export HOME=$PWD
22 echo -e '[local]\ntype = local\nnounc =' > ~/.rclone.conf
23 # to pacify git/git-annex
24 git config --global user.name Me
25 git config --global user.email me@example.com
26 git config --global init.defaultBranch master
27
28 git_annex_version=$(git annex version | awk '/git-annex version:/{print $3;}')
29
30 # Prepare rclone remote local store
31 mkdir rclone-local
32 export RCLONE_PREFIX=$PWD/rclone-local
33
34 git-annex version
35 mkdir testrepo
36 cd testrepo
37 git init .
38 git-annex init
39 git-annex initremote GA-rclone-CI type=external externaltype=rclone target=local prefix=$RCLONE_PREFIX chunk=100MiB encryption=${GARR_TEST_ENCRYPTION:-shared} mac=HMACSHA512
40
41 # Rudimentary test, spaces in the filename must be ok, 0 length files should be ok
42 if verlte "10.20220525+git73" "$git_annex_version"; then
43 # Was fixed in 10.20220525-73-g13fc6a9b6
44 echo "I: Fixed git-annex $git_annex_version, adding empty file"
45 touch "test 0"
46 fi
47
48 echo 1 > "test 1"
49 git-annex add *
50 git-annex copy * --to GA-rclone-CI
51 git-annex drop *
52 git-annex get *
53
54 # Do a cycle with --debug to ensure that we are passing desired DEBUG output
55 git-annex --debug drop test\ 1 2>&1 | grep -q 'grep.*exited with rc='
56 git-annex --debug get test\ 1 2>/dev/null
57
58 # test copy/drop/get cycle with parallel execution and good number of files and spaces in the names, and duplicated content/keys
59 set +x
60 for f in `seq 1 20`; do echo "load $f" | tee "test-$f.dat" >| "test $f.dat"; done
61 set -x
62 git annex add -J5 --quiet .
63 git-annex copy -J5 --quiet . --to GA-rclone-CI
64 git-annex drop -J5 --quiet .
65 git-annex get -J5 --quiet .
66 git-annex drop --from GA-rclone-CI -J5 --quiet .
67
68 # annex testremote --fast
69 git-annex testremote GA-rclone-CI --fast