1# Copyright 2014 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5 6# pylint: disable=W0201 7 8 9from recipe_engine import recipe_api 10from recipe_engine import config_types 11 12 13class CheckoutApi(recipe_api.RecipeApi): 14 15 @property 16 def default_checkout_root(self): 17 """The default location for cached persistent checkouts.""" 18 return self.m.vars.cache_dir.join('work') 19 20 def assert_git_is_from_cipd(self): 21 """Fail if git is not obtained from CIPD.""" 22 self.m.run(self.m.python.inline, 'Assert that Git is from CIPD', program=''' 23from __future__ import print_function 24import subprocess 25import sys 26 27which = 'where' if sys.platform == 'win32' else 'which' 28git = subprocess.check_output([which, 'git']) 29print('git was found at %s' % git) 30if 'cipd_bin_packages' not in git: 31 print('Git must be obtained through CIPD.', file=sys.stderr) 32 sys.exit(1) 33''') 34 35 def git(self, checkout_root): 36 """Run the steps to perform a pure-git checkout without DEPS.""" 37 self.assert_git_is_from_cipd() 38 skia_dir = checkout_root.join('skia') 39 self.m.git.checkout( 40 self.m.properties['repository'], dir_path=skia_dir, 41 ref=self.m.properties['revision'], submodules=False) 42 if self.m.vars.is_trybot: 43 self.m.git('fetch', 'origin', self.m.properties['patch_ref']) 44 self.m.git('checkout', 'FETCH_HEAD') 45 self.m.git('rebase', self.m.properties['revision']) 46 return self.m.properties['revision'] 47 48 def bot_update(self, checkout_root, gclient_cache=None, 49 checkout_chromium=False, checkout_flutter=False, 50 extra_gclient_env=None, 51 flutter_android=False): 52 """Run the steps to obtain a checkout using bot_update. 53 54 Args: 55 checkout_root: Root directory where the code will be synced. 56 gclient_cache: Optional, directory of the gclient cache. 57 checkout_chromium: If True, will check out chromium/src.git in addition 58 to the primary repo. 59 checkout_flutter: If True, will checkout flutter in addition to the 60 primary repo. 61 extra_gclient_env: Map of extra environment variable names to their values 62 to supply while running gclient. 63 flutter_android: Indicates that we're checking out flutter for Android. 64 """ 65 self.assert_git_is_from_cipd() 66 if not gclient_cache: 67 gclient_cache = self.m.vars.cache_dir.join('git') 68 if not extra_gclient_env: 69 extra_gclient_env = {} 70 71 cfg_kwargs = {} 72 73 # Use a persistent gclient cache for Swarming. 74 cfg_kwargs['CACHE_DIR'] = gclient_cache 75 76 if checkout_flutter: 77 # Delete the flutter cache to start from scratch every time. 78 # See skbug.com/9994. 79 self.m.run.rmtree(checkout_root) 80 81 # Create the checkout path if necessary. 82 # TODO(borenet): 'makedirs checkout_root' 83 self.m.file.ensure_directory('makedirs checkout_path', checkout_root) 84 85 # Initial cleanup. 86 gclient_cfg = self.m.gclient.make_config(**cfg_kwargs) 87 88 main_repo = self.m.properties['repository'] 89 if checkout_flutter: 90 main_repo = 'https://github.com/flutter/engine.git' 91 main_name = self.m.path.basename(main_repo) 92 if main_name.endswith('.git'): 93 main_name = main_name[:-len('.git')] 94 # Special case for flutter because it seems to need a very specific 95 # directory structure to successfully build. 96 if checkout_flutter and main_name == 'engine': 97 main_name = 'src/flutter' 98 main = gclient_cfg.solutions.add() 99 main.name = main_name 100 main.managed = False 101 main.url = main_repo 102 main.revision = self.m.properties.get('revision') or 'origin/main' 103 m = gclient_cfg.got_revision_mapping 104 m[main_name] = 'got_revision' 105 patch_root = main_name 106 patch_repo = main.url 107 if self.m.properties.get('patch_repo'): 108 patch_repo = self.m.properties['patch_repo'] 109 patch_root = patch_repo.split('/')[-1] 110 if patch_root.endswith('.git'): 111 patch_root = patch_root[:-4] 112 113 if checkout_flutter: 114 # Skia is a DEP of Flutter; the 'revision' property is a Skia revision, 115 # and any patch should be applied to Skia, not Flutter. 116 main.revision = 'origin/master' 117 main.managed = True 118 m[main_name] = 'got_flutter_revision' 119 if flutter_android: 120 gclient_cfg.target_os.add('android') 121 122 skia_dep_path = 'src/third_party/skia' 123 gclient_cfg.repo_path_map['https://skia.googlesource.com/skia'] = ( 124 skia_dep_path, 'HEAD') 125 gclient_cfg.revisions[skia_dep_path] = self.m.properties['revision'] 126 m[skia_dep_path] = 'got_revision' 127 patch_root = skia_dep_path 128 129 if checkout_chromium: 130 main.custom_vars['checkout_chromium'] = True 131 extra_gclient_env['GYP_CHROMIUM_NO_ACTION'] = '0' 132 133 # TODO(rmistry): Remove the below block after there is a solution for 134 # crbug.com/616443 135 entries_file = checkout_root.join('.gclient_entries') 136 if self.m.path.exists(entries_file) or self._test_data.enabled: 137 self.m.file.remove('remove %s' % entries_file, 138 entries_file) 139 140 # Run bot_update. 141 patch_refs = None 142 patch_ref = self.m.properties.get('patch_ref') 143 if patch_ref: 144 patch_refs = ['%s@%s:%s' % (self.m.properties['patch_repo'], 145 self.m.properties['revision'], 146 patch_ref)] 147 148 self.m.gclient.c = gclient_cfg 149 with self.m.context(cwd=checkout_root): 150 update_step = self.m.bot_update.ensure_checkout( 151 patch_root=patch_root, 152 # The logic in ensure_checkout for this arg is fairly naive, so if 153 # patch=False, we'll see "... (without patch)" in the step names, even 154 # for non-trybot runs, which is misleading and confusing. Therefore, 155 # always specify patch=True. 156 patch=True, 157 patch_refs=patch_refs, 158 ) 159 160 if checkout_chromium or checkout_flutter: 161 gclient_env = {'DEPOT_TOOLS_UPDATE': '0'} 162 if extra_gclient_env: 163 gclient_env.update(extra_gclient_env) 164 with self.m.context(cwd=checkout_root, env=gclient_env): 165 self.m.gclient.runhooks() 166 return update_step.presentation.properties['got_revision'] 167