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

import argparse
import os
import sys

from common_includes import *

DEPS_FILE = "DEPS_FILE"
CHROMIUM = "CHROMIUM"

CONFIG = {
  PERSISTFILE_BASENAME: "/tmp/v8-chromium-roll-tempfile",
  DOT_GIT_LOCATION: ".git",
  DEPS_FILE: "DEPS",
}


class Preparation(Step):
  MESSAGE = "Preparation."

  def RunStep(self):
    self.CommonPrepare()


class DetectLastPush(Step):
  MESSAGE = "Detect commit ID of last push to trunk."

  def RunStep(self):
    self["last_push"] = self._options.last_push or self.FindLastTrunkPush(
        include_patches=True)
    self["trunk_revision"] = self.GitSVNFindSVNRev(self["last_push"])
    self["push_title"] = self.GitLog(n=1, format="%s",
                                     git_hash=self["last_push"])


class CheckChromium(Step):
  MESSAGE = "Ask for chromium checkout."

  def Run(self):
    self["chrome_path"] = self._options.chromium
    while not self["chrome_path"]:
      self.DieNoManualMode("Please specify the path to a Chromium checkout in "
                           "forced mode.")
      print ("Please specify the path to the chromium \"src\" directory: "),
      self["chrome_path"] = self.ReadLine()


class SwitchChromium(Step):
  MESSAGE = "Switch to Chromium checkout."
  REQUIRES = "chrome_path"

  def RunStep(self):
    self["v8_path"] = os.getcwd()
    os.chdir(self["chrome_path"])
    self.InitialEnvironmentChecks()
    # Check for a clean workdir.
    if not self.GitIsWorkdirClean():  # pragma: no cover
      self.Die("Workspace is not clean. Please commit or undo your changes.")
    # Assert that the DEPS file is there.
    if not os.path.exists(self.Config(DEPS_FILE)):  # pragma: no cover
      self.Die("DEPS file not present.")


class UpdateChromiumCheckout(Step):
  MESSAGE = "Update the checkout and create a new branch."
  REQUIRES = "chrome_path"

  def RunStep(self):
    os.chdir(self["chrome_path"])
    self.GitCheckout("master")
    self.GitPull()
    self.GitCreateBranch("v8-roll-%s" % self["trunk_revision"])


class UploadCL(Step):
  MESSAGE = "Create and upload CL."
  REQUIRES = "chrome_path"

  def RunStep(self):
    os.chdir(self["chrome_path"])

    # Patch DEPS file.
    deps = FileToText(self.Config(DEPS_FILE))
    deps = re.sub("(?<=\"v8_revision\": \")([0-9]+)(?=\")",
                  self["trunk_revision"],
                  deps)
    TextToFile(deps, self.Config(DEPS_FILE))

    if self._options.reviewer and not self._options.manual:
      print "Using account %s for review." % self._options.reviewer
      rev = self._options.reviewer
    else:
      print "Please enter the email address of a reviewer for the roll CL: ",
      self.DieNoManualMode("A reviewer must be specified in forced mode.")
      rev = self.ReadLine()

    commit_title = "Update V8 to %s." % self["push_title"].lower()
    sheriff = ""
    if self["sheriff"]:
      sheriff = ("\n\nPlease reply to the V8 sheriff %s in case of problems."
                 % self["sheriff"])
    self.GitCommit("%s%s\n\nTBR=%s" % (commit_title, sheriff, rev))
    self.GitUpload(author=self._options.author,
                   force=self._options.force_upload,
                   cq=self._options.use_commit_queue)
    print "CL uploaded."


class SwitchV8(Step):
  MESSAGE = "Returning to V8 checkout."
  REQUIRES = "chrome_path"

  def RunStep(self):
    os.chdir(self["v8_path"])


class CleanUp(Step):
  MESSAGE = "Done!"

  def RunStep(self):
    print("Congratulations, you have successfully rolled the push r%s it into "
          "Chromium. Please don't forget to update the v8rel spreadsheet."
          % self["trunk_revision"])

    # Clean up all temporary files.
    Command("rm", "-f %s*" % self._config[PERSISTFILE_BASENAME])


class ChromiumRoll(ScriptsBase):
  def _PrepareOptions(self, parser):
    group = parser.add_mutually_exclusive_group()
    group.add_argument("-f", "--force",
                      help="Don't prompt the user.",
                      default=False, action="store_true")
    group.add_argument("-m", "--manual",
                      help="Prompt the user at every important step.",
                      default=False, action="store_true")
    parser.add_argument("-c", "--chromium",
                        help=("The path to your Chromium src/ "
                              "directory to automate the V8 roll."))
    parser.add_argument("-l", "--last-push",
                        help="The git commit ID of the last push to trunk.")
    parser.add_argument("--use-commit-queue",
                        help="Check the CQ bit on upload.",
                        default=False, action="store_true")

  def _ProcessOptions(self, options):  # pragma: no cover
    if not options.manual and not options.reviewer:
      print "A reviewer (-r) is required in (semi-)automatic mode."
      return False
    if not options.manual and not options.chromium:
      print "A chromium checkout (-c) is required in (semi-)automatic mode."
      return False
    if not options.manual and not options.author:
      print "Specify your chromium.org email with -a in (semi-)automatic mode."
      return False

    options.tbr_commit = not options.manual
    return True

  def _Steps(self):
    return [
      Preparation,
      DetectLastPush,
      CheckChromium,
      DetermineV8Sheriff,
      SwitchChromium,
      UpdateChromiumCheckout,
      UploadCL,
      SwitchV8,
      CleanUp,
    ]


if __name__ == "__main__":  # pragma: no cover
  sys.exit(ChromiumRoll(CONFIG).Run())
