1*c8dee2aaSAndroid Build Coastguard Worker#! /usr/bin/env python 2*c8dee2aaSAndroid Build Coastguard Worker# Copyright 2019 Google LLC. 3*c8dee2aaSAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*c8dee2aaSAndroid Build Coastguard Worker# found in the LICENSE file. 5*c8dee2aaSAndroid Build Coastguard Worker 6*c8dee2aaSAndroid Build Coastguard Workerimport os 7*c8dee2aaSAndroid Build Coastguard Workerimport shutil 8*c8dee2aaSAndroid Build Coastguard Workerimport subprocess 9*c8dee2aaSAndroid Build Coastguard Workerimport sys 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Workerdef copy_git_directory(src, dst, out=None): 12*c8dee2aaSAndroid Build Coastguard Worker ''' 13*c8dee2aaSAndroid Build Coastguard Worker Makes a copy of `src` directory in `dst` directory. If files already exist 14*c8dee2aaSAndroid Build Coastguard Worker and are identical, do not touch them. If extra files or directories exist, 15*c8dee2aaSAndroid Build Coastguard Worker remove them. Assume that `src` is a git directory so that `git ls-files` can 16*c8dee2aaSAndroid Build Coastguard Worker be used to enumerate files. This has the added benefit of ignoring files 17*c8dee2aaSAndroid Build Coastguard Worker not tracked by git. Also, if out is not None, write summary of actions to out. 18*c8dee2aaSAndroid Build Coastguard Worker If `dst` is a top-level git directory, the `.git` directory will be removed. 19*c8dee2aaSAndroid Build Coastguard Worker ''' 20*c8dee2aaSAndroid Build Coastguard Worker if not os.path.isdir(src): 21*c8dee2aaSAndroid Build Coastguard Worker raise Exception('Directory "%s" does not exist.' % src) 22*c8dee2aaSAndroid Build Coastguard Worker if not os.path.isdir(dst): 23*c8dee2aaSAndroid Build Coastguard Worker os.makedirs(dst) 24*c8dee2aaSAndroid Build Coastguard Worker ls_files = subprocess.check_output([ 25*c8dee2aaSAndroid Build Coastguard Worker 'git', 'ls-files', '-z', '.'], cwd=src).decode('utf-8') 26*c8dee2aaSAndroid Build Coastguard Worker src_files = set(p for p in ls_files.split('\0') if p) 27*c8dee2aaSAndroid Build Coastguard Worker abs_src = os.path.abspath(src) 28*c8dee2aaSAndroid Build Coastguard Worker cwd = os.getcwd() 29*c8dee2aaSAndroid Build Coastguard Worker try: 30*c8dee2aaSAndroid Build Coastguard Worker os.chdir(dst) 31*c8dee2aaSAndroid Build Coastguard Worker def output(out, sym, dst, path): 32*c8dee2aaSAndroid Build Coastguard Worker if out: 33*c8dee2aaSAndroid Build Coastguard Worker out.write('%s %s%s%s\n' % (sym, dst, os.sep, path)) 34*c8dee2aaSAndroid Build Coastguard Worker for dirpath, dirnames, filenames in os.walk('.', topdown=False): 35*c8dee2aaSAndroid Build Coastguard Worker for filename in filenames: 36*c8dee2aaSAndroid Build Coastguard Worker path = os.path.normpath(os.path.join(dirpath, filename)) 37*c8dee2aaSAndroid Build Coastguard Worker if path not in src_files: 38*c8dee2aaSAndroid Build Coastguard Worker output(out, '-', dst, path) 39*c8dee2aaSAndroid Build Coastguard Worker os.remove(path) 40*c8dee2aaSAndroid Build Coastguard Worker for filename in dirnames: 41*c8dee2aaSAndroid Build Coastguard Worker path = os.path.normpath(os.path.join(dirpath, filename)) 42*c8dee2aaSAndroid Build Coastguard Worker if not os.listdir(path): # Remove empty subfolders. 43*c8dee2aaSAndroid Build Coastguard Worker output(out, '-', dst, path + os.sep) 44*c8dee2aaSAndroid Build Coastguard Worker os.rmdir(path) 45*c8dee2aaSAndroid Build Coastguard Worker for path in src_files: 46*c8dee2aaSAndroid Build Coastguard Worker src_path = os.path.join(abs_src, path) 47*c8dee2aaSAndroid Build Coastguard Worker if os.path.exists(path): 48*c8dee2aaSAndroid Build Coastguard Worker with open(path) as f1: 49*c8dee2aaSAndroid Build Coastguard Worker with open(src_path) as f2: 50*c8dee2aaSAndroid Build Coastguard Worker if f1.read() == f2.read(): 51*c8dee2aaSAndroid Build Coastguard Worker continue 52*c8dee2aaSAndroid Build Coastguard Worker output(out, '+', dst, path) 53*c8dee2aaSAndroid Build Coastguard Worker shutil.copy2(src_path, path) 54*c8dee2aaSAndroid Build Coastguard Worker finally: 55*c8dee2aaSAndroid Build Coastguard Worker os.chdir(cwd) 56*c8dee2aaSAndroid Build Coastguard Worker 57*c8dee2aaSAndroid Build Coastguard Workerif __name__ == '__main__': 58*c8dee2aaSAndroid Build Coastguard Worker if len(sys.argv) != 3: 59*c8dee2aaSAndroid Build Coastguard Worker sys.stderr.write('\nUsage:\n %s SRC_DIR DST_DIR\n\n' % sys.argv[0]) 60*c8dee2aaSAndroid Build Coastguard Worker sys.exit(1) 61*c8dee2aaSAndroid Build Coastguard Worker copy_git_directory(sys.argv[1], sys.argv[2], sys.stdout) 62