1*89a63228SAndroid Build Coastguard Worker#!/usr/bin/python 2*89a63228SAndroid Build Coastguard Worker# 3*89a63228SAndroid Build Coastguard Worker# Copyright (C) 2021 The Android Open Source Project 4*89a63228SAndroid Build Coastguard Worker# 5*89a63228SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*89a63228SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*89a63228SAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*89a63228SAndroid Build Coastguard Worker# 9*89a63228SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*89a63228SAndroid Build Coastguard Worker# 11*89a63228SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*89a63228SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*89a63228SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*89a63228SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*89a63228SAndroid Build Coastguard Worker# limitations under the License. 16*89a63228SAndroid Build Coastguard Worker 17*89a63228SAndroid Build Coastguard Worker 18*89a63228SAndroid Build Coastguard Worker""" 19*89a63228SAndroid Build Coastguard WorkerMerges upstream files to ojluni. This is done by using git to perform a 3-way 20*89a63228SAndroid Build Coastguard Workermerge between the current (base) upstream version, ojluni and the new (target) 21*89a63228SAndroid Build Coastguard Workerupstream version. The 3-way merge is needed because ojluni sometimes contains 22*89a63228SAndroid Build Coastguard Workersome Android-specific changes from the upstream version. 23*89a63228SAndroid Build Coastguard Worker 24*89a63228SAndroid Build Coastguard WorkerThis tool is for libcore maintenance; if you're not maintaining libcore, 25*89a63228SAndroid Build Coastguard Workeryou won't need it (and might not have access to some of the instructions 26*89a63228SAndroid Build Coastguard Workerbelow). 27*89a63228SAndroid Build Coastguard Worker 28*89a63228SAndroid Build Coastguard WorkerThe naming of the repositories (expected, ojluni, 7u40, 8u121-b13, 29*89a63228SAndroid Build Coastguard Worker9b113+, 9+181) is based on the directory name where corresponding 30*89a63228SAndroid Build Coastguard Workersnapshots are stored when following the instructions at 31*89a63228SAndroid Build Coastguard Workerhttp://go/libcore-o-verify 32*89a63228SAndroid Build Coastguard Worker 33*89a63228SAndroid Build Coastguard WorkerThis script tries to preserve Android changes to upstream code when moving to a 34*89a63228SAndroid Build Coastguard Workernewer version. 35*89a63228SAndroid Build Coastguard Worker 36*89a63228SAndroid Build Coastguard WorkerAll the work is made in a new directory which is initialized as a git 37*89a63228SAndroid Build Coastguard Workerrepository. An example of the repository structure, where an update is made 38*89a63228SAndroid Build Coastguard Workerfrom version 9b113+ to 11+28, would be: 39*89a63228SAndroid Build Coastguard Worker 40*89a63228SAndroid Build Coastguard Worker * 5593705 (HEAD -> main) Merge branch 'ojluni' 41*89a63228SAndroid Build Coastguard Worker |\ 42*89a63228SAndroid Build Coastguard Worker | * 2effe03 (ojluni) Ojluni commit 43*89a63228SAndroid Build Coastguard Worker * | 1bef5f3 Target commit (11+28) 44*89a63228SAndroid Build Coastguard Worker |/ 45*89a63228SAndroid Build Coastguard Worker * 9ae2fbf Base commit (9b113+) 46*89a63228SAndroid Build Coastguard Worker 47*89a63228SAndroid Build Coastguard WorkerThe conflicts during the merge get resolved by git whenever possible. However, 48*89a63228SAndroid Build Coastguard Workersometimes there are conflicts that need to be resolved manually. If that is the 49*89a63228SAndroid Build Coastguard Workercase, the script will terminate to allow for the resolving. Once the user has 50*89a63228SAndroid Build Coastguard Workerresolved the conflicts, they should rerun the script with the --continue 51*89a63228SAndroid Build Coastguard Workeroption. 52*89a63228SAndroid Build Coastguard Worker 53*89a63228SAndroid Build Coastguard WorkerOnce the merge is complete, the script will copy the merged version back to 54*89a63228SAndroid Build Coastguard Workerojluni within the $ANDROID_BUILD_TOP location. 55*89a63228SAndroid Build Coastguard Worker 56*89a63228SAndroid Build Coastguard WorkerFor the script to run correctly, it needs the following environment variables 57*89a63228SAndroid Build Coastguard Workerdefined: 58*89a63228SAndroid Build Coastguard Worker - OJLUNI_UPSTREAMS 59*89a63228SAndroid Build Coastguard Worker - ANDROID_BUILD_TOP 60*89a63228SAndroid Build Coastguard Worker 61*89a63228SAndroid Build Coastguard WorkerPossible uses: 62*89a63228SAndroid Build Coastguard Worker 63*89a63228SAndroid Build Coastguard WorkerTo merge in changes from a newer version of the upstream using a default 64*89a63228SAndroid Build Coastguard Workerworking dir created in /tmp: 65*89a63228SAndroid Build Coastguard Worker merge-from-upstream -f expected -t 11+28 java/util/concurrent 66*89a63228SAndroid Build Coastguard Worker 67*89a63228SAndroid Build Coastguard WorkerTo merge in changes from a newer version of the upstream using a custom 68*89a63228SAndroid Build Coastguard Workerworking dir: 69*89a63228SAndroid Build Coastguard Worker merge-from-upstream -f expected -t 11+28 \ 70*89a63228SAndroid Build Coastguard Worker -d $HOME/tmp/ojluni-merge java/util/concurrent 71*89a63228SAndroid Build Coastguard Worker 72*89a63228SAndroid Build Coastguard WorkerTo merge in changes for a single file: 73*89a63228SAndroid Build Coastguard Worker merge-from-upstream -f 9b113+ -t 11+28 \ 74*89a63228SAndroid Build Coastguard Worker java/util/concurrent/atomic/AtomicInteger.java 75*89a63228SAndroid Build Coastguard Worker 76*89a63228SAndroid Build Coastguard WorkerTo merge in changes, using a custom folder, that require conflict resolution: 77*89a63228SAndroid Build Coastguard Worker merge-from-upstream -f expected -t 11+28 \ 78*89a63228SAndroid Build Coastguard Worker -d $HOME/tmp/ojluni-merge \ 79*89a63228SAndroid Build Coastguard Worker java/util/concurrent 80*89a63228SAndroid Build Coastguard Worker <manually resolve conflicts and add them to git staging> 81*89a63228SAndroid Build Coastguard Worker merge-from-upstream --continue \ 82*89a63228SAndroid Build Coastguard Worker -d $HOME/tmp/ojluni-merge java/util/concurrent 83*89a63228SAndroid Build Coastguard Worker""" 84*89a63228SAndroid Build Coastguard Worker 85*89a63228SAndroid Build Coastguard Workerimport argparse 86*89a63228SAndroid Build Coastguard Workerimport os 87*89a63228SAndroid Build Coastguard Workerimport os.path 88*89a63228SAndroid Build Coastguard Workerimport subprocess 89*89a63228SAndroid Build Coastguard Workerimport sys 90*89a63228SAndroid Build Coastguard Workerimport shutil 91*89a63228SAndroid Build Coastguard Worker 92*89a63228SAndroid Build Coastguard Worker 93*89a63228SAndroid Build Coastguard Workerdef printerr(msg): 94*89a63228SAndroid Build Coastguard Worker sys.stderr.write(msg + "\r\n") 95*89a63228SAndroid Build Coastguard Worker 96*89a63228SAndroid Build Coastguard Worker 97*89a63228SAndroid Build Coastguard Workerdef user_check(msg): 98*89a63228SAndroid Build Coastguard Worker choice = str(input(msg + " [y/N] ")).strip().lower() 99*89a63228SAndroid Build Coastguard Worker if choice[:1] == 'y': 100*89a63228SAndroid Build Coastguard Worker return True 101*89a63228SAndroid Build Coastguard Worker return False 102*89a63228SAndroid Build Coastguard Worker 103*89a63228SAndroid Build Coastguard Worker 104*89a63228SAndroid Build Coastguard Workerdef check_env_vars(): 105*89a63228SAndroid Build Coastguard Worker keys = [ 106*89a63228SAndroid Build Coastguard Worker 'OJLUNI_UPSTREAMS', 107*89a63228SAndroid Build Coastguard Worker 'ANDROID_BUILD_TOP', 108*89a63228SAndroid Build Coastguard Worker ] 109*89a63228SAndroid Build Coastguard Worker result = True 110*89a63228SAndroid Build Coastguard Worker for key in keys: 111*89a63228SAndroid Build Coastguard Worker if key not in os.environ: 112*89a63228SAndroid Build Coastguard Worker printerr("Unable to run, you must have {} defined".format(key)) 113*89a63228SAndroid Build Coastguard Worker result = False 114*89a63228SAndroid Build Coastguard Worker return result 115*89a63228SAndroid Build Coastguard Worker 116*89a63228SAndroid Build Coastguard Worker 117*89a63228SAndroid Build Coastguard Workerdef get_upstream_path(version, rel_path): 118*89a63228SAndroid Build Coastguard Worker upstreams = os.environ['OJLUNI_UPSTREAMS'] 119*89a63228SAndroid Build Coastguard Worker return '{}/{}/{}'.format(upstreams, version, rel_path) 120*89a63228SAndroid Build Coastguard Worker 121*89a63228SAndroid Build Coastguard Worker 122*89a63228SAndroid Build Coastguard Workerdef get_ojluni_path(rel_path): 123*89a63228SAndroid Build Coastguard Worker android_build_top = os.environ['ANDROID_BUILD_TOP'] 124*89a63228SAndroid Build Coastguard Worker return '{}/libcore/ojluni/src/main/java/{}'.format( 125*89a63228SAndroid Build Coastguard Worker android_build_top, rel_path) 126*89a63228SAndroid Build Coastguard Worker 127*89a63228SAndroid Build Coastguard Worker 128*89a63228SAndroid Build Coastguard Workerdef make_copy(src, dst): 129*89a63228SAndroid Build Coastguard Worker print("Copy " + src + " -> " + dst) 130*89a63228SAndroid Build Coastguard Worker if os.path.isfile(src): 131*89a63228SAndroid Build Coastguard Worker if os.path.exists(dst) and os.path.isfile(dst): 132*89a63228SAndroid Build Coastguard Worker os.remove(dst) 133*89a63228SAndroid Build Coastguard Worker shutil.copy(src, dst) 134*89a63228SAndroid Build Coastguard Worker else: 135*89a63228SAndroid Build Coastguard Worker shutil.copytree(src, dst, dirs_exist_ok=True) 136*89a63228SAndroid Build Coastguard Worker 137*89a63228SAndroid Build Coastguard Worker 138*89a63228SAndroid Build Coastguard Workerclass Repo: 139*89a63228SAndroid Build Coastguard Worker def __init__(self, dir): 140*89a63228SAndroid Build Coastguard Worker self.dir = dir 141*89a63228SAndroid Build Coastguard Worker 142*89a63228SAndroid Build Coastguard Worker def init(self): 143*89a63228SAndroid Build Coastguard Worker if 0 != subprocess.call(['git', 'init', '-b', 'main', self.dir]): 144*89a63228SAndroid Build Coastguard Worker raise RuntimeError( 145*89a63228SAndroid Build Coastguard Worker "Unable to initialize working git repository.") 146*89a63228SAndroid Build Coastguard Worker subprocess.call(['git', '-C', self.dir, 147*89a63228SAndroid Build Coastguard Worker 'config', 'rerere.enabled', 'true']) 148*89a63228SAndroid Build Coastguard Worker 149*89a63228SAndroid Build Coastguard Worker def commit_all(self, id, msg): 150*89a63228SAndroid Build Coastguard Worker if 0 != subprocess.call(['git', '-C', self.dir, 'add', '*']): 151*89a63228SAndroid Build Coastguard Worker raise RuntimeError("Unable to add the {} files.".format(id)) 152*89a63228SAndroid Build Coastguard Worker if 0 != subprocess.call(['git', '-C', self.dir, 'commit', 153*89a63228SAndroid Build Coastguard Worker '-m', msg]): 154*89a63228SAndroid Build Coastguard Worker raise RuntimeError("Unable to commit the {} files.".format(id)) 155*89a63228SAndroid Build Coastguard Worker 156*89a63228SAndroid Build Coastguard Worker def checkout_branch(self, branch, is_new=False): 157*89a63228SAndroid Build Coastguard Worker cmd = ['git', '-C', self.dir, 'checkout'] 158*89a63228SAndroid Build Coastguard Worker if is_new: 159*89a63228SAndroid Build Coastguard Worker cmd.append('-b') 160*89a63228SAndroid Build Coastguard Worker cmd.append(branch) 161*89a63228SAndroid Build Coastguard Worker if 0 != subprocess.call(cmd): 162*89a63228SAndroid Build Coastguard Worker raise RuntimeError("Unable to checkout the {} branch." 163*89a63228SAndroid Build Coastguard Worker .format(branch)) 164*89a63228SAndroid Build Coastguard Worker 165*89a63228SAndroid Build Coastguard Worker def merge(self, branch): 166*89a63228SAndroid Build Coastguard Worker """ 167*89a63228SAndroid Build Coastguard Worker Tries to merge in a branch and returns True if the merge commit has 168*89a63228SAndroid Build Coastguard Worker been created. If there are conflicts to be resolved, this returns 169*89a63228SAndroid Build Coastguard Worker False. 170*89a63228SAndroid Build Coastguard Worker """ 171*89a63228SAndroid Build Coastguard Worker if 0 == subprocess.call(['git', '-C', self.dir, 172*89a63228SAndroid Build Coastguard Worker 'merge', branch, '--no-edit']): 173*89a63228SAndroid Build Coastguard Worker return True 174*89a63228SAndroid Build Coastguard Worker if not self.is_merging(): 175*89a63228SAndroid Build Coastguard Worker raise RuntimeError("Unable to run merge for the {} branch." 176*89a63228SAndroid Build Coastguard Worker .format(branch)) 177*89a63228SAndroid Build Coastguard Worker subprocess.call(['git', '-C', self.dir, 'rerere']) 178*89a63228SAndroid Build Coastguard Worker return False 179*89a63228SAndroid Build Coastguard Worker 180*89a63228SAndroid Build Coastguard Worker def check_resolved_from_cache(self): 181*89a63228SAndroid Build Coastguard Worker """ 182*89a63228SAndroid Build Coastguard Worker Checks if some conflicts have been resolved by the git rerere tool. The 183*89a63228SAndroid Build Coastguard Worker tool only applies the previous resolution, but does not mark the file 184*89a63228SAndroid Build Coastguard Worker as resolved afterwards. Therefore this function will go through the 185*89a63228SAndroid Build Coastguard Worker unresolved files and see if there are outstanding conflicts. If all 186*89a63228SAndroid Build Coastguard Worker conflicts have been resolved, the file gets stages. 187*89a63228SAndroid Build Coastguard Worker 188*89a63228SAndroid Build Coastguard Worker Returns True if all conflicts are resolved, False otherwise. 189*89a63228SAndroid Build Coastguard Worker """ 190*89a63228SAndroid Build Coastguard Worker # git diff --check will exit with error if there are conflicts to be 191*89a63228SAndroid Build Coastguard Worker # resolved, therefore we need to use check=False option to avoid an 192*89a63228SAndroid Build Coastguard Worker # exception to be raised 193*89a63228SAndroid Build Coastguard Worker conflict_markers = subprocess.run(['git', '-C', self.dir, 194*89a63228SAndroid Build Coastguard Worker 'diff', '--check'], 195*89a63228SAndroid Build Coastguard Worker stdout=subprocess.PIPE, 196*89a63228SAndroid Build Coastguard Worker check=False).stdout 197*89a63228SAndroid Build Coastguard Worker conflicts = subprocess.check_output(['git', '-C', self.dir, 'diff', 198*89a63228SAndroid Build Coastguard Worker '--name-only', '--diff-filter=U']) 199*89a63228SAndroid Build Coastguard Worker 200*89a63228SAndroid Build Coastguard Worker for filename in conflicts.splitlines(): 201*89a63228SAndroid Build Coastguard Worker if conflict_markers.find(filename) != -1: 202*89a63228SAndroid Build Coastguard Worker print("{} still has conflicts, please resolve manually". 203*89a63228SAndroid Build Coastguard Worker format(filename)) 204*89a63228SAndroid Build Coastguard Worker else: 205*89a63228SAndroid Build Coastguard Worker print("{} has been resolved, staging it".format(filename)) 206*89a63228SAndroid Build Coastguard Worker subprocess.call(['git', '-C', self.dir, 'add', filename]) 207*89a63228SAndroid Build Coastguard Worker 208*89a63228SAndroid Build Coastguard Worker return not self.has_conflicts() 209*89a63228SAndroid Build Coastguard Worker 210*89a63228SAndroid Build Coastguard Worker def has_changes(self): 211*89a63228SAndroid Build Coastguard Worker result = subprocess.check_output(['git', '-C', self.dir, 'status', 212*89a63228SAndroid Build Coastguard Worker '--porcelain']) 213*89a63228SAndroid Build Coastguard Worker return len(result) != 0 214*89a63228SAndroid Build Coastguard Worker 215*89a63228SAndroid Build Coastguard Worker def has_conflicts(self): 216*89a63228SAndroid Build Coastguard Worker conflicts = subprocess.check_output(['git', '-C', self.dir, 'diff', 217*89a63228SAndroid Build Coastguard Worker '--name-only', '--diff-filter=U']) 218*89a63228SAndroid Build Coastguard Worker return len(conflicts) != 0 219*89a63228SAndroid Build Coastguard Worker 220*89a63228SAndroid Build Coastguard Worker def is_merging(self): 221*89a63228SAndroid Build Coastguard Worker return 0 == subprocess.call(['git', '-C', self.dir, 'rev-parse', 222*89a63228SAndroid Build Coastguard Worker '-q', '--verify', 'MERGE_HEAD'], 223*89a63228SAndroid Build Coastguard Worker stdout=subprocess.DEVNULL) 224*89a63228SAndroid Build Coastguard Worker 225*89a63228SAndroid Build Coastguard Worker def complete_merge(self): 226*89a63228SAndroid Build Coastguard Worker print("Completing merge in {}".format(self.dir)) 227*89a63228SAndroid Build Coastguard Worker subprocess.call(['git', '-C', self.dir, 'rerere']) 228*89a63228SAndroid Build Coastguard Worker if 0 != subprocess.call(['git', '-C', self.dir, 229*89a63228SAndroid Build Coastguard Worker 'commit', '--no-edit']): 230*89a63228SAndroid Build Coastguard Worker raise RuntimeError("Unable to complete the merge in {}." 231*89a63228SAndroid Build Coastguard Worker .format(self.dir)) 232*89a63228SAndroid Build Coastguard Worker if self.is_merging(): 233*89a63228SAndroid Build Coastguard Worker raise RuntimeError( 234*89a63228SAndroid Build Coastguard Worker "Merging in {} is not complete".format(self.dir)) 235*89a63228SAndroid Build Coastguard Worker 236*89a63228SAndroid Build Coastguard Worker def load_resolve_files(self, resolve_dir): 237*89a63228SAndroid Build Coastguard Worker print("Loading resolve files from {}".format(resolve_dir)) 238*89a63228SAndroid Build Coastguard Worker if not os.path.lexists(resolve_dir): 239*89a63228SAndroid Build Coastguard Worker print("Resolve dir {} not found, no resolutions will be used" 240*89a63228SAndroid Build Coastguard Worker .format(resolve_dir)) 241*89a63228SAndroid Build Coastguard Worker return 242*89a63228SAndroid Build Coastguard Worker make_copy(resolve_dir, self.dir + "/.git/rr-cache") 243*89a63228SAndroid Build Coastguard Worker 244*89a63228SAndroid Build Coastguard Worker def save_resolve_files(self, resolve_dir): 245*89a63228SAndroid Build Coastguard Worker print("Saving resolve files to {}".format(resolve_dir)) 246*89a63228SAndroid Build Coastguard Worker if not os.path.lexists(resolve_dir): 247*89a63228SAndroid Build Coastguard Worker os.makedirs(resolve_dir) 248*89a63228SAndroid Build Coastguard Worker make_copy(self.dir + "/.git/rr-cache", resolve_dir) 249*89a63228SAndroid Build Coastguard Worker 250*89a63228SAndroid Build Coastguard Worker 251*89a63228SAndroid Build Coastguard Workerclass Merger: 252*89a63228SAndroid Build Coastguard Worker def __init__(self, repo_dir, rel_path, resolve_dir): 253*89a63228SAndroid Build Coastguard Worker self.repo = Repo(repo_dir) 254*89a63228SAndroid Build Coastguard Worker # Have all the source files copied inside a src dir, so we don't have 255*89a63228SAndroid Build Coastguard Worker # any issue with copying back the .git dir 256*89a63228SAndroid Build Coastguard Worker self.working_dir = repo_dir + "/src" 257*89a63228SAndroid Build Coastguard Worker self.rel_path = rel_path 258*89a63228SAndroid Build Coastguard Worker self.resolve_dir = resolve_dir 259*89a63228SAndroid Build Coastguard Worker 260*89a63228SAndroid Build Coastguard Worker def create_working_dir(self): 261*89a63228SAndroid Build Coastguard Worker if os.path.lexists(self.repo.dir): 262*89a63228SAndroid Build Coastguard Worker if not user_check( 263*89a63228SAndroid Build Coastguard Worker '{} already exists. Can it be removed?' 264*89a63228SAndroid Build Coastguard Worker .format(self.repo.dir)): 265*89a63228SAndroid Build Coastguard Worker raise RuntimeError( 266*89a63228SAndroid Build Coastguard Worker 'Will not remove {}. Consider using another ' 267*89a63228SAndroid Build Coastguard Worker 'working dir'.format(self.repo.dir)) 268*89a63228SAndroid Build Coastguard Worker try: 269*89a63228SAndroid Build Coastguard Worker shutil.rmtree(self.repo.dir) 270*89a63228SAndroid Build Coastguard Worker except OSError: 271*89a63228SAndroid Build Coastguard Worker printerr("Unable to delete {}.".format(self.repo.dir)) 272*89a63228SAndroid Build Coastguard Worker raise 273*89a63228SAndroid Build Coastguard Worker os.makedirs(self.working_dir) 274*89a63228SAndroid Build Coastguard Worker self.repo.init() 275*89a63228SAndroid Build Coastguard Worker if self.resolve_dir is not None: 276*89a63228SAndroid Build Coastguard Worker self.repo.load_resolve_files(self.resolve_dir) 277*89a63228SAndroid Build Coastguard Worker 278*89a63228SAndroid Build Coastguard Worker def copy_upstream_files(self, version, msg): 279*89a63228SAndroid Build Coastguard Worker full_path = get_upstream_path(version, self.rel_path) 280*89a63228SAndroid Build Coastguard Worker make_copy(full_path, self.working_dir) 281*89a63228SAndroid Build Coastguard Worker self.repo.commit_all(version, msg) 282*89a63228SAndroid Build Coastguard Worker 283*89a63228SAndroid Build Coastguard Worker def copy_base_files(self, base_version): 284*89a63228SAndroid Build Coastguard Worker self.copy_upstream_files(base_version, 285*89a63228SAndroid Build Coastguard Worker 'Base commit ({})'.format(base_version)) 286*89a63228SAndroid Build Coastguard Worker 287*89a63228SAndroid Build Coastguard Worker def copy_target_files(self, target_version): 288*89a63228SAndroid Build Coastguard Worker self.copy_upstream_files(target_version, 289*89a63228SAndroid Build Coastguard Worker 'Target commit ({})'.format(target_version)) 290*89a63228SAndroid Build Coastguard Worker 291*89a63228SAndroid Build Coastguard Worker def copy_ojluni_files(self): 292*89a63228SAndroid Build Coastguard Worker full_path = get_ojluni_path(self.rel_path) 293*89a63228SAndroid Build Coastguard Worker make_copy(full_path, self.working_dir) 294*89a63228SAndroid Build Coastguard Worker if self.repo.has_changes(): 295*89a63228SAndroid Build Coastguard Worker self.repo.commit_all('ojluni', 'Ojluni commit') 296*89a63228SAndroid Build Coastguard Worker return True 297*89a63228SAndroid Build Coastguard Worker else: 298*89a63228SAndroid Build Coastguard Worker return False 299*89a63228SAndroid Build Coastguard Worker 300*89a63228SAndroid Build Coastguard Worker def run_ojluni_merge(self): 301*89a63228SAndroid Build Coastguard Worker if self.repo.merge('ojluni'): 302*89a63228SAndroid Build Coastguard Worker return 303*89a63228SAndroid Build Coastguard Worker if self.repo.check_resolved_from_cache(): 304*89a63228SAndroid Build Coastguard Worker self.repo.complete_merge() 305*89a63228SAndroid Build Coastguard Worker return 306*89a63228SAndroid Build Coastguard Worker raise RuntimeError('\r\nThere are conflicts to be resolved.' 307*89a63228SAndroid Build Coastguard Worker '\r\nManually merge the changes and rerun ' 308*89a63228SAndroid Build Coastguard Worker 'this script with --continue') 309*89a63228SAndroid Build Coastguard Worker 310*89a63228SAndroid Build Coastguard Worker def copy_back_to_ojluni(self): 311*89a63228SAndroid Build Coastguard Worker # Save any resolutions that were made for future reuse 312*89a63228SAndroid Build Coastguard Worker if self.resolve_dir is not None: 313*89a63228SAndroid Build Coastguard Worker self.repo.save_resolve_files(self.resolve_dir) 314*89a63228SAndroid Build Coastguard Worker 315*89a63228SAndroid Build Coastguard Worker src_path = self.working_dir 316*89a63228SAndroid Build Coastguard Worker dst_path = get_ojluni_path(self.rel_path) 317*89a63228SAndroid Build Coastguard Worker if os.path.isfile(dst_path): 318*89a63228SAndroid Build Coastguard Worker src_path += '/' + os.path.basename(self.rel_path) 319*89a63228SAndroid Build Coastguard Worker make_copy(src_path, dst_path) 320*89a63228SAndroid Build Coastguard Worker 321*89a63228SAndroid Build Coastguard Worker def run(self, base_version, target_version): 322*89a63228SAndroid Build Coastguard Worker print("Merging {} from {} into ojluni (based on {}). " 323*89a63228SAndroid Build Coastguard Worker "Using {} as working dir." 324*89a63228SAndroid Build Coastguard Worker .format(self.rel_path, target_version, 325*89a63228SAndroid Build Coastguard Worker base_version, self.repo.dir)) 326*89a63228SAndroid Build Coastguard Worker self.create_working_dir() 327*89a63228SAndroid Build Coastguard Worker self.copy_base_files(base_version) 328*89a63228SAndroid Build Coastguard Worker # The ojluni code should be added in its own branch. This is to make 329*89a63228SAndroid Build Coastguard Worker # Git perform the 3-way merge once a commit is added with the latest 330*89a63228SAndroid Build Coastguard Worker # upstream code. 331*89a63228SAndroid Build Coastguard Worker self.repo.checkout_branch('ojluni', is_new=True) 332*89a63228SAndroid Build Coastguard Worker merge_needed = self.copy_ojluni_files() 333*89a63228SAndroid Build Coastguard Worker self.repo.checkout_branch('main') 334*89a63228SAndroid Build Coastguard Worker self.copy_target_files(target_version) 335*89a63228SAndroid Build Coastguard Worker if merge_needed: 336*89a63228SAndroid Build Coastguard Worker # Runs the merge in the working directory, if some conflicts need 337*89a63228SAndroid Build Coastguard Worker # to be resolved manually, then an exception is raised which will 338*89a63228SAndroid Build Coastguard Worker # terminate the script, informing the user that manual intervention 339*89a63228SAndroid Build Coastguard Worker # is needed. 340*89a63228SAndroid Build Coastguard Worker self.run_ojluni_merge() 341*89a63228SAndroid Build Coastguard Worker else: 342*89a63228SAndroid Build Coastguard Worker print("No merging needed as there were no " 343*89a63228SAndroid Build Coastguard Worker "Android-specific changes, forwarding to new version ({})" 344*89a63228SAndroid Build Coastguard Worker .format(target_version)) 345*89a63228SAndroid Build Coastguard Worker self.copy_back_to_ojluni() 346*89a63228SAndroid Build Coastguard Worker 347*89a63228SAndroid Build Coastguard Worker def complete_existing_run(self): 348*89a63228SAndroid Build Coastguard Worker if self.repo.is_merging(): 349*89a63228SAndroid Build Coastguard Worker self.repo.complete_merge() 350*89a63228SAndroid Build Coastguard Worker self.copy_back_to_ojluni() 351*89a63228SAndroid Build Coastguard Worker 352*89a63228SAndroid Build Coastguard Worker 353*89a63228SAndroid Build Coastguard Workerdef main(): 354*89a63228SAndroid Build Coastguard Worker if not check_env_vars(): 355*89a63228SAndroid Build Coastguard Worker return 356*89a63228SAndroid Build Coastguard Worker 357*89a63228SAndroid Build Coastguard Worker upstreams = os.environ['OJLUNI_UPSTREAMS'] 358*89a63228SAndroid Build Coastguard Worker repositories = sorted( 359*89a63228SAndroid Build Coastguard Worker [d for d in os.listdir(upstreams) 360*89a63228SAndroid Build Coastguard Worker if os.path.isdir(os.path.join(upstreams, d))] 361*89a63228SAndroid Build Coastguard Worker ) 362*89a63228SAndroid Build Coastguard Worker 363*89a63228SAndroid Build Coastguard Worker parser = argparse.ArgumentParser( 364*89a63228SAndroid Build Coastguard Worker description=''' 365*89a63228SAndroid Build Coastguard Worker Merge upstream files from ${OJLUNI_UPSTREAMS} to libcore/ojluni. 366*89a63228SAndroid Build Coastguard Worker Needs the base (from) repository as well as the target (to) repository. 367*89a63228SAndroid Build Coastguard Worker Repositories can be chosen from: 368*89a63228SAndroid Build Coastguard Worker ''' + ' '.join(repositories) + '.', 369*89a63228SAndroid Build Coastguard Worker # include default values in help 370*89a63228SAndroid Build Coastguard Worker formatter_class=argparse.ArgumentDefaultsHelpFormatter, 371*89a63228SAndroid Build Coastguard Worker ) 372*89a63228SAndroid Build Coastguard Worker parser.add_argument('-f', '--from', default='expected', 373*89a63228SAndroid Build Coastguard Worker choices=repositories, 374*89a63228SAndroid Build Coastguard Worker dest='base', 375*89a63228SAndroid Build Coastguard Worker help='Repository on which the requested ojluni ' 376*89a63228SAndroid Build Coastguard Worker 'files are based.') 377*89a63228SAndroid Build Coastguard Worker parser.add_argument('-t', '--to', 378*89a63228SAndroid Build Coastguard Worker choices=repositories, 379*89a63228SAndroid Build Coastguard Worker dest='target', 380*89a63228SAndroid Build Coastguard Worker help='Repository to which the requested ojluni ' 381*89a63228SAndroid Build Coastguard Worker 'files will be updated.') 382*89a63228SAndroid Build Coastguard Worker parser.add_argument('-d', '--work-dir', default='/tmp/ojluni-merge', 383*89a63228SAndroid Build Coastguard Worker help='Path where the merge will be performed. ' 384*89a63228SAndroid Build Coastguard Worker 'Any existing files in the path will be removed') 385*89a63228SAndroid Build Coastguard Worker parser.add_argument('-r', '--resolve-dir', default=None, 386*89a63228SAndroid Build Coastguard Worker dest='resolve_dir', 387*89a63228SAndroid Build Coastguard Worker help='Path where the git resolutions are cached. ' 388*89a63228SAndroid Build Coastguard Worker 'By default, no cache is used.') 389*89a63228SAndroid Build Coastguard Worker parser.add_argument('--continue', action='store_true', dest='proceed', 390*89a63228SAndroid Build Coastguard Worker help='Flag to specify after merge conflicts ' 391*89a63228SAndroid Build Coastguard Worker 'are resolved') 392*89a63228SAndroid Build Coastguard Worker parser.add_argument('rel_path', nargs=1, metavar='<relative_path>', 393*89a63228SAndroid Build Coastguard Worker help='File to merge: a relative path below ' 394*89a63228SAndroid Build Coastguard Worker 'libcore/ojluni/ which could point to ' 395*89a63228SAndroid Build Coastguard Worker 'a file or folder.') 396*89a63228SAndroid Build Coastguard Worker args = parser.parse_args() 397*89a63228SAndroid Build Coastguard Worker try: 398*89a63228SAndroid Build Coastguard Worker merger = Merger(args.work_dir, args.rel_path[0], args.resolve_dir) 399*89a63228SAndroid Build Coastguard Worker if args.proceed: 400*89a63228SAndroid Build Coastguard Worker merger.complete_existing_run() 401*89a63228SAndroid Build Coastguard Worker else: 402*89a63228SAndroid Build Coastguard Worker if args.target is None: 403*89a63228SAndroid Build Coastguard Worker raise RuntimeError('Please specify the target upstream ' 404*89a63228SAndroid Build Coastguard Worker 'version using the -t/--to argument') 405*89a63228SAndroid Build Coastguard Worker merger.run(args.base, args.target) 406*89a63228SAndroid Build Coastguard Worker except Exception as e: 407*89a63228SAndroid Build Coastguard Worker printerr(str(e)) 408*89a63228SAndroid Build Coastguard Worker 409*89a63228SAndroid Build Coastguard Worker 410*89a63228SAndroid Build Coastguard Workerif __name__ == "__main__": 411*89a63228SAndroid Build Coastguard Worker main() 412