def RunPackage(output_dir, target, package_path, run_args, symbolizer_config=None): """Copies the Fuchsia package at |package_path| to the target, executes it with |run_args|, and symbolizes its output. output_dir: The path containing the build output files. target: The deployment Target object that will run the package. package_path: The path to the .far package file. run_args: The command-linearguments which will be passed to the Fuchsia process. symbolizer_config: A newline delimited list of source files contained in the package. Omitting this parameter will disable symbolization. Returns the exit code of the remote package process.""" if symbolizer_config: if logging.getLogger().getEffectiveLevel() == logging.DEBUG: logging.debug('Contents of package "%s":' % os.path.basename(package_path)) for next_line in open(symbolizer_config, 'r'): logging.debug(' ' + next_line.strip().split('=')[0]) logging.debug('') # Deploy the package file to a unique path on the target. # The package's UUID length is truncated so as to not overrun the filename # field in the backtrace output. unique_package_name = 'package-%s.far' % str(uuid.uuid4())[:18] deployed_package_path = '/tmp/' + unique_package_name target.PutFile(package_path, deployed_package_path) try: command = ['run', deployed_package_path] + run_args process = target.RunCommandPiped(command, stdin=open(os.devnull, 'r'), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if symbolizer_config: # Decorate the process output stream with the symbolizer. output = FilterStream(process.stdout, unique_package_name, symbolizer_config, output_dir) else: output = process.stdout for next_line in output: print next_line process.wait() if process.returncode != 0: # The test runner returns an error status code if *any* tests fail, # so we should proceed anyway. logging.warning('Command exited with non-zero status code %d.' % process.returncode) finally: logging.debug('Cleaning up package file.') target.RunCommand(['rm', deployed_package_path]) return process.returncode
def RunPackage(output_dir, target, package_path, package_name, run_args, symbolizer_config=None): """Copies the Fuchsia package at |package_path| to the target, executes it with |run_args|, and symbolizes its output. output_dir: The path containing the build output files. target: The deployment Target object that will run the package. package_path: The path to the .far package file. package_name: The name of app specified by package metadata. run_args: The arguments which will be passed to the Fuchsia process. symbolizer_config: A newline delimited list of source files contained in the package. Omitting this parameter will disable symbolization. Returns the exit code of the remote package process.""" logging.debug('Copying package to target.') tmp_path = os.path.join('/tmp', os.path.basename(package_path)) target.PutFile(package_path, tmp_path) logging.debug('Installing package.') p = target.RunCommandPiped(['pm', 'install', tmp_path], stderr=subprocess.PIPE) output = p.stderr.readlines() p.wait() if p.returncode != 0: # Don't error out if the package already exists on the device. if len(output) != 1 or 'ErrAlreadyExists' not in output[0]: raise Exception('Error when installing package: %s' % '\n'.join(output)) logging.debug('Running package.') command = ['run', package_name] + run_args process = target.RunCommandPiped(command, stdin=open(os.devnull, 'r'), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if symbolizer_config: # Decorate the process output stream with the symbolizer. output = FilterStream(process.stdout, package_name, symbolizer_config, output_dir) else: logging.warn('Symbolization is DISABLED.') output = process.stdout for next_line in output: print next_line.strip() process.wait() if process.returncode != 0: # The test runner returns an error status code if *any* tests fail, # so we should proceed anyway. logging.warning('Command exited with non-zero status code %d.' % process.returncode) return process.returncode
def RunPackage(output_dir, target, package_path, run_args, symbolizer_config=None): """Copies the Fuchsia package at |package_path| to the target, executes it with |run_args|, and symbolizes its output. output_dir: The path containing the build output files. target: The deployment Target object that will run the package. package_path: The path to the .far package file. run_args: The command-linearguments which will be passed to the Fuchsia process. symbolizer_config: A newline delimited list of source files contained in the package. Omitting this parameter will disable symbolization. Returns the exit code of the remote package process.""" package_name = _Deploy(target, output_dir, package_path) command = ['run', package_name] + run_args process = target.RunCommandPiped(command, stdin=open(os.devnull, 'r'), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if symbolizer_config: # Decorate the process output stream with the symbolizer. output = FilterStream(process.stdout, package_name, symbolizer_config, output_dir) else: output = process.stdout for next_line in output: print next_line process.wait() if process.returncode != 0: # The test runner returns an error status code if *any* tests fail, # so we should proceed anyway. logging.warning('Command exited with non-zero status code %d.' % process.returncode) return process.returncode
def RunPackage(output_dir, target, package_path, package_name, package_deps, package_args, args): """Copies the Fuchsia package at |package_path| to the target, executes it with |package_args|, and symbolizes its output. output_dir: The path containing the build output files. target: The deployment Target object that will run the package. package_path: The path to the .far package file. package_name: The name of app specified by package metadata. package_args: The arguments which will be passed to the Fuchsia process. args: Structure of arguments to configure how the package will be run. Returns the exit code of the remote package process.""" system_logger = (_AttachKernelLogReader(target) if args.system_logging else None) try: if system_logger: # Spin up a thread to asynchronously dump the system log to stdout # for easier diagnoses of early, pre-execution failures. log_output_quit_event = multiprocessing.Event() log_output_thread = threading.Thread( target=lambda: _DrainStreamToStdout(system_logger.stdout, log_output_quit_event)) log_output_thread.daemon = True log_output_thread.start() tuf_root = tempfile.mkdtemp() pm_serve_task = None # Publish all packages to the serving TUF repository under |tuf_root|. subprocess.check_call([PM, 'newrepo', '-repo', tuf_root]) all_packages = [package_path] + package_deps for next_package_path in all_packages: PublishPackage(tuf_root, next_package_path) # Serve the |tuf_root| using 'pm serve' and configure the target to pull # from it. # TODO(kmarshall): Use -q to suppress pm serve output once blob push # is confirmed to be running stably on bots. serve_port = common.GetAvailableTcpPort() pm_serve_task = subprocess.Popen([ PM, 'serve', '-d', os.path.join(tuf_root, 'repository'), '-l', ':%d' % serve_port, '-q' ]) remote_port = common.ConnectPortForwardingTask(target, serve_port, 0) _RegisterAmberRepository(target, tuf_root, remote_port) # Install all packages. for next_package_path in all_packages: install_package_name, package_version = GetPackageInfo( next_package_path) logging.info('Installing %s version %s.' % (install_package_name, package_version)) return_code = target.RunCommand([ 'amber_ctl', 'get_up', '-n', install_package_name, '-v', package_version ]) if return_code != 0: raise Exception('Error while installing %s.' % install_package_name) if system_logger: log_output_quit_event.set() log_output_thread.join(timeout=_JOIN_TIMEOUT_SECS) if args.install_only: logging.info('Installation complete.') return logging.info('Running application.') command = ['run', _GetComponentUri(package_name)] + package_args process = target.RunCommandPiped(command, stdin=open(os.devnull, 'r'), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if system_logger: task_output = _ReadMergedLines( [process.stdout, system_logger.stdout]) else: task_output = process.stdout if args.symbolizer_config: # Decorate the process output stream with the symbolizer. output = FilterStream(task_output, package_name, args.symbolizer_config, output_dir) else: logging.warn('Symbolization is DISABLED.') output = process.stdout for next_line in output: print next_line.rstrip() process.wait() if process.returncode == 0: logging.info('Process exited normally with status code 0.') else: # The test runner returns an error status code if *any* tests fail, # so we should proceed anyway. logging.warning('Process exited with status code %d.' % process.returncode) finally: if system_logger: logging.info('Terminating kernel log reader.') log_output_quit_event.set() log_output_thread.join() system_logger.kill() _UnregisterAmberRepository(target) if pm_serve_task: pm_serve_task.kill() shutil.rmtree(tuf_root) return process.returncode
def RunPackage(output_dir, target, package_path, package_name, package_deps, run_args, system_logging, install_only, symbolizer_config=None): """Copies the Fuchsia package at |package_path| to the target, executes it with |run_args|, and symbolizes its output. output_dir: The path containing the build output files. target: The deployment Target object that will run the package. package_path: The path to the .far package file. package_name: The name of app specified by package metadata. run_args: The arguments which will be passed to the Fuchsia process. system_logging: If set, connects a system log reader to the target. install_only: If set, skips the package execution step. symbolizer_config: A newline delimited list of source files contained in the package. Omitting this parameter will disable symbolization. Returns the exit code of the remote package process.""" system_logger = _AttachKernelLogReader(target) if system_logging else None try: if system_logger: # Spin up a thread to asynchronously dump the system log to stdout # for easier diagnoses of early, pre-execution failures. log_output_quit_event = multiprocessing.Event() log_output_thread = threading.Thread( target=lambda: DrainStreamToStdout(system_logger.stdout, log_output_quit_event)) log_output_thread.daemon = True log_output_thread.start() for next_package_path in ([package_path] + package_deps): logging.info('Installing ' + os.path.basename(next_package_path) + '.') # Copy the package archive. install_path = os.path.join('/data', os.path.basename(next_package_path)) target.PutFile(next_package_path, install_path) # Install the package. p = target.RunCommandPiped(['pm', 'install', install_path], stderr=subprocess.PIPE) output = p.stderr.readlines() p.wait() if p.returncode != 0: # Don't error out if the package already exists on the device. if len(output) != 1 or 'ErrAlreadyExists' not in output[0]: raise Exception('Error while installing: %s' % '\n'.join(output)) # Clean up the package archive. target.RunCommand(['rm', install_path]) if system_logger: log_output_quit_event.set() log_output_thread.join(timeout=_JOIN_TIMEOUT_SECS) if install_only: logging.info('Installation complete.') return logging.info('Running application.') command = ['run', package_name] + run_args process = target.RunCommandPiped(command, stdin=open(os.devnull, 'r'), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if system_logger: task_output = _ReadMergedLines( [process.stdout, system_logger.stdout]) else: task_output = process.stdout if symbolizer_config: # Decorate the process output stream with the symbolizer. output = FilterStream(task_output, package_name, symbolizer_config, output_dir) else: logging.warn('Symbolization is DISABLED.') output = process.stdout for next_line in output: print next_line.rstrip() process.wait() if process.returncode == 0: logging.info('Process exited normally with status code 0.') else: # The test runner returns an error status code if *any* tests fail, # so we should proceed anyway. logging.warning('Process exited with status code %d.' % process.returncode) finally: if system_logger: logging.info('Terminating kernel log reader.') log_output_quit_event.set() log_output_thread.join() system_logger.kill() return process.returncode