[email protected] | 62d817c | 2013-11-05 15:18:13 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # 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 (陳威尹) | 0520349 | 2017-05-11 07:07:53 | [diff] [blame] | 7 | # gclient-new-workdir.py [options] <repository> <new_workdir> |
[email protected] | 62d817c | 2013-11-05 15:18:13 | [diff] [blame] | 8 | # |
| 9 | |
Wei-Yin Chen (陳威尹) | 0520349 | 2017-05-11 07:07:53 | [diff] [blame] | 10 | import argparse |
[email protected] | 62d817c | 2013-11-05 15:18:13 | [diff] [blame] | 11 | import os |
| 12 | import shutil |
| 13 | import subprocess |
| 14 | import sys |
Wei-Yin Chen (陳威尹) | 56e4ad9 | 2017-05-23 08:05:38 | [diff] [blame] | 15 | import textwrap |
[email protected] | 62d817c | 2013-11-05 15:18:13 | [diff] [blame] | 16 | |
[email protected] | 900a33f | 2015-09-29 06:57:09 | [diff] [blame] | 17 | import git_common |
| 18 | |
[email protected] | 62d817c | 2013-11-05 15:18:13 | [diff] [blame] | 19 | |
[email protected] | f13c205 | 2013-11-15 20:09:23 | [diff] [blame] | 20 | def parse_options(): |
| 21 | if sys.platform == 'win32': |
Wei-Yin Chen (陳威尹) | 0520349 | 2017-05-11 07:07:53 | [diff] [blame] | 22 | print('ERROR: This script cannot run on Windows because it uses symlinks.') |
| 23 | sys.exit(1) |
[email protected] | f13c205 | 2013-11-15 20:09:23 | [diff] [blame] | 24 | |
Wei-Yin Chen (陳威尹) | 0520349 | 2017-05-11 07:07:53 | [diff] [blame] | 25 | parser = argparse.ArgumentParser(description='''\ |
| 26 | Clone an existing gclient directory, taking care of all sub-repositories. |
| 27 | Works similarly to 'git new-workdir'.''') |
| 28 | parser.add_argument('repository', type=os.path.abspath, |
| 29 | help='should contain a .gclient file') |
| 30 | parser.add_argument('new_workdir', help='must not exist') |
Wei-Yin Chen (陳威尹) | 704be87 | 2017-05-11 07:58:26 | [diff] [blame] | 31 | parser.add_argument('--reflink', action='store_true', default=None, |
| 32 | help='''force to use "cp --reflink" for speed and disk |
| 33 | space. need supported FS like btrfs or ZFS.''') |
| 34 | parser.add_argument('--no-reflink', action='store_false', dest='reflink', |
| 35 | help='''force not to use "cp --reflink" even on supported |
| 36 | FS like btrfs or ZFS.''') |
Wei-Yin Chen (陳威尹) | 0520349 | 2017-05-11 07:07:53 | [diff] [blame] | 37 | args = parser.parse_args() |
[email protected] | f13c205 | 2013-11-15 20:09:23 | [diff] [blame] | 38 | |
Wei-Yin Chen (陳威尹) | 0520349 | 2017-05-11 07:07:53 | [diff] [blame] | 39 | if not os.path.exists(args.repository): |
| 40 | parser.error('Repository "%s" does not exist.' % args.repository) |
[email protected] | 62d817c | 2013-11-05 15:18:13 | [diff] [blame] | 41 | |
Wei-Yin Chen (陳威尹) | 0520349 | 2017-05-11 07:07:53 | [diff] [blame] | 42 | gclient = os.path.join(args.repository, '.gclient') |
| 43 | if not os.path.exists(gclient): |
| 44 | parser.error('No .gclient file at "%s".' % gclient) |
[email protected] | 62d817c | 2013-11-05 15:18:13 | [diff] [blame] | 45 | |
Wei-Yin Chen (陳威尹) | 0520349 | 2017-05-11 07:07:53 | [diff] [blame] | 46 | if os.path.exists(args.new_workdir): |
| 47 | parser.error('New workdir "%s" already exists.' % args.new_workdir) |
[email protected] | 62d817c | 2013-11-05 15:18:13 | [diff] [blame] | 48 | |
Wei-Yin Chen (陳威尹) | 0520349 | 2017-05-11 07:07:53 | [diff] [blame] | 49 | return args |
[email protected] | 62d817c | 2013-11-05 15:18:13 | [diff] [blame] | 50 | |
| 51 | |
Wei-Yin Chen (陳威尹) | 704be87 | 2017-05-11 07:58:26 | [diff] [blame] | 52 | def support_cow(src, dest): |
Henrique Ferreiro | fd4ad24 | 2018-01-10 11:19:18 | [diff] [blame] | 53 | # 'cp --reflink' always succeeds when 'src' is a symlink or a directory |
| 54 | assert os.path.isfile(src) and not os.path.islink(src) |
Wei-Yin Chen (陳威尹) | 704be87 | 2017-05-11 07:58:26 | [diff] [blame] | 55 | try: |
| 56 | subprocess.check_output(['cp', '-a', '--reflink', src, dest], |
| 57 | stderr=subprocess.STDOUT) |
| 58 | except subprocess.CalledProcessError: |
| 59 | return False |
| 60 | finally: |
Wei-Yin Chen (陳威尹) | 2fa1203 | 2017-06-02 03:30:11 | [diff] [blame] | 61 | if os.path.isfile(dest): |
| 62 | os.remove(dest) |
Wei-Yin Chen (陳威尹) | 704be87 | 2017-05-11 07:58:26 | [diff] [blame] | 63 | return True |
| 64 | |
| 65 | |
Wei-Yin Chen (陳威尹) | 5666446 | 2017-05-24 01:37:23 | [diff] [blame] | 66 | def try_vol_snapshot(src, dest): |
| 67 | try: |
| 68 | subprocess.check_call(['btrfs', 'subvol', 'snapshot', src, dest], |
| 69 | stderr=subprocess.STDOUT) |
Wei-Yin Chen (陳威尹) | 2fa1203 | 2017-06-02 03:30:11 | [diff] [blame] | 70 | except (subprocess.CalledProcessError, OSError): |
Wei-Yin Chen (陳威尹) | 5666446 | 2017-05-24 01:37:23 | [diff] [blame] | 71 | return False |
| 72 | return True |
| 73 | |
| 74 | |
[email protected] | f13c205 | 2013-11-15 20:09:23 | [diff] [blame] | 75 | def main(): |
Wei-Yin Chen (陳威尹) | 0520349 | 2017-05-11 07:07:53 | [diff] [blame] | 76 | args = parse_options() |
[email protected] | 62d817c | 2013-11-05 15:18:13 | [diff] [blame] | 77 | |
Wei-Yin Chen (陳威尹) | 0520349 | 2017-05-11 07:07:53 | [diff] [blame] | 78 | gclient = os.path.join(args.repository, '.gclient') |
Henrique Ferreiro | fd4ad24 | 2018-01-10 11:19:18 | [diff] [blame] | 79 | if os.path.islink(gclient): |
Henrique Ferreiro | aea45d2 | 2018-02-19 08:48:36 | [diff] [blame] | 80 | gclient = os.path.realpath(gclient) |
Wei-Yin Chen (陳威尹) | 704be87 | 2017-05-11 07:58:26 | [diff] [blame] | 81 | new_gclient = os.path.join(args.new_workdir, '.gclient') |
[email protected] | 62d817c | 2013-11-05 15:18:13 | [diff] [blame] | 82 | |
Wei-Yin Chen (陳威尹) | 5666446 | 2017-05-24 01:37:23 | [diff] [blame] | 83 | if try_vol_snapshot(args.repository, args.new_workdir): |
| 84 | args.reflink = True |
| 85 | else: |
| 86 | os.makedirs(args.new_workdir) |
| 87 | if args.reflink is None: |
| 88 | args.reflink = support_cow(gclient, new_gclient) |
| 89 | if args.reflink: |
| 90 | print('Copy-on-write support is detected.') |
| 91 | os.symlink(gclient, new_gclient) |
[email protected] | 62d817c | 2013-11-05 15:18:13 | [diff] [blame] | 92 | |
Wei-Yin Chen (陳威尹) | 0520349 | 2017-05-11 07:07:53 | [diff] [blame] | 93 | for root, dirs, _ in os.walk(args.repository): |
[email protected] | f13c205 | 2013-11-15 20:09:23 | [diff] [blame] | 94 | if '.git' in dirs: |
Wei-Yin Chen (陳威尹) | 0520349 | 2017-05-11 07:07:53 | [diff] [blame] | 95 | workdir = root.replace(args.repository, args.new_workdir, 1) |
[email protected] | 900a33f | 2015-09-29 06:57:09 | [diff] [blame] | 96 | print('Creating: %s' % workdir) |
Wei-Yin Chen (陳威尹) | 704be87 | 2017-05-11 07:58:26 | [diff] [blame] | 97 | |
| 98 | if args.reflink: |
| 99 | if not os.path.exists(workdir): |
| 100 | print('Copying: %s' % workdir) |
| 101 | subprocess.check_call(['cp', '-a', '--reflink', root, workdir]) |
| 102 | shutil.rmtree(os.path.join(workdir, '.git')) |
| 103 | |
[email protected] | 900a33f | 2015-09-29 06:57:09 | [diff] [blame] | 104 | git_common.make_workdir(os.path.join(root, '.git'), |
| 105 | os.path.join(workdir, '.git')) |
Wei-Yin Chen (陳威尹) | 704be87 | 2017-05-11 07:58:26 | [diff] [blame] | 106 | if args.reflink: |
| 107 | subprocess.check_call(['cp', '-a', '--reflink', |
| 108 | os.path.join(root, '.git', 'index'), |
| 109 | os.path.join(workdir, '.git', 'index')]) |
| 110 | else: |
| 111 | subprocess.check_call(['git', 'checkout', '-f'], cwd=workdir) |
| 112 | |
Wei-Yin Chen (陳威尹) | 56e4ad9 | 2017-05-23 08:05:38 | [diff] [blame] | 113 | if args.reflink: |
| 114 | print(textwrap.dedent('''\ |
| 115 | The repo was copied with copy-on-write, and the artifacts were retained. |
| 116 | More details on http://crbug.com/721585. |
[email protected] | 62d817c | 2013-11-05 15:18:13 | [diff] [blame] | 117 | |
Wei-Yin Chen (陳威尹) | 56e4ad9 | 2017-05-23 08:05:38 | [diff] [blame] | 118 | Depending on your usage pattern, you might want to do "gn gen" |
| 119 | on the output directories. More details: http://crbug.com/723856.''')) |
[email protected] | 62d817c | 2013-11-05 15:18:13 | [diff] [blame] | 120 | |
| 121 | if __name__ == '__main__': |
[email protected] | f13c205 | 2013-11-15 20:09:23 | [diff] [blame] | 122 | sys.exit(main()) |