# -*- cpy-indent-level: 4; indent-tabs-mode: nil -*-
# ex: set expandtab softtabstop=4 shiftwidth=4:
#
# Copyright (C) 2010,2011,2012,2013,2014,2015  Contributor
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Contains the logic for `aq publish`."""

import os
import re
from tempfile import mkstemp, mkdtemp
from base64 import b64decode

from aquilon.worker.broker import BrokerCommand  # pylint: disable=W0611
from aquilon.exceptions_ import ProcessException, ArgumentError
from aquilon.aqdb.model import Sandbox
from aquilon.worker.dbwrappers.branch import force_my_sandbox
from aquilon.worker.processes import run_git, sync_domain
from aquilon.worker.logger import CLIENT_INFO
from aquilon.utils import write_file, remove_file, remove_dir


class CommandPublish(BrokerCommand):

    required_parameters = ["bundle"]

    def render(self, session, logger, dbuser, branch, sandbox, bundle, sync,
               rebase, **arguments):
        if sandbox:
            # pylint: disable=W0612
            sandbox, dbauthor = force_my_sandbox(session, dbuser, sandbox)
            dbsandbox = Sandbox.get_unique(session, sandbox, compel=True)
        elif branch:
            dbsandbox = Sandbox.get_unique(session, branch, compel=True)

        handle, filename = mkstemp()  # pylint: disable=W0612
        contents = b64decode(bundle)
        write_file(filename, contents, logger=logger)

        if sync and not dbsandbox.is_sync_valid and dbsandbox.trackers:
            # FIXME: Maybe raise an ArgumentError and request that the
            # command run with --nosync?  Maybe provide a --validate flag?
            # For now, we just auto-flip anyway (below) making the point moot.
            pass
        if not dbsandbox.is_sync_valid:
            dbsandbox.is_sync_valid = True

        if rebase and dbsandbox.trackers:
            raise ArgumentError("{0} has trackers, rebasing is not allowed."
                                .format(dbsandbox))

        # Most of the logic here is duplicated in deploy
        kingdir = self.config.get("broker", "kingdir")
        rundir = self.config.get("broker", "rundir")

        tempdir = mkdtemp(prefix="publish_", suffix="_%s" % dbsandbox.name,
                          dir=rundir)
        try:
            run_git(["clone", "--shared", "--branch", dbsandbox.name, "--",
                     kingdir, dbsandbox.name],
                    path=tempdir, logger=logger)
            temprepo = os.path.join(tempdir, dbsandbox.name)
            run_git(["bundle", "verify", filename],
                    path=temprepo, logger=logger)
            ref = "HEAD:%s" % (dbsandbox.name)
            command = ["pull", filename, ref]
            if rebase:
                command.append("--force")
            run_git(command, path=temprepo, logger=logger,
                    stream_level=CLIENT_INFO)

            # Using --force above allows rewriting any history, even before the
            # start of the sandbox. We don't want to allow that, so verify that
            # the starting point of the sandbox is still part of its history.
            if rebase:
                filterre = re.compile('^' + dbsandbox.base_commit + '$')
                try:
                    found = run_git(['rev-list', dbsandbox.name],
                                    filterre=filterre, path=temprepo,
                                    logger=logger)
                except ProcessException as pe:
                    if pe.code != 128:
                        raise
                    else:
                        found = False

                if not found:
                    raise ArgumentError("The published branch no longer "
                                        "contains commit %s it was branched "
                                        "from." % dbsandbox.base_commit)

            # FIXME: Run tests before pushing back to template-king
            if rebase:
                target_ref = "+" + dbsandbox.name
            else:
                target_ref = dbsandbox.name
            run_git(["push", "origin", target_ref],
                    path=temprepo, logger=logger)
        except ProcessException as e:
            raise ArgumentError("\n%s%s" % (e.out, e.err))
        finally:
            remove_file(filename, logger=logger)
            remove_dir(tempdir, logger=logger)

        client_command = "git fetch"
        if not sync or not dbsandbox.autosync:
            return client_command

        for domain in dbsandbox.trackers:
            if not domain.autosync:
                continue
            try:
                sync_domain(domain, logger=logger)
            except ProcessException as e:
                logger.warning("Error syncing domain %s: %s" % (domain.name, e))

        return client_command

@@ -786,23 +786,34 @@
  import 
-mkstemp
+NamedTemporaryFile
 , mkdtem
@@ -1215,33 +1215,8 @@
 port
- write_file, remove_file,
  rem
@@ -1719,162 +1719,8 @@
 e)%0A%0A
-        handle, filename = mkstemp()  # pylint: disable=W0612%0A        contents = b64decode(bundle)%0A        write_file(filename, contents, logger=logger)%0A%0A
     
@@ -2451,16 +2451,121 @@
 ndir%22)%0A%0A
+        tmpfile = NamedTemporaryFile()%0A        tmpfile.write(b64decode(bundle))%0A        tmpfile.flush()%0A%0A
         
@@ -2957,20 +2957,24 @@
 erify%22, 
+tmp
 file
+.
 name%5D,%0A 
@@ -3100,20 +3100,24 @@
 %22pull%22, 
+tmp
 file
+.
 name, re
@@ -4704,43 +4704,22 @@
     
-remove_file(filename, logger=logger
+tmpfile.close(
 )%0A  

Fix a file descriptor leak in 'aq publish'