1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
#!/usr/bin/env python3
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# Usage:
# gclient-new-workdir.py [options] <repository> <new_workdir>
#
import argparse
import os
import shutil
import subprocess
import sys
import textwrap
import gclient_utils
import git_common
def parse_options():
if sys.platform == 'win32':
print(
'ERROR: This script cannot run on Windows because it uses symlinks.'
)
sys.exit(1)
if gclient_utils.IsEnvCog():
print('ERROR: This script cannot run in non-git environment.')
sys.exit(1)
parser = argparse.ArgumentParser(description='''\
Clone an existing gclient directory, taking care of all sub-repositories.
Works similarly to 'git new-workdir'.''')
parser.add_argument('repository',
type=os.path.abspath,
help='should contain a .gclient file')
parser.add_argument('new_workdir', help='must not exist')
parser.add_argument('--reflink',
action='store_true',
default=None,
help='''force to use "cp --reflink" for speed and disk
space. need supported FS like btrfs or ZFS.''')
parser.add_argument(
'--no-reflink',
action='store_false',
dest='reflink',
help='''force not to use "cp --reflink" even on supported
FS like btrfs or ZFS.''')
args = parser.parse_args()
if not os.path.exists(args.repository):
parser.error('Repository "%s" does not exist.' % args.repository)
gclient = os.path.join(args.repository, '.gclient')
if not os.path.exists(gclient):
parser.error('No .gclient file at "%s".' % gclient)
if os.path.exists(args.new_workdir):
parser.error('New workdir "%s" already exists.' % args.new_workdir)
return args
def support_cow(src, dest):
# 'cp --reflink' always succeeds when 'src' is a symlink or a directory
assert os.path.isfile(src) and not os.path.islink(src)
try:
subprocess.check_output(['cp', '-a', '--reflink', src, dest],
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError:
return False
finally:
if os.path.isfile(dest):
os.remove(dest)
return True
def try_vol_snapshot(src, dest):
try:
subprocess.check_call(['btrfs', 'subvol', 'snapshot', src, dest],
stderr=subprocess.STDOUT)
except (subprocess.CalledProcessError, OSError):
return False
return True
def main():
args = parse_options()
gclient = os.path.join(args.repository, '.gclient')
if os.path.islink(gclient):
gclient = os.path.realpath(gclient)
new_gclient = os.path.join(args.new_workdir, '.gclient')
if try_vol_snapshot(args.repository, args.new_workdir):
args.reflink = True
else:
os.makedirs(args.new_workdir)
if args.reflink is None:
args.reflink = support_cow(gclient, new_gclient)
if args.reflink:
print('Copy-on-write support is detected.')
os.symlink(gclient, new_gclient)
for root, dirs, _ in os.walk(args.repository):
if '.git' in dirs:
workdir = root.replace(args.repository, args.new_workdir, 1)
print('Creating: %s' % workdir)
if args.reflink:
if not os.path.exists(workdir):
print('Copying: %s' % workdir)
subprocess.check_call(
['cp', '-a', '--reflink', root, workdir])
shutil.rmtree(os.path.join(workdir, '.git'))
git_common.make_workdir(os.path.join(root, '.git'),
os.path.join(workdir, '.git'))
if args.reflink:
subprocess.check_call([
'cp', '-a', '--reflink',
os.path.join(root, '.git', 'index'),
os.path.join(workdir, '.git', 'index')
])
else:
subprocess.check_call(['git', 'checkout', '-f'], cwd=workdir)
if args.reflink:
print(
textwrap.dedent('''\
The repo was copied with copy-on-write, and the artifacts were retained.
More details on http://crbug.com/721585.
Depending on your usage pattern, you might want to do "gn gen"
on the output directories. More details: http://crbug.com/723856.'''))
if __name__ == '__main__':
sys.exit(main())
|