-- 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. -- -- Since the functionality is generically useful however, it is supported here -- in Gitano upstream. -- -- Copyright 2014-2017 Daniel Silverstone -- All rights reserved. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions -- are met: -- 1. Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- 2. Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution. -- 3. Neither the name of the author nor the names of their contributors -- may be used to endorse or promote products derived from this software -- without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -- ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -- SUCH DAMAGE. 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 or repo.is_nascent) and repopath ~= ""do gitano.log.error("Trying " .. repopath) repo, msg = gitano.repository.find(config, repopath) if not repo or repo.is_nascent 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 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 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, true, false, rsync_detect_repo))