gsi_util: adding check_compat subcommand
'check_compat' command can check the compatibility between
system and vendor image, which can be any source supported by
mounters, ex. image file, folder or adb.
Uses following command for the detail:
$ ./gsu_util.py check_compat --help
The patch also includes a 'checker' framework. There is only
one checker 'VintfChecker' at this time. VintfChecker uses a
host tool, 'checkvintf', to check the compatibility.
Bug: 70253825
Test: check_compat with different mounters
Change-Id: I459b4cbd38465c0058087b4c68bca66e491c940e
This commit is contained in:
@@ -17,6 +17,7 @@ python_binary_host {
|
|||||||
srcs: [
|
srcs: [
|
||||||
"gsi_util.py",
|
"gsi_util.py",
|
||||||
"gsi_util/*.py",
|
"gsi_util/*.py",
|
||||||
|
"gsi_util/checkers/*.py",
|
||||||
"gsi_util/commands/*.py",
|
"gsi_util/commands/*.py",
|
||||||
"gsi_util/dumpers/*.py",
|
"gsi_util/dumpers/*.py",
|
||||||
"gsi_util/mounters/*.py",
|
"gsi_util/mounters/*.py",
|
||||||
@@ -25,6 +26,7 @@ python_binary_host {
|
|||||||
required: [
|
required: [
|
||||||
"adb",
|
"adb",
|
||||||
"avbtool",
|
"avbtool",
|
||||||
|
"checkvintf",
|
||||||
"simg2img",
|
"simg2img",
|
||||||
],
|
],
|
||||||
version: {
|
version: {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class GsiUtil(object):
|
|||||||
|
|
||||||
# Adds gsi_util COMMAND here.
|
# Adds gsi_util COMMAND here.
|
||||||
# TODO(bowgotsai): auto collect from gsi_util/commands/*.py
|
# TODO(bowgotsai): auto collect from gsi_util/commands/*.py
|
||||||
_COMMANDS = ['flash_gsi', 'pull', 'dump', 'hello']
|
_COMMANDS = ['flash_gsi', 'pull', 'dump', 'check_compat', 'hello']
|
||||||
|
|
||||||
_LOGGING_FORMAT = '%(message)s'
|
_LOGGING_FORMAT = '%(message)s'
|
||||||
_LOGGING_LEVEL = logging.WARNING
|
_LOGGING_LEVEL = logging.WARNING
|
||||||
|
|||||||
0
gsi/gsi_util/gsi_util/checkers/__init__.py
Normal file
0
gsi/gsi_util/gsi_util/checkers/__init__.py
Normal file
19
gsi/gsi_util/gsi_util/checkers/check_result.py
Normal file
19
gsi/gsi_util/gsi_util/checkers/check_result.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Copyright 2017 - 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.
|
||||||
|
|
||||||
|
"""Provide namedtuple CheckResultItem."""
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
CheckResultItem = namedtuple('CheckResultItem', 'name result message')
|
||||||
57
gsi/gsi_util/gsi_util/checkers/checker.py
Normal file
57
gsi/gsi_util/gsi_util/checkers/checker.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# Copyright 2017 - 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.
|
||||||
|
|
||||||
|
"""Provide class Checker and maintain the checking list."""
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
from gsi_util.checkers.vintf_checker import VintfChecker
|
||||||
|
|
||||||
|
CheckListItem = namedtuple('CheckListItem', 'id checker_class')
|
||||||
|
|
||||||
|
_CHECK_LIST = [
|
||||||
|
CheckListItem('checkvintf', VintfChecker),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Checker(object):
|
||||||
|
"""Implement methods and utils to checking compatibility a FileAccessor."""
|
||||||
|
|
||||||
|
def __init__(self, file_accessor):
|
||||||
|
self._file_accessor = file_accessor
|
||||||
|
|
||||||
|
def check(self, check_list):
|
||||||
|
check_result_items = []
|
||||||
|
|
||||||
|
for x in check_list:
|
||||||
|
checker = x.checker_class(self._file_accessor)
|
||||||
|
check_result_items += checker.check()
|
||||||
|
|
||||||
|
return check_result_items
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def make_check_list_with_ids(ids):
|
||||||
|
check_list = []
|
||||||
|
for check_id in ids:
|
||||||
|
# Find the first item matched check_id
|
||||||
|
matched_check_item = next((x for x in _CHECK_LIST if x.id == check_id),
|
||||||
|
None)
|
||||||
|
if not matched_check_item:
|
||||||
|
raise RuntimeError('Unknown check ID: "{}"'.format(check_id))
|
||||||
|
check_list.append(matched_check_item)
|
||||||
|
return check_list
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_all_check_list():
|
||||||
|
return _CHECK_LIST
|
||||||
42
gsi/gsi_util/gsi_util/checkers/vintf_checker.py
Normal file
42
gsi/gsi_util/gsi_util/checkers/vintf_checker.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# Copyright 2017 - 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.
|
||||||
|
|
||||||
|
"""Provides class VintfChecker."""
|
||||||
|
|
||||||
|
from gsi_util.checkers.check_result import CheckResultItem
|
||||||
|
import gsi_util.utils.vintf_utils as vintf_utils
|
||||||
|
|
||||||
|
|
||||||
|
class VintfChecker(object):
|
||||||
|
|
||||||
|
_SYSTEM_MANIFEST_XML = '/system/manifest.xml'
|
||||||
|
_VENDOR_MATRIX_XML = '/vendor/compatibility_matrix.xml'
|
||||||
|
_REQUIRED_FILES = [_SYSTEM_MANIFEST_XML, _VENDOR_MATRIX_XML]
|
||||||
|
|
||||||
|
def __init__(self, file_accessor):
|
||||||
|
self._file_accessor = file_accessor
|
||||||
|
|
||||||
|
def check(self):
|
||||||
|
fa = self._file_accessor
|
||||||
|
|
||||||
|
with fa.prepare_multi_files(self._REQUIRED_FILES) as [manifest, matrix]:
|
||||||
|
if not manifest:
|
||||||
|
raise RuntimeError('Cannot open manifest file: {}'.format(
|
||||||
|
self._SYSTEM_MANIFEST_XML))
|
||||||
|
if not matrix:
|
||||||
|
raise RuntimeError('Cannot open matrix file: {}'.format(
|
||||||
|
self._VENDOR_MATRIX_XML))
|
||||||
|
|
||||||
|
result, error_message = vintf_utils.checkvintf(manifest, matrix)
|
||||||
|
return [CheckResultItem('checkvintf', result, error_message)]
|
||||||
145
gsi/gsi_util/gsi_util/commands/check_compat.py
Normal file
145
gsi/gsi_util/gsi_util/commands/check_compat.py
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
# Copyright 2017 - 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.
|
||||||
|
"""Provide command 'check_compat'."""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from gsi_util.checkers.checker import Checker
|
||||||
|
from gsi_util.mounters.composite_mounter import CompositeMounter
|
||||||
|
|
||||||
|
|
||||||
|
class CheckReporter(object):
|
||||||
|
"""Output the checker result with formating."""
|
||||||
|
|
||||||
|
_OUTPUT_FORMAT = '{:30}: {}'
|
||||||
|
_ERR_MSE_FORMAT = ' {}'
|
||||||
|
_SUMMARY_NAME = 'summary'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_pass_str(is_pass):
|
||||||
|
return 'pass' if is_pass else 'fail'
|
||||||
|
|
||||||
|
def _output_result_item(self, result_item):
|
||||||
|
name, result, message = result_item
|
||||||
|
if not self._only_summary:
|
||||||
|
result_str = self._get_pass_str(result)
|
||||||
|
print self._OUTPUT_FORMAT.format(name, result_str)
|
||||||
|
if message:
|
||||||
|
print self._ERR_MSE_FORMAT.format(message)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _output_summary(self, summary_result):
|
||||||
|
summary_result_str = self._get_pass_str(summary_result)
|
||||||
|
print self._OUTPUT_FORMAT.format(self._SUMMARY_NAME, summary_result_str)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._only_summary = False
|
||||||
|
|
||||||
|
def set_only_summary(self):
|
||||||
|
self._only_summary = True
|
||||||
|
|
||||||
|
def output(self, check_results):
|
||||||
|
all_pass = True
|
||||||
|
for result_item in check_results:
|
||||||
|
item_pass = self._output_result_item(result_item)
|
||||||
|
all_pass = all_pass and item_pass
|
||||||
|
self._output_summary(all_pass)
|
||||||
|
|
||||||
|
|
||||||
|
def do_list_check(_):
|
||||||
|
for info in Checker.get_all_check_list():
|
||||||
|
print info.id
|
||||||
|
|
||||||
|
|
||||||
|
def do_check_compat(args):
|
||||||
|
logging.info('==== CHECK_COMPAT ====')
|
||||||
|
logging.info(' system=%s vendor=%s', args.system, args.vendor)
|
||||||
|
|
||||||
|
# args.system and args.vendor are required
|
||||||
|
mounter = CompositeMounter()
|
||||||
|
mounter.add_by_mount_target('system', args.system)
|
||||||
|
mounter.add_by_mount_target('vendor', args.vendor)
|
||||||
|
|
||||||
|
logging.debug('Checking ID list: %s', args.ID)
|
||||||
|
check_list = Checker.make_check_list_with_ids(args.ID) if len(
|
||||||
|
args.ID) else Checker.get_all_check_list()
|
||||||
|
|
||||||
|
with mounter as file_accessor:
|
||||||
|
checker = Checker(file_accessor)
|
||||||
|
check_result = checker.check(check_list)
|
||||||
|
|
||||||
|
reporter = CheckReporter()
|
||||||
|
if args.only_summary:
|
||||||
|
reporter.set_only_summary()
|
||||||
|
reporter.output(check_result)
|
||||||
|
|
||||||
|
logging.info('==== DONE ====')
|
||||||
|
|
||||||
|
|
||||||
|
DUMP_DESCRIPTION = """'check_compat' command checks compatibility images
|
||||||
|
|
||||||
|
You must assign at least one image source by SYSTEM and/or VENDOR.
|
||||||
|
Image source could be:
|
||||||
|
|
||||||
|
adb[:SERIAL_NUM]: form the device which be connected with adb
|
||||||
|
image file name: from the given image file, e.g. the file name of a GSI.
|
||||||
|
If a image file is assigned to be the source of system
|
||||||
|
image, gsu_util will detect system-as-root automatically.
|
||||||
|
folder name: from the given folder, e.g. the system/vendor folder in an
|
||||||
|
Android build out folder.
|
||||||
|
|
||||||
|
You could use command 'list_check' to query all IDs:
|
||||||
|
|
||||||
|
$ ./gsi_util.py list_check
|
||||||
|
|
||||||
|
Here is an examples to check a system.img and a device are compatible:
|
||||||
|
|
||||||
|
$ ./gsi_util.py check_compat --system system.img --vendor adb"""
|
||||||
|
|
||||||
|
|
||||||
|
def setup_command_args(parser):
|
||||||
|
"""Setup command 'list_check' and 'check_compat'."""
|
||||||
|
|
||||||
|
# command 'list_check'
|
||||||
|
list_check_parser = parser.add_parser(
|
||||||
|
'list_check', help='list all possible checking IDs')
|
||||||
|
list_check_parser.set_defaults(func=do_list_check)
|
||||||
|
|
||||||
|
# command 'check_compat'
|
||||||
|
check_compat_parser = parser.add_parser(
|
||||||
|
'check_compat',
|
||||||
|
help='checks compatibility between a system and a vendor',
|
||||||
|
description=DUMP_DESCRIPTION,
|
||||||
|
formatter_class=argparse.RawTextHelpFormatter)
|
||||||
|
check_compat_parser.add_argument(
|
||||||
|
'--system',
|
||||||
|
type=str,
|
||||||
|
required=True,
|
||||||
|
help='system image file name, folder name or "adb"')
|
||||||
|
check_compat_parser.add_argument(
|
||||||
|
'--vendor',
|
||||||
|
type=str,
|
||||||
|
required=True,
|
||||||
|
help='vendor image file name, folder name or "adb"')
|
||||||
|
check_compat_parser.add_argument(
|
||||||
|
'--only-summary',
|
||||||
|
action='store_true',
|
||||||
|
help='only output the summary result')
|
||||||
|
check_compat_parser.add_argument(
|
||||||
|
'ID',
|
||||||
|
type=str,
|
||||||
|
nargs='*',
|
||||||
|
help='the checking ID to be dumped. Check all if not given')
|
||||||
|
check_compat_parser.set_defaults(func=do_check_compat)
|
||||||
41
gsi/gsi_util/gsi_util/utils/vintf_utils.py
Normal file
41
gsi/gsi_util/gsi_util/utils/vintf_utils.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2017 - 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.
|
||||||
|
"""VINTF-related utilities."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from gsi_util.utils.cmd_utils import run_command
|
||||||
|
|
||||||
|
|
||||||
|
def checkvintf(manifest, matrix):
|
||||||
|
"""call checkvintf.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
manifest: manifest file
|
||||||
|
matrix: matrix file
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A tuple with (check_result, error_message)
|
||||||
|
"""
|
||||||
|
logging.debug('checkvintf %s %s...', manifest, matrix)
|
||||||
|
|
||||||
|
# 'read_stdout=True' to disable output
|
||||||
|
(returncode, _, stderrdata) = run_command(
|
||||||
|
['checkvintf', manifest, matrix],
|
||||||
|
raise_on_error=False,
|
||||||
|
read_stdout=True,
|
||||||
|
read_stderr=True)
|
||||||
|
return (returncode == 0, stderrdata)
|
||||||
Reference in New Issue
Block a user