def _StageOnMoblab(self, tempdir): """Stage the generated payloads and test bits on a moblab device. Args: tempdir: Temporary Directory that contains the generated payloads and test bits. """ with remote_access.ChromiumOSDeviceHandler( self.options.remote) as device: device.RunCommand(['mkdir', '-p', self.stage_directory]) for f in os.listdir(tempdir): device.CopyToDevice(os.path.join(tempdir, f), self.stage_directory) device.RunCommand(['chown', '-R', 'moblab:moblab', MOBLAB_TMP_DIR]) # Delete this image from the Devserver in case it was previously staged. device.RunCommand([ 'rm', '-rf', os.path.join(MOBLAB_STATIC_DIR, self.staged_image_name) ]) stage_url = DEVSERVER_STAGE_URL % dict( moblab=self.options.remote, staged_dir=self.stage_directory) # Stage the image from the moblab, as port 8080 might not be reachable # from the developer's system. res = device.RunCommand( ['curl', '--fail', cros_build_lib.ShellQuote(stage_url)], error_code_ok=True) if res.returncode == 0: logging.info('\n\nStaging Completed!') logging.info('Image is staged on Moblab as %s', self.staged_image_name) else: logging.info('Staging failed. Error Message: %s', res.error) device.RunCommand(['rm', '-rf', self.stage_directory])
def run(self, cmd, **kwargs): """Executes a shell command on the device with output captured by default. Also sets environment variables using dictionary provided by keyword argument |extra_env|. Args: cmd: command to run. See RemoteAccess.RemoteSh documentation. **kwargs: keyword arguments to pass along with cmd. See RemoteAccess.RemoteSh documentation. """ # Handle setting environment variables on the device by copying # and sourcing a temporary environment file. extra_env = kwargs.pop('extra_env', None) if extra_env: remote_sudo = kwargs.pop('remote_sudo', False) if remote_sudo and self.GetAgent().username == ROOT_ACCOUNT: remote_sudo = False new_cmd = [] flat_vars = ['%s=%s' % (k, cros_build_lib.ShellQuote(v)) for k, v in extra_env.items()] # If the vars are too large for the command line, do it indirectly. # We pick 32k somewhat arbitrarily -- the kernel should accept this # and rarely should remote commands get near that size. ARG_MAX = 32 * 1024 # What the command line would generally look like on the remote. if isinstance(cmd, six.string_types): if not kwargs.get('shell', False): raise ValueError("'shell' must be True when 'cmd' is a string.") cmdline = ' '.join(flat_vars) + ' ' + cmd else: if kwargs.get('shell', False): raise ValueError("'shell' must be False when 'cmd' is a list.") cmdline = ' '.join(flat_vars + cmd) if len(cmdline) > ARG_MAX: env_list = ['export %s' % x for x in flat_vars] with tempfile.NamedTemporaryFile(dir=self.tempdir.tempdir, prefix='env') as f: logging.debug('Environment variables: %s', ' '.join(env_list)) osutils.WriteFile(f.name, '\n'.join(env_list)) self.CopyToWorkDir(f.name) env_file = os.path.join(self.work_dir, os.path.basename(f.name)) new_cmd += ['.', '%s;' % env_file] if remote_sudo: new_cmd += ['sudo', '-E'] else: if remote_sudo: new_cmd += ['sudo'] new_cmd += flat_vars if isinstance(cmd, six.string_types): cmd = ' '.join(new_cmd) + ' ' + cmd else: cmd = new_cmd + cmd return self.BaseRunCommand(cmd, **kwargs)
def _QuickProvision(self, device): """Performs a quick provision of device. Returns: A dictionary of extracted key-value pairs returned from the script execution. Raises: cros_build_lib.RunCommandError: error executing command or script remote_access.SSHConnectionError: SSH connection error """ pid = os.getpid() pgid = os.getpgid(pid) if self.progress_tracker is None: self.progress_tracker = cros_update_progress.AUProgress(self.host_name, pgid) dut_script = '/tmp/quick-provision' status_url = self._MakeStatusUrl(self.devserver_url, self.host_name, pgid) cmd = ('curl -o %s %s && bash ' '%s --status_url %s %s %s') % ( dut_script, os.path.join(self.static_url, 'quick-provision'), dut_script, cros_build_lib.ShellQuote(status_url), self.build_name, self.static_url, ) # Quick provision script issues a reboot and might result in the SSH # connection being terminated so set ssh_error_ok so that output can # still be captured. results = device.RunCommand(cmd, log_output=True, capture_output=True, ssh_error_ok=True, shell=True, encoding='utf-8') key_re = re.compile(r'^KEYVAL: ([^\d\W]\w*)=(.*)$') matches = [key_re.match(l) for l in results.output.splitlines()] keyvals = {m.group(1): m.group(2) for m in matches if m} logging.info('DUT returned keyvals: %s', keyvals) # If there was an SSH error, check the keyvals to see if it actually # completed and suppress the error if so. if results.returncode == remote_access.SSH_ERROR_CODE: if 'COMPLETED' in keyvals: logging.warning('Quick provision completed with ssh error, ignoring...') else: logging.error('Incomplete quick provision failed with ssh error') raise remote_access.SSHConnectionError(results.error) return keyvals
def RemoteSh(self, cmd, connect_settings=None, check=True, remote_sudo=False, remote_user=None, ssh_error_ok=False, **kwargs): """Run a sh command on the remote device through ssh. Args: cmd: The command string or list to run. None or empty string/list will start an interactive session. connect_settings: The SSH connect settings to use. check: Throw an exception when the command exits with a non-zero returncode. This does not cover the case where the ssh command itself fails (return code 255). See ssh_error_ok. ssh_error_ok: Does not throw an exception when the ssh command itself fails (return code 255). remote_sudo: If set, run the command in remote shell with sudo. remote_user: If set, run the command as the specified user. **kwargs: See cros_build_lib.run documentation. Returns: A CommandResult object. The returncode is the returncode of the command, or 255 if ssh encountered an error (could not connect, connection interrupted, etc.) Raises: RunCommandError when error is not ignored through the check flag. SSHConnectionError when ssh command error is not ignored through the ssh_error_ok flag. """ kwargs.setdefault('capture_output', True) kwargs.setdefault('encoding', 'utf-8') kwargs.setdefault('debug_level', self.debug_level) # Force English SSH messages. SSHConnectionError.IsKnownHostsMismatch() # requires English errors to detect a known_hosts key mismatch error. kwargs.setdefault('extra_env', {})['LC_MESSAGES'] = 'C' prev_user = self.username if remote_user: self.username = remote_user ssh_cmd = self.GetSSHCommand(connect_settings=connect_settings) if cmd: ssh_cmd.append('--') if remote_sudo and self.username != ROOT_ACCOUNT: # Prepend sudo to cmd. ssh_cmd.append('sudo') if isinstance(cmd, six.string_types): if kwargs.get('shell'): ssh_cmd = '%s %s' % (' '.join(ssh_cmd), cros_build_lib.ShellQuote(cmd)) else: ssh_cmd += [cmd] else: ssh_cmd += cmd try: return cros_build_lib.run(ssh_cmd, **kwargs) except cros_build_lib.RunCommandError as e: if ((e.result.returncode == SSH_ERROR_CODE and ssh_error_ok) or (e.result.returncode and e.result.returncode != SSH_ERROR_CODE and not check)): return e.result elif e.result.returncode == SSH_ERROR_CODE: raise SSHConnectionError(e.result.error) else: raise finally: # Restore the previous user if we temporarily changed it earlier. self.username = prev_user
def testShellQuoteOjbects(self): """Test objects passed to ShellQuote.""" self.assertEqual('None', cros_build_lib.ShellQuote(None)) self.assertNotEqual('', cros_build_lib.ShellQuote(object))
def aux(s): return cros_build_lib.ShellUnquote(cros_build_lib.ShellQuote(s))
def main(argv): """Checks if a project is correctly formatted with clang-format. Returns 1 if there are any clang-format-worthy changes in the project (or on a provided list of files/directories in the project), 0 otherwise. """ parser = commandline.ArgumentParser(description=__doc__) parser.add_argument('--clang-format', default=_GetDefaultClangFormatPath(), help='The path of the clang-format executable.') parser.add_argument('--git-clang-format', default=os.path.join(BUILDTOOLS_PATH, 'clang_format', 'script', 'git-clang-format'), help='The path of the git-clang-format executable.') parser.add_argument('--style', metavar='STYLE', type=str, default='file', help='The style that clang-format will use.') parser.add_argument('--extensions', metavar='EXTENSIONS', type=str, help='Comma-separated list of file extensions to ' 'format.') parser.add_argument('--fix', action='store_true', help='Fix any formatting errors automatically.') scope = parser.add_mutually_exclusive_group(required=True) scope.add_argument('--commit', type=str, default='HEAD', help='Specify the commit to validate.') scope.add_argument('--working-tree', action='store_true', help='Validates the files that have changed from ' 'HEAD in the working directory.') parser.add_argument('files', type=str, nargs='*', help='If specified, only consider differences in ' 'these files/directories.') opts = parser.parse_args(argv) cmd = [opts.git_clang_format, '--binary', opts.clang_format, '--diff'] if opts.style: cmd.extend(['--style', opts.style]) if opts.extensions: cmd.extend(['--extensions', opts.extensions]) if not opts.working_tree: cmd.extend(['%s^' % opts.commit, opts.commit]) cmd.extend(['--'] + opts.files) # Fail gracefully if clang-format itself aborts/fails. try: result = cros_build_lib.RunCommand(cmd=cmd, print_cmd=False, stdout_to_pipe=True) except cros_build_lib.RunCommandError as e: print('clang-format failed:\n' + str(e), file=sys.stderr) print('\nPlease report this to the clang team.', file=sys.stderr) return 1 stdout = result.output if stdout.rstrip('\n') == 'no modified files to format': # This is always printed when only files that clang-format does not # understand were modified. return 0 diff_filenames = [] for line in stdout.splitlines(): if line.startswith(DIFF_MARKER_PREFIX): diff_filenames.append(line[len(DIFF_MARKER_PREFIX):].rstrip()) if diff_filenames: if opts.fix: cros_build_lib.RunCommand(cmd=['git', 'apply'], print_cmd=False, input=stdout) else: print('The following files have formatting errors:') for filename in diff_filenames: print('\t%s' % filename) print('You can run `%s --fix %s` to fix this' % (sys.argv[0], ' '.join( cros_build_lib.ShellQuote(arg) for arg in argv))) return 1