lint_fix: split into separate main and common modules
- Convert most logic into a common class "SoongLintFix" - Clean up code for clarity - Execute using /bin/bash (python uses /bin/sh by default) This change also makes it easier to consume common code from experimental projects. Bug: 232058525 Test: TH Change-Id: I421a78d5ede481baeaa5e082ce4e4ba537259bc5
This commit is contained in:
@@ -25,4 +25,10 @@ python_binary_host {
|
||||
name: "lint_fix",
|
||||
main: "lint_fix.py",
|
||||
srcs: ["lint_fix.py"],
|
||||
libs: ["soong_lint_fix"],
|
||||
}
|
||||
|
||||
python_library_host {
|
||||
name: "soong_lint_fix",
|
||||
srcs: ["soong_lint_fix.py"],
|
||||
}
|
||||
|
||||
@@ -1,77 +1,29 @@
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
# Copyright (C) 2023 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
ANDROID_BUILD_TOP = os.environ.get("ANDROID_BUILD_TOP")
|
||||
PATH_PREFIX = "out/soong/.intermediates"
|
||||
PATH_SUFFIX = "android_common/lint"
|
||||
FIX_DIR = "suggested-fixes"
|
||||
from soong_lint_fix import SoongLintFix
|
||||
|
||||
parser = argparse.ArgumentParser(description="""
|
||||
This is a python script that applies lint fixes to the platform:
|
||||
1. Set up the environment, etc.
|
||||
2. Build the lint and run it.
|
||||
3. Unpack soong's intermediate zip containing source files modified by lint.
|
||||
4. Copy the modified files back into the tree.
|
||||
|
||||
**Gotcha**: You must have run `source build/envsetup.sh` and `lunch` \
|
||||
so that the `ANDROID_BUILD_TOP` environment variable has been set.
|
||||
Alternatively, set it manually in your shell.
|
||||
""", formatter_class=argparse.RawTextHelpFormatter)
|
||||
|
||||
parser.add_argument('build_path', metavar='build_path', type=str,
|
||||
help='The build module to run '
|
||||
'(e.g. frameworks/base/framework-minus-apex or '
|
||||
'frameworks/base/services/core/services.core.unboosted)')
|
||||
|
||||
parser.add_argument('--check', metavar='check', type=str,
|
||||
help='Which lint to run. Passed to the ANDROID_LINT_CHECK environment variable.')
|
||||
|
||||
parser.add_argument('--dry-run', dest='dry_run', action='store_true',
|
||||
help='Just print the resulting shell script instead of running it.')
|
||||
|
||||
parser.add_argument('--no-fix', dest='no_fix', action='store_true',
|
||||
help='Just build and run the lint, do NOT apply the fixes.')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
path = f"{PATH_PREFIX}/{args.build_path}/{PATH_SUFFIX}"
|
||||
target = f"{path}/lint-report.html"
|
||||
|
||||
commands = []
|
||||
|
||||
if not args.dry_run:
|
||||
commands += [f"export ANDROID_BUILD_TOP={ANDROID_BUILD_TOP}"]
|
||||
|
||||
if args.check:
|
||||
commands += [f"export ANDROID_LINT_CHECK={args.check}"]
|
||||
|
||||
commands += [
|
||||
"cd $ANDROID_BUILD_TOP",
|
||||
"source build/envsetup.sh",
|
||||
f"rm {target}", # remove the file first so soong doesn't think there is no work to do
|
||||
f"rm {path}/{FIX_DIR}.zip", # remove in case there are fixes from a prior run that we don't want applied if this run fails
|
||||
f"m {target}",
|
||||
]
|
||||
|
||||
if not args.no_fix:
|
||||
commands += [
|
||||
f"cd {path}",
|
||||
f"unzip {FIX_DIR}.zip -d {FIX_DIR}",
|
||||
f"cd {FIX_DIR}",
|
||||
# Find all the java files in the fix directory, excluding the ./out subdirectory,
|
||||
# and copy them back into the same path within the tree.
|
||||
f"find . -path ./out -prune -o -name '*.java' -print | xargs -n 1 sh -c 'cp $1 $ANDROID_BUILD_TOP/$1' --",
|
||||
f"rm -rf {FIX_DIR}"
|
||||
]
|
||||
|
||||
if args.dry_run:
|
||||
print("(\n" + ";\n".join(commands) + "\n)")
|
||||
sys.exit(0)
|
||||
|
||||
with_echo = []
|
||||
for c in commands:
|
||||
with_echo.append(f'echo "{c}"')
|
||||
with_echo.append(c)
|
||||
|
||||
os.system("(\n" + ";\n".join(with_echo) + "\n)")
|
||||
SoongLintFix().run()
|
||||
|
||||
169
tools/lint/fix/soong_lint_fix.py
Normal file
169
tools/lint/fix/soong_lint_fix.py
Normal file
@@ -0,0 +1,169 @@
|
||||
# Copyright (C) 2022 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
ANDROID_BUILD_TOP = os.environ.get("ANDROID_BUILD_TOP")
|
||||
PATH_PREFIX = "out/soong/.intermediates"
|
||||
PATH_SUFFIX = "android_common/lint"
|
||||
FIX_DIR = "suggested-fixes"
|
||||
|
||||
class SoongLintFix:
|
||||
"""
|
||||
This class creates a command line tool that will
|
||||
apply lint fixes to the platform via the necessary
|
||||
combination of soong and shell commands.
|
||||
|
||||
It provides some basic hooks for experimental code
|
||||
to tweak the generation of the resulting shell script.
|
||||
|
||||
By default, it will apply lint fixes using the intermediate `suggested-fixes`
|
||||
directory that soong creates during its invocation of lint.
|
||||
|
||||
The default argument parser configures a number of command line arguments to
|
||||
facilitate running lint via soong.
|
||||
|
||||
Basic usage:
|
||||
```
|
||||
from soong_lint_fix import SoongLintFix
|
||||
|
||||
SoongLintFix().run()
|
||||
```
|
||||
"""
|
||||
def __init__(self):
|
||||
self._commands = None
|
||||
self._args = None
|
||||
self._path = None
|
||||
self._target = None
|
||||
self._parser = _setup_parser()
|
||||
|
||||
|
||||
def add_argument(self, *args, **kwargs):
|
||||
"""
|
||||
If necessary, add arguments to the underlying argparse.ArgumentParser before running
|
||||
"""
|
||||
self._parser.add_argument(*args, **kwargs)
|
||||
|
||||
|
||||
def run(self, add_setup_commands=None, override_fix_commands=None):
|
||||
"""
|
||||
Run the script
|
||||
:param add_setup_commands: OPTIONAL function to add additional setup commands
|
||||
passed the command line arguments, path, and build target
|
||||
must return a list of strings (the additional commands)
|
||||
:param override_fix_commands: OPTIONAL function to override the fix commands
|
||||
passed the command line arguments, path, and build target
|
||||
must return a list of strings (the fix commands)
|
||||
"""
|
||||
self._setup()
|
||||
if add_setup_commands:
|
||||
self._commands += add_setup_commands(self._args, self._path, self._target)
|
||||
|
||||
self._add_lint_report_commands()
|
||||
|
||||
if not self._args.no_fix:
|
||||
if override_fix_commands:
|
||||
self._commands += override_fix_commands(self._args, self._path, self._target)
|
||||
else:
|
||||
self._commands += [
|
||||
f"cd {self._path}",
|
||||
f"unzip {FIX_DIR}.zip -d {FIX_DIR}",
|
||||
f"cd {FIX_DIR}",
|
||||
# Find all the java files in the fix directory, excluding the ./out subdirectory,
|
||||
# and copy them back into the same path within the tree.
|
||||
f"find . -path ./out -prune -o -name '*.java' -print | xargs -n 1 sh -c 'cp $1 $ANDROID_BUILD_TOP/$1 || exit 255' --",
|
||||
f"rm -rf {FIX_DIR}"
|
||||
]
|
||||
|
||||
|
||||
if self._args.dry_run:
|
||||
print(self._get_commands_str())
|
||||
else:
|
||||
self._execute()
|
||||
|
||||
|
||||
def _setup(self):
|
||||
self._args = self._parser.parse_args()
|
||||
self._commands = []
|
||||
self._path = f"{PATH_PREFIX}/{self._args.build_path}/{PATH_SUFFIX}"
|
||||
self._target = f"{self._path}/lint-report.html"
|
||||
|
||||
if not self._args.dry_run:
|
||||
self._commands += [f"export ANDROID_BUILD_TOP={ANDROID_BUILD_TOP}"]
|
||||
|
||||
if self._args.check:
|
||||
self._commands += [f"export ANDROID_LINT_CHECK={self._args.check}"]
|
||||
|
||||
|
||||
def _add_lint_report_commands(self):
|
||||
self._commands += [
|
||||
"cd $ANDROID_BUILD_TOP",
|
||||
"source build/envsetup.sh",
|
||||
# remove the file first so soong doesn't think there is no work to do
|
||||
f"rm {self._target}",
|
||||
# remove in case there are fixes from a prior run,
|
||||
# that we don't want applied if this run fails
|
||||
f"rm {self._path}/{FIX_DIR}.zip",
|
||||
f"m {self._target}",
|
||||
]
|
||||
|
||||
|
||||
def _get_commands_str(self):
|
||||
prefix = "(\n"
|
||||
delimiter = ";\n"
|
||||
suffix = "\n)"
|
||||
return f"{prefix}{delimiter.join(self._commands)}{suffix}"
|
||||
|
||||
|
||||
def _execute(self, with_echo=True):
|
||||
if with_echo:
|
||||
exec_commands = []
|
||||
for c in self._commands:
|
||||
exec_commands.append(f'echo "{c}"')
|
||||
exec_commands.append(c)
|
||||
self._commands = exec_commands
|
||||
|
||||
subprocess.call(self._get_commands_str(), executable='/bin/bash', shell=True)
|
||||
|
||||
|
||||
def _setup_parser():
|
||||
parser = argparse.ArgumentParser(description="""
|
||||
This is a python script that applies lint fixes to the platform:
|
||||
1. Set up the environment, etc.
|
||||
2. Run lint on the specified target.
|
||||
3. Copy the modified files, from soong's intermediate directory, back into the tree.
|
||||
|
||||
**Gotcha**: You must have run `source build/envsetup.sh` and `lunch`
|
||||
so that the `ANDROID_BUILD_TOP` environment variable has been set.
|
||||
Alternatively, set it manually in your shell.
|
||||
""", formatter_class=argparse.RawTextHelpFormatter)
|
||||
|
||||
parser.add_argument('build_path', metavar='build_path', type=str,
|
||||
help='The build module to run '
|
||||
'(e.g. frameworks/base/framework-minus-apex or '
|
||||
'frameworks/base/services/core/services.core.unboosted)')
|
||||
|
||||
parser.add_argument('--check', metavar='check', type=str,
|
||||
help='Which lint to run. Passed to the ANDROID_LINT_CHECK environment variable.')
|
||||
|
||||
parser.add_argument('--dry-run', dest='dry_run', action='store_true',
|
||||
help='Just print the resulting shell script instead of running it.')
|
||||
|
||||
parser.add_argument('--no-fix', dest='no_fix', action='store_true',
|
||||
help='Just build and run the lint, do NOT apply the fixes.')
|
||||
|
||||
return parser
|
||||
Reference in New Issue
Block a user