133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#!/usr/bin/env python
233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#
333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# Copyright 2012 the V8 project authors. All rights reserved.
433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# Redistribution and use in source and binary forms, with or without
533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# modification, are permitted provided that the following conditions are
633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# met:
733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#
833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#     * Redistributions of source code must retain the above copyright
933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       notice, this list of conditions and the following disclaimer.
1033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#     * Redistributions in binary form must reproduce the above
1133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       copyright notice, this list of conditions and the following
1233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       disclaimer in the documentation and/or other materials provided
1333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       with the distribution.
1433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#     * Neither the name of Google Inc. nor the names of its
1533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       contributors may be used to endorse or promote products derived
1633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       from this software without specific prior written permission.
1733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#
1833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
3033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
3133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgimport os
3233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgimport subprocess
3333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgimport sys
3433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
3533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
3633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgPIDFILE = "/tmp/v8-distributed-testing-server.pid"
3733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgROOT = os.path.abspath(os.path.dirname(sys.argv[0]))
3833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
3933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
4033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgdef _PrintUsage():
4133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  print("""Usage: python %s COMMAND
4233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
4333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgWhere COMMAND can be any of:
4433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  start     Starts the server. Forks to the background.
4533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  stop      Stops the server.
4633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  restart   Stops, then restarts the server.
4733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  setup     Creates or updates the environment for the server to run.
4833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  update    Alias for "setup".
4933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  trust <keyfile>  Adds the given public key to the list of trusted keys.
5033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  help      Displays this help text.
5133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  """ % sys.argv[0])
5233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
5333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
5433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgdef _IsDaemonRunning():
5533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  return os.path.exists(PIDFILE)
5633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
5733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
5833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgdef _Cmd(cmd):
5933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  code = subprocess.call(cmd, shell=True)
6033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  if code != 0:
6133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    print("Command '%s' returned error code %d" % (cmd, code))
6233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    sys.exit(code)
6333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
6433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
6533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgdef Update():
6633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  # Create directory for private data storage.
6733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  data_dir = os.path.join(ROOT, "data")
6833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  if not os.path.exists(data_dir):
6933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    os.makedirs(data_dir)
7033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
7133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  # Create directory for trusted public keys of peers (and self).
7233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  trusted_dir = os.path.join(ROOT, "trusted")
7333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  if not os.path.exists(trusted_dir):
7433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    os.makedirs(trusted_dir)
7533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
7633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  # Install UltraJSON. It is much faster than Python's builtin json.
7733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  try:
7833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    import ujson  #@UnusedImport
7933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  except ImportError:
8033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    # Install pip if it doesn't exist.
8133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    code = subprocess.call("which pip > /dev/null", shell=True)
8233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if code != 0:
8333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      apt_get_code = subprocess.call("which apt-get > /dev/null", shell=True)
8433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      if apt_get_code == 0:
8533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        print("Installing pip...")
8633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        _Cmd("sudo apt-get install python-pip")
8733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      else:
8833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        print("Please install pip on your machine. You can get it at: "
8933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org              "http://www.pip-installer.org/en/latest/installing.html "
9033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org              "or via your distro's package manager.")
9133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        sys.exit(1)
9233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    print("Using pip to install UltraJSON...")
9333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    _Cmd("sudo pip install ujson")
9433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
9533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  # Make sure we have a key pair for signing binaries.
9633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  privkeyfile = os.path.expanduser("~/.ssh/v8_dtest")
9733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  if not os.path.exists(privkeyfile):
9833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    _Cmd("ssh-keygen -t rsa -f %s -N '' -q" % privkeyfile)
9933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  fingerprint = subprocess.check_output("ssh-keygen -lf %s" % privkeyfile,
10033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                                        shell=True)
10133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  fingerprint = fingerprint.split(" ")[1].replace(":", "")[:16]
10233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  pubkeyfile = os.path.join(trusted_dir, "%s.pem" % fingerprint)
10333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  if (not os.path.exists(pubkeyfile) or
10433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      os.path.getmtime(pubkeyfile) < os.path.getmtime(privkeyfile)):
10533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    _Cmd("openssl rsa -in %s -out %s -pubout" % (privkeyfile, pubkeyfile))
10633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    with open(pubkeyfile, "a") as f:
10733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      f.write(fingerprint + "\n")
10833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    datafile = os.path.join(data_dir, "mypubkey")
10933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    with open(datafile, "w") as f:
11033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      f.write(fingerprint + "\n")
11133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
11233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  # Check out or update the server implementation in the current directory.
11333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  testrunner_dir = os.path.join(ROOT, "testrunner")
11433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  if os.path.exists(os.path.join(testrunner_dir, "server/daemon.py")):
11533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    _Cmd("cd %s; svn up" % testrunner_dir)
11633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  else:
11733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    path = ("http://v8.googlecode.com/svn/branches/bleeding_edge/"
11833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org            "tools/testrunner")
11933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    _Cmd("svn checkout --force %s %s" % (path, testrunner_dir))
12033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
12133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  # Update this very script.
12233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  path = ("http://v8.googlecode.com/svn/branches/bleeding_edge/"
12333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          "tools/test-server.py")
12433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  scriptname = os.path.abspath(sys.argv[0])
12533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  _Cmd("svn cat %s > %s" % (path, scriptname))
12633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
12733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  # Check out or update V8.
12833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  v8_dir = os.path.join(ROOT, "v8")
12933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  if os.path.exists(v8_dir):
13033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    _Cmd("cd %s; git fetch" % v8_dir)
13133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  else:
13233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    _Cmd("git clone git://github.com/v8/v8.git %s" % v8_dir)
13333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
13433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  print("Finished.")
13533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
13633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
13733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# Handle "setup" here, because when executing that we can't import anything
13833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# else yet.
13933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgif __name__ == "__main__" and len(sys.argv) == 2:
14033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  if sys.argv[1] in ("setup", "update"):
14133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if _IsDaemonRunning():
14233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      print("Please stop the server before updating. Exiting.")
14333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      sys.exit(1)
14433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    Update()
14533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    sys.exit(0)
14633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  # Other parameters are handled below.
14733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
14833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
14933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#==========================================================
15033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# At this point we can assume that the implementation is available,
15133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# so we can import it.
15233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgtry:
15333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  from testrunner.server import constants
15433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  from testrunner.server import local_handler
15533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  from testrunner.server import main
15633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgexcept Exception, e:
15733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  print(e)
15833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  print("Failed to import implementation. Have you run 'setup'?")
15933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  sys.exit(1)
16033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
16133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
16233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgdef _StartDaemon(daemon):
16333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  if not os.path.isdir(os.path.join(ROOT, "v8")):
16433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    print("No 'v8' working directory found. Have you run 'setup'?")
16533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    sys.exit(1)
16633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  daemon.start()
16733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
16833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
16933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgif __name__ == "__main__":
17033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  if len(sys.argv) == 2:
17133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    arg = sys.argv[1]
17233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if arg == "start":
17333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      daemon = main.Server(PIDFILE, ROOT)
17433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      _StartDaemon(daemon)
17533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    elif arg == "stop":
17633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      daemon = main.Server(PIDFILE, ROOT)
17733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      daemon.stop()
17833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    elif arg == "restart":
17933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      daemon = main.Server(PIDFILE, ROOT)
18033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      daemon.stop()
18133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      _StartDaemon(daemon)
18233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    elif arg in ("help", "-h", "--help"):
18333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      _PrintUsage()
18433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    elif arg == "status":
18533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      if not _IsDaemonRunning():
18633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        print("Server not running.")
18733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      else:
18833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        print(local_handler.LocalQuery([constants.REQUEST_STATUS]))
18933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    else:
19033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      print("Unknown command")
19133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      _PrintUsage()
19233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      sys.exit(2)
19333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  elif len(sys.argv) == 3:
19433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    arg = sys.argv[1]
19533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if arg == "approve":
19633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      filename = sys.argv[2]
19733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      if not os.path.exists(filename):
19833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        print("%s does not exist.")
19933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        sys.exit(1)
20033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      filename = os.path.abspath(filename)
20133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      if _IsDaemonRunning():
20233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        response = local_handler.LocalQuery([constants.ADD_TRUSTED, filename])
20333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      else:
20433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        daemon = main.Server(PIDFILE, ROOT)
20533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        response = daemon.CopyToTrusted(filename)
20633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      print("Added certificate %s to trusted certificates." % response)
20733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    else:
20833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      print("Unknown command")
20933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      _PrintUsage()
21033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      sys.exit(2)
21133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  else:
21233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    print("Unknown command")
21333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    _PrintUsage()
21433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    sys.exit(2)
21533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  sys.exit(0)
216