blob: 32603e869b11f406af43a74c3adb7836c2fb2e5c [file] [log] [blame]
Colin Cross72119102019-05-20 13:14:18 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2018 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
Jaewoong Junge5cd4e12019-11-22 14:34:55 -080017"""A tool for inserting values from the build system into a manifest or a test config."""
Colin Cross72119102019-05-20 13:14:18 -070018
19from __future__ import print_function
20from xml.dom import minidom
21
22
23android_ns = 'http://schemas.android.com/apk/res/android'
24
25
Colin Crosse1ab8492024-09-11 13:28:16 -070026def get_or_create_applications(doc, manifest):
27 """Get all <application> tags from the manifest, or create one if none exist.
28 Multiple <application> tags may exist when manifest feature flagging is used.
29 """
30 applications = get_children_with_tag(manifest, 'application')
31 if len(applications) == 0:
32 application = doc.createElement('application')
33 indent = get_indent(manifest.firstChild, 1)
34 first = manifest.firstChild
35 manifest.insertBefore(doc.createTextNode(indent), first)
36 manifest.insertBefore(application, first)
37 applications.append(application)
38 return applications
39
40
41def get_or_create_uses_sdks(doc, manifest):
42 """Get all <uses-sdk> tags from the manifest, or create one if none exist.
43 Multiple <uses-sdk> tags may exist when manifest feature flagging is used.
44 """
45 uses_sdks = get_children_with_tag(manifest, 'uses-sdk')
46 if len(uses_sdks) == 0:
47 uses_sdk = doc.createElement('uses-sdk')
48 indent = get_indent(manifest.firstChild, 1)
49 manifest.insertBefore(uses_sdk, manifest.firstChild)
50
51 # Insert an indent before uses-sdk to line it up with the indentation of the
52 # other children of the <manifest> tag.
53 manifest.insertBefore(doc.createTextNode(indent), manifest.firstChild)
54 uses_sdks.append(uses_sdk)
55 return uses_sdks
56
Colin Cross72119102019-05-20 13:14:18 -070057def get_children_with_tag(parent, tag_name):
58 children = []
Colin Cross6cb462b2024-09-11 11:34:35 -070059 for child in parent.childNodes:
Colin Cross72119102019-05-20 13:14:18 -070060 if child.nodeType == minidom.Node.ELEMENT_NODE and \
61 child.tagName == tag_name:
62 children.append(child)
63 return children
64
65
66def find_child_with_attribute(element, tag_name, namespace_uri,
67 attr_name, value):
68 for child in get_children_with_tag(element, tag_name):
69 attr = child.getAttributeNodeNS(namespace_uri, attr_name)
70 if attr is not None and attr.value == value:
71 return child
72 return None
73
74
75def parse_manifest(doc):
76 """Get the manifest element."""
77
78 manifest = doc.documentElement
79 if manifest.tagName != 'manifest':
80 raise RuntimeError('expected manifest tag at root')
81 return manifest
82
83
84def ensure_manifest_android_ns(doc):
85 """Make sure the manifest tag defines the android namespace."""
86
87 manifest = parse_manifest(doc)
88
89 ns = manifest.getAttributeNodeNS(minidom.XMLNS_NAMESPACE, 'android')
90 if ns is None:
91 attr = doc.createAttributeNS(minidom.XMLNS_NAMESPACE, 'xmlns:android')
92 attr.value = android_ns
93 manifest.setAttributeNode(attr)
94 elif ns.value != android_ns:
95 raise RuntimeError('manifest tag has incorrect android namespace ' +
96 ns.value)
97
98
Jaewoong Junge5cd4e12019-11-22 14:34:55 -080099def parse_test_config(doc):
100 """ Get the configuration element. """
101
102 test_config = doc.documentElement
103 if test_config.tagName != 'configuration':
104 raise RuntimeError('expected configuration tag at root')
105 return test_config
106
107
Colin Cross72119102019-05-20 13:14:18 -0700108def as_int(s):
109 try:
110 i = int(s)
111 except ValueError:
112 return s, False
113 return i, True
114
115
116def compare_version_gt(a, b):
117 """Compare two SDK versions.
118
119 Compares a and b, treating codenames like 'Q' as higher
120 than numerical versions like '28'.
121
122 Returns True if a > b
123
124 Args:
125 a: value to compare
126 b: value to compare
127 Returns:
128 True if a is a higher version than b
129 """
130
131 a, a_is_int = as_int(a.upper())
132 b, b_is_int = as_int(b.upper())
133
134 if a_is_int == b_is_int:
135 # Both are codenames or both are versions, compare directly
136 return a > b
137 else:
138 # One is a codename, the other is not. Return true if
139 # b is an integer version
140 return b_is_int
141
142
143def get_indent(element, default_level):
144 indent = ''
145 if element is not None and element.nodeType == minidom.Node.TEXT_NODE:
146 text = element.nodeValue
147 indent = text[:len(text)-len(text.lstrip())]
148 if not indent or indent == '\n':
149 # 1 indent = 4 space
150 indent = '\n' + (' ' * default_level * 4)
151 return indent
152
153
154def write_xml(f, doc):
155 f.write('<?xml version="1.0" encoding="utf-8"?>\n')
156 for node in doc.childNodes:
Cole Faustc41dd722021-11-09 15:08:26 -0800157 f.write(node.toxml() + '\n')