151 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
| #!/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
 | |
| 
 | |
| To verify a folder:
 | |
|   upstream-diff java/util/concurrent
 | |
| 
 | |
| To verify a package:
 | |
|   upstream-diff java.util.concurrent
 | |
| 
 | |
| 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 get_path_type(rel_path):
 | |
|     ext = os.path.splitext(rel_path)[-1]
 | |
|     # Check the extension and if it is a C/C++ extension then we're dealing
 | |
|     # with a native path. Otherwise we would be dealing with a java path, which
 | |
|     # can be a filename, folder name, package name, or fully qualified class
 | |
|     # name.
 | |
|     if re.match('\\.(c|cc|cpp|cxx|h|hpp|hxx|icc)$', ext):
 | |
|         return 'native'
 | |
|     return 'java'
 | |
| 
 | |
| 
 | |
| def normalize_java_path(rel_path):
 | |
|     if re.match('.+\\.java$', rel_path):
 | |
|         # Path ends in '.java' so a filename with its path is expected
 | |
|         return rel_path
 | |
| 
 | |
|     if '/' not in rel_path:
 | |
|         # Convert package name, or fully qualified class name into path
 | |
|         rel_path = rel_path.replace('.', '/')
 | |
| 
 | |
|     if any(c.isupper() for c in rel_path):
 | |
|         # If the name includes an uppercase character, we guess that this is a
 | |
|         # class rather than a package name, so the extension needs to be appended
 | |
|         # to get the full filename
 | |
|         # Note: Test packages may have upper case characters in the package name,
 | |
|         # so, if trying to diff a test package, the ".java" suffix will be added
 | |
|         # unnecessarily, causing a wrong diff input. Therefore, for test packages,
 | |
|         # the tool should be used for each file individually
 | |
|         rel_path += '.java'
 | |
|     elif rel_path[-1] != '/':
 | |
|         # No upper case characters, so this must be a folder/package
 | |
|         rel_path += '/'
 | |
| 
 | |
|     return rel_path
 | |
| 
 | |
| 
 | |
| 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:
 | |
|         path_type = get_path_type(rel_path)
 | |
|         if path_type == 'java':
 | |
|             rel_path = normalize_java_path(rel_path)
 | |
|         paths = []
 | |
| 
 | |
|         for repository in repositories:
 | |
|             if repository == 'ojluni':
 | |
|                 paths.append('%s/libcore/ojluni/src/main/%s/%s'
 | |
|                              % (android_build_top, path_type, 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()
 |