Josip Sokcevic | 4de5dea | 2022-03-23 21:15:14 +0000 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
adam.treat@samsung.com | 62d817c | 2013-11-05 15:18:13 +0000 | [diff] [blame] | 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 00:07:53 -0700 | [diff] [blame] | 7 | # gclient-new-workdir.py [options] <repository> <new_workdir> |
adam.treat@samsung.com | 62d817c | 2013-11-05 15:18:13 +0000 | [diff] [blame] | 8 | # |
| 9 | |
Wei-Yin Chen (陳威尹) | 0520349 | 2017-05-11 00:07:53 -0700 | [diff] [blame] | 10 | import argparse |
adam.treat@samsung.com | 62d817c | 2013-11-05 15:18:13 +0000 | [diff] [blame] | 11 | import os |
| 12 | import shutil |
| 13 | import subprocess |
| 14 | import sys |
Wei-Yin Chen (陳威尹) | 56e4ad9 | 2017-05-23 01:05:38 -0700 | [diff] [blame] | 15 | import textwrap |
adam.treat@samsung.com | 62d817c | 2013-11-05 15:18:13 +0000 | [diff] [blame] | 16 | |
sammc@chromium.org | 900a33f | 2015-09-29 06:57:09 +0000 | [diff] [blame] | 17 | import git_common |
| 18 | |
adam.treat@samsung.com | 62d817c | 2013-11-05 15:18:13 +0000 | [diff] [blame] | 19 | |
pgervais@chromium.org | f13c205 | 2013-11-15 20:09:23 +0000 | [diff] [blame] | 20 | def parse_options(): |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 21 | 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.org | f13c205 | 2013-11-15 20:09:23 +0000 | [diff] [blame] | 26 | |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 27 | parser = argparse.ArgumentParser(description='''\ |
Wei-Yin Chen (陳威尹) | 0520349 | 2017-05-11 00:07:53 -0700 | [diff] [blame] | 28 | Clone an existing gclient directory, taking care of all sub-repositories. |
| 29 | Works similarly to 'git new-workdir'.''') |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 30 | 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 (陳威尹) | 704be87 | 2017-05-11 00:58:26 -0700 | [diff] [blame] | 38 | space. need supported FS like btrfs or ZFS.''') |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 39 | 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 (陳威尹) | 704be87 | 2017-05-11 00:58:26 -0700 | [diff] [blame] | 44 | FS like btrfs or ZFS.''') |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 45 | args = parser.parse_args() |
pgervais@chromium.org | f13c205 | 2013-11-15 20:09:23 +0000 | [diff] [blame] | 46 | |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 47 | if not os.path.exists(args.repository): |
| 48 | parser.error('Repository "%s" does not exist.' % args.repository) |
adam.treat@samsung.com | 62d817c | 2013-11-05 15:18:13 +0000 | [diff] [blame] | 49 | |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 50 | 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.com | 62d817c | 2013-11-05 15:18:13 +0000 | [diff] [blame] | 53 | |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 54 | if os.path.exists(args.new_workdir): |
| 55 | parser.error('New workdir "%s" already exists.' % args.new_workdir) |
adam.treat@samsung.com | 62d817c | 2013-11-05 15:18:13 +0000 | [diff] [blame] | 56 | |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 57 | return args |
adam.treat@samsung.com | 62d817c | 2013-11-05 15:18:13 +0000 | [diff] [blame] | 58 | |
| 59 | |
Wei-Yin Chen (陳威尹) | 704be87 | 2017-05-11 00:58:26 -0700 | [diff] [blame] | 60 | def support_cow(src, dest): |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 61 | # '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 (陳威尹) | 704be87 | 2017-05-11 00:58:26 -0700 | [diff] [blame] | 72 | |
| 73 | |
Wei-Yin Chen (陳威尹) | 5666446 | 2017-05-23 18:37:23 -0700 | [diff] [blame] | 74 | def try_vol_snapshot(src, dest): |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 75 | 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 (陳威尹) | 5666446 | 2017-05-23 18:37:23 -0700 | [diff] [blame] | 81 | |
| 82 | |
pgervais@chromium.org | f13c205 | 2013-11-15 20:09:23 +0000 | [diff] [blame] | 83 | def main(): |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 84 | args = parse_options() |
adam.treat@samsung.com | 62d817c | 2013-11-05 15:18:13 +0000 | [diff] [blame] | 85 | |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 86 | 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.com | 62d817c | 2013-11-05 15:18:13 +0000 | [diff] [blame] | 90 | |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 91 | 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.com | 62d817c | 2013-11-05 15:18:13 +0000 | [diff] [blame] | 100 | |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 101 | 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 (陳威尹) | 704be87 | 2017-05-11 00:58:26 -0700 | [diff] [blame] | 105 | |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 106 | 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 (陳威尹) | 704be87 | 2017-05-11 00:58:26 -0700 | [diff] [blame] | 112 | |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 113 | 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 (陳威尹) | 704be87 | 2017-05-11 00:58:26 -0700 | [diff] [blame] | 123 | |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 124 | if args.reflink: |
| 125 | print( |
| 126 | textwrap.dedent('''\ |
Wei-Yin Chen (陳威尹) | 56e4ad9 | 2017-05-23 01:05:38 -0700 | [diff] [blame] | 127 | The repo was copied with copy-on-write, and the artifacts were retained. |
| 128 | More details on http://crbug.com/721585. |
adam.treat@samsung.com | 62d817c | 2013-11-05 15:18:13 +0000 | [diff] [blame] | 129 | |
Wei-Yin Chen (陳威尹) | 56e4ad9 | 2017-05-23 01:05:38 -0700 | [diff] [blame] | 130 | 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.com | 62d817c | 2013-11-05 15:18:13 +0000 | [diff] [blame] | 132 | |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 133 | |
adam.treat@samsung.com | 62d817c | 2013-11-05 15:18:13 +0000 | [diff] [blame] | 134 | if __name__ == '__main__': |
Mike Frysinger | 124bb8e | 2023-09-06 05:48:55 +0000 | [diff] [blame] | 135 | sys.exit(main()) |