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