tools(ci): support running with podman

Also turns of sudo if user in the `docker` group

Change-Id: Ife5a74f36d2b061b67d218a3c376f6415dd6ad30
diff --git a/tools/run_test_like_ci b/tools/run_test_like_ci
index e569b98..98b788e 100755
--- a/tools/run_test_like_ci
+++ b/tools/run_test_like_ci
@@ -15,31 +15,92 @@
 
 from __future__ import print_function
 import argparse
+import distutils
+import grp
+import os
+import readline
 import sys
 import shutil
 import subprocess
-import os
+from pipes import quote
+
+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()
+  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(
+      '--image', default=SANDBOX_IMG, help='The image to use to run the tests')
+  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)
+  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 press CTRL+C, commit and then re-run this script')
+    print('I suggest you stop, commit and then re-run this script')
     print('Modified files:\n' + modified_files)
-    raw_input('If you think you know what you are doing, press Enter instead')
+    decision('Do you know what you are doing', confirm=args.confirm)
 
   env = {
       'PERFETTO_TEST_GIT_REF': 'file:///ci/source',
@@ -47,31 +108,37 @@
   env.update(JOB_CONFIGS[args.config])
 
   workdir = os.path.join(REPO_ROOT, 'out', 'tmp.ci')
-  cmd = [
-      'sudo', '--', 'docker', 'run', '-it', '--name', 'perfetto_ci',
-      '--cap-add', 'SYS_PTRACE', '--rm', '--volume',
+  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:/ci/source:ro' % REPO_ROOT
   ]
   for kv in env.items():
     cmd += ['--env', '%s=%s' % kv]
-  cmd += [SANDBOX_IMG]
+  cmd += [args.image]
   cmd += [
       'bash', '-c',
       'cd /ci/ramdisk; bash /ci/init.sh || sudo -u perfetto -EH bash -i'
   ]
 
-  print('About to run\n', ' '.join(cmd))
+  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 will have read-only acess to: %s, mounted as /ci/source' %
         REPO_ROOT)
   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)
-  raw_input('Press a key to continue')
+  decision(confirm=args.confirm)
 
   shutil.rmtree(workdir, ignore_errors=True)
   os.makedirs(workdir)
-  os.execvp(cmd[0], cmd[1:])
+  os.execvp(cmd[0], cmd)
 
 
 if __name__ == '__main__':