-- gitano.copycommand
--
-- Gitano repository copy commands
--
-- Copyright 2013-2017 Richard Maw <richard.maw@gmail.com>
-- 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 repository = require "gitano.repository"
local log = require "gitano.log"
local util = require "gitano.util"

local builtin_copy_short = "Copy a repository to a new path"

local builtin_copy_helptext = [[
usage: copy <oldrepo> <newrepo>

Copy a git repository locally. This is quicker than fetching the
old repository, creating the new one, then pushing to the new one.
]]

local function builtin_copy_validate(config, srcrepo, cmdline)
   if #cmdline ~= 3 then
      log.error("usage: copy <oldrepo> <newrepo>")
      return false
   end
   -- Check if source repository is nascent
   if srcrepo.is_nascent then
      log.error("Cannot copy a repository which does not exist")
      return false
   end
   -- Create the target repository object
   local tgtrepo, msg = repository.find(config, cmdline[3])
   if not tgtrepo then
      log.critical("Unable to locate repository.")
      log.critical("  * " .. (tostring(msg)))
      log.fatal("Cannot continue")
      return false
   end
   cmdline.tgtrepo = tgtrepo
   return true
end

local function builtin_copy_prep(config, srcrepo, cmdline, context)
   local ctx, action, reason
   -- Check 1, source repository can be read
   ctx = util.deep_copy(context)
   ctx.operation = "read"
   action, reason = srcrepo:run_lace(ctx)
   if action ~= "allow" then
      return action, reason
   end
   -- Check 2, target repository can be written to
   ctx = util.deep_copy(context)
   ctx.operation = "write"
   action, reason = cmdline.tgtrepo:run_lace(ctx)
   if action ~= "allow" then
      return action, reason
   end
   -- Check 3, target repository does not already exist
   -- We knew this for a while but failing earlier would leak its existence.
   if not cmdline.tgtrepo.is_nascent then
      log.error("Repository", cmdline.tgtrepo.name, "already exists")
      return "deny", "Repository already exists"
   end
   -- Check 4, target repository can be created
   ctx = util.deep_copy(context)
   ctx.operation = "createrepo"
   action, reason = cmdline.tgtrepo:run_lace(ctx)
   if action ~= "allow" then
      return action, reason
   end
   -- Able to read, create, and write; thus can copy
   return "allow", "Passed all checks, can copy"
end

local function builtin_copy_run(config, repo, cmdline, env)
   local ok, msg = repo:copy_to(cmdline.tgtrepo)
   if not ok then
      log.error(msg)
      return "exit", 1
   end
   log.state("Copied", cmdline[2], "to", cmdline[3])

   local tgtrepo, msg = repository.find(config, cmdline[3])
   if not tgtrepo then
      log.critical("Unable to locate repository.")
      log.critical("  * " .. (tostring(msg)))
      log.fatal("Cannot continue")
      return false
   end

   local owner = env["GITANO_USER"]
   log.chat("Setting repository owner to", owner)
   ok, msg = tgtrepo:conf_set_and_save("project.owner", owner,
                                       env.GITANO_USER, env.GITANO_ORIG_USER)
   if not ok then
      log.error(msg)
      return "exit", 1
   end
   log.chat("Running checks to ensure hooks etc are configured")
   ok, msg = tgtrepo:run_checks()
   if not ok then
      log.error(msg)
      return "exit", 1
   end
   log.state("Repository", tgtrepo.name,
             "copied ok.  Remember to configure rules etc.")

   return "exit", 0
end

local function register_commands(reg)
   assert(reg("copy", builtin_copy_short, builtin_copy_helptext,
              builtin_copy_validate, builtin_copy_prep, builtin_copy_run,
              true, false, false))
end

return {
   register = register_commands
}
