Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(492)

Unified Diff: scripts/run_cmd.py

Issue 648353002: Remove Skia's forked buildbot code (Closed) Base URL: https://skia.googlesource.com/buildbot.git@master
Patch Set: Address comment Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « scripts/restart_masters.py ('k') | scripts/run_on_all_slave_hosts.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: scripts/run_cmd.py
diff --git a/scripts/run_cmd.py b/scripts/run_cmd.py
deleted file mode 100755
index c0d7d05a249cf843659407479bf025610f5aedcf..0000000000000000000000000000000000000000
--- a/scripts/run_cmd.py
+++ /dev/null
@@ -1,461 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-
-"""Run a command and report its results in machine-readable format."""
-
-
-import collections
-import optparse
-import os
-import pickle
-import pprint
-import socket
-import subprocess
-import sys
-import traceback
-
-buildbot_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
- os.pardir))
-sys.path.append(os.path.join(buildbot_path))
-
-from site_config import slave_hosts_cfg
-
-
-class BaseCommandResults(object):
- """Base class for CommandResults classes."""
-
- # We print this string before and after the important output from the command.
- # This makes it easy to ignore output from SSH, shells, etc.
- BOOKEND_STR = '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'
-
- def encode(self):
- """Convert the results into a machine-readable string.
-
- Returns:
- A hex-encoded string, bookended by BOOKEND_STR for easy parsing.
- """
- raise NotImplementedError()
-
- @staticmethod
- def decode(results_str):
- """Convert a machine-readable string into a CommandResults instance.
-
- Args:
- results_str: string; output from "run" or one of its siblings.
- Returns:
- A dictionary of results.
- """
- decoded_dict = pickle.loads(
- results_str.split(BaseCommandResults.BOOKEND_STR)[1].decode('hex'))
- errors = []
- # First, try to interpret the dict as SingleCommandResults.
- try:
- # This will fail unless decoded_dict has the following set of keys:
- # ('returncode', 'stdout', 'stderr')
- return SingleCommandResults(**decoded_dict)
- except TypeError:
- errors.append(traceback.format_exc())
- # Next, try to interpret the dict as MultiCommandResults.
- try:
- results_dict = {}
- for (slavename, results) in decoded_dict.iteritems():
- results_dict[slavename] = BaseCommandResults.decode(results)
- return MultiCommandResults(results_dict)
- except Exception:
- errors.append(traceback.format_exc())
- raise Exception('Unable to decode CommandResults from dict:\n\n%s\n%s'
- % ('\n'.join(errors), decoded_dict))
-
- def print_results(self, pretty=False):
- """Print the results of a command.
-
- Args:
- pretty: bool; whether or not to print in human-readable format.
- """
- if pretty:
- print pprint.pformat(self.__dict__)
- else:
- print self.encode()
-
-
-class SingleCommandResults(collections.namedtuple('CommandResults_tuple',
- 'stdout, stderr, returncode'),
- BaseCommandResults):
- """Results for a single command. Properties: stdout, stderr, and returncode"""
-
- def encode(self):
- """Convert the results into a machine-readable string.
-
- Returns:
- A hex-encoded string, bookended by BOOKEND_STR for easy parsing.
- """
- return (BaseCommandResults.BOOKEND_STR +
- pickle.dumps(self.__dict__).encode('hex') +
- BaseCommandResults.BOOKEND_STR)
-
- @staticmethod
- def make(stdout='', stderr='', returncode=1):
- """Create CommandResults for a command.
-
- Args:
- stdout: string; stdout from a command.
- stderr: string; stderr from a command.
- returncode: string; return code of a command.
- """
- return SingleCommandResults(stdout=stdout,
- stderr=stderr,
- returncode=returncode)
-
- @property
- def __dict__(self):
- """Return a dictionary representation of this CommandResults instance.
-
- Since collections.NamedTuple.__dict__ returns an OrderedDict, we have to
- create this wrapper to get a normal dict.
- """
- return dict(self._asdict())
-
-
-class MultiCommandResults(BaseCommandResults):
- """Encapsulates CommandResults for multiple buildslaves or hosts.
-
- MultiCommandResults can form tree structures whose leaves are instances of
- SingleComamandResults and interior nodes are instances of MultiCommandResults:
-
- MultiCommandResults({
- 'remote_slave_host_name': MultiCommandResults({
- 'slave_name': SingleCommandResults,
- 'slave_name2': SingleCommandResults,
- }),
- 'local_slave_name': SingleCommandResults,
- })
- """
-
- def __init__(self, results):
- """Instantiate the MultiCommandResults.
-
- Args:
- results: dict whose keys are slavenames or slave host names and values
- are instances of a BaseCommandResults subclass.
- """
- super(MultiCommandResults, self).__init__()
- self._dict = {}
- for (slavename, result) in results.iteritems():
- if not issubclass(result.__class__, BaseCommandResults):
- raise ValueError('%s is not a subclass of BaseCommandResults.'
- % result.__class__)
- self._dict[slavename] = result
-
- def __getitem__(self, key):
- return self._dict[key]
-
- def __iter__(self):
- return self._dict.__iter__()
-
- def __len__(self):
- return self._dict.__len__()
-
- def iteritems(self):
- return self._dict.iteritems()
-
- def iterkeys(self):
- return self._dict.iterkeys()
-
- def encode(self):
- """Convert the results into a machine-readable string.
-
- Returns:
- A hex-encoded string, bookended by BOOKEND_STR for easy parsing.
- """
- encoded_dict = dict([(key, value.encode())
- for (key, value) in self._dict.iteritems()])
- return (BaseCommandResults.BOOKEND_STR +
- pickle.dumps(encoded_dict).encode('hex') +
- BaseCommandResults.BOOKEND_STR)
-
- @property
- def __dict__(self):
- return dict([(key, value.__dict__)
- for (key, value) in self._dict.iteritems()])
-
-
-class ResolvableCommandElement(object):
- """Base class for elements of commands which have different string values
- depending on the properties of the host."""
-
- def resolve(self, slave_host_name):
- """Resolve this ResolvableCommandElement as appropriate.
-
- Args:
- slave_host_name: string; name of the slave host.
- Returns:
- string whose value depends on the given slave_host_name in some way.
- """
- raise NotImplementedError
-
-
-class ResolvablePath(ResolvableCommandElement):
- """Represents a path."""
-
- def __init__(self, *path_elems):
- """Instantiate this ResolvablePath.
-
- Args:
- path_elems: strings or ResolvableCommandElements which will be joined to
- form a path.
- """
- super(ResolvablePath, self).__init__()
- self._path_elems = list(path_elems)
-
- def resolve(self, slave_host_name):
- """Resolve this ResolvablePath as appropriate.
-
- Args:
- slave_host_name: string; name of the slave host.
- Returns:
- string whose value depends on the given slave_host_name in some way.
- """
- host_data = slave_hosts_cfg.get_slave_host_config(slave_host_name)
- fixed_path_elems = _fixup_cmd(self._path_elems, slave_host_name)
- return host_data.path_module.join(*fixed_path_elems)
-
-
-def _fixup_cmd(cmd, slave_host_name):
- """Resolve the command into a list of strings.
-
- Args:
- cmd: list containing strings or ResolvableCommandElements.
- slave_host_name: string; the name of the relevant slave host machine.
- """
- new_cmd = []
- for elem in cmd:
- if isinstance(elem, ResolvableCommandElement):
- resolved_elem = elem.resolve(slave_host_name)
- new_cmd.append(resolved_elem)
- else:
- new_cmd.append(elem)
- return new_cmd
-
-
-def _launch_cmd(cmd, cwd=None):
- """Launch the given command. Non-blocking.
-
- Args:
- cmd: list of strings; command to run.
- cwd: working directory in which to run the process. Defaults to the root
- of the buildbot checkout containing this file.
- Returns:
- subprocess.Popen instance.
- """
- if not cwd:
- cwd = buildbot_path
- return subprocess.Popen(cmd, shell=False, cwd=cwd, stderr=subprocess.PIPE,
- stdout=subprocess.PIPE)
-
-
-def _get_result(popen):
- """Get the results from a running process. Blocks until the process completes.
-
- Args:
- popen: subprocess.Popen instance.
- Returns:
- CommandResults instance, decoded from the results of the process.
- """
- stdout, stderr = popen.communicate()
- try:
- return BaseCommandResults.decode(stdout)
- except Exception:
- pass
- return SingleCommandResults.make(stdout=stdout,
- stderr=stderr,
- returncode=popen.returncode)
-
-
-def run(cmd):
- """Run the command, block until it completes, and return a results dictionary.
-
- Args:
- cmd: string or list of strings; the command to run.
- Returns:
- CommandResults instance, decoded from the results of the command.
- """
- try:
- proc = _launch_cmd(cmd)
- except OSError as e:
- return SingleCommandResults.make(stderr=str(e))
- return _get_result(proc)
-
-
-def run_on_local_slaves(cmd):
- """Run the command on each local buildslave, blocking until completion.
-
- Args:
- cmd: list of strings; the command to run.
- Returns:
- MultiCommandResults instance containing the results of the command on each
- of the local slaves.
- """
- slave_host = slave_hosts_cfg.get_slave_host_config(socket.gethostname())
- slaves = slave_host.slaves
- results = {}
- procs = []
- for (slave, _) in slaves:
- try:
- proc = _launch_cmd(cmd, cwd=os.path.join(buildbot_path, slave,
- 'buildbot'))
- procs.append((slave, proc))
- except OSError as e:
- results[slave] = SingleCommandResults.make(stderr=str(e))
-
- for slavename, proc in procs:
- results[slavename] = _get_result(proc)
-
- return MultiCommandResults(results)
-
-
-def _launch_on_remote_host(slave_host_name, cmd):
- """Launch the command on a remote slave host machine. Non-blocking.
-
- Args:
- slave_host_name: string; name of the slave host machine.
- cmd: list of strings; command to run.
- Returns:
- subprocess.Popen instance.
- """
- host = slave_hosts_cfg.SLAVE_HOSTS[slave_host_name]
- login_cmd = host.login_cmd
- if not login_cmd:
- raise ValueError('%s does not have a remote login procedure defined in '
- 'slave_hosts_cfg.py.' % slave_host_name)
- path_to_buildbot = host.path_module.join(*host.path_to_buildbot)
- path_to_run_cmd = host.path_module.join(path_to_buildbot, 'scripts',
- 'run_cmd.py')
- return _launch_cmd(login_cmd + ['python', path_to_run_cmd] +
- _fixup_cmd(cmd, slave_host_name))
-
-
-def run_on_remote_host(slave_host_name, cmd):
- """Run a command on a remote slave host machine, blocking until completion.
-
- Args:
- slave_host_name: string; name of the slave host machine.
- cmd: list of strings or ResolvableCommandElements; the command to run.
- Returns:
- CommandResults instance containing the results of the command.
- """
- proc = _launch_on_remote_host(slave_host_name, cmd)
- return _get_result(proc)
-
-
-def _get_remote_slaves_cmd(cmd):
- """Build a command which runs the command on all slaves on a remote host.
-
- Args:
- cmd: list of strings or ResolvableCommandElements; the command to run.
- Returns:
- list of strings or ResolvableCommandElements; a command which results in
- the given command being run on all of the slaves on the remote host.
- """
- return ['python', ResolvablePath('scripts', 'run_on_local_slaves.py')] + cmd
-
-
-def run_on_remote_slaves(slave_host_name, cmd):
- """Run a command on each buildslave on a remote slave host machine, blocking
- until completion.
-
- Args:
- slave_host_name: string; name of the slave host machine.
- cmd: list of strings or ResolvableCommandElements; the command to run.
- Returns:
- MultiCommandResults instance with results from each slave on the remote
- host.
- """
- proc = _launch_on_remote_host(slave_host_name, _get_remote_slaves_cmd(cmd))
- return _get_result(proc)
-
-
-def run_on_all_slave_hosts(cmd):
- """Run the given command on all slave hosts, blocking until all complete.
-
- Args:
- cmd: list of strings or ResolvableCommandElements; the command to run.
- Returns:
- MultiCommandResults instance with results from each remote slave host.
- """
- results = {}
- procs = []
-
- for hostname in slave_hosts_cfg.SLAVE_HOSTS.iterkeys():
- if not slave_hosts_cfg.SLAVE_HOSTS[hostname].remote_access:
- continue
- if not slave_hosts_cfg.SLAVE_HOSTS[hostname].login_cmd:
- results.update({
- hostname: SingleCommandResults.make(stderr='No procedure for login.'),
- })
- else:
- procs.append((hostname, _launch_on_remote_host(hostname, cmd)))
-
- for slavename, proc in procs:
- results[slavename] = _get_result(proc)
-
- return MultiCommandResults(results)
-
-
-def run_on_all_slaves_on_all_hosts(cmd):
- """Run the given command on all slaves on all hosts. Blocks until completion.
-
- Args:
- cmd: list of strings or ResolvableCommandElements; the command to run.
- Returns:
- MultiCommandResults instance with results from each slave on each remote
- slave host.
- """
- return run_on_all_slave_hosts(_get_remote_slaves_cmd(cmd))
-
-
-def parse_args(positional_args=None):
- """Common argument parser for scripts using this module.
-
- Args:
- positional_args: optional list of strings; extra positional arguments to
- the script.
- """
- parser = optparse.OptionParser()
- parser.disable_interspersed_args()
- parser.add_option('-p', '--pretty', action='store_true', dest='pretty',
- help='Print output in a human-readable form.')
-
- # Fixup the usage message to include the positional args.
- cmd = 'cmd'
- all_positional_args = (positional_args or []) + [cmd]
- usage = parser.get_usage().rstrip()
- for arg in all_positional_args:
- usage += ' ' + arg
- parser.set_usage(usage)
-
- options, args = parser.parse_args()
-
- # Set positional arguments.
- for positional_arg in positional_args or []:
- try:
- setattr(options, positional_arg, args[0])
- except IndexError:
- parser.print_usage()
- sys.exit(1)
- args = args[1:]
-
- # Everything else is part of the command to run.
- try:
- setattr(options, cmd, args)
- except IndexError:
- parser.print_usage()
- sys.exit(1)
- return options
-
-
-if '__main__' == __name__:
- parsed_args = parse_args()
- run(parsed_args.cmd).print_results(pretty=parsed_args.pretty)
« no previous file with comments | « scripts/restart_masters.py ('k') | scripts/run_on_all_slave_hosts.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698