diff options
Diffstat (limited to 'plugins/rsync.lua')
-rw-r--r-- | plugins/rsync.lua | 105 |
1 files changed, 105 insertions, 0 deletions
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)) |