summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--plugins/rsync.lua105
2 files changed, 107 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 4a94015..cab0162 100644
--- a/Makefile
+++ b/Makefile
@@ -61,7 +61,8 @@ SKEL_FILES := gitano-admin/rules/selfchecks.lace \
MAN1S := gitano-setup.1
-PLUGINS :=
+
+PLUGINS := rsync.lua
MOD_DIRS := gitano
MOD_FILES := $(patsubst %,%.lua,$(subst .,/,$(MODS)))
diff --git a/plugins/rsync.lua b/plugins/rsync.lua
new file mode 100644
index 0000000..4c07233
--- /dev/null
+++ b/plugins/rsync.lua
@@ -0,0 +1,105 @@
+-- rsync Plugin
+--
+-- This plugin is part of Trove. Trove is Codethink's Baserock central server
+-- and uses Gitano as the Git service. This plugin adds support to Trove for
+-- supporting 'rsync' as a command in Gitano. This means that every repository
+-- has an rsync tree attached to it which can be used by remote ends sshing
+-- into the Trove.
+--
+-- Copyright 2014 Daniel Silverstone <daniel.silverstone@codethink.co.uk>
+
+local gitano = require "gitano"
+
+local sp = require "luxio.subprocess"
+
+local rsync_short_help = "An rsync endpoint within Gitano"
+local rsync_helptext = [[
+Users are not expected to use this command directly, but instead to
+instruct their local rsync to use a remote of user@gitanohost:reponame
+when pushing or pulling rsync content.
+]]
+
+local function rsync_detect_repo(config, cmdline)
+ local repo, msg
+ local repopath = cmdline[#cmdline]
+
+ if #cmdline < 4 then
+ -- Validate will fail with a nice error, give up now
+ return nil, cmdline
+ end
+
+ if repopath:match("^/") then
+ repopath = repopath:sub(2)
+ end
+
+ local origpath = repopath
+
+ -- Basically, while there's still something to the repopath
+ -- and we've not yet found a repo, strip an element and try again...
+ while not repo and repopath ~= ""do
+ repo, msg = gitano.repository.find(config, repopath)
+ if not repo then
+ repopath = repopath:match("^(.*)/[^/]*$") or ""
+ end
+ end
+
+ if not repo then
+ gitano.log.error("Unable to find a repository for " .. cmdline[#cmdline])
+ return nil, nil
+ end
+
+ if repo.is_nascent then
+ gitano.log.error("Repository " .. repo.name .. " is nascent")
+ gitano.log.error("Cannot use rsync command with nascent repositories")
+ return nil, nil
+ end
+
+ -- Okay, so repopath represented a repository, let's convert the path
+ -- into something which we can work with...
+ cmdline[#cmdline] = repo:fs_path() .. "/rsync" .. origpath:sub(#repopath+1)
+ if origpath:match("/$") and not (cmdline[#cmdline]):match("/$") then
+ cmdline[#cmdline] = cmdline[#cmdline] .. "/"
+ end
+
+ gitano.util.mkdir_p(repo:fs_path() .. "/rsync")
+
+ -- And give back the repo for ruleset running and the cmdline for the rsync
+
+ gitano.log.error(cmdline[#cmdline])
+
+ return repo, cmdline
+end
+
+local function rsync_validate(config, repo, cmdline)
+ if #cmdline < 4 then
+ gitano.log.error("usage: rsync --server <rsync arguments> . <server-side-path>")
+ return false
+ end
+ if cmdline[2] ~= "--server" then
+ gitano.log.error("Second cmdline element must always be --server")
+ return false
+ end
+ return true
+end
+
+local function rsync_prep(config, repo, cmdline, context)
+ if cmdline[3] == "--sender" then
+ context.operation = "read"
+ else
+ context.operation = "write"
+ end
+ return config.repo:run_lace(context)
+end
+
+local function rsync_run(config, repo, cmdline, env)
+ local cmdcopy = {env=env}
+ for i = 1, #cmdline do cmdcopy[i] = cmdline[i] end
+ local proc = sp.spawn(cmdcopy)
+ return proc:wait()
+end
+
+assert(gitano.command.register("rsync",
+ rsync_short_help, rsync_helptext,
+ rsync_validate, rsync_prep, rsync_run,
+ true, false, false,
+ rsync_detect_repo))