# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- # vim: set filetype=python: # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/.
import glob import itertools import json import os import re import shlex import subprocess import sys import xml.etree.ElementTree as ET
import mozpack.path as mozpath from mozlint import result from mozpack.files import FileFinder
# The Gradle target invocations are serialized with a simple locking file scheme. It's fine for # them to take a while, since the first will compile all the Java, etc, and then perform # potentially expensive static analyses.
GRADLE_LOCK_MAX_WAIT_SECONDS = 20 * 60
with gradle_lock(topobjdir, max_wait_seconds=GRADLE_LOCK_MAX_WAIT_SECONDS): # The android-lint parameter can be used by gradle tasks to run special # logic when they are run for a lint using # project.hasProperty('android-lint')
cmd_args = (
[
sys.executable,
os.path.join(topsrcdir, "mach"), "gradle", "--verbose", "-Pandroid-lint", "--",
]
+ tasks
+ extra_args
)
cmd = " ".join(shlex.quote(arg) for arg in cmd_args)
log.debug(cmd)
# Gradle and mozprocess do not get along well, so we use subprocess # directly.
proc = subprocess.Popen(cmd_args, cwd=topsrcdir)
status = None # Leave it to the subprocess to handle Ctrl+C. If it terminates as a result # of Ctrl+C, proc.wait() will return a status code, and, we get out of the # loop. If it doesn't, like e.g. gdb, we continue waiting. while status isNone: try:
status = proc.wait() except KeyboardInterrupt: pass
with gradle_lock(topobjdir, max_wait_seconds=GRADLE_LOCK_MAX_WAIT_SECONDS): # The android-lint parameter can be used by gradle tasks to run special # logic when they are run for a lint using # project.hasProperty('android-lint')
cmd_args = ["./gradlew"] + tasks
cmd = " ".join(shlex.quote(arg) for arg in cmd_args)
log.debug(cmd)
# Gradle and mozprocess do not get along well, so we use subprocess # directly.
proc = subprocess.Popen(cmd_args, cwd=cwd)
status = None # Leave it to the subprocess to handle Ctrl+C. If it terminates as a result # of Ctrl+C, proc.wait() will return a status code, and, we get out of the # loop. If it doesn't, like e.g. gdb, we continue waiting. while status isNone: try:
status = proc.wait() except KeyboardInterrupt: pass
excludes = [] for path in EXCLUSION_FILES: with open(os.path.join(topsrcdir, path), "r") as fh: for f in fh.readlines(): if"*"in f:
excludes.extend(glob.glob(f.strip())) elif f.startswith(subdir):
excludes.append(f.strip())
with open(os.path.join(topobjdir, folder, "apilint-result.json")) as f:
issues = json.load(f)
for rule in ("compat_failures", "failures"): for r in issues[rule]:
err = { "rule": r["rule"] if rule == "failures"else"compat_failures", "path": r["file"], "lineno": int(r["line"]), "column": int(r.get("column") or 0), "message": r["msg"], "level": "error"if r["error"] else"warning",
}
results.append(result.from_config(config, **err))
for r in issues["api_changes"]:
err = { "rule": "api_changes", "path": r["file"], "lineno": int(r["line"]), "column": int(r.get("column") or 0), "message": "Unexpected api change. Please run ./mach gradle {} for more " "information".format( " ".join(lintargs["substs"]["GRADLE_ANDROID_API_LINT_TASKS"])
),
}
results.append(result.from_config(config, **err))
for output_file in output_files: with open(os.path.join(topobjdir, output_file)) as f: # Like: '[{"path":"/absolute/path/to/topsrcdir/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ContentBlocking.java","lineno":"462","level":"warning","message":"no @return"}]'. # NOQA: E501
issues = json.load(f)
for issue in issues: # We want warnings to be errors for linting purposes. # TODO: Bug 1316188 - resolve missing javadoc comments
issue["level"] = ( "error"if issue["message"] != ": no comment"else"warning"
)
results.append(result.from_config(config, **issue))
gradle(
lintargs["log"],
topsrcdir=topsrcdir,
topobjdir=topobjdir,
tasks=lintargs["substs"]["GRADLE_ANDROID_CHECKSTYLE_TASKS"],
extra_args=lintargs.get("extra_args") or [],
)
results = []
for relative_path in lintargs["substs"]["GRADLE_ANDROID_CHECKSTYLE_OUTPUT_FILES"]:
report_path = os.path.join(lintargs["topobjdir"], relative_path)
results.extend(
_parse_checkstyle_output(
config, topsrcdir=lintargs["root"], report_path=report_path
)
)
return results
def _parse_android_test_results(config, topsrcdir=None, report_dir=None): # A brute force way to turn a Java FQN into a path on disk. Assumes Java # and Kotlin sources are in mobile/android for performance and simplicity.
sourcepath_finder = FileFinder(os.path.join(topsrcdir, "mobile", "android"))
finder = FileFinder(report_dir)
reports = list(finder.find("TEST-*.xml")) ifnot reports: raise RuntimeError("No reports found under {}".format(report_dir))
for report, _ in reports:
tree = ET.parse(open(os.path.join(finder.base, report), "rt"))
root = tree.getroot()
for testcase in root.findall("testcase"):
function_name = testcase.get("name")
# Schema cribbed from http://llg.cubic.org/docs/junit/. for unexpected in itertools.chain(
testcase.findall("error"), testcase.findall("failure")
):
sourcepaths = list(sourcepath_finder.find(path)) ifnot sourcepaths: raise RuntimeError( "No sourcepath found for class {class_name}".format(
class_name=class_name
)
)
for sourcepath, _ in sourcepaths:
lineno = 0
message = unexpected.get("message") # Turn '... at org.mozilla.gecko.permissions.TestPermissions.testMultipleRequestsAreQueuedAndDispatchedSequentially(TestPermissions.java:118)' into 118. # NOQA: E501
pattern = r"at {class_name}\.{function_name}\(.*:(\d+)\)"
pattern = pattern.format(
class_name=class_name, function_name=function_name
)
match = re.search(pattern, message) if match:
lineno = int(match.group(1)) else:
msg = "No source line found for {class_name}.{function_name}".format(
class_name=class_name, function_name=function_name
) raise RuntimeError(msg)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.