def Run(exclude, classes_to_analyze, auxiliary_classes, output_file, findbug_args, jars): """Run FindBugs. Args: exclude: the exclude xml file, refer to FindBugs's -exclude command option. classes_to_analyze: the list of classes need to analyze, refer to FindBug's -onlyAnalyze command line option. auxiliary_classes: the classes help to analyze, refer to FindBug's -auxclasspath command line option. output_file: An optional path to dump XML results to. findbug_args: A list of addtional command line options to pass to Findbugs. """ # TODO(jbudorick): Get this from the build system. system_classes = [ os.path.join(constants.ANDROID_SDK_ROOT, 'platforms', 'android-%s' % constants.ANDROID_SDK_VERSION, 'android.jar') ] system_classes.extend( os.path.abspath(classes) for classes in auxiliary_classes or []) cmd = [ 'java', '-classpath', '%s:' % _FINDBUGS_JAR, '-Xmx%dm' % _FINDBUGS_MAX_HEAP, '-Dfindbugs.home="%s"' % _FINDBUGS_HOME, '-jar', _FINDBUGS_JAR, '-textui', '-sortByClass', '-pluginList', _FINDBUGS_PLUGIN_PATH, '-xml:withMessages' ] if system_classes: cmd.extend(['-auxclasspath', ':'.join(system_classes)]) if classes_to_analyze: cmd.extend(['-onlyAnalyze', classes_to_analyze]) if exclude: cmd.extend(['-exclude', os.path.abspath(exclude)]) if output_file: cmd.extend(['-output', output_file]) if findbug_args: cmd.extend(findbug_args) cmd.extend(os.path.abspath(j) for j in jars or []) if output_file: _, _, stderr = cmd_helper.GetCmdStatusOutputAndError(cmd) results_doc = xml.dom.minidom.parse(output_file) else: _, raw_out, stderr = cmd_helper.GetCmdStatusOutputAndError(cmd) results_doc = xml.dom.minidom.parseString(raw_out) for line in stderr.splitlines(): logging.debug(' %s', line) current_warnings_set = _ParseXmlResults(results_doc) return (' '.join(cmd), current_warnings_set)
def _ParseManifestFromBundle(bundle): cmd = [bundle.path, 'dump-manifest'] status, stdout, stderr = cmd_helper.GetCmdStatusOutputAndError(cmd) if status != 0: raise Exception('Failed running {} with output\n{}\n{}'.format( ' '.join(cmd), stdout, stderr)) return ParseManifestFromXml(stdout)
def WriteZipFile(zip_path, zip_contents): """Writes the provided contents to the given zip file. Note that this uses python's zipfile module and is done in a separate process to avoid hogging the GIL. Args: zip_path: String path to the zip file to write. zip_contents: A list of (host path, archive path) tuples. Raises: ZipFailedError on failure. """ zip_spec = { 'zip_path': zip_path, 'zip_contents': zip_contents, } with tempfile_ext.NamedTemporaryDirectory() as tmpdir: json_path = os.path.join(tmpdir, 'zip_spec.json') with open(json_path, 'w') as json_file: json.dump(zip_spec, json_file) ret, output, error = cmd_helper.GetCmdStatusOutputAndError([ sys.executable, os.path.abspath(__file__), '--zip-spec', json_path ]) if ret != 0: exc_msg = ['Failed to create %s' % zip_path] exc_msg.extend('stdout: %s' % l for l in output.splitlines()) exc_msg.extend('stderr: %s' % l for l in error.splitlines()) raise ZipFailedError('\n'.join(exc_msg))
def Authenticate(self, use_luci=True): """Authenticates with Skia Gold for this session. Args: use_luci: If true, authentication will use the service account provided by the LUCI context. If false, will attempt to use whatever is set up in gsutil, which is only supported for local runs. Returns: A tuple (return_code, output). |return_code| is the return code of the authentication process. |output| is the stdout + stderr of the authentication process. """ if self._authenticated: return 0, None if self._gold_properties.bypass_skia_gold_functionality: logging.warning('Not actually authenticating with Gold due to ' '--bypass-skia-gold-functionality being present.') return 0, None auth_cmd = [GOLDCTL_BINARY, 'auth', '--work-dir', self._working_dir] if use_luci: auth_cmd.append('--luci') elif not self._gold_properties.local_pixel_tests: raise RuntimeError( 'Cannot authenticate to Skia Gold with use_luci=False unless running ' 'local pixel tests') rc, stdout, _ = cmd_helper.GetCmdStatusOutputAndError( auth_cmd, merge_stderr=True) if rc == 0: self._authenticated = True return rc, stdout
def get_cipd_dependency_rev(self): """Return CTS CIPD revision in the checkout's DEPS file.""" deps_file = os.path.join(self._root_dir, DEPS_FILE) # Use the gclient command instead of gclient_eval since the latter is not # intended for direct use outside of depot_tools. The .bat file extension # must be explicitly specified when shell=False. gclient = 'gclient.bat' if os.name == 'nt' else 'gclient' cmd = [ gclient, 'getdep', '--revision', '%s:%s' % (CTS_DEP_NAME, CTS_DEP_PACKAGE), '--deps-file', deps_file ] env = os.environ # Disable auto-update of depot tools since update_depot_tools may not be # available (for example, on the presubmit bot), and it's probably best not # to perform surprise updates anyways. env.update({'DEPOT_TOOLS_UPDATE': '0'}) status, output, err = cmd_helper.GetCmdStatusOutputAndError(cmd, env=env) if status != 0: raise Exception('Command "%s" failed: %s' % (' '.join(cmd), err)) return output.strip()
def Initialize(self): """Initializes the working directory if necessary. This can technically be skipped if the same information is passed to the command used for image comparison, but that is less efficient under the hood. Doing it that way effectively requires an initialization for every comparison (~250 ms) instead of once at the beginning. Returns: A tuple (return_code, output). |return_code| is the return code of the initialization process. |output| is the stdout + stderr of the initialization process. """ if self._initialized: return 0, None if self._gold_properties.bypass_skia_gold_functionality: logging.warning('Not actually initializing Gold due to ' '--bypass-skia-gold-functionality being present.') return 0, None init_cmd = [ GOLDCTL_BINARY, 'imgtest', 'init', '--passfail', '--instance', self._instance, '--corpus', self._corpus, '--keys-file', self._keys_file, '--work-dir', self._working_dir, '--failure-file', self._triage_link_file, '--commit', self._gold_properties.git_revision, ] if self._gold_properties.IsTryjobRun(): init_cmd.extend([ '--issue', str(self._gold_properties.issue), '--patchset', str(self._gold_properties.patchset), '--jobid', str(self._gold_properties.job_id), '--crs', str(self._gold_properties.code_review_system), '--cis', str(self._gold_properties.continuous_integration_system), ]) rc, stdout, _ = cmd_helper.GetCmdStatusOutputAndError( init_cmd, merge_stderr=True) if rc == 0: self._initialized = True return rc, stdout
def Compare(self, name, png_file): """Compares the given image to images known to Gold. Triage links can later be retrieved using GetTriageLink(). Args: name: The name of the image being compared. png_file: A path to a PNG file containing the image to be compared. Returns: A tuple (return_code, output). |return_code| is the return code of the comparison process. |output| is the stdout + stderr of the comparison process. """ if self._gold_properties.bypass_skia_gold_functionality: logging.warning('Not actually comparing with Gold due to ' '--bypass-skia-gold-functionality being present.') return 0, None compare_cmd = [ GOLDCTL_BINARY, 'imgtest', 'add', '--test-name', name, '--png-file', png_file, '--work-dir', self._working_dir, ] if self._gold_properties.local_pixel_tests: compare_cmd.append('--dryrun') self._ClearTriageLinkFile() rc, stdout, _ = cmd_helper.GetCmdStatusOutputAndError( compare_cmd, merge_stderr=True) self._comparison_results[name] = self.ComparisonResults() if rc == 0: self._comparison_results[name].triage_link_omission_reason = ( 'Comparison succeeded, no triage link') elif self._gold_properties.IsTryjobRun(): cl_triage_link = ('https://{instance}-gold.skia.org/search?' 'issue={issue}') cl_triage_link = cl_triage_link.format( instance=self._instance, issue=self._gold_properties.issue) self._comparison_results[name].triage_link = cl_triage_link else: try: with open(self._triage_link_file) as tlf: triage_link = tlf.read().strip() self._comparison_results[name].triage_link = triage_link except IOError: self._comparison_results[name].triage_link_omission_reason = ( 'Failed to read triage link from file') return rc, stdout
def ExtractApks(output_dir, apks_path, abis, locales, features, pixel_density, sdk_version, modules=None): """Extracts splits from APKS archive. Args: output_dir: Directory to extract splits into. apks_path: Path to APKS archive. abis: ABIs to support. locales: Locales to support. features: Device features to support. pixel_density: Pixel density to support. sdk_version: Target SDK version. modules: Extra modules to install. """ device_spec = { 'supportedAbis': abis, 'supportedLocales': ['%s-%s' % l for l in locales], 'deviceFeatures': features, 'screenDensity': pixel_density, 'sdkVersion': sdk_version, } with tempfile_ext.TemporaryFileName(suffix='.json') as device_spec_path: with open(device_spec_path, 'w') as f: json.dump(device_spec, f) cmd = [ 'java', '-jar', _bundletool_path.read(), 'extract-apks', '--apks=%s' % apks_path, '--device-spec=%s' % device_spec_path, '--output-dir=%s' % output_dir, ] if modules: cmd += ['--modules=%s' % ','.join(modules)] status, stdout, stderr = cmd_helper.GetCmdStatusOutputAndError(cmd) if status != 0: raise base_error.BaseError( 'Failed running {} with output\n{}\n{}'.format( ' '.join(cmd), stdout, stderr))
def Install(self): """Installs the requested CIPD packages. Returns: None Raises: AvdException on failure to install. """ pkgs_by_dir = {} for pkg in (self._config.emulator_package, self._config.system_image_package, self._config.avd_package): if not pkg.dest_path in pkgs_by_dir: pkgs_by_dir[pkg.dest_path] = [] pkgs_by_dir[pkg.dest_path].append(pkg) for pkg_dir, pkgs in pkgs_by_dir.iteritems(): logging.info('Installing packages in %s', pkg_dir) cipd_root = os.path.join(_SRC_ROOT, pkg_dir) if not os.path.exists(cipd_root): os.makedirs(cipd_root) ensure_path = os.path.join(cipd_root, '.ensure') with open(ensure_path, 'w') as ensure_file: # Make CIPD ensure that all files are present, even if # it thinks the package is installed. ensure_file.write('$ParanoidMode CheckPresence\n\n') for pkg in pkgs: ensure_file.write('%s %s\n' % (pkg.package_name, pkg.version)) logging.info(' %s %s', pkg.package_name, pkg.version) ensure_cmd = [ 'cipd', 'ensure', '-ensure-file', ensure_path, '-root', cipd_root, ] status, output, error = cmd_helper.GetCmdStatusOutputAndError(ensure_cmd) if status: raise AvdException( 'Failed to install CIPD package %s' % pkg.package_name, command=ensure_cmd, stdout=output, stderr=error) # The emulator requires that some files are writable. for dirname, _, filenames in os.walk(self._emulator_home): for f in filenames: path = os.path.join(dirname, f) if (os.lstat(path).st_mode & (stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) == stat.S_IRUSR): os.chmod(path, stat.S_IRUSR | stat.S_IWUSR)
def _GetApksPath(self): apks_path = None try: fd, apks_path = tempfile.mkstemp(suffix='.apks') os.close(fd) cmd = [ self._bundle_script_path, 'build-bundle-apks', '--output-apks', apks_path, ] status, stdout, stderr = cmd_helper.GetCmdStatusOutputAndError(cmd) if status != 0: raise ApkHelperError('Failed running {} with output\n{}\n{}'.format( ' '.join(cmd), stdout, stderr)) return _DeleteHelper(apks_path, apks_path) except: if apks_path: os.remove(apks_path) raise
def _RunCmdForRcAndOutput(cmd): rc, stdout, _ = cmd_helper.GetCmdStatusOutputAndError(cmd, merge_stderr=True) return rc, stdout
def check_call(self, *args): logging.debug('Calling command "%s"', str(args)) return cmd_helper.GetCmdStatusOutputAndError(args)
def Diff(self, name, png_file, corpus, output_manager): """Performs a local image diff against the closest known positive in Gold. This is used for running tests on a workstation, where uploading data to Gold for ingestion is not allowed, and thus the web UI is not available. Image links can later be retrieved using Get*ImageLink(). Args: name: The name of the image being compared. png_file: The path to a PNG file containing the image to be diffed. corpus: The corpus that the image belongs to. output_manager: The output manager used to save local diff images. Returns: A tuple (return_code, output). |return_code| is the return code of the diff process. |output| is the stdout + stderr of the diff process. """ # Output managers only support archived files, not directories, so we have # to use a temporary directory and later move the data into the archived # files. output_dir = tempfile.mkdtemp(dir=self._working_dir) diff_cmd = [ GOLDCTL_BINARY, 'diff', '--corpus', corpus, '--instance', self._instance, '--input', png_file, '--test', name, '--work-dir', self._working_dir, '--out-dir', output_dir, ] rc, stdout, _ = cmd_helper.GetCmdStatusOutputAndError( diff_cmd, merge_stderr=True) given_path = closest_path = diff_path = None # The directory should contain "input-<hash>.png", "closest-<hash>.png", # and "diff.png". for f in os.listdir(output_dir): filepath = os.path.join(output_dir, f) if f.startswith('input-'): given_path = filepath elif f.startswith('closest-'): closest_path = filepath elif f == 'diff.png': diff_path = filepath results = self._comparison_results.setdefault(name, self.ComparisonResults()) if given_path: with output_manager.ArchivedTempfile('given_%s.png' % name, 'gold_local_diffs', Datatype.PNG) as given_file: shutil.move(given_path, given_file.name) results.local_diff_given_image = given_file.Link() if closest_path: with output_manager.ArchivedTempfile('closest_%s.png' % name, 'gold_local_diffs', Datatype.PNG) as closest_file: shutil.move(closest_path, closest_file.name) results.local_diff_closest_image = closest_file.Link() if diff_path: with output_manager.ArchivedTempfile('diff_%s.png' % name, 'gold_local_diffs', Datatype.PNG) as diff_file: shutil.move(diff_path, diff_file.name) results.local_diff_diff_image = diff_file.Link() return rc, stdout
def Compare(self, name, keys_file, png_file, corpus): """Compares the given image to images known to Gold. Triage links can later be retrieved using GetTriageLink(). Args: name: The name of the image being compared. keys_file: A path to a JSON file containing various comparison config data such as corpus and debug information like the hardware/software configuration the image was produced on. png_file: A path to a PNG file containing the image to be compared. corpus: The corpus that the image belongs to. Returns: A tuple (return_code, output). |return_code| is the return code of the comparison process. |output| is the stdout + stderr of the comparison process. """ compare_cmd = [ GOLDCTL_BINARY, 'imgtest', 'add', '--passfail', '--test-name', name, '--instance', self._instance, '--corpus', corpus, '--keys-file', keys_file, '--png-file', png_file, '--work-dir', self._working_dir, '--failure-file', self._triage_link_file, '--commit', self._gold_properties.git_revision, ] if self._gold_properties.local_pixel_tests: compare_cmd.append('--dryrun') if self._gold_properties.IsTryjobRun(): compare_cmd.extend([ '--issue', str(self._gold_properties.issue), '--patchset', str(self._gold_properties.patchset), '--jobid', str(self._gold_properties.job_id), '--crs', str(self._gold_properties.code_review_system), '--cis', str(self._gold_properties.continuous_integration_system), ]) rc, stdout, _ = cmd_helper.GetCmdStatusOutputAndError( compare_cmd, merge_stderr=True) self._comparison_results[name] = self.ComparisonResults() if rc == 0: self._comparison_results[name].triage_link_omission_reason = ( 'Comparison succeeded, no triage link') elif self._gold_properties.IsTryjobRun(): # TODO(skbug.com/9879): Remove the explicit corpus when Gold's UI is # updated to show results from all corpora for tryjobs. cl_triage_link = ('https://{instance}-gold.skia.org/search?' 'issue={issue}&' 'new_clstore=true&' 'query=source_type%3D{corpus}') cl_triage_link = cl_triage_link.format( instance=self._instance, issue=self._gold_properties.issue, corpus=corpus) self._comparison_results[name].triage_link = cl_triage_link else: try: with open(self._triage_link_file) as tlf: triage_link = tlf.read().strip() self._comparison_results[name].triage_link = triage_link except IOError: self._comparison_results[name].triage_link_omission_reason = ( 'Failed to read triage link from file') return rc, stdout