<commit_before>#!/usr/bin/python
# Copyright (c) 2009 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.
"""Client-side script to send a try job to the try server. It communicates to
the try server by either writting to a svn repository or by directly connecting
to the server by HTTP.
"""

import datetime
import errno
import getpass
import logging
import optparse
import os
import posixpath
import shutil
import sys
import tempfile
import urllib

try:
  import breakpad
except ImportError:
  pass

import gclient_utils
import scm

__version__ = '1.2'


# Constants
HELP_STRING = "Sorry, Tryserver is not available."
USAGE = r"""%prog [options]

Client-side script to send a try job to the try server. It communicates to
the try server by either writting to a svn repository or by directly connecting
to the server by HTTP.

Examples:
  Try a change against a particular revision:
    %prog change_name -r 123

  A git patch off a web site (git inserts a/ and b/) and fix the base dir:
    %prog --url http://url/to/patch.diff --patchlevel 1 --root src

  Use svn to store the try job, specify an alternate email address and use a
  premade diff file on the local drive:
    %prog --email <EMAIL>
            --svn_repo svn://svn.chromium.org/chrome-try/try --diff foo.diff

  Running only on a 'mac' slave with revision 123 and clobber first; specify
  manually the 3 source files to use for the try job:
    %prog --bot mac --revision 123 --clobber -f src/a.cc -f src/a.h
            -f include/b.h

  When called from gcl, use the format gcl try <change_name>.
"""

class InvalidScript(Exception):
  def __str__(self):
    return self.args[0] + '\n' + HELP_STRING


class NoTryServerAccess(Exception):
  def __str__(self):
    return self.args[0] + '\n' + HELP_STRING


def EscapeDot(name):
  return name.replace('.', '-')


class SCM(object):
  """Simplistic base class to implement one function: ProcessOptions."""
  def __init__(self, options, path):
    items = path.split('@')
    assert len(items) <= 2
    self.checkout_root = items[0]
    items.append(None)
    self.diff_against = items[1]
    self.options = options
    self.files = self.options.files
    self.options.files = None
    self.codereview_settings = None
    self.codereview_settings_file = 'codereview.settings'

  def GetFileNames(self):
    """Return the list of files in the diff."""
    return self.files

  def GetCodeReviewSetting(self, key):
    """Returns a value for the given key for this repository.

    Uses gcl-style settings from the repository."""
    if self.codereview_settings is None:
      self.codereview_settings = {}
      settings_file = self.ReadRootFile(self.codereview_settings_file)
      if settings_file:
        for line in settings_file.splitlines():
          if not line or line.lstrip().startswith('#'):
            continue
          k, v = line.split(":", 1)
          self.codereview_settings[k.strip()] = v.strip()
    return self.codereview_settings.get(key, '')

  def GclStyleSettings(self):
    """Set default settings based on the gcl-style settings from the
    repository."""
    settings = {
      'port': self.GetCodeReviewSetting('TRYSERVER_HTTP_PORT'),
      'host': self.GetCodeReviewSetting('TRYSERVER_HTTP_HOST'),
      'svn_repo': self.GetCodeReviewSetting('TRYSERVER_SVN_URL'),
      'project': self.GetCodeReviewSetting('TRYSERVER_PROJECT'),
      'root': self.GetCodeReviewSetting('TRYSERVER_ROOT'),
      'patchlevel': self.GetCodeReviewSetting('TRYSERVER_PATCHLEVEL'),
    }
    for (k, v) in settings.iteritems():
      if v and getattr(self.options, k) is None:
        setattr(self.options, k, v)

  def GclientStyleSettings(self):
    """Find the root, assuming a gclient-style checkout."""
    if not self.options.no_gclient and not self.options.root:
      root = self.checkout_root
      gclient_root = gclient_utils.FindGclientRoot(root)
      if gclient_root:
        self.options.root = gclient_utils.PathDifference(gclient_root, root)

  def AutomagicalSettings(self):
    """Determines settings based on supported code review and checkout tools.
    """
    self.GclStyleSettings()
    self.GclientStyleSettings()

  def ReadRootFile(self, filename):
    raise NotImplementedError()


class SVN(SCM):
  """Gathers the options and diff for a subversion checkout."""
  def __init__(self, *args, **kwargs):
    SCM.__init__(self, *args, **kwargs)
    self.checkout_root = scm.SVN.GetCheckoutRoot(self.checkout_root)
    if not self.options.email:
      # Assumes the svn credential is an email address.
      self.options.email = scm.SVN.GetEmail(self.checkout_root)
    logging.info("SVN(%s)" % self.checkout_root)

  def ReadRootFile(self, filename):
    try:
      # Try to search on the subversion repository for the file.
      import gcl
      data = gcl.GetCachedFile(filename, use_root=True)
      logging.debug('%s:\n%s' % (filename, data))
      return data
    except ImportError:
      try:
        data = gclient_utils.FileRead(os.path.join(self.checkout_root,
                                                   filename))
        logging.debug('%s:\n%s' % (filename, data))
        return data
      except (IOError, OSError):
        logging.debug('%s:\nNone' % filename)
        return None

  def GenerateDiff(self):
    """Returns a string containing the diff for the given file list.

    The files in the list should either be absolute paths or relative to the
    given root.
    """
    if not self.files:
      previous_cwd = os.getcwd()
      os.chdir(self.checkout_root)
      excluded = ['!', '?', 'X', ' ', '~']
      self.files = [
          f[1] for f in scm.SVN.CaptureStatus(self.checkout_root)
          if f[0][0] not in excluded
      ]
      os.chdir(previous_cwd)
    return scm.SVN.GenerateDiff(self.files, self.checkout_root, full_move=True,<commit_msg>Using the root codereview.settings seems to be a problem for NACL (there isn't one in their repo). They've been manually specifying --host etc for over a week.<commit_after>#!/usr/bin/python
# Copyright (c) 2009 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.
"""Client-side script to send a try job to the try server. It communicates to
the try server by either writting to a svn repository or by directly connecting
to the server by HTTP.
"""

import datetime
import errno
import getpass
import logging
import optparse
import os
import posixpath
import shutil
import sys
import tempfile
import urllib

try:
  import breakpad
except ImportError:
  pass

import gclient_utils
import scm

__version__ = '1.2'


# Constants
HELP_STRING = "Sorry, Tryserver is not available."
USAGE = r"""%prog [options]

Client-side script to send a try job to the try server. It communicates to
the try server by either writting to a svn repository or by directly connecting
to the server by HTTP.

Examples:
  Try a change against a particular revision:
    %prog change_name -r 123

  A git patch off a web site (git inserts a/ and b/) and fix the base dir:
    %prog --url http://url/to/patch.diff --patchlevel 1 --root src

  Use svn to store the try job, specify an alternate email address and use a
  premade diff file on the local drive:
    %prog --email <EMAIL>
            --svn_repo svn://svn.chromium.org/chrome-try/try --diff foo.diff

  Running only on a 'mac' slave with revision 123 and clobber first; specify
  manually the 3 source files to use for the try job:
    %prog --bot mac --revision 123 --clobber -f src/a.cc -f src/a.h
            -f include/b.h

  When called from gcl, use the format gcl try <change_name>.
"""

class InvalidScript(Exception):
  def __str__(self):
    return self.args[0] + '\n' + HELP_STRING


class NoTryServerAccess(Exception):
  def __str__(self):
    return self.args[0] + '\n' + HELP_STRING


def EscapeDot(name):
  return name.replace('.', '-')


class SCM(object):
  """Simplistic base class to implement one function: ProcessOptions."""
  def __init__(self, options, path):
    items = path.split('@')
    assert len(items) <= 2
    self.checkout_root = items[0]
    items.append(None)
    self.diff_against = items[1]
    self.options = options
    self.files = self.options.files
    self.options.files = None
    self.codereview_settings = None
    self.codereview_settings_file = 'codereview.settings'

  def GetFileNames(self):
    """Return the list of files in the diff."""
    return self.files

  def GetCodeReviewSetting(self, key):
    """Returns a value for the given key for this repository.

    Uses gcl-style settings from the repository."""
    if self.codereview_settings is None:
      self.codereview_settings = {}
      settings_file = self.ReadRootFile(self.codereview_settings_file)
      if settings_file:
        for line in settings_file.splitlines():
          if not line or line.lstrip().startswith('#'):
            continue
          k, v = line.split(":", 1)
          self.codereview_settings[k.strip()] = v.strip()
    return self.codereview_settings.get(key, '')

  def GclStyleSettings(self):
    """Set default settings based on the gcl-style settings from the
    repository."""
    settings = {
      'port': self.GetCodeReviewSetting('TRYSERVER_HTTP_PORT'),
      'host': self.GetCodeReviewSetting('TRYSERVER_HTTP_HOST'),
      'svn_repo': self.GetCodeReviewSetting('TRYSERVER_SVN_URL'),
      'project': self.GetCodeReviewSetting('TRYSERVER_PROJECT'),
      'root': self.GetCodeReviewSetting('TRYSERVER_ROOT'),
      'patchlevel': self.GetCodeReviewSetting('TRYSERVER_PATCHLEVEL'),
    }
    for (k, v) in settings.iteritems():
      if v and getattr(self.options, k) is None:
        setattr(self.options, k, v)

  def GclientStyleSettings(self):
    """Find the root, assuming a gclient-style checkout."""
    if not self.options.no_gclient and not self.options.root:
      root = self.checkout_root
      gclient_root = gclient_utils.FindGclientRoot(root)
      if gclient_root:
        self.options.root = gclient_utils.PathDifference(gclient_root, root)

  def AutomagicalSettings(self):
    """Determines settings based on supported code review and checkout tools.
    """
    self.GclStyleSettings()
    self.GclientStyleSettings()

  def ReadRootFile(self, filename):
    raise NotImplementedError()


class SVN(SCM):
  """Gathers the options and diff for a subversion checkout."""
  def __init__(self, *args, **kwargs):
    SCM.__init__(self, *args, **kwargs)
    self.checkout_root = scm.SVN.GetCheckoutRoot(self.checkout_root)
    if not self.options.email:
      # Assumes the svn credential is an email address.
      self.options.email = scm.SVN.GetEmail(self.checkout_root)
    logging.info("SVN(%s)" % self.checkout_root)

  def ReadRootFile(self, filename):
    try:
      # Try to search on the subversion repository for the file.
      import gcl
      data = gcl.GetCachedFile(filename)
      logging.debug('%s:\n%s' % (filename, data))
      return data
    except ImportError:
      try:
        data = gclient_utils.FileRead(os.path.join(self.checkout_root,
                                                   filename))
        logging.debug('%s:\n%s' % (filename, data))
        return data
      except (IOError, OSError):
        logging.debug('%s:\nNone' % filename)
        return None

  def GenerateDiff(self):
    """Returns a string containing the diff for the given file list.

    The files in the list should either be absolute paths or relative to the
    given root.
    """
    if not self.files:
      previous_cwd = os.getcwd()
      os.chdir(self.checkout_root)
      excluded = ['!', '?', 'X', ' ', '~']
      self.files = [
          f[1] for f in scm.SVN.CaptureStatus(self.checkout_root)
          if f[0][0] not in excluded
      ]
      os.chdir(previous_cwd)
    return scm.SVN.GenerateDiff(self.files, self.checkout_root, full_move=True,
{'fraction_non_alphanumeric': 0.10295956648603585, 'fraction_numerical': 0.0043351396415172985, 'mean_word_length': 3.149429263230716, 'pattern_counts': {'":': 2, '<': 9, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3982625', 'n_tokens_mistral': 3735, 'n_tokens_neox': 3635, 'n_words': 1176}