sync/projectutil.py (75 lines of code) (raw):
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""Utility functions for performing various Git functionality."""
import logging
import os
import subprocess
import types
import newrelic
from sync import repos
from sync.env import Environment
from typing import Any, Callable, Dict, List, Optional, Tuple
env = Environment()
logger = logging.getLogger(__name__)
class Command:
"""Helper class for running git commands"""
def __init__(self, name, path):
"""
:param name: name of the command to call
:param path: the full path to the command.
"""
self.name = name
self.path = path
self.logger = logger
def get(self, *subcommand: str, **opts: Any) -> bytes:
""" Run the specified subcommand with `command` and return the result.
eg. r = mach.get('test-info', 'path/to/test')
"""
assert subcommand and len(subcommand)
command = [os.path.join(self.path, self.name)] + list(subcommand)
logger.info("Running command:\n %s" % " ".join(command))
try:
return subprocess.check_output(command, cwd=self.path, **opts)
except subprocess.CalledProcessError as e:
newrelic.agent.record_exception(params={
"command": self.name,
"exit_code": e.returncode,
"command_output": e.output})
raise e
def __getattr__(self, name: str) -> Callable:
if name.endswith("_"):
name = name[:-1]
def call(self: Any, *args: str, **kwargs: Any) -> str:
return self.get(name.replace("_", "-"), *args, **kwargs)
call.__name__ = name
args: Tuple[Any, ...] = (call, self)
self.__dict__[name] = types.MethodType(*args)
return self.__dict__[name]
class Mach(Command):
def __init__(self, path):
Command.__init__(self, "mach", path)
def get(self, *subcommand: str, **opts: Any) -> bytes:
state_path = repos.Gecko.get_state_path(env.config, self.path)
if "env" in opts:
cmd_env = opts["env"]
else:
cmd_env = os.environ.copy()
cmd_env["MOZBUILD_STATE_PATH"] = state_path
opts["env"] = cmd_env
return super().get(*subcommand, **opts)
class WPT(Command):
def __init__(self, path):
Command.__init__(self, "wpt", path)
def create_mock(name):
class MockCommand(Command):
_data = {}
_log = []
def __init__(self, path: Optional[str]) -> None:
self.name = name
self.path = path
@classmethod
def set_data(cls, command: str, value: str) -> None:
cls._data[command] = value
@classmethod
def get_log(cls) -> List[Dict[str, Any]]:
return cls._log
def get(self, *args: str, **kwargs: Any) -> bytes:
data = self._data.get(args[0], b"")
if callable(data):
data = data(*args[1:], **kwargs)
self._log.append({"command": self.name,
"cwd": self.path,
"args": args,
"kwargs": kwargs,
"rv": data})
return data
return MockCommand