From 115c62b1d3e0b98020ec4493ce1d9de512a4995a Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Mon, 10 Mar 2014 16:35:58 +0000 Subject: Support for rsync in Troves In order to support ingesting of binary artifacts, we are proposing the use of `git-fat` which is a content filter which uses rsync to store the binary artifacts. That requires an access controlled binary artifact repository, so we take advantage of Gitano's ACLs and associate an optional rsync repository with every git repository on the server. By placing it inside the git repository, all of gitano's destroy and graveyard behaviour automatically works with the new rsync content. Signed-off-by: Daniel Silverstone --- Makefile | 3 +- plugins/rsync.lua | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 plugins/rsync.lua 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 + +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 . ") + 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)) -- cgit v1.2.1