blob: 621606dd81462f9694d3650d24024ac1b9689f22 [file] [log] [blame]
Edward Lemur3c814952019-08-12 19:43:00 +00001#!/usr/bin/env vpython
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
Raul Tambre80ee78e2019-05-06 22:41:05 +000010from __future__ import print_function
11
Wei-Yin Chen (陳威尹)05203492017-05-11 00:07:53 -070012import argparse
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000013import os
14import shutil
15import subprocess
16import sys
Wei-Yin Chen (陳威尹)56e4ad92017-05-23 01:05:38 -070017import textwrap
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000018
sammc@chromium.org900a33f2015-09-29 06:57:09 +000019import git_common
20
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000021
pgervais@chromium.orgf13c2052013-11-15 20:09:23 +000022def parse_options():
23 if sys.platform == 'win32':
Wei-Yin Chen (陳威尹)05203492017-05-11 00:07:53 -070024 print('ERROR: This script cannot run on Windows because it uses symlinks.')
25 sys.exit(1)
pgervais@chromium.orgf13c2052013-11-15 20:09:23 +000026
Wei-Yin Chen (陳威尹)05203492017-05-11 00:07:53 -070027 parser = argparse.ArgumentParser(description='''\
28 Clone an existing gclient directory, taking care of all sub-repositories.
29 Works similarly to 'git new-workdir'.''')
30 parser.add_argument('repository', type=os.path.abspath,
31 help='should contain a .gclient file')
32 parser.add_argument('new_workdir', help='must not exist')
Wei-Yin Chen (陳威尹)704be872017-05-11 00:58:26 -070033 parser.add_argument('--reflink', action='store_true', default=None,
34 help='''force to use "cp --reflink" for speed and disk
35 space. need supported FS like btrfs or ZFS.''')
36 parser.add_argument('--no-reflink', action='store_false', dest='reflink',
37 help='''force not to use "cp --reflink" even on supported
38 FS like btrfs or ZFS.''')
Wei-Yin Chen (陳威尹)05203492017-05-11 00:07:53 -070039 args = parser.parse_args()
pgervais@chromium.orgf13c2052013-11-15 20:09:23 +000040
Wei-Yin Chen (陳威尹)05203492017-05-11 00:07:53 -070041 if not os.path.exists(args.repository):
42 parser.error('Repository "%s" does not exist.' % args.repository)
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000043
Wei-Yin Chen (陳威尹)05203492017-05-11 00:07:53 -070044 gclient = os.path.join(args.repository, '.gclient')
45 if not os.path.exists(gclient):
46 parser.error('No .gclient file at "%s".' % gclient)
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000047
Wei-Yin Chen (陳威尹)05203492017-05-11 00:07:53 -070048 if os.path.exists(args.new_workdir):
49 parser.error('New workdir "%s" already exists.' % args.new_workdir)
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000050
Wei-Yin Chen (陳威尹)05203492017-05-11 00:07:53 -070051 return args
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000052
53
Wei-Yin Chen (陳威尹)704be872017-05-11 00:58:26 -070054def support_cow(src, dest):
Henrique Ferreirofd4ad242018-01-10 12:19:18 +010055 # 'cp --reflink' always succeeds when 'src' is a symlink or a directory
56 assert os.path.isfile(src) and not os.path.islink(src)
Wei-Yin Chen (陳威尹)704be872017-05-11 00:58:26 -070057 try:
58 subprocess.check_output(['cp', '-a', '--reflink', src, dest],
59 stderr=subprocess.STDOUT)
60 except subprocess.CalledProcessError:
61 return False
62 finally:
Wei-Yin Chen (陳威尹)2fa12032017-06-01 20:30:11 -070063 if os.path.isfile(dest):
64 os.remove(dest)
Wei-Yin Chen (陳威尹)704be872017-05-11 00:58:26 -070065 return True
66
67
Wei-Yin Chen (陳威尹)56664462017-05-23 18:37:23 -070068def try_vol_snapshot(src, dest):
69 try:
70 subprocess.check_call(['btrfs', 'subvol', 'snapshot', src, dest],
71 stderr=subprocess.STDOUT)
Wei-Yin Chen (陳威尹)2fa12032017-06-01 20:30:11 -070072 except (subprocess.CalledProcessError, OSError):
Wei-Yin Chen (陳威尹)56664462017-05-23 18:37:23 -070073 return False
74 return True
75
76
pgervais@chromium.orgf13c2052013-11-15 20:09:23 +000077def main():
Wei-Yin Chen (陳威尹)05203492017-05-11 00:07:53 -070078 args = parse_options()
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000079
Wei-Yin Chen (陳威尹)05203492017-05-11 00:07:53 -070080 gclient = os.path.join(args.repository, '.gclient')
Henrique Ferreirofd4ad242018-01-10 12:19:18 +010081 if os.path.islink(gclient):
Henrique Ferreiroaea45d22018-02-19 09:48:36 +010082 gclient = os.path.realpath(gclient)
Wei-Yin Chen (陳威尹)704be872017-05-11 00:58:26 -070083 new_gclient = os.path.join(args.new_workdir, '.gclient')
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000084
Wei-Yin Chen (陳威尹)56664462017-05-23 18:37:23 -070085 if try_vol_snapshot(args.repository, args.new_workdir):
86 args.reflink = True
87 else:
88 os.makedirs(args.new_workdir)
89 if args.reflink is None:
90 args.reflink = support_cow(gclient, new_gclient)
91 if args.reflink:
92 print('Copy-on-write support is detected.')
93 os.symlink(gclient, new_gclient)
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +000094
Wei-Yin Chen (陳威尹)05203492017-05-11 00:07:53 -070095 for root, dirs, _ in os.walk(args.repository):
pgervais@chromium.orgf13c2052013-11-15 20:09:23 +000096 if '.git' in dirs:
Wei-Yin Chen (陳威尹)05203492017-05-11 00:07:53 -070097 workdir = root.replace(args.repository, args.new_workdir, 1)
sammc@chromium.org900a33f2015-09-29 06:57:09 +000098 print('Creating: %s' % workdir)
Wei-Yin Chen (陳威尹)704be872017-05-11 00:58:26 -070099
100 if args.reflink:
101 if not os.path.exists(workdir):
102 print('Copying: %s' % workdir)
103 subprocess.check_call(['cp', '-a', '--reflink', root, workdir])
104 shutil.rmtree(os.path.join(workdir, '.git'))
105
sammc@chromium.org900a33f2015-09-29 06:57:09 +0000106 git_common.make_workdir(os.path.join(root, '.git'),
107 os.path.join(workdir, '.git'))
Wei-Yin Chen (陳威尹)704be872017-05-11 00:58:26 -0700108 if args.reflink:
109 subprocess.check_call(['cp', '-a', '--reflink',
110 os.path.join(root, '.git', 'index'),
111 os.path.join(workdir, '.git', 'index')])
112 else:
113 subprocess.check_call(['git', 'checkout', '-f'], cwd=workdir)
114
Wei-Yin Chen (陳威尹)56e4ad92017-05-23 01:05:38 -0700115 if args.reflink:
116 print(textwrap.dedent('''\
117 The repo was copied with copy-on-write, and the artifacts were retained.
118 More details on http://crbug.com/721585.
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +0000119
Wei-Yin Chen (陳威尹)56e4ad92017-05-23 01:05:38 -0700120 Depending on your usage pattern, you might want to do "gn gen"
121 on the output directories. More details: http://crbug.com/723856.'''))
adam.treat@samsung.com62d817c2013-11-05 15:18:13 +0000122
123if __name__ == '__main__':
pgervais@chromium.orgf13c2052013-11-15 20:09:23 +0000124 sys.exit(main())