blob: 4f35def27c4c5384e3b9289ba2304ff045bc6e68 [file] [log] [blame]
Primiano Tuccif7647392019-10-04 00:42:11 +01001#!/usr/bin/env python
2# 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
Matthew Clarkson63028d62019-10-10 15:48:23 +0100117 env = {
118 'PERFETTO_TEST_GIT_REF': 'file:///ci/source',
119 }
120 env.update(JOB_CONFIGS[args.config])
Primiano Tuccif7647392019-10-04 00:42:11 +0100121
Matthew Clarkson63028d62019-10-10 15:48:23 +0100122 workdir = os.path.join(REPO_ROOT, 'out', 'tmp.ci')
Matthew Clarkson1ed6a042019-10-25 11:18:05 +0100123 cmd = []
124 if args.runner == 'docker' and not user_in_docker_group():
125 cmd += ['sudo', '--']
126 cmd += [
127 args.runner, 'run', '-it', '--name', 'perfetto_ci', '--cap-add',
128 'SYS_PTRACE', '--rm', '--volume',
Matthew Clarkson63028d62019-10-10 15:48:23 +0100129 '%s:/ci/ramdisk' % workdir, '--tmpfs', '/tmp:exec',
130 '--volume=%s:/ci/source:ro' % REPO_ROOT
131 ]
132 for kv in env.items():
133 cmd += ['--env', '%s=%s' % kv]
Matthew Clarksonb4645a22019-11-06 13:34:39 +0000134 cmd += [SANDBOX_IMG]
Matthew Clarkson63028d62019-10-10 15:48:23 +0100135 cmd += [
136 'bash', '-c',
137 'cd /ci/ramdisk; bash /ci/init.sh || sudo -u perfetto -EH bash -i'
138 ]
Primiano Tuccif7647392019-10-04 00:42:11 +0100139
Matthew Clarkson1ed6a042019-10-25 11:18:05 +0100140 print(
141 'About to run\n',
142 ' '.join('\n ' + c if c.startswith('--') or c == 'bash' else quote(c)
143 for c in cmd))
Matthew Clarkson63028d62019-10-10 15:48:23 +0100144 print('')
145 print('The VM will have read-only acess to: %s, mounted as /ci/source' %
146 REPO_ROOT)
147 print('The VM workdir /ci/ramdisk will be mounted into: %s' % workdir)
148 print('The contents of %s will be deleted before starting the VM' % workdir)
Matthew Clarkson1ed6a042019-10-25 11:18:05 +0100149 decision(confirm=args.confirm)
Primiano Tuccif7647392019-10-04 00:42:11 +0100150
Matthew Clarksonb4645a22019-11-06 13:34:39 +0000151 try:
152 shutil.rmtree(workdir)
153 except EnvironmentError as e:
154 if e.errno == errno.ENOENT:
155 pass
156 elif e.errno == errno.EACCES:
157 print('')
158 print('Removing previous volume %r' % workdir)
159 check_call(('sudo', 'rm', '-r', quote(workdir)))
160 else:
161 raise
162
Matthew Clarkson63028d62019-10-10 15:48:23 +0100163 os.makedirs(workdir)
Matthew Clarkson1ed6a042019-10-25 11:18:05 +0100164 os.execvp(cmd[0], cmd)
Primiano Tuccif7647392019-10-04 00:42:11 +0100165
166
167if __name__ == '__main__':
Matthew Clarkson63028d62019-10-10 15:48:23 +0100168 sys.exit(main())