You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
5.1 KiB
170 lines
5.1 KiB
#!/usr/bin/env python3
|
|
# Copyright (C) 2019 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
from __future__ import print_function
|
|
import argparse
|
|
import distutils
|
|
import errno
|
|
import grp
|
|
import os
|
|
import readline
|
|
import sys
|
|
import shutil
|
|
import subprocess
|
|
from pipes import quote
|
|
from subprocess import check_call
|
|
|
|
try:
|
|
from shutil import which as find_executable
|
|
except AttributeError:
|
|
from distutils.spawn import find_executable
|
|
|
|
REPO_ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
|
sys.path.append(os.path.join(REPO_ROOT, 'infra', 'ci'))
|
|
from config import JOB_CONFIGS, SANDBOX_IMG
|
|
|
|
try:
|
|
input = raw_input
|
|
except NameError:
|
|
pass
|
|
|
|
|
|
def user_in_docker_group():
|
|
try:
|
|
group = grp.getgrnam('docker')
|
|
except KeyError:
|
|
return False
|
|
else:
|
|
return group.gr_gid in os.getgroups()
|
|
|
|
|
|
def decision(question='Would you like to continue', confirm=True, default='n'):
|
|
default = default.lower().strip()
|
|
yes = default in {'y', 'yes'}
|
|
no = default in {'n', 'no'}
|
|
default = 'y' if yes else 'n'
|
|
prompt = '%s? [%s/%s]: ' % (question, 'Y' if yes else 'y', 'N' if no else 'n')
|
|
if not confirm:
|
|
print('%sy' % prompt)
|
|
return
|
|
while True:
|
|
choice = input(prompt).lower().strip()
|
|
if not choice:
|
|
choice = default
|
|
if choice in {'y', 'yes'}:
|
|
return
|
|
elif choice in {'n', 'no'}:
|
|
sys.exit(3)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
parser.add_argument('config', choices=JOB_CONFIGS.keys())
|
|
parser.add_argument(
|
|
'--runner',
|
|
help='The container runner executable to use',
|
|
choices=('podman', 'docker'),
|
|
default='podman' if find_executable('podman') else 'docker')
|
|
parser.add_argument(
|
|
'--build',
|
|
action='store_true',
|
|
help='Will perform a build of sandbox image')
|
|
group = parser.add_mutually_exclusive_group()
|
|
group.add_argument(
|
|
'--confirm',
|
|
action='store_true',
|
|
default=True,
|
|
help='User confirmation of decision prompts')
|
|
group.add_argument(
|
|
'--no-confirm',
|
|
dest='confirm',
|
|
action='store_false',
|
|
help='Forces confirmation of decision prompts')
|
|
args = parser.parse_args()
|
|
|
|
# Check that the directory is clean.
|
|
git_cmd = ['git', '-C', REPO_ROOT, 'status', '--porcelain']
|
|
modified_files = subprocess.check_output(git_cmd).decode()
|
|
if modified_files:
|
|
print('The current Git repo has modified/untracked files.')
|
|
print('The sandboxed VM will fetch the HEAD of your current git repo.')
|
|
print('This is probably not the state you want to be in.')
|
|
print('I suggest you stop, commit and then re-run this script')
|
|
print('Modified files:\n' + modified_files)
|
|
decision('Do you know what you are doing', confirm=args.confirm)
|
|
|
|
if args.build:
|
|
print('')
|
|
print('About to build %r locally with %r' % (args.image, args.runner))
|
|
decision(confirm=args.confirm)
|
|
check_call(('make', '-C', os.path.join(REPO_ROOT, 'infra',
|
|
'ci'),
|
|
'BUILDER=%s' % args.runner, 'build-sandbox'))
|
|
|
|
bundle_path = '/tmp/perfetto-ci.bundle'
|
|
check_call(['git', '-C', REPO_ROOT, 'bundle', 'create', bundle_path, 'HEAD' ])
|
|
os.chmod(bundle_path, 0o664)
|
|
env = {
|
|
'PERFETTO_TEST_GIT_REF': bundle_path,
|
|
}
|
|
env.update(JOB_CONFIGS[args.config])
|
|
|
|
workdir = os.path.join(REPO_ROOT, 'out', 'tmp.ci')
|
|
cmd = []
|
|
if args.runner == 'docker' and not user_in_docker_group():
|
|
cmd += ['sudo', '--']
|
|
cmd += [
|
|
args.runner, 'run', '-it', '--name', 'perfetto_ci', '--cap-add',
|
|
'SYS_PTRACE', '--rm', '--volume',
|
|
'%s:/ci/ramdisk' % workdir, '--tmpfs', '/tmp:exec',
|
|
'--volume=%s:%s:ro' % (bundle_path, bundle_path)
|
|
]
|
|
for kv in env.items():
|
|
cmd += ['--env', '%s=%s' % kv]
|
|
cmd += [SANDBOX_IMG]
|
|
cmd += [
|
|
'bash', '-c',
|
|
'cd /ci/ramdisk; bash /ci/init.sh || sudo -u perfetto -EH bash -i'
|
|
]
|
|
|
|
print(
|
|
'About to run\n',
|
|
' '.join('\n ' + c if c.startswith('--') or c == 'bash' else quote(c)
|
|
for c in cmd))
|
|
print('')
|
|
print('The VM workdir /ci/ramdisk will be mounted into: %s' % workdir)
|
|
print('The contents of %s will be deleted before starting the VM' % workdir)
|
|
decision(confirm=args.confirm)
|
|
|
|
try:
|
|
shutil.rmtree(workdir)
|
|
except EnvironmentError as e:
|
|
if e.errno == errno.ENOENT:
|
|
pass
|
|
elif e.errno == errno.EACCES:
|
|
print('')
|
|
print('Removing previous volume %r' % workdir)
|
|
check_call(('sudo', 'rm', '-r', quote(workdir)))
|
|
else:
|
|
raise
|
|
|
|
os.makedirs(workdir)
|
|
os.execvp(cmd[0], cmd)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|