blob: 45307c2c9cd3161fd11c05e4c4b13c0fabe524ee [file] [log] [blame]
Xixuan Wu26d06e02017-09-20 14:50:28 -07001# Copyright 2017 The Chromium OS 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.
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -07004"""Module for setup environemtn for local testing & Google App Engine.
5
6DO NOT RUN THIS MODULE DIRECTLY.
7
8Use bin/setup_environment instead.
9See [README.md].
10"""
Xixuan Wu26d06e02017-09-20 14:50:28 -070011
Xixuan Wu8929a302017-12-07 18:09:31 -080012from __future__ import print_function
13
Xixuan Wu26d06e02017-09-20 14:50:28 -070014import argparse
Prathmesh Prabhu4a880bc2020-06-22 13:38:50 -070015import collections
Xixuan Wu26d06e02017-09-20 14:50:28 -070016import os
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -070017import pipes
Xixuan Wu30244f92019-03-21 09:49:17 -070018import shutil
Xixuan Wu26d06e02017-09-20 14:50:28 -070019import subprocess
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -070020import sys
Xixuan Wu26d06e02017-09-20 14:50:28 -070021
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -070022_ROOT = os.path.dirname(os.path.realpath(__file__))
Xixuan Wu26d06e02017-09-20 14:50:28 -070023
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -070024_INFRA_LIBS_PATH = os.path.join(_ROOT, 'infra_libs')
25_REFRESH_CREDENTIALS_SCRIPT = os.path.join(_ROOT, 'bin', 'refresh_credentials')
26_REQUIREMENTS_PATH = os.path.join(_ROOT, "requirements.txt")
27_THIRD_PARTY_LIB_PATH = os.path.join(_ROOT, 'lib')
Xixuan Wu26d06e02017-09-20 14:50:28 -070028
Xinan Lin3ba18a02019-08-13 15:44:55 -070029
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -070030def _install_third_party_lib():
Xixuan Wu26d06e02017-09-20 14:50:28 -070031 """Install useful third-party lib.
32
33 The libraries are specified in requirement.txt. They're used in both local
34 development environment and Google App Engine, which means they will be
35 uploaded to GAE.
Xixuan Wu26d06e02017-09-20 14:50:28 -070036 """
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -070037 if os.path.exists(_THIRD_PARTY_LIB_PATH):
38 shutil.rmtree(_THIRD_PARTY_LIB_PATH)
39 os.mkdir(_THIRD_PARTY_LIB_PATH)
40 print('Installing third party dependencies in %s' %
41 (_THIRD_PARTY_LIB_PATH, ))
42 try:
43 subprocess.check_call([
44 sys.executable, '-m', 'pip', 'install', '-t', _THIRD_PARTY_LIB_PATH,
45 '-r', _REQUIREMENTS_PATH
46 ])
47 except OSError:
48 print('Please check that `pip` is installed. See README.md')
49 raise
Prathmesh Prabhu4a880bc2020-06-22 13:38:50 -070050
51
Sean McAllisteraf32bfb2021-07-19 09:20:17 -060052def create_file(fname):
53 """Create an empty file by opening it for writing and closing."""
54 open(fname, 'w').close()
55
56
57def fixup_chromite_imports():
58 """Fixup chromite __init__.py files.
59
60 Chromite runs Python3 now so relies on implicit namespacing, which Python2
61 doesn't support, so we have to go back and add a few __init__.py files to make
62 things importable.
63 """
64 def remove_third_party(fname, package):
65 "Remove 'chromite.third_party.' prefix from given import string."
66 cmd = [
67 'sed',
68 '-i',
69 's/%s/%s/' % ('chromite.third_party.%s' % package, package),
70 fname,
71 ]
72 subprocess.check_call(cmd)
73
74 for root, _, files in os.walk('infra_libs/chromite'):
75 for fname in files:
76 if fname.endswith('_pb2.py'):
77 path = os.path.join(root, fname)
78 remove_third_party(path, 'google.protobuf')
79
80 # Add explicit __init__.py files to workaround implicit namespaces in python3
81 create_file('infra_libs/chromite/__init__.py')
82 create_file('infra_libs/chromite/third_party/__init__.py')
83 create_file('infra_libs/chromite/third_party/google/__init__.py')
84 create_file('infra_libs/chromite/third_party/google/api/__init__.py')
85
86
87# _GITDEP Specifies a dependency in the form of a particular reference in a git
Prathmesh Prabhu4a880bc2020-06-22 13:38:50 -070088# project.
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -070089#
90# local_name: Name of the local directory to fetch into.
91# project: URL to the git project to fetch from.
92# ref: Git ref to fetch.
93# sparse_checkout_paths: A list of paths to checkout. Some of the dependencies
94# contain too many files and AppEngine does not allow uploading > 10K files.
95# Thus, we checkout only required sub-packages. This list is passed in to
96# (and interpreted by) `git sparse-checkout`.
Sean McAllisteraf32bfb2021-07-19 09:20:17 -060097# post_process: An optional callable to evaluate after cloning dependency
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -070098_GitDep = collections.namedtuple(
Sean McAllisteraf32bfb2021-07-19 09:20:17 -060099 '_GitDep',
100 'local_name git_project git_ref sparse_checkout_paths post_process')
Prathmesh Prabhu4a880bc2020-06-22 13:38:50 -0700101
102# List of all git project dependencies.
103_GIT_DEPS = [
Sean McAllisteraf32bfb2021-07-19 09:20:17 -0600104 # Note: When upreving chromite, ensure that protobuf version in
105 # requirements.txt still matches the protobuf version used by chromite.
Prathmesh Prabhu4a880bc2020-06-22 13:38:50 -0700106 _GitDep(
107 'chromite',
108 'https://chromium.googlesource.com/chromiumos/chromite',
Azizur Rahmana9a189f2022-07-29 20:28:28 +0000109 '1678d4792a11268172ff7ff79535706b6c0f7c03',
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -0700110 [
Sean McAllisteraf32bfb2021-07-19 09:20:17 -0600111 '/api/gen/**/*.py',
112 '/api/__init__.py',
113 '/third_party/infra_libs/*',
114 '/third_party/six/*',
115 '/third_party/google/api/*',
116 '/third_party/google/rpc/*',
117 '/third_party/__init__.py',
118 '/__init__.py',
119 '!*test.py',
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -0700120 ],
Sean McAllisteraf32bfb2021-07-19 09:20:17 -0600121 fixup_chromite_imports,
Prathmesh Prabhu4a880bc2020-06-22 13:38:50 -0700122 ),
Sean McAllisteraf32bfb2021-07-19 09:20:17 -0600123 _GitDep('luci', 'https://chromium.googlesource.com/infra/luci/luci-py',
124 '33a910c714948a5189f9c58101ce9b131f01c1fd', [
125 '/appengine/components/components/auth/**/*.py',
126 '/appengine/components/components/datastore_utils/**/*.py',
127 '/appengine/components/components/prpc/**/*.py',
128 '/appengine/components/components/*.py',
129 '!*test.py',
130 ], None),
Prathmesh Prabhu4a880bc2020-06-22 13:38:50 -0700131]
Xixuan Wu26d06e02017-09-20 14:50:28 -0700132
Xinan Lin3ba18a02019-08-13 15:44:55 -0700133
Xinan Lin83c1a312020-04-13 23:31:47 -0700134def _install_infra_libs():
Xinan Lincd6d40b2019-08-09 15:53:43 -0700135 """Install useful libs from Chromium infra and Chromite.
136
137 infra_libs consists of prpc client from luci and necessary proto files from
138 Chromite. Suite scheduler relies on those libs to conduct prpc call to
139 Buildbucket.
Xinan Lincd6d40b2019-08-09 15:53:43 -0700140 """
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -0700141 if os.path.exists(_INFRA_LIBS_PATH):
142 shutil.rmtree(_INFRA_LIBS_PATH)
143 os.mkdir(_INFRA_LIBS_PATH)
Xinan Lincd6d40b2019-08-09 15:53:43 -0700144
Prathmesh Prabhu4a880bc2020-06-22 13:38:50 -0700145 for dep in _GIT_DEPS:
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -0700146 dep_path = os.path.join(_INFRA_LIBS_PATH, dep.local_name)
147 print('Creating sparse checkout of %s at %s in %s' %
148 (dep.git_project, dep.git_ref, dep_path))
149 subprocess.check_call(
150 ['git', 'clone', '--no-checkout', dep.git_project, dep.local_name],
151 cwd=_INFRA_LIBS_PATH)
152 subprocess.check_call(['git', 'sparse-checkout', 'init'], cwd=dep_path)
153 _set_sparse_checkout_paths(dep_path, dep.sparse_checkout_paths)
Xinan Lind37e6222020-07-07 22:37:57 -0700154 subprocess.check_call(
155 ['git', 'checkout', dep.git_ref, '-b', 'deploy', '-f'], cwd=dep_path)
Xixuan Wu26d06e02017-09-20 14:50:28 -0700156
Sean McAllisteraf32bfb2021-07-19 09:20:17 -0600157 if dep.post_process:
158 dep.post_process()
159
Xinan Lin3ba18a02019-08-13 15:44:55 -0700160
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -0700161def _set_sparse_checkout_paths(checkout_dir, sparse_checkout_paths):
162 """Set the path patterns to checkout in a git checkout."""
163 # Pass in path patterns via stdin to avoid shell escaping issues.
Jack Neus366cadb2022-06-24 21:24:28 +0000164 proc = subprocess.Popen(['git', 'sparse-checkout', 'set', '--no-cone', '--stdin'],
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -0700165 stdin=subprocess.PIPE,
166 cwd=checkout_dir)
167 proc.communicate(input='\n'.join(sparse_checkout_paths))
168 if proc.poll() is None:
169 raise Exception('Leaked process when setting sparse checkout paths')
170 if proc.poll() != 0:
171 raise Exception('Failed to set sparse checkout paths')
Xixuan Wu26d06e02017-09-20 14:50:28 -0700172
173
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -0700174def _load_credentials():
175 subprocess.check_call([_REFRESH_CREDENTIALS_SCRIPT])
Xixuan Wu26d06e02017-09-20 14:50:28 -0700176
177
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -0700178def main():
179 """Entry point of the script"""
Xixuan Wu26d06e02017-09-20 14:50:28 -0700180 parser = argparse.ArgumentParser(
181 description=__doc__,
182 formatter_class=argparse.RawDescriptionHelpFormatter)
183 parser.add_argument(
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -0700184 '--load-creds',
Xixuan Wu26d06e02017-09-20 14:50:28 -0700185 action='store_true',
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -0700186 help='Also install credentials needed for releasing suite '
187 'scheduler. Not needed to modify config/*')
188
189 args = parser.parse_args()
190 _install_third_party_lib()
191 _install_infra_libs()
192 if args.load_creds:
193 _load_credentials()
Xixuan Wu26d06e02017-09-20 14:50:28 -0700194
195
196if __name__ == '__main__':
Prathmesh Prabhu8dff3e22020-06-23 13:49:45 -0700197 main()