blob: 86f0b3d764ec121bf5edc7be4ef536bcafbee60b [file] [log] [blame]
Josip Sokcevic4de5dea2022-03-23 21:15:14 +00001#!/usr/bin/env python3
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +00002# Copyright 2013 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5#
6# Usage:
Wei-Yin Chen (陳威尹)05203492017-05-11 00:07:53 -07007# gclient-new-workdir.py [options] <repository> <new_workdir>
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +00008#
9
Wei-Yin Chen (陳威尹)05203492017-05-11 00:07:53 -070010import argparse
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000011import os
12import shutil
13import subprocess
14import sys
Wei-Yin Chen (陳威尹)56e4ad92017-05-23 01:05:38 -070015import textwrap
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000016
sammc@chromium.org900a33f2015-09-29 06:57:09 +000017import git_common
18
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000019
pgervais@chromium.orgf13c2052013-11-15 20:09:23 +000020def parse_options():
Mike Frysinger124bb8e2023-09-06 05:48:55 +000021 if sys.platform == 'win32':
22 print(
23 'ERROR: This script cannot run on Windows because it uses symlinks.'
24 )
25 sys.exit(1)
pgervais@chromium.orgf13c2052013-11-15 20:09:23 +000026
Mike Frysinger124bb8e2023-09-06 05:48:55 +000027 parser = argparse.ArgumentParser(description='''\
Wei-Yin Chen (陳威尹)05203492017-05-11 00:07:53 -070028 Clone an existing gclient directory, taking care of all sub-repositories.
29 Works similarly to 'git new-workdir'.''')
Mike Frysinger124bb8e2023-09-06 05:48:55 +000030 parser.add_argument('repository',
31 type=os.path.abspath,
32 help='should contain a .gclient file')
33 parser.add_argument('new_workdir', help='must not exist')
34 parser.add_argument('--reflink',
35 action='store_true',
36 default=None,
37 help='''force to use "cp --reflink" for speed and disk
Wei-Yin Chen (陳威尹)704be872017-05-11 00:58:26 -070038 space. need supported FS like btrfs or ZFS.''')
Mike Frysinger124bb8e2023-09-06 05:48:55 +000039 parser.add_argument(
40 '--no-reflink',
41 action='store_false',
42 dest='reflink',
43 help='''force not to use "cp --reflink" even on supported
Wei-Yin Chen (陳威尹)704be872017-05-11 00:58:26 -070044 FS like btrfs or ZFS.''')
Mike Frysinger124bb8e2023-09-06 05:48:55 +000045 args = parser.parse_args()
pgervais@chromium.orgf13c2052013-11-15 20:09:23 +000046
Mike Frysinger124bb8e2023-09-06 05:48:55 +000047 if not os.path.exists(args.repository):
48 parser.error('Repository "%s" does not exist.' % args.repository)
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000049
Mike Frysinger124bb8e2023-09-06 05:48:55 +000050 gclient = os.path.join(args.repository, '.gclient')
51 if not os.path.exists(gclient):
52 parser.error('No .gclient file at "%s".' % gclient)
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000053
Mike Frysinger124bb8e2023-09-06 05:48:55 +000054 if os.path.exists(args.new_workdir):
55 parser.error('New workdir "%s" already exists.' % args.new_workdir)
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000056
Mike Frysinger124bb8e2023-09-06 05:48:55 +000057 return args
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000058
59
Wei-Yin Chen (陳威尹)704be872017-05-11 00:58:26 -070060def support_cow(src, dest):
Mike Frysinger124bb8e2023-09-06 05:48:55 +000061 # 'cp --reflink' always succeeds when 'src' is a symlink or a directory
62 assert os.path.isfile(src) and not os.path.islink(src)
63 try:
64 subprocess.check_output(['cp', '-a', '--reflink', src, dest],
65 stderr=subprocess.STDOUT)
66 except subprocess.CalledProcessError:
67 return False
68 finally:
69 if os.path.isfile(dest):
70 os.remove(dest)
71 return True
Wei-Yin Chen (陳威尹)704be872017-05-11 00:58:26 -070072
73
Wei-Yin Chen (陳威尹)56664462017-05-23 18:37:23 -070074def try_vol_snapshot(src, dest):
Mike Frysinger124bb8e2023-09-06 05:48:55 +000075 try:
76 subprocess.check_call(['btrfs', 'subvol', 'snapshot', src, dest],
77 stderr=subprocess.STDOUT)
78 except (subprocess.CalledProcessError, OSError):
79 return False
80 return True
Wei-Yin Chen (陳威尹)56664462017-05-23 18:37:23 -070081
82
pgervais@chromium.orgf13c2052013-11-15 20:09:23 +000083def main():
Mike Frysinger124bb8e2023-09-06 05:48:55 +000084 args = parse_options()
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000085
Mike Frysinger124bb8e2023-09-06 05:48:55 +000086 gclient = os.path.join(args.repository, '.gclient')
87 if os.path.islink(gclient):
88 gclient = os.path.realpath(gclient)
89 new_gclient = os.path.join(args.new_workdir, '.gclient')
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000090
Mike Frysinger124bb8e2023-09-06 05:48:55 +000091 if try_vol_snapshot(args.repository, args.new_workdir):
92 args.reflink = True
93 else:
94 os.makedirs(args.new_workdir)
95 if args.reflink is None:
96 args.reflink = support_cow(gclient, new_gclient)
97 if args.reflink:
98 print('Copy-on-write support is detected.')
99 os.symlink(gclient, new_gclient)
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +0000100
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000101 for root, dirs, _ in os.walk(args.repository):
102 if '.git' in dirs:
103 workdir = root.replace(args.repository, args.new_workdir, 1)
104 print('Creating: %s' % workdir)
Wei-Yin Chen (陳威尹)704be872017-05-11 00:58:26 -0700105
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000106 if args.reflink:
107 if not os.path.exists(workdir):
108 print('Copying: %s' % workdir)
109 subprocess.check_call(
110 ['cp', '-a', '--reflink', root, workdir])
111 shutil.rmtree(os.path.join(workdir, '.git'))
Wei-Yin Chen (陳威尹)704be872017-05-11 00:58:26 -0700112
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000113 git_common.make_workdir(os.path.join(root, '.git'),
114 os.path.join(workdir, '.git'))
115 if args.reflink:
116 subprocess.check_call([
117 'cp', '-a', '--reflink',
118 os.path.join(root, '.git', 'index'),
119 os.path.join(workdir, '.git', 'index')
120 ])
121 else:
122 subprocess.check_call(['git', 'checkout', '-f'], cwd=workdir)
Wei-Yin Chen (陳威尹)704be872017-05-11 00:58:26 -0700123
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000124 if args.reflink:
125 print(
126 textwrap.dedent('''\
Wei-Yin Chen (陳威尹)56e4ad92017-05-23 01:05:38 -0700127 The repo was copied with copy-on-write, and the artifacts were retained.
128 More details on http://crbug.com/721585.
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +0000129
Wei-Yin Chen (陳威尹)56e4ad92017-05-23 01:05:38 -0700130 Depending on your usage pattern, you might want to do "gn gen"
131 on the output directories. More details: http://crbug.com/723856.'''))
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +0000132
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000133
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +0000134if __name__ == '__main__':
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000135 sys.exit(main())