blob: 84d2842073f386c4c0235a80845400ab07d577dd [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
import os
import shlex
import shutil
import subprocess
from .logger import logger, ctx
def default_bin(name, default):
assert(default)
env_name = "ARCHERY_{0}_BIN".format(default.upper())
return name if name else os.environ.get(env_name, default)
# Decorator running a command and returning stdout
class capture_stdout:
def __init__(self, strip=False, listify=False):
self.strip = strip
self.listify = listify
def __call__(self, f):
def strip_it(x):
return x.strip() if self.strip else x
def list_it(x):
return x.decode('utf-8').splitlines() if self.listify else x
def wrapper(*argv, **kwargs):
# Ensure stdout is captured
kwargs["stdout"] = subprocess.PIPE
return list_it(strip_it(f(*argv, **kwargs).stdout))
return wrapper
class Command:
""" A runnable command.
Class inheriting from the Command class must provide the bin
property/attribute.
"""
def __init__(self, bin):
self.bin = bin
def run(self, *argv, **kwargs):
assert hasattr(self, "bin")
invocation = shlex.split(self.bin)
invocation.extend(argv)
for key in ["stdout", "stderr"]:
# Preserve caller intention, otherwise silence
if key not in kwargs and ctx.quiet:
kwargs[key] = subprocess.PIPE
# Prefer safe by default
if "check" not in kwargs:
kwargs["check"] = True
logger.debug("Executing `{}`".format(invocation))
return subprocess.run(invocation, **kwargs)
@property
def available(self):
""" Indicate if the command binary is found in PATH. """
binary = shlex.split(self.bin)[0]
return shutil.which(binary) is not None
def __call__(self, *argv, **kwargs):
return self.run(*argv, **kwargs)
class CommandStackMixin:
def run(self, *argv, **kwargs):
stacked_args = self.argv + argv
return super(CommandStackMixin, self).run(*stacked_args, **kwargs)
class Bash(Command):
def __init__(self, bash_bin=None):
self.bin = default_bin(bash_bin, "bash")