#!/usr/bin/python # # 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. """ Compares one or more corresponding files from ojluni against one or more upstream or from upstreams against each other. The repositories (default: ojluni vs. expected current upstream) and the diff tool (default: meld) can be specified by command line options. This tool is for libcore maintenance; if you're not maintaining libcore, you won't need it (and might not have access to some of the instructions below). The naming of the repositories (expected, ojluni, 7u40, 8u121-b13, 9b113+, 9+181) is based on the directory name where corresponding snapshots are stored when following the instructions at http://go/libcore-o-verify This in turn derives from the instructions at the top of: libcore/tools/upstream/src/main/java/libcore/CompareUpstreams.java Possible uses: To verify that ArrayList has been updated to the expected upstream and that all local patches carry change markers, we compare that file from ojluni against the expected upstream (the default): upstream-diff java/util/ArrayList.java To verify multiple files: upstream-diff java.util.ArrayList java.util.LinkedList Use a three-way merge to integrate changes from 9+181 into ArrayList: upstream-diff -r 8u121-b13,ojluni,9+181 java/util/ArrayList.java or to investigate which version of upstream introduced a change: upstream-diff -r 7u40,8u60,8u121-b13 java/util/ArrayList.java """ import argparse import os import os.path import re import subprocess import sys def run_diff(diff, repositories, rel_paths): # Root of checked-out Android sources, set by the "lunch" command. android_build_top = os.environ['ANDROID_BUILD_TOP'] # Root of repository snapshots. See go/libcore-o-verify for how you'd want to set this. ojluni_upstreams = os.environ['OJLUNI_UPSTREAMS'] for rel_path in rel_paths: # Paths end with a dot and lowercase file extension (.c, .java, ...) but # fully qualified class names do not. if ('/' not in rel_path) and (not re.match('.+\\.[a-z]{1,4}$', rel_path)): # Assume a fully qualified class name rel_path = rel_path.replace('.', '/') + '.java' paths = [] for repository in repositories: if repository == 'ojluni': file_group = 'java/' if rel_path.endswith('.java') else 'native/' paths.append('%s/libcore/ojluni/src/main/%s/%s' % (android_build_top, file_group, rel_path)) else: paths.append('%s/%s/%s' % (ojluni_upstreams, repository, rel_path)) subprocess.call([diff] + paths) def main(): parser = argparse.ArgumentParser( description='Compare files between libcore/ojluni and ${OJLUNI_UPSTREAMS}.', formatter_class=argparse.ArgumentDefaultsHelpFormatter, # include default values in help ) upstreams = os.environ['OJLUNI_UPSTREAMS'] # natsort.natsorted() would be a nicer sort order, but I'd rather avoid the dependency repositories = ['ojluni'] + sorted( [d for d in os.listdir(upstreams) if os.path.isdir(os.path.join(upstreams, d))] ) parser.add_argument('-r', '--repositories', default='ojluni,expected', help='Comma-separated list of 2-3 repositories, to compare, in order; ' 'available repositories: ' + ' '.join(repositories) + '.') parser.add_argument('-d', '--diff', default='meld', help='Application to use for diffing.') parser.add_argument('rel_path', nargs="+", help='File to compare: either a relative path below libcore/ojluni/' 'src/main/{java,native}, or a fully qualified class name.') args = parser.parse_args() repositories = args.repositories.split(',') if (len(repositories) < 2): print('Expected >= 2 repositories to compare, got: ' + str(repositories)) parser.print_help() sys.exit(1) run_diff(args.diff, repositories, args.rel_path) if __name__ == "__main__": main()