blob: 1df5fff3ebc9efaea2362e5e1675889f082a942b [file] [log] [blame]
Primiano Tuccic8be6812021-02-09 18:08:49 +01001#!/usr/bin/env python3
Primiano Tuccif7647392019-10-04 00:42:11 +01002# Copyright (C) 2019 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16from __future__ import print_function
17import argparse
Matthew Clarkson1ed6a042019-10-25 11:18:05 +010018import distutils
Matthew Clarksonb4645a22019-11-06 13:34:39 +000019import errno
Matthew Clarkson1ed6a042019-10-25 11:18:05 +010020import grp
21import os
22import readline
Primiano Tuccif7647392019-10-04 00:42:11 +010023import sys
24import shutil
25import subprocess
Matthew Clarkson1ed6a042019-10-25 11:18:05 +010026from pipes import quote
Matthew Clarksonb4645a22019-11-06 13:34:39 +000027from subprocess import check_call
Matthew Clarkson1ed6a042019-10-25 11:18:05 +010028
29try:
30 from shutil import which as find_executable
31except AttributeError:
32 from distutils.spawn import find_executable
Primiano Tuccif7647392019-10-04 00:42:11 +010033
34REPO_ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
35sys.path.append(os.path.join(REPO_ROOT, 'infra', 'ci'))
36from config import JOB_CONFIGS, SANDBOX_IMG
37
Matthew Clarkson1ed6a042019-10-25 11:18:05 +010038try:
39 input = raw_input
40except NameError:
41 pass
42
43
44def user_in_docker_group():
45 try:
46 group = grp.getgrnam('docker')
47 except KeyError:
48 return False
49 else:
50 return group.gr_gid in os.getgroups()
51
52
53def decision(question='Would you like to continue', confirm=True, default='n'):
54 default = default.lower().strip()
55 yes = default in {'y', 'yes'}
56 no = default in {'n', 'no'}
57 default = 'y' if yes else 'n'
58 prompt = '%s? [%s/%s]: ' % (question, 'Y' if yes else 'y', 'N' if no else 'n')
59 if not confirm:
60 print('%sy' % prompt)
61 return
62 while True:
63 choice = input(prompt).lower().strip()
64 if not choice:
65 choice = default
66 if choice in {'y', 'yes'}:
67 return
68 elif choice in {'n', 'no'}:
69 sys.exit(3)
70
Primiano Tuccif7647392019-10-04 00:42:11 +010071
72def main():
Matthew Clarkson1ed6a042019-10-25 11:18:05 +010073 parser = argparse.ArgumentParser(
74 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
Matthew Clarkson63028d62019-10-10 15:48:23 +010075 parser.add_argument('config', choices=JOB_CONFIGS.keys())
Matthew Clarkson1ed6a042019-10-25 11:18:05 +010076 parser.add_argument(
77 '--runner',
78 help='The container runner executable to use',
79 choices=('podman', 'docker'),
80 default='podman' if find_executable('podman') else 'docker')
81 parser.add_argument(
Matthew Clarksonb4645a22019-11-06 13:34:39 +000082 '--build',
83 action='store_true',
84 help='Will perform a build of sandbox image')
Matthew Clarkson1ed6a042019-10-25 11:18:05 +010085 group = parser.add_mutually_exclusive_group()
86 group.add_argument(
87 '--confirm',
88 action='store_true',
89 default=True,
90 help='User confirmation of decision prompts')
91 group.add_argument(
92 '--no-confirm',
93 dest='confirm',
94 action='store_false',
95 help='Forces confirmation of decision prompts')
Matthew Clarkson63028d62019-10-10 15:48:23 +010096 args = parser.parse_args()
Primiano Tuccif7647392019-10-04 00:42:11 +010097
Matthew Clarkson63028d62019-10-10 15:48:23 +010098 # Check that the directory is clean.
99 git_cmd = ['git', '-C', REPO_ROOT, 'status', '--porcelain']
Matthew Clarkson1ed6a042019-10-25 11:18:05 +0100100 modified_files = subprocess.check_output(git_cmd).decode()
Matthew Clarkson63028d62019-10-10 15:48:23 +0100101 if modified_files:
102 print('The current Git repo has modified/untracked files.')
103 print('The sandboxed VM will fetch the HEAD of your current git repo.')
104 print('This is probably not the state you want to be in.')
Matthew Clarkson1ed6a042019-10-25 11:18:05 +0100105 print('I suggest you stop, commit and then re-run this script')
Matthew Clarkson63028d62019-10-10 15:48:23 +0100106 print('Modified files:\n' + modified_files)
Matthew Clarkson1ed6a042019-10-25 11:18:05 +0100107 decision('Do you know what you are doing', confirm=args.confirm)
Primiano Tuccif7647392019-10-04 00:42:11 +0100108
Matthew Clarksonb4645a22019-11-06 13:34:39 +0000109 if args.build:
110 print('')
111 print('About to build %r locally with %r' % (args.image, args.runner))
112 decision(confirm=args.confirm)
113 check_call(('make', '-C', os.path.join(REPO_ROOT, 'infra',
114 'ci'),
115 'BUILDER=%s' % args.runner, 'build-sandbox'))
116
Primiano Tuccie9790ab2021-02-22 14:58:01 +0100117 bundle_path = '/tmp/perfetto-ci.bundle'
118 check_call(['git', '-C', REPO_ROOT, 'bundle', 'create', bundle_path, 'HEAD' ])
119 os.chmod(bundle_path, 0o664)
Matthew Clarkson63028d62019-10-10 15:48:23 +0100120 env = {
Primiano Tuccie9790ab2021-02-22 14:58:01 +0100121 'PERFETTO_TEST_GIT_REF': bundle_path,
Matthew Clarkson63028d62019-10-10 15:48:23 +0100122 }
123 env.update(JOB_CONFIGS[args.config])
Primiano Tuccif7647392019-10-04 00:42:11 +0100124
Matthew Clarkson63028d62019-10-10 15:48:23 +0100125 workdir = os.path.join(REPO_ROOT, 'out', 'tmp.ci')
Matthew Clarkson1ed6a042019-10-25 11:18:05 +0100126 cmd = []
127 if args.runner == 'docker' and not user_in_docker_group():
128 cmd += ['sudo', '--']
129 cmd += [
130 args.runner, 'run', '-it', '--name', 'perfetto_ci', '--cap-add',
131 'SYS_PTRACE', '--rm', '--volume',
Matthew Clarkson63028d62019-10-10 15:48:23 +0100132 '%s:/ci/ramdisk' % workdir, '--tmpfs', '/tmp:exec',
Primiano Tuccie9790ab2021-02-22 14:58:01 +0100133 '--volume=%s:%s:ro' % (bundle_path, bundle_path)
Matthew Clarkson63028d62019-10-10 15:48:23 +0100134 ]
135 for kv in env.items():
136 cmd += ['--env', '%s=%s' % kv]
Matthew Clarksonb4645a22019-11-06 13:34:39 +0000137 cmd += [SANDBOX_IMG]
Matthew Clarkson63028d62019-10-10 15:48:23 +0100138 cmd += [
139 'bash', '-c',
140 'cd /ci/ramdisk; bash /ci/init.sh || sudo -u perfetto -EH bash -i'
141 ]
Primiano Tuccif7647392019-10-04 00:42:11 +0100142
Matthew Clarkson1ed6a042019-10-25 11:18:05 +0100143 print(
144 'About to run\n',
145 ' '.join('\n ' + c if c.startswith('--') or c == 'bash' else quote(c)
146 for c in cmd))
Matthew Clarkson63028d62019-10-10 15:48:23 +0100147 print('')
Matthew Clarkson63028d62019-10-10 15:48:23 +0100148 print('The VM workdir /ci/ramdisk will be mounted into: %s' % workdir)
149 print('The contents of %s will be deleted before starting the VM' % workdir)
Matthew Clarkson1ed6a042019-10-25 11:18:05 +0100150 decision(confirm=args.confirm)
Primiano Tuccif7647392019-10-04 00:42:11 +0100151
Matthew Clarksonb4645a22019-11-06 13:34:39 +0000152 try:
153 shutil.rmtree(workdir)
154 except EnvironmentError as e:
155 if e.errno == errno.ENOENT:
156 pass
157 elif e.errno == errno.EACCES:
158 print('')
159 print('Removing previous volume %r' % workdir)
160 check_call(('sudo', 'rm', '-r', quote(workdir)))
161 else:
162 raise
163
Matthew Clarkson63028d62019-10-10 15:48:23 +0100164 os.makedirs(workdir)
Matthew Clarkson1ed6a042019-10-25 11:18:05 +0100165 os.execvp(cmd[0], cmd)
Primiano Tuccif7647392019-10-04 00:42:11 +0100166
167
168if __name__ == '__main__':
Matthew Clarkson63028d62019-10-10 15:48:23 +0100169 sys.exit(main())