#!/usr/bin/env python
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Upload a cherry pick CL to rietveld."""

import argparse
import md5
import subprocess2
import sys

from git_cl import Changelist
from git_common import config, run
from third_party.upload import EncodeMultipartFormData, GitVCS
from rietveld import Rietveld


def cherry_pick(target_branch, commit):
  """Attempt to upload a cherry pick CL to rietveld.

  Args:
    target_branch: The branch to cherry pick onto.
    commit: The git hash of the commit to cherry pick.
  """
  author = config('user.email')

  description = '%s\n\n(cherry picked from commit %s)\n' % (
      run('show', '--pretty=%B', '--quiet', commit), commit)

  parent = run('show', '--pretty=%P', '--quiet', commit)
  print 'Found parent revision:', parent

  class Options(object):
    def __init__(self):
      self.emulate_svn_auto_props = False

  content_type, payload = EncodeMultipartFormData([
      ('base', '%s@%s' % (Changelist().GetRemoteUrl(), target_branch)),
      ('cc', config('rietveld.cc')),
      ('content_upload', '1'),
      ('description', description),
      ('project', '%s@%s' % (config('rietveld.project'), target_branch)),
      ('subject', description.splitlines()[0]),
      ('user', author),
  ], [
      ('data', 'data.diff', GitVCS(Options()).PostProcessDiff(
          run('diff', parent, commit))),
  ])

  rietveld = Rietveld(config('rietveld.server'), author, None)
  # pylint: disable=W0212
  output = rietveld._send(
    '/upload',
    payload=payload,
    content_type=content_type,
  ).splitlines()

  # If successful, output will look like:
  # Issue created. URL: https://codereview.chromium.org/1234567890
  # 1
  # 10001 some/path/first.file
  # 10002 some/path/second.file
  # 10003 some/path/third.file

  if output[0].startswith('Issue created. URL: '):
    print output[0]
    issue = output[0].rsplit('/', 1)[-1]
    patchset = output[1]
    files = output[2:]

    for f in files:
      file_id, filename = f.split()
      mode = 'M'

      try:
        content = run('show', '%s:%s' % (parent, filename))
      except subprocess2.CalledProcessError:
        # File didn't exist in the parent revision.
        content = ''
        mode = 'A'

      content_type, payload = EncodeMultipartFormData([
        ('checksum', md5.md5(content).hexdigest()),
        ('filename', filename),
        ('is_current', 'False'),
        ('status', mode),
      ], [
        ('data', filename, content),
      ])

      # pylint: disable=W0212
      print '  Uploading base file for %s:' % filename, rietveld._send(
        '/%s/upload_content/%s/%s' % (issue, patchset, file_id),
        payload=payload,
        content_type=content_type,
      )

      try:
        content = run('show', '%s:%s' % (commit, filename))
      except subprocess2.CalledProcessError:
        # File no longer exists in the new commit.
        content = ''
        mode = 'D'

      content_type, payload = EncodeMultipartFormData([
        ('checksum', md5.md5(content).hexdigest()),
        ('filename', filename),
        ('is_current', 'True'),
        ('status', mode),
      ], [
        ('data', filename, content),
      ])

      # pylint: disable=W0212
      print '  Uploading %s:' % filename, rietveld._send(
        '/%s/upload_content/%s/%s' % (issue, patchset, file_id),
        payload=payload,
        content_type=content_type,
      )

    # pylint: disable=W0212
    print 'Finalizing upload:', rietveld._send('/%s/upload_complete/1' % issue)


def main():
  parser = argparse.ArgumentParser()
  parser.add_argument(
      '--branch',
      '-b',
      help='The upstream branch to cherry pick to.',
      metavar='<branch>',
      required=True,
  )
  parser.add_argument(
      'commit',
      help='SHA to cherry pick.',
      metavar='<commit>',
  )
  args = parser.parse_args()
  cherry_pick(args.branch, args.commit)

if __name__ == '__main__':
  sys.exit(main())
