Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ debian/.debhelper
obj-x86_64-linux-gnu/

.idea

systemd/grive-timer\@.service

systemd/grive-changes\@.service
22 changes: 16 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,22 +80,32 @@ Google Drive clients on other platforms (it misses the almost instantious
download of changed files in the google drive).

Grive installs such a basic solution which uses inotify-tools together with
systemd timer and services. You can enable it for a folder in your `$HOME`
directory (in this case the `$HOME/google-drive`):
systemd timer and services. You can enable it for a directory. The name can
either be an absolute path or one relative to `${HOME}`. Let's use
`${HOME}/google-drive` (so relative: `google-drive`):

First install the `inotify-tools` (seems to be named like that in all major distros):
test that it works by calling `inotifywait -h`.

Prepare a Google Drive folder in your $HOME directory with `grive -a`.
Prepare a Google Drive folder in your `${HOME}` directory with:

```bash
# 'google-drive' is the name of your Google Drive folder in your $HOME directory
mkdir -p ${HOME}/google-drive
cd ${HOME}/google-drive
grive -a
```

Afterwards, the scheduled sync can be enabled via:

```bash
# 'google-drive' is in this case the relative name of your Google Drive folder
# in your ${HOME} directory
systemctl --user enable grive@$(systemd-escape google-drive).service
systemctl --user start grive@$(systemd-escape google-drive).service
```

You can enable and start this unit for multiple folders in your `$HOME`
directory if you need to sync with multiple google accounts.
You can enable and start this unit for multiple folders if you need to sync
with multiple google accounts.

You can also only enable the time based syncing or the changes based syncing
by only directly enabling and starting the corresponding unit:
Expand Down
53 changes: 35 additions & 18 deletions systemd/grive-sync.sh
Original file line number Diff line number Diff line change
@@ -1,24 +1,42 @@
#!/bin/bash

# Copyright (C) 2009 Przemyslaw Pawelczyk <[email protected]>
# (C) 2017 Jan Schulz <[email protected]>
# (C) 2017 Jan Katins <[email protected]>
##
## This script is licensed under the terms of the MIT license.
## https://opensource.org/licenses/MIT

# Fail on all errors
set -o pipefail

abort() {
echo >&2 "${*}";
exit 1;
}

check_command(){
type ${1} >/dev/null 2>&1 || abort "I require '${1}' command but it's not available. Aborting."
}

# We always start in the current users home directory so that names always start there
cd ~
cd ${HOME} || abort "Cannot switch to HOME dir: ${HOME}"

check_command flock
check_command timeout
check_command inotifywait
check_command ping

### ARGUMENT PARSING ###
SCRIPT="${0}"
DIRECTORY=$(systemd-escape --unescape -- "$2")
DIRECTORY=$(systemd-escape --unescape -- "${2}")

# Defaults:
# let grive run for 20min and then abort, assuming that it hangs. This might be wrong for big syncs,
# but we will restart...
GRIVE_TIMEOUT="${GRIVE_TIMEOUT:-20m}"

if [[ -z "$DIRECTORY" ]] || [[ ! -d "$DIRECTORY" ]] ; then
echo "Need a directory name in the current users home directory as second argument. Aborting."
if [[ -z "${DIRECTORY}" ]] || [[ ! -d "${DIRECTORY}" ]] ; then
echo "Need a directory name (absolute or relative to the current users home directory) as second argument. Got ${DIRECTORY}. Aborting."
exit 1
fi

Expand All @@ -39,7 +57,7 @@ fi


### LOCKFILE BOILERPLATE ###
LOCKFILE="/run/user/"$(id -u)"/"$(basename "$0")"_"${DIRECTORY//\//_}""
LOCKFILE="/run/user/$(id -u)/$(basename "$0")_${DIRECTORY//\//_}"
LOCKFD=99

# PRIVATE
Expand All @@ -57,13 +75,13 @@ shlock() { _lock s; } # obtain a shared lock
unlock() { _lock u; } # drop a lock

### SYNC SCRIPT ###
# Idea: only let one script run, but if the sync script is called a second time
# Idea: only let one script run, but if the sync script is called a second time
# make sure we sync a second time, too

sync_directory() {
_directory="${1}"

reset_timer_and_exit() { echo "Retriggered google drive sync ('${_directory}')" && touch -m $LOCKFILE && exit; }
reset_timer_and_exit() { echo "Retriggered google drive sync ('${_directory}')" && touch -m "${LOCKFILE}" && exit; }

exlock_now || reset_timer_and_exit

Expand All @@ -79,11 +97,12 @@ sync_directory() {
TIME_AT_START=0
TIME_AT_END=1
while [[ "${TIME_AT_START}" -lt "${TIME_AT_END}" ]]; do
echo "Syncing '${_directory}'..."
TIME_AT_START="$(stat -c %Y "$LOCKFILE")"
grive -p "${_directory}" 2>&1 | grep -v -E "^Reading local directories$|^Reading remote server file list$|^Synchronizing files$|^Finished!$"
TIME_AT_END="$(stat -c %Y "$LOCKFILE")"
echo "Sync of '${_directory}' done."
echo "Syncing '${_directory}'..."
TIME_AT_START="$(stat -c %Y "${LOCKFILE}")"
# brace group: only error in case grive fails or hung, not because grep filtered out everything when nothing needed to be synced...
timeout "${GRIVE_TIMEOUT}" grive -p "${_directory}" 2>&1 | { grep -v -E "^Reading local directories$|^Reading remote server file list$|^Synchronizing files$|^Finished!$" || true ; }
TIME_AT_END="$(stat -c %Y "${LOCKFILE}")"
echo "Sync of '${_directory}' done."
done

# always exit ok, so that we never go into a wrong systemd state
Expand All @@ -97,15 +116,13 @@ sync_directory() {
listen_directory() {
_directory="${1}"

type inotifywait >/dev/null 2>&1 || { echo >&2 "I require inotifywait but it's not installed. Aborting."; exit 1; }

echo "Listening for changes in '${_directory}'"

while true #run indefinitely
do
do
# Use a different call to not need to change exit into return
inotifywait -q -r -e modify,attrib,close_write,move,create,delete --exclude ".grive_state|.grive" "${_directory}" > /dev/null 2>&1 && ${SCRIPT} sync $(systemd-escape "${_directory}")
#echo ${SCRIPT} "${_directory}"
# Ignore errors
inotifywait -q -r -e modify,attrib,close_write,move,create,delete --exclude ".grive_state|.grive" "${_directory}" > /dev/null 2>&1 && ${SCRIPT} sync "$(systemd-escape "${_directory}")" || continue
done

# always exit ok, so that we never go into a wrong systemd state
Expand Down
1 change: 1 addition & 0 deletions systemd/[email protected]
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[Unit]
Description=Google drive sync (main)
Requires=grive-timer@%i.timer grive-changes@%i.service
PropagatesStopTo=grive-timer@%i.timer grive-changes@%i.service

# dummy service
[Service]
Expand Down