xref: /aosp_15_r20/external/skia/gn/copy_git_directory.py (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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