Tobias Thierer | 573c7b0 | 2017-12-19 16:24:58 +0000 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | # |
| 3 | # Copyright (C) 2017 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 | |
| 17 | """ |
| 18 | Compares one or more corresponding files from ojluni against one or |
| 19 | more upstream or from upstreams against each other. |
| 20 | The repositories (default: ojluni vs. expected current upstream) and |
| 21 | the diff tool (default: meld) can be specified by command line options. |
| 22 | |
| 23 | This tool is for libcore maintenance; if you're not maintaining libcore, |
| 24 | you won't need it (and might not have access to some of the instructions |
| 25 | below). |
| 26 | |
| 27 | The naming of the repositories (expected, ojluni, 7u40, 8u121-b13, |
| 28 | 9b113+, 9+181) is based on the directory name where corresponding |
| 29 | snapshots are stored when following the instructions at |
| 30 | http://go/libcore-o-verify |
| 31 | |
| 32 | This in turn derives from the instructions at the top of: |
| 33 | libcore/tools/upstream/src/main/java/libcore/CompareUpstreams.java |
| 34 | |
| 35 | Possible uses: |
| 36 | |
| 37 | To verify that ArrayList has been updated to the expected upstream |
| 38 | and that all local patches carry change markers, we compare that |
| 39 | file from ojluni against the expected upstream (the default): |
| 40 | upstream-diff java/util/ArrayList.java |
| 41 | |
| 42 | To verify multiple files: |
Tobias Thierer | 573c7b0 | 2017-12-19 16:24:58 +0000 | [diff] [blame] | 43 | upstream-diff java.util.ArrayList java.util.LinkedList |
| 44 | |
Sorin Basca | 6593262 | 2021-04-26 06:53:23 +0000 | [diff] [blame] | 45 | To verify a folder: |
| 46 | upstream-diff java/util/concurrent |
| 47 | |
| 48 | To verify a package: |
| 49 | upstream-diff java.util.concurrent |
| 50 | |
Tobias Thierer | 573c7b0 | 2017-12-19 16:24:58 +0000 | [diff] [blame] | 51 | Use a three-way merge to integrate changes from 9+181 into ArrayList: |
| 52 | upstream-diff -r 8u121-b13,ojluni,9+181 java/util/ArrayList.java |
| 53 | or to investigate which version of upstream introduced a change: |
| 54 | upstream-diff -r 7u40,8u60,8u121-b13 java/util/ArrayList.java |
| 55 | """ |
| 56 | |
| 57 | import argparse |
| 58 | import os |
Tobias Thierer | bc8f124 | 2018-03-13 16:53:09 +0000 | [diff] [blame] | 59 | import os.path |
Tobias Thierer | dc7557c | 2018-03-31 20:21:30 +0100 | [diff] [blame] | 60 | import re |
Tobias Thierer | 573c7b0 | 2017-12-19 16:24:58 +0000 | [diff] [blame] | 61 | import subprocess |
| 62 | import sys |
| 63 | |
Sorin Basca | 6593262 | 2021-04-26 06:53:23 +0000 | [diff] [blame] | 64 | |
| 65 | def get_path_type(rel_path): |
| 66 | ext = os.path.splitext(rel_path)[-1] |
| 67 | # Check the extension and if it is a C/C++ extension then we're dealing |
| 68 | # with a native path. Otherwise we would be dealing with a java path, which |
| 69 | # can be a filename, folder name, package name, or fully qualified class |
| 70 | # name. |
| 71 | if re.match('\\.(c|cc|cpp|cxx|h|hpp|hxx|icc)$', ext): |
| 72 | return 'native' |
| 73 | return 'java' |
| 74 | |
| 75 | |
| 76 | def normalize_java_path(rel_path): |
| 77 | if re.match('.+\\.java$', rel_path): |
| 78 | # Path ends in '.java' so a filename with its path is expected |
| 79 | return rel_path |
| 80 | |
| 81 | if '/' not in rel_path: |
| 82 | # Convert package name, or fully qualified class name into path |
| 83 | rel_path = rel_path.replace('.', '/') |
| 84 | |
| 85 | if any(c.isupper() for c in rel_path): |
| 86 | # If the name includes an uppercase character, we guess that this is a |
| 87 | # class rather than a package name, so the extension needs to be appended |
| 88 | # to get the full filename |
| 89 | # Note: Test packages may have upper case characters in the package name, |
| 90 | # so, if trying to diff a test package, the ".java" suffix will be added |
| 91 | # unnecessarily, causing a wrong diff input. Therefore, for test packages, |
| 92 | # the tool should be used for each file individually |
| 93 | rel_path += '.java' |
| 94 | elif rel_path[-1] != '/': |
| 95 | # No upper case characters, so this must be a folder/package |
| 96 | rel_path += '/' |
| 97 | |
| 98 | return rel_path |
| 99 | |
| 100 | |
Tobias Thierer | 573c7b0 | 2017-12-19 16:24:58 +0000 | [diff] [blame] | 101 | def run_diff(diff, repositories, rel_paths): |
| 102 | # Root of checked-out Android sources, set by the "lunch" command. |
| 103 | android_build_top = os.environ['ANDROID_BUILD_TOP'] |
Sorin Basca | 6593262 | 2021-04-26 06:53:23 +0000 | [diff] [blame] | 104 | # Root of repository snapshots. See go/libcore-o-verify for how you'd want |
| 105 | # to set this. |
Tobias Thierer | 573c7b0 | 2017-12-19 16:24:58 +0000 | [diff] [blame] | 106 | ojluni_upstreams = os.environ['OJLUNI_UPSTREAMS'] |
| 107 | for rel_path in rel_paths: |
Sorin Basca | 6593262 | 2021-04-26 06:53:23 +0000 | [diff] [blame] | 108 | path_type = get_path_type(rel_path) |
| 109 | if path_type == 'java': |
| 110 | rel_path = normalize_java_path(rel_path) |
Tobias Thierer | 573c7b0 | 2017-12-19 16:24:58 +0000 | [diff] [blame] | 111 | paths = [] |
Sorin Basca | 6593262 | 2021-04-26 06:53:23 +0000 | [diff] [blame] | 112 | |
Tobias Thierer | 573c7b0 | 2017-12-19 16:24:58 +0000 | [diff] [blame] | 113 | for repository in repositories: |
Tobias Thierer | dc7557c | 2018-03-31 20:21:30 +0100 | [diff] [blame] | 114 | if repository == 'ojluni': |
Tobias Thierer | dc7557c | 2018-03-31 20:21:30 +0100 | [diff] [blame] | 115 | paths.append('%s/libcore/ojluni/src/main/%s/%s' |
Sorin Basca | 6593262 | 2021-04-26 06:53:23 +0000 | [diff] [blame] | 116 | % (android_build_top, path_type, rel_path)) |
Tobias Thierer | 573c7b0 | 2017-12-19 16:24:58 +0000 | [diff] [blame] | 117 | else: |
| 118 | paths.append('%s/%s/%s' % (ojluni_upstreams, repository, rel_path)) |
| 119 | subprocess.call([diff] + paths) |
| 120 | |
Sorin Basca | 6593262 | 2021-04-26 06:53:23 +0000 | [diff] [blame] | 121 | |
Tobias Thierer | 573c7b0 | 2017-12-19 16:24:58 +0000 | [diff] [blame] | 122 | def main(): |
| 123 | parser = argparse.ArgumentParser( |
Tobias Thierer | bc8f124 | 2018-03-13 16:53:09 +0000 | [diff] [blame] | 124 | description='Compare files between libcore/ojluni and ${OJLUNI_UPSTREAMS}.', |
| 125 | formatter_class=argparse.ArgumentDefaultsHelpFormatter, # include default values in help |
| 126 | ) |
| 127 | upstreams = os.environ['OJLUNI_UPSTREAMS'] |
| 128 | # natsort.natsorted() would be a nicer sort order, but I'd rather avoid the dependency |
| 129 | repositories = ['ojluni'] + sorted( |
| 130 | [d for d in os.listdir(upstreams) if os.path.isdir(os.path.join(upstreams, d))] |
| 131 | ) |
Tobias Thierer | 573c7b0 | 2017-12-19 16:24:58 +0000 | [diff] [blame] | 132 | parser.add_argument('-r', '--repositories', default='ojluni,expected', |
Tobias Thierer | bc8f124 | 2018-03-13 16:53:09 +0000 | [diff] [blame] | 133 | help='Comma-separated list of 2-3 repositories, to compare, in order; ' |
| 134 | 'available repositories: ' + ' '.join(repositories) + '.') |
Tobias Thierer | 573c7b0 | 2017-12-19 16:24:58 +0000 | [diff] [blame] | 135 | parser.add_argument('-d', '--diff', default='meld', |
| 136 | help='Application to use for diffing.') |
| 137 | parser.add_argument('rel_path', nargs="+", |
Tobias Thierer | dc7557c | 2018-03-31 20:21:30 +0100 | [diff] [blame] | 138 | help='File to compare: either a relative path below libcore/ojluni/' |
| 139 | 'src/main/{java,native}, or a fully qualified class name.') |
Tobias Thierer | 573c7b0 | 2017-12-19 16:24:58 +0000 | [diff] [blame] | 140 | args = parser.parse_args() |
| 141 | repositories = args.repositories.split(',') |
| 142 | if (len(repositories) < 2): |
| 143 | print('Expected >= 2 repositories to compare, got: ' + str(repositories)) |
| 144 | parser.print_help() |
| 145 | sys.exit(1) |
| 146 | run_diff(args.diff, repositories, args.rel_path) |
| 147 | |
Sorin Basca | 6593262 | 2021-04-26 06:53:23 +0000 | [diff] [blame] | 148 | |
Tobias Thierer | 573c7b0 | 2017-12-19 16:24:58 +0000 | [diff] [blame] | 149 | if __name__ == "__main__": |
| 150 | main() |