| # |
| # Copyright (C) 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. |
| # |
| """Extracts values from the AndroidManifest.xml file.""" |
| from __future__ import print_function |
| |
| import argparse |
| import os.path |
| import xml.etree.ElementTree |
| |
| |
| def parse_args() -> argparse.Namespace: |
| """Parse and return command line arguments.""" |
| parser = argparse.ArgumentParser() |
| |
| parser.add_argument( |
| "property", |
| metavar="PROPERTY", |
| choices=("minSdkVersion", "debuggable"), |
| help="Property to extract from the manifest file.", |
| ) |
| |
| parser.add_argument( |
| "manifest_file", |
| metavar="MANIFEST_FILE", |
| type=os.path.abspath, # type: ignore |
| help="Path to the AndroidManifest.xml file.", |
| ) |
| |
| return parser.parse_args() |
| |
| |
| def get_rpath_attribute( |
| root: xml.etree.ElementTree.Element, |
| element_path: str, |
| attribute: str, |
| default: str = "", |
| ) -> str: |
| """Returns the value of an attribute at an rpath. |
| |
| If more than one element exists with the same name, only the first is |
| checked. |
| |
| Args: |
| root: The XML element to search from. |
| path: The path to the element. |
| attribute: The name of the attribute to fetch. |
| |
| Returns: |
| The attribute's value as a string if found, else the value of |
| `default`. |
| """ |
| ns_url = "http://schemas.android.com/apk/res/android" |
| ns = { |
| "android": ns_url, |
| } |
| |
| elem = root.find(element_path, ns) |
| if elem is None: |
| return "" |
| # ElementTree elements don't have the same helpful namespace parameter that |
| # the find family does :( |
| attrib_name = attribute.replace("android:", "{" + ns_url + "}") |
| return str(elem.get(attrib_name, default)) |
| |
| |
| def get_minsdkversion(root: xml.etree.ElementTree.Element) -> str: |
| """Finds and returns the value of android:minSdkVersion in the manifest. |
| |
| Returns: |
| String form of android:minSdkVersion if found, else the empty string. |
| """ |
| return get_rpath_attribute(root, "./uses-sdk", "android:minSdkVersion", "") |
| |
| |
| def get_debuggable(root: xml.etree.ElementTree.Element) -> str: |
| """Finds and returns the value of android:debuggable in the manifest. |
| |
| Returns: |
| String form of android:debuggable if found, else the empty string. |
| """ |
| debuggable = get_rpath_attribute(root, "./application", "android:debuggable", "") |
| |
| # Though any such manifest would be invalid, the awk script rewrote bogus |
| # values to false. Missing attributes should also be false. |
| if debuggable != "true": |
| debuggable = "false" |
| |
| return debuggable |
| |
| |
| def main() -> None: |
| args = parse_args() |
| |
| tree = xml.etree.ElementTree.parse(args.manifest_file) |
| if args.property == "minSdkVersion": |
| print(get_minsdkversion(tree.getroot())) |
| elif args.property == "debuggable": |
| print(get_debuggable(tree.getroot())) |
| else: |
| raise ValueError |
| |
| |
| if __name__ == "__main__": |
| main() |