lin
2025-08-21 57113df3a0e2be01232281fad9a5f2c060567981
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# Copyright (C) 2018 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.
"""Helper functions for updaters."""
 
import os
import re
import subprocess
import sys
 
 
def create_updater(metadata, proj_path, updaters):
    """Creates corresponding updater object for a project.
 
    Args:
      metadata: Parsed proto for METADATA file.
      proj_path: Absolute path for the project.
 
    Returns:
      An updater object.
 
    Raises:
      ValueError: Occurred when there's no updater for all urls.
    """
    for url in metadata.third_party.url:
        for updater in updaters:
            try:
                return updater(url, proj_path, metadata)
            except ValueError:
                pass
 
    raise ValueError('No supported URL.')
 
 
def replace_package(source_dir, target_dir):
    """Invokes a shell script to prepare and update a project.
 
    Args:
      source_dir: Path to the new downloaded and extracted package.
      target_dir: The path to the project in Android source tree.
    """
 
    print('Updating {} using {}.'.format(target_dir, source_dir))
    script_path = os.path.join(
        os.path.dirname(
            sys.argv[0]),
        'update_package.sh')
    subprocess.check_call(['bash', script_path, source_dir, target_dir])
 
VERSION_SPLITTER_PATTERN = r'[\.\-_]'
VERSION_PATTERN = (r'^(?P<prefix>[^\d]*)' +
                   r'(?P<version>\d+(' + VERSION_SPLITTER_PATTERN + r'\d+)*)' +
                   r'(?P<suffix>.*)$')
VERSION_RE = re.compile(VERSION_PATTERN)
VERSION_SPLITTER_RE = re.compile(VERSION_SPLITTER_PATTERN)
 
 
def _parse_version(version):
    match = VERSION_RE.match(version)
    if match is None:
        raise ValueError('Invalid version.')
    try:
        return match.group('prefix', 'version', 'suffix')
    except IndexError:
        raise ValueError('Invalid version.')
 
 
def _match_and_get_version(prefix, suffix, version):
    try:
        version_prefix, version, version_suffix = _parse_version(version)
    except ValueError:
        return []
 
    right_format = (version_prefix == prefix and version_suffix == suffix)
 
    return [right_format] + [int(v) for v in VERSION_SPLITTER_RE.split(version)]
 
 
def get_latest_version(current_version, version_list):
    """Gets the latest version name from a list of versions.
 
    The new version must have the same prefix and suffix with old version.
    If no matched version is newer, current version name will be returned.
    """
    prefix, _, suffix = _parse_version(current_version)
 
    latest = max(version_list,
                 key=lambda ver: _match_and_get_version(
                     prefix, suffix, ver),
                 default=[])
    if not latest:
        raise ValueError('No matching version.')
    return latest