aboutsummaryrefslogtreecommitdiff
path: root/deprecated/automation/common/command.py
diff options
context:
space:
mode:
authorTiancong Wang <tcwang@google.com>2020-02-13 21:08:49 +0000
committerTiancong Wang <tcwang@google.com>2020-02-13 21:08:49 +0000
commitb75f321fc8978b92ce3db6886ccb966768f0c7a8 (patch)
tree35fa0fbaeaaddd9cc2a126a05eee3527b51e83a8 /deprecated/automation/common/command.py
parentcddd960b0ba2eb62c372c0d3176c75f0bd05d5e8 (diff)
parente617e3393dd24003aa976ece5050bb291070041c (diff)
downloadtoolchain-utils-android11-mainline-media-release.tar.gz
Merging 18 commit(s) from Chromium's toolchain-utils am: 0ae38c8498 am: 2a19d36a82 am: e617e3393dr_aml_301500702android-mainline-12.0.0_r55android-mainline-11.0.0_r9android-mainline-11.0.0_r8android-mainline-11.0.0_r7android-mainline-11.0.0_r6android-mainline-11.0.0_r5android-mainline-11.0.0_r45android-mainline-11.0.0_r44android-mainline-11.0.0_r43android-mainline-11.0.0_r42android-mainline-11.0.0_r41android-mainline-11.0.0_r40android-mainline-11.0.0_r4android-mainline-11.0.0_r39android-mainline-11.0.0_r38android-mainline-11.0.0_r37android-mainline-11.0.0_r36android-mainline-11.0.0_r35android-mainline-11.0.0_r34android-mainline-11.0.0_r33android-mainline-11.0.0_r32android-mainline-11.0.0_r31android-mainline-11.0.0_r30android-mainline-11.0.0_r3android-mainline-11.0.0_r29android-mainline-11.0.0_r28android-mainline-11.0.0_r27android-mainline-11.0.0_r26android-mainline-11.0.0_r25android-mainline-11.0.0_r24android-mainline-11.0.0_r23android-mainline-11.0.0_r22android-mainline-11.0.0_r21android-mainline-11.0.0_r20android-mainline-11.0.0_r2android-mainline-11.0.0_r19android-mainline-11.0.0_r18android-mainline-11.0.0_r17android-mainline-11.0.0_r16android-mainline-11.0.0_r15android-mainline-11.0.0_r14android-mainline-11.0.0_r13android-mainline-11.0.0_r12android-mainline-11.0.0_r10android-mainline-11.0.0_r1android-11.0.0_r48android-11.0.0_r47android-11.0.0_r46android-11.0.0_r45android-11.0.0_r44android-11.0.0_r43android-11.0.0_r42android-11.0.0_r41android-11.0.0_r40android-11.0.0_r39android-11.0.0_r38android-11.0.0_r37android-11.0.0_r36android-11.0.0_r35android-11.0.0_r34android-11.0.0_r33android-11.0.0_r32android-11.0.0_r31android-11.0.0_r30android-11.0.0_r29android-11.0.0_r28android-11.0.0_r27android-11.0.0_r26android-11.0.0_r24android-11.0.0_r23android-11.0.0_r22android-11.0.0_r21android-11.0.0_r20android-11.0.0_r19android-11.0.0_r18android-11.0.0_r16android11-qpr3-s1-releaseandroid11-qpr3-releaseandroid11-qpr2-releaseandroid11-qpr1-s2-releaseandroid11-qpr1-s1-releaseandroid11-qpr1-releaseandroid11-qpr1-d-s1-releaseandroid11-qpr1-d-releaseandroid11-qpr1-c-releaseandroid11-mainline-tethering-releaseandroid11-mainline-sparse-2021-jan-releaseandroid11-mainline-sparse-2020-dec-releaseandroid11-mainline-releaseandroid11-mainline-permission-releaseandroid11-mainline-os-statsd-releaseandroid11-mainline-networkstack-releaseandroid11-mainline-media-swcodec-releaseandroid11-mainline-media-releaseandroid11-mainline-extservices-releaseandroid11-mainline-documentsui-releaseandroid11-mainline-conscrypt-releaseandroid11-mainline-cellbroadcast-releaseandroid11-mainline-captiveportallogin-releaseandroid11-devandroid11-d2-releaseandroid11-d1-b-release
Change-Id: I3f25c7ee034b2e20e37ed941b8eae24eec7043eb
Diffstat (limited to 'deprecated/automation/common/command.py')
-rw-r--r--deprecated/automation/common/command.py241
1 files changed, 241 insertions, 0 deletions
diff --git a/deprecated/automation/common/command.py b/deprecated/automation/common/command.py
new file mode 100644
index 00000000..c56e9fad
--- /dev/null
+++ b/deprecated/automation/common/command.py
@@ -0,0 +1,241 @@
+# Copyright 2011 Google Inc. All Rights Reserved.
+
+__author__ = 'kbaclawski@google.com (Krystian Baclawski)'
+
+import abc
+import collections
+import os.path
+
+
+class Shell(object):
+ """Class used to build a string representation of a shell command."""
+
+ def __init__(self, cmd, *args, **kwargs):
+ assert all(key in ['path', 'ignore_error'] for key in kwargs)
+
+ self._cmd = cmd
+ self._args = list(args)
+ self._path = kwargs.get('path', '')
+ self._ignore_error = bool(kwargs.get('ignore_error', False))
+
+ def __str__(self):
+ cmdline = [os.path.join(self._path, self._cmd)]
+ cmdline.extend(self._args)
+
+ cmd = ' '.join(cmdline)
+
+ if self._ignore_error:
+ cmd = '{ %s; true; }' % cmd
+
+ return cmd
+
+ def AddOption(self, option):
+ self._args.append(option)
+
+
+class Wrapper(object):
+ """Wraps a command with environment which gets cleaned up after execution."""
+
+ _counter = 1
+
+ def __init__(self, command, cwd=None, env=None, umask=None):
+ # @param cwd: temporary working directory
+ # @param env: dictionary of environment variables
+ self._command = command
+ self._prefix = Chain()
+ self._suffix = Chain()
+
+ if cwd:
+ self._prefix.append(Shell('pushd', cwd))
+ self._suffix.insert(0, Shell('popd'))
+
+ if env:
+ for env_var, value in env.items():
+ self._prefix.append(Shell('%s=%s' % (env_var, value)))
+ self._suffix.insert(0, Shell('unset', env_var))
+
+ if umask:
+ umask_save_var = 'OLD_UMASK_%d' % self.counter
+
+ self._prefix.append(Shell('%s=$(umask)' % umask_save_var))
+ self._prefix.append(Shell('umask', umask))
+ self._suffix.insert(0, Shell('umask', '$%s' % umask_save_var))
+
+ @property
+ def counter(self):
+ counter = self._counter
+ self._counter += 1
+ return counter
+
+ def __str__(self):
+ return str(Chain(self._prefix, self._command, self._suffix))
+
+
+class AbstractCommandContainer(collections.MutableSequence):
+ """Common base for all classes that behave like command container."""
+
+ def __init__(self, *commands):
+ self._commands = list(commands)
+
+ def __contains__(self, command):
+ return command in self._commands
+
+ def __iter__(self):
+ return iter(self._commands)
+
+ def __len__(self):
+ return len(self._commands)
+
+ def __getitem__(self, index):
+ return self._commands[index]
+
+ def __setitem__(self, index, command):
+ self._commands[index] = self._ValidateCommandType(command)
+
+ def __delitem__(self, index):
+ del self._commands[index]
+
+ def insert(self, index, command):
+ self._commands.insert(index, self._ValidateCommandType(command))
+
+ @abc.abstractmethod
+ def __str__(self):
+ pass
+
+ @abc.abstractproperty
+ def stored_types(self):
+ pass
+
+ def _ValidateCommandType(self, command):
+ if type(command) not in self.stored_types:
+ raise TypeError('Command cannot have %s type.' % type(command))
+ else:
+ return command
+
+ def _StringifyCommands(self):
+ cmds = []
+
+ for cmd in self:
+ if isinstance(cmd, AbstractCommandContainer) and len(cmd) > 1:
+ cmds.append('{ %s; }' % cmd)
+ else:
+ cmds.append(str(cmd))
+
+ return cmds
+
+
+class Chain(AbstractCommandContainer):
+ """Container that chains shell commands using (&&) shell operator."""
+
+ @property
+ def stored_types(self):
+ return [str, Shell, Chain, Pipe]
+
+ def __str__(self):
+ return ' && '.join(self._StringifyCommands())
+
+
+class Pipe(AbstractCommandContainer):
+ """Container that chains shell commands using pipe (|) operator."""
+
+ def __init__(self, *commands, **kwargs):
+ assert all(key in ['input', 'output'] for key in kwargs)
+
+ AbstractCommandContainer.__init__(self, *commands)
+
+ self._input = kwargs.get('input', None)
+ self._output = kwargs.get('output', None)
+
+ @property
+ def stored_types(self):
+ return [str, Shell]
+
+ def __str__(self):
+ pipe = self._StringifyCommands()
+
+ if self._input:
+ pipe.insert(str(Shell('cat', self._input), 0))
+
+ if self._output:
+ pipe.append(str(Shell('tee', self._output)))
+
+ return ' | '.join(pipe)
+
+# TODO(kbaclawski): Unfortunately we don't have any policy describing which
+# directories can or cannot be touched by a job. Thus, I cannot decide how to
+# protect a system against commands that are considered to be dangerous (like
+# RmTree("${HOME}")). AFAIK we'll have to execute some commands with root access
+# (especially for ChromeOS related jobs, which involve chroot-ing), which is
+# even more scary.
+
+
+def Copy(*args, **kwargs):
+ assert all(key in ['to_dir', 'recursive'] for key in kwargs.keys())
+
+ options = []
+
+ if 'to_dir' in kwargs:
+ options.extend(['-t', kwargs['to_dir']])
+
+ if 'recursive' in kwargs:
+ options.append('-r')
+
+ options.extend(args)
+
+ return Shell('cp', *options)
+
+
+def RemoteCopyFrom(from_machine, from_path, to_path, username=None):
+ from_path = os.path.expanduser(from_path) + '/'
+ to_path = os.path.expanduser(to_path) + '/'
+
+ if not username:
+ login = from_machine
+ else:
+ login = '%s@%s' % (username, from_machine)
+
+ return Chain(
+ MakeDir(to_path), Shell('rsync', '-a', '%s:%s' %
+ (login, from_path), to_path))
+
+
+def MakeSymlink(to_path, link_name):
+ return Shell('ln', '-f', '-s', '-T', to_path, link_name)
+
+
+def MakeDir(*dirs, **kwargs):
+ options = ['-p']
+
+ mode = kwargs.get('mode', None)
+
+ if mode:
+ options.extend(['-m', str(mode)])
+
+ options.extend(dirs)
+
+ return Shell('mkdir', *options)
+
+
+def RmTree(*dirs):
+ return Shell('rm', '-r', '-f', *dirs)
+
+
+def UnTar(tar_file, dest_dir):
+ return Chain(
+ MakeDir(dest_dir), Shell('tar', '-x', '-f', tar_file, '-C', dest_dir))
+
+
+def Tar(tar_file, *args):
+ options = ['-c']
+
+ if tar_file.endswith('.tar.bz2'):
+ options.append('-j')
+ elif tar_file.endswith('.tar.gz'):
+ options.append('-z')
+ else:
+ assert tar_file.endswith('.tar')
+
+ options.extend(['-f', tar_file])
+ options.extend(args)
+
+ return Chain(MakeDir(os.path.dirname(tar_file)), Shell('tar', *options))