# (Be in -*- python -*- mode.)
#
# ====================================================================
# Copyright (c) 2000-2008 CollabNet.  All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution.  The terms
# are also available at http://subversion.tigris.org/license-1.html.
# If newer versions of this license are posted there, you may use a
# newer version instead, at your option.
#
# This software consists of voluntary contributions made by many
# individuals.  For exact contribution history, see the revision
# history and logs, available at http://cvs2svn.tigris.org/.
# ====================================================================

"""This module contains generic utilities used by cvs2svn."""


import subprocess

from cvs2hg_lib.common import FatalError
from cvs2hg_lib.common import CommandError


def call_command(command, **kw):
    """Call the specified command, checking that it exits successfully.

    Raise a FatalError if the command cannot be executed, or if it exits
    with a non-zero exit code.  Pass KW as keyword arguments to
    subprocess.call()."""

    try:
        retcode = subprocess.call(command, **kw)
        if retcode < 0:
            raise FatalError(
                'Command terminated by signal %d: "%s"'
                % (-retcode, ' '.join(command),)
                )
        elif retcode > 0:
            raise FatalError(
                'Command failed with return code %d: "%s"'
                % (retcode, ' '.join(command),)
                )
    except OSError as e:
        raise FatalError(
            'Command execution failed (%s): "%s"'
            % (e, ' '.join(command),)
            )


class CommandFailedException(Exception):
    """Exception raised if check_command_runs() fails."""

    pass


def check_command_runs(cmd, cmdname):
    """Check whether the command CMD can be executed without errors.

    CMD is a list or string, as accepted by subprocess.Popen().  CMDNAME
    is the name of the command as it should be included in exception
    error messages.

    This function checks three things: (1) the command can be run
    without throwing an OSError; (2) it exits with status=0; (3) it
    doesn't output anything to stderr.  If any of these conditions is
    not met, raise a CommandFailedException describing the problem."""

    try:
        pipe = subprocess.Popen(
            cmd,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            )
    except OSError as e:
        raise CommandFailedException('error executing %s: %s' % (cmdname, e,))
    pipe.stdin.close()
    pipe.stdout.read()
    errmsg = pipe.stderr.read()
    status = pipe.wait()
    if status or errmsg:
        msg = 'error executing %s: status %s' % (cmdname, status,)
        if errmsg:
            msg += ', error output:\n%s' % (errmsg,)
        raise CommandFailedException(msg)


def get_command_output(command):
    """Run COMMAND and return its stdout.

    COMMAND is a list of strings.  Run the command and return its stdout
    as a string.  If the command exits with a nonzero return code or
    writes something to stderr, raise a CommandError."""

    """A file-like object from which revision contents can be read."""

    pipe = subprocess.Popen(
        command,
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        )
    (stdout, stderr) = pipe.communicate()
    if pipe.returncode or stderr:
        raise CommandError(' '.join(command), pipe.returncode, stderr)
    return stdout


