Add symlink to pythonic cros_workon replacement

BUG=brillo:817
TEST=common workflows (e.g. starting/stopping packages, listing
packages, list-all, iterate seem to work in similar ways for both
scripts).

Change-Id: I4597266f45d8c8871d7d8ada1d10e791f9b121fd
Reviewed-on: https://chromium-review.googlesource.com/265747
Reviewed-by: Bertrand Simonnet <bsimonnet@chromium.org>
Trybot-Ready: Christopher Wiley <wiley@chromium.org>
Tested-by: Christopher Wiley <wiley@chromium.org>
Commit-Queue: Christopher Wiley <wiley@chromium.org>
diff --git a/bin/cros_workon b/bin/cros_workon
new file mode 120000
index 0000000..72196ce
--- /dev/null
+++ b/bin/cros_workon
@@ -0,0 +1 @@
+../scripts/wrapper.py
\ No newline at end of file
diff --git a/scripts/cros_workon.py b/scripts/cros_workon.py
new file mode 100644
index 0000000..5e9462f
--- /dev/null
+++ b/scripts/cros_workon.py
@@ -0,0 +1,110 @@
+# Copyright 2015 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""This script moves ebuilds between 'stable' and 'live' states.
+
+By default 'stable' ebuilds point at and build from source at the
+last known good commit. Moving an ebuild to 'live' (via cros_workon start)
+is intended to support development. The current source tip is fetched,
+source modified and built using the unstable 'live' (9999) ebuild.
+
+commands:
+  start:     Moves an ebuild to live (intended to support development)
+  stop:      Moves an ebuild to stable (use last known good)
+  info:      Print package name, repo name, and source directory.
+  list:      List of live ebuilds (workon ebuilds if --all)
+  list-all:  List all of the live ebuilds for all setup boards
+  iterate:   For each ebuild, cd to the source dir and run a command"
+
+"""
+
+from __future__ import print_function
+
+from chromite.lib import brick_lib
+from chromite.lib import commandline
+from chromite.lib import cros_build_lib
+from chromite.lib import terminal
+from chromite.lib import workon_helper
+
+
+def main(argv):
+  parser = commandline.ArgumentParser(description=__doc__)
+  parser.add_argument(
+      'command',
+      choices=('start', 'stop', 'info', 'list', 'list-all', 'iterate'),
+      help='cros_workon command to run.')
+  parser.add_argument('--board', default=cros_build_lib.GetDefaultBoard(),
+                      help='The board to set package keywords for.')
+  parser.add_argument('--brick', help='The brick to set package keywords for.')
+  parser.add_argument('--host', default=False, action='store_true',
+                      help='Uses the host instead of board')
+  parser.add_argument('--remote', default='',
+                      help='For non-workon projects, the git remote to use.')
+  parser.add_argument('--revision', default='',
+                      help='Use to override the manifest defined default '
+                           'revision used for a project')
+  parser.add_argument('--command', default='git status', dest='iterate_command',
+                      help='The command to be run by forall.')
+  parser.add_argument('--workon_only', default=False, action='store_true',
+                      help='Apply to packages that have a workon ebuild only')
+  parser.add_argument('--all', default=False, action='store_true',
+                      help='Apply to all possible packages for the '
+                           'given command (overrides workon_only)')
+  parser.add_argument('packages', nargs='*',
+                      help='The packages to run command against.')
+  options = parser.parse_args(argv)
+  options.Freeze()
+
+  if options.command == 'list-all':
+    board_to_packages = workon_helper.ListAllWorkedOnAtoms()
+    color = terminal.Color()
+    for board in sorted(board_to_packages):
+      print(color.Start(color.GREEN) + board + ':' + color.Stop())
+      for package in board_to_packages[board]:
+        print('    ' + package)
+      print('')
+    return 0
+
+  # TODO(wiley): Assert that we're not running as root.
+  cros_build_lib.AssertInsideChroot()
+
+  if options.host:
+    friendly_name = 'host'
+    sysroot = '/'
+  elif options.board:
+    friendly_name = options.board
+    sysroot = cros_build_lib.GetSysroot(board=options.board)
+  elif options.brick:
+    brick = brick_lib.Brick(options.brick)
+    friendly_name = brick.FriendlyName()
+    # TODO(wiley) This is a hack.  It doesn't really make sense to calculate
+    #             the sysroot from a brick alone, since bricks are installed
+    #             into sysroots.  Revisit this when blueprints are working.
+    sysroot = cros_build_lib.GetSysroot(friendly_name)
+  else:
+    cros_build_lib.Die('You must specify either --host, --board or --brick')
+
+  helper = workon_helper.WorkonHelper(sysroot, friendly_name)
+  try:
+    if options.command == 'start':
+      helper.StartWorkingOnPackages(options.packages, use_all=options.all,
+                                    use_workon_only=options.workon_only)
+    elif options.command == 'stop':
+      helper.StopWorkingOnPackages(options.packages, use_all=options.all,
+                                   use_workon_only=options.workon_only)
+    elif options.command == 'info':
+      cros_build_lib.Die('%s is not implemented.', options.command)
+    elif options.command == 'list':
+      packages = helper.ListAtoms(
+          use_all=options.all, use_workon_only=options.workon_only)
+      if packages:
+        print('\n'.join(packages))
+    elif options.command == 'iterate':
+      helper.RunCommandInPackages(options.packages, options.iterate_command,
+                                  use_all=options.all,
+                                  use_workon_only=options.workon_only)
+  except workon_helper.WorkonError as e:
+    cros_build_lib.Die(e.message)
+
+  return 0