-
Notifications
You must be signed in to change notification settings - Fork 0
/
gclient-new-workdir.py
executable file
·139 lines (115 loc) · 4.6 KB
/
gclient-new-workdir.py
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())