Initial Contribution
diff --git a/subcmds/upload.py b/subcmds/upload.py
new file mode 100644
index 0000000..ad05050
--- /dev/null
+++ b/subcmds/upload.py
@@ -0,0 +1,180 @@
+#
+# Copyright (C) 2008 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.
+
+import re
+import sys
+
+from command import InteractiveCommand
+from editor import Editor
+from error import UploadError
+
+def _die(fmt, *args):
+  msg = fmt % args
+  print >>sys.stderr, 'error: %s' % msg
+  sys.exit(1)
+
+class Upload(InteractiveCommand):
+  common = True
+  helpSummary = "Upload changes for code review"
+  helpUsage="""
+%prog [<project>]...
+"""
+  helpDescription = """
+The '%prog' command is used to send changes to the Gerrit code
+review system.  It searches for changes in local projects that do
+not yet exist in the corresponding remote repository.  If multiple
+changes are found, '%prog' opens an editor to allow the
+user to choose which change to upload.  After a successful upload,
+repo prints the URL for the change in the Gerrit code review system.
+
+'%prog' searches for uploadable changes in all projects listed
+at the command line.  Projects can be specified either by name, or
+by a relative or absolute path to the project's local directory. If
+no projects are specified, '%prog' will search for uploadable
+changes in all projects listed in the manifest.
+"""
+
+  def _SingleBranch(self, branch):
+    project = branch.project
+    name = branch.name
+    date = branch.date
+    list = branch.commits
+
+    print 'Upload project %s/:' % project.relpath
+    print '  branch %s (%2d commit%s, %s):' % (
+                  name,
+                  len(list),
+                  len(list) != 1 and 's' or '',
+                  date)
+    for commit in list:
+      print '         %s' % commit
+
+    sys.stdout.write('(y/n)? ')
+    answer = sys.stdin.readline().strip()
+    if answer in ('y', 'Y', 'yes', '1', 'true', 't'):
+      self._UploadAndReport([branch])
+    else:
+      _die("upload aborted by user")
+
+  def _MultipleBranches(self, pending):
+    projects = {}
+    branches = {}
+
+    script = []
+    script.append('# Uncomment the branches to upload:')
+    for project, avail in pending:
+      script.append('#')
+      script.append('# project %s/:' % project.relpath)
+
+      b = {}
+      for branch in avail:
+        name = branch.name
+        date = branch.date
+        list = branch.commits
+
+        if b:
+          script.append('#')
+        script.append('#  branch %s (%2d commit%s, %s):' % (
+                      name,
+                      len(list),
+                      len(list) != 1 and 's' or '',
+                      date))
+        for commit in list:
+          script.append('#         %s' % commit)
+        b[name] = branch
+
+      projects[project.relpath] = project
+      branches[project.name] = b
+    script.append('')
+
+    script = Editor.EditString("\n".join(script)).split("\n")
+
+    project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
+    branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*')
+
+    project = None
+    todo = []
+
+    for line in script:
+      m = project_re.match(line)
+      if m:
+        name = m.group(1)
+        project = projects.get(name)
+        if not project:
+          _die('project %s not available for upload', name)
+        continue
+
+      m = branch_re.match(line)
+      if m:
+        name = m.group(1)
+        if not project:
+          _die('project for branch %s not in script', name)
+        branch = branches[project.name].get(name)
+        if not branch:
+          _die('branch %s not in %s', name, project.relpath)
+        todo.append(branch)
+    if not todo:
+      _die("nothing uncommented for upload")
+    self._UploadAndReport(todo)
+
+  def _UploadAndReport(self, todo):
+    have_errors = False
+    for branch in todo:
+      try:
+        branch.UploadForReview()
+        branch.uploaded = True
+      except UploadError, e:
+        branch.error = e
+        branch.uploaded = False
+        have_errors = True
+
+    print >>sys.stderr, ''
+    print >>sys.stderr, '--------------------------------------------'
+
+    if have_errors:
+      for branch in todo:
+        if not branch.uploaded:
+          print >>sys.stderr, '[FAILED] %-15s %-15s  (%s)' % (
+                 branch.project.relpath + '/', \
+                 branch.name, \
+                 branch.error)
+      print >>sys.stderr, ''
+
+    for branch in todo:
+        if branch.uploaded:
+          print >>sys.stderr, '[OK    ] %-15s %s' % (
+                 branch.project.relpath + '/',
+                 branch.name)
+          print >>sys.stderr, '%s' % branch.tip_url
+          print >>sys.stderr, ''
+
+    if have_errors:
+      sys.exit(1)
+
+  def Execute(self, opt, args):
+    project_list = self.GetProjects(args)
+    pending = []
+
+    for project in project_list:
+      avail = project.GetUploadableBranches()
+      if avail:
+        pending.append((project, avail))
+
+    if not pending:
+      print >>sys.stdout, "no branches ready for upload"
+    elif len(pending) == 1 and len(pending[0][1]) == 1:
+      self._SingleBranch(pending[0][1][0])
+    else:
+      self._MultipleBranches(pending)