thirdparty/rietveld/upload.py
author Todd Larsen <tlarsen@google.com>
Tue, 14 Oct 2008 21:39:57 +0000
changeset 329 2d90d49ce78a
parent 148 37505d64e57b
child 478 613951c35706
permissions -rwxr-xr-x
Add is_featured boolean property to the Work model, so that Works can be designated as "featured" items in various places in the UI. This will be used to allow Sponsors, Programs, and Organizations to select Documents that should be included in their sidebar menus. Perhaps featured "site" Documents, such as site-wide Terms of Service, should probably be listed below the "User (sign-out)" menu, since the User will have to read and agree to these before being allowed to use the site. A collapsable Javascript sidebar is probably going to be needed soon... Patch by: Todd Larsen Review by: to-be-reviewed
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
147
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
     1
#!/usr/bin/env python
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
     2
#
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
     3
# Copyright 2007 Google Inc.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
     4
#
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
     5
# Licensed under the Apache License, Version 2.0 (the "License");
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
     6
# you may not use this file except in compliance with the License.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
     7
# You may obtain a copy of the License at
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
     8
#
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
     9
#     http://www.apache.org/licenses/LICENSE-2.0
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    10
#
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    11
# Unless required by applicable law or agreed to in writing, software
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    12
# distributed under the License is distributed on an "AS IS" BASIS,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    13
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    14
# See the License for the specific language governing permissions and
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    15
# limitations under the License.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    16
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    17
"""Tool for uploading diffs from a version control system to the codereview app.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    18
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    19
Usage summary: upload.py [options] [-- diff_options]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    20
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    21
Diff options are passed to the diff command of the underlying system.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    22
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    23
Supported version control systems:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    24
  Git
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    25
  Subversion
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    26
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    27
(It is important for Git users to specify a tree-ish to diff against.)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    28
"""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    29
# This code is derived from appcfg.py in the App Engine SDK (open source),
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    30
# and from ASPN recipe #146306.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    31
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    32
import cookielib
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    33
import getpass
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    34
import logging
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    35
import md5
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    36
import mimetypes
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    37
import optparse
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    38
import os
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    39
import re
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    40
import socket
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    41
import subprocess
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    42
import sys
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    43
import urllib
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    44
import urllib2
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    45
import urlparse
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    46
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    47
try:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    48
  import readline
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    49
except ImportError:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    50
  pass
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    51
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    52
# The logging verbosity:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    53
#  0: Errors only.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    54
#  1: Status messages.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    55
#  2: Info logs.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    56
#  3: Debug logs.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    57
verbosity = 1
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    58
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    59
# Max size of patch or base file.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    60
MAX_UPLOAD_SIZE = 900 * 1024
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    61
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    62
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    63
def StatusUpdate(msg):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    64
  """Print a status message to stdout.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    65
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    66
  If 'verbosity' is greater than 0, print the message.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    67
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    68
  Args:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    69
    msg: The string to print.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    70
  """
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    71
  if verbosity > 0:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    72
    print msg
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    73
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    74
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    75
def ErrorExit(msg):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    76
  """Print an error message to stderr and exit."""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    77
  print >>sys.stderr, msg
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    78
  sys.exit(1)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    79
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    80
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    81
class ClientLoginError(urllib2.HTTPError):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    82
  """Raised to indicate there was an error authenticating with ClientLogin."""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    83
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    84
  def __init__(self, url, code, msg, headers, args):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    85
    urllib2.HTTPError.__init__(self, url, code, msg, headers, None)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    86
    self.args = args
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    87
    self.reason = args["Error"]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    88
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    89
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    90
class AbstractRpcServer(object):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    91
  """Provides a common interface for a simple RPC server."""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    92
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    93
  def __init__(self, host, auth_function, host_override=None, extra_headers={},
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    94
               save_cookies=False):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    95
    """Creates a new HttpRpcServer.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    96
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    97
    Args:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    98
      host: The host to send requests to.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
    99
      auth_function: A function that takes no arguments and returns an
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   100
        (email, password) tuple when called. Will be called if authentication
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   101
        is required.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   102
      host_override: The host header to send to the server (defaults to host).
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   103
      extra_headers: A dict of extra headers to append to every request.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   104
      save_cookies: If True, save the authentication cookies to local disk.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   105
        If False, use an in-memory cookiejar instead.  Subclasses must
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   106
        implement this functionality.  Defaults to False.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   107
    """
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   108
    self.host = host
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   109
    self.host_override = host_override
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   110
    self.auth_function = auth_function
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   111
    self.authenticated = False
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   112
    self.extra_headers = extra_headers
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   113
    self.save_cookies = save_cookies
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   114
    self.opener = self._GetOpener()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   115
    if self.host_override:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   116
      logging.info("Server: %s; Host: %s", self.host, self.host_override)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   117
    else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   118
      logging.info("Server: %s", self.host)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   119
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   120
  def _GetOpener(self):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   121
    """Returns an OpenerDirector for making HTTP requests.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   122
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   123
    Returns:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   124
      A urllib2.OpenerDirector object.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   125
    """
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   126
    raise NotImplementedError()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   127
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   128
  def _CreateRequest(self, url, data=None):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   129
    """Creates a new urllib request."""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   130
    logging.debug("Creating request for: '%s' with payload:\n%s", url, data)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   131
    req = urllib2.Request(url, data=data)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   132
    if self.host_override:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   133
      req.add_header("Host", self.host_override)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   134
    for key, value in self.extra_headers.iteritems():
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   135
      req.add_header(key, value)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   136
    return req
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   137
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   138
  def _GetAuthToken(self, email, password):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   139
    """Uses ClientLogin to authenticate the user, returning an auth token.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   140
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   141
    Args:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   142
      email:    The user's email address
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   143
      password: The user's password
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   144
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   145
    Raises:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   146
      ClientLoginError: If there was an error authenticating with ClientLogin.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   147
      HTTPError: If there was some other form of HTTP error.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   148
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   149
    Returns:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   150
      The authentication token returned by ClientLogin.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   151
    """
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   152
    req = self._CreateRequest(
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   153
        url="https://www.google.com/accounts/ClientLogin",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   154
        data=urllib.urlencode({
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   155
            "Email": email,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   156
            "Passwd": password,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   157
            "service": "ah",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   158
            "source": "rietveld-codereview-upload",
148
37505d64e57b upload.py customized to work with codereviews.googleopensourceprograms.com.
Todd Larsen <tlarsen@google.com>
parents: 147
diff changeset
   159
            "accountType": "HOSTED_OR_GOOGLE",
147
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   160
        })
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   161
    )
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   162
    try:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   163
      response = self.opener.open(req)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   164
      response_body = response.read()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   165
      response_dict = dict(x.split("=")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   166
                           for x in response_body.split("\n") if x)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   167
      return response_dict["Auth"]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   168
    except urllib2.HTTPError, e:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   169
      if e.code == 403:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   170
        body = e.read()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   171
        response_dict = dict(x.split("=", 1) for x in body.split("\n") if x)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   172
        raise ClientLoginError(req.get_full_url(), e.code, e.msg,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   173
                               e.headers, response_dict)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   174
      else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   175
        raise
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   176
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   177
  def _GetAuthCookie(self, auth_token):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   178
    """Fetches authentication cookies for an authentication token.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   179
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   180
    Args:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   181
      auth_token: The authentication token returned by ClientLogin.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   182
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   183
    Raises:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   184
      HTTPError: If there was an error fetching the authentication cookies.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   185
    """
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   186
    # This is a dummy value to allow us to identify when we're successful.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   187
    continue_location = "http://localhost/"
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   188
    args = {"continue": continue_location, "auth": auth_token}
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   189
    req = self._CreateRequest("http://%s/_ah/login?%s" %
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   190
                              (self.host, urllib.urlencode(args)))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   191
    try:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   192
      response = self.opener.open(req)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   193
    except urllib2.HTTPError, e:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   194
      response = e
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   195
    if (response.code != 302 or
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   196
        response.info()["location"] != continue_location):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   197
      raise urllib2.HTTPError(req.get_full_url(), response.code, response.msg,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   198
                              response.headers, response.fp)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   199
    self.authenticated = True
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   200
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   201
  def _Authenticate(self):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   202
    """Authenticates the user.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   203
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   204
    The authentication process works as follows:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   205
     1) We get a username and password from the user
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   206
     2) We use ClientLogin to obtain an AUTH token for the user
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   207
        (see http://code.google.com/apis/accounts/AuthForInstalledApps.html).
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   208
     3) We pass the auth token to /_ah/login on the server to obtain an
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   209
        authentication cookie. If login was successful, it tries to redirect
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   210
        us to the URL we provided.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   211
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   212
    If we attempt to access the upload API without first obtaining an
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   213
    authentication cookie, it returns a 401 response and directs us to
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   214
    authenticate ourselves with ClientLogin.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   215
    """
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   216
    for i in range(3):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   217
      credentials = self.auth_function()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   218
      try:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   219
        auth_token = self._GetAuthToken(credentials[0], credentials[1])
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   220
      except ClientLoginError, e:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   221
        if e.reason == "BadAuthentication":
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   222
          print >>sys.stderr, "Invalid username or password."
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   223
          continue
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   224
        if e.reason == "CaptchaRequired":
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   225
          print >>sys.stderr, (
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   226
              "Please go to\n"
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   227
              "https://www.google.com/accounts/DisplayUnlockCaptcha\n"
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   228
              "and verify you are a human.  Then try again.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   229
          break
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   230
        if e.reason == "NotVerified":
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   231
          print >>sys.stderr, "Account not verified."
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   232
          break
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   233
        if e.reason == "TermsNotAgreed":
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   234
          print >>sys.stderr, "User has not agreed to TOS."
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   235
          break
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   236
        if e.reason == "AccountDeleted":
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   237
          print >>sys.stderr, "The user account has been deleted."
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   238
          break
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   239
        if e.reason == "AccountDisabled":
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   240
          print >>sys.stderr, "The user account has been disabled."
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   241
          break
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   242
        if e.reason == "ServiceDisabled":
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   243
          print >>sys.stderr, ("The user's access to the service has been "
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   244
                               "disabled.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   245
          break
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   246
        if e.reason == "ServiceUnavailable":
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   247
          print >>sys.stderr, "The service is not available; try again later."
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   248
          break
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   249
        raise
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   250
      self._GetAuthCookie(auth_token)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   251
      return
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   252
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   253
  def Send(self, request_path, payload=None,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   254
           content_type="application/octet-stream",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   255
           timeout=None,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   256
           **kwargs):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   257
    """Sends an RPC and returns the response.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   258
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   259
    Args:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   260
      request_path: The path to send the request to, eg /api/appversion/create.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   261
      payload: The body of the request, or None to send an empty request.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   262
      content_type: The Content-Type header to use.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   263
      timeout: timeout in seconds; default None i.e. no timeout.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   264
        (Note: for large requests on OS X, the timeout doesn't work right.)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   265
      kwargs: Any keyword arguments are converted into query string parameters.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   266
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   267
    Returns:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   268
      The response body, as a string.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   269
    """
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   270
    # TODO: Don't require authentication.  Let the server say
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   271
    # whether it is necessary.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   272
    if not self.authenticated:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   273
      self._Authenticate()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   274
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   275
    old_timeout = socket.getdefaulttimeout()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   276
    socket.setdefaulttimeout(timeout)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   277
    try:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   278
      tries = 0
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   279
      while True:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   280
        tries += 1
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   281
        args = dict(kwargs)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   282
        url = "http://%s%s" % (self.host, request_path)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   283
        if args:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   284
          url += "?" + urllib.urlencode(args)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   285
        req = self._CreateRequest(url=url, data=payload)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   286
        req.add_header("Content-Type", content_type)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   287
        try:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   288
          f = self.opener.open(req)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   289
          response = f.read()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   290
          f.close()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   291
          return response
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   292
        except urllib2.HTTPError, e:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   293
          if tries > 3:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   294
            raise
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   295
          elif e.code == 401:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   296
            self._Authenticate()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   297
##           elif e.code >= 500 and e.code < 600:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   298
##             # Server Error - try again.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   299
##             continue
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   300
          else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   301
            raise
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   302
    finally:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   303
      socket.setdefaulttimeout(old_timeout)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   304
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   305
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   306
class HttpRpcServer(AbstractRpcServer):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   307
  """Provides a simplified RPC-style interface for HTTP requests."""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   308
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   309
  def _Authenticate(self):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   310
    """Save the cookie jar after authentication."""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   311
    super(HttpRpcServer, self)._Authenticate()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   312
    if self.save_cookies:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   313
      StatusUpdate("Saving authentication cookies to %s" % self.cookie_file)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   314
      self.cookie_jar.save()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   315
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   316
  def _GetOpener(self):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   317
    """Returns an OpenerDirector that supports cookies and ignores redirects.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   318
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   319
    Returns:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   320
      A urllib2.OpenerDirector object.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   321
    """
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   322
    opener = urllib2.OpenerDirector()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   323
    opener.add_handler(urllib2.ProxyHandler())
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   324
    opener.add_handler(urllib2.UnknownHandler())
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   325
    opener.add_handler(urllib2.HTTPHandler())
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   326
    opener.add_handler(urllib2.HTTPDefaultErrorHandler())
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   327
    opener.add_handler(urllib2.HTTPSHandler())
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   328
    opener.add_handler(urllib2.HTTPErrorProcessor())
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   329
    if self.save_cookies:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   330
      self.cookie_file = os.path.expanduser("~/.codereview_upload_cookies")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   331
      self.cookie_jar = cookielib.MozillaCookieJar(self.cookie_file)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   332
      if os.path.exists(self.cookie_file):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   333
        try:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   334
          self.cookie_jar.load()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   335
          self.authenticated = True
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   336
          StatusUpdate("Loaded authentication cookies from %s" %
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   337
                       self.cookie_file)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   338
        except (cookielib.LoadError, IOError):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   339
          # Failed to load cookies - just ignore them.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   340
          pass
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   341
      else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   342
        # Create an empty cookie file with mode 600
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   343
        fd = os.open(self.cookie_file, os.O_CREAT, 0600)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   344
        os.close(fd)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   345
      # Always chmod the cookie file
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   346
      os.chmod(self.cookie_file, 0600)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   347
    else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   348
      # Don't save cookies across runs of update.py.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   349
      self.cookie_jar = cookielib.CookieJar()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   350
    opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   351
    return opener
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   352
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   353
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   354
parser = optparse.OptionParser(usage="%prog [options] [-- diff_options]")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   355
parser.add_option("-y", "--assume_yes", action="store_true",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   356
                  dest="assume_yes", default=False,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   357
                  help="Assume that the answer to yes/no questions is 'yes'.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   358
# Logging
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   359
group = parser.add_option_group("Logging options")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   360
group.add_option("-q", "--quiet", action="store_const", const=0,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   361
                 dest="verbose", help="Print errors only.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   362
group.add_option("-v", "--verbose", action="store_const", const=2,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   363
                 dest="verbose", default=1,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   364
                 help="Print info level logs (default).")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   365
group.add_option("--noisy", action="store_const", const=3,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   366
                 dest="verbose", help="Print all logs.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   367
# Review server
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   368
group = parser.add_option_group("Review server options")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   369
group.add_option("-s", "--server", action="store", dest="server",
148
37505d64e57b upload.py customized to work with codereviews.googleopensourceprograms.com.
Todd Larsen <tlarsen@google.com>
parents: 147
diff changeset
   370
                 default="codereviews.googleopensourceprograms.com",
147
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   371
                 metavar="SERVER",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   372
                 help=("The server to upload to. The format is host[:port]. "
148
37505d64e57b upload.py customized to work with codereviews.googleopensourceprograms.com.
Todd Larsen <tlarsen@google.com>
parents: 147
diff changeset
   373
                       "Defaults to 'codereviews.googleopensourceprograms.com'."))
147
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   374
group.add_option("-e", "--email", action="store", dest="email",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   375
                 metavar="EMAIL", default=None,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   376
                 help="The username to use. Will prompt if omitted.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   377
group.add_option("-H", "--host", action="store", dest="host",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   378
                 metavar="HOST", default=None,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   379
                 help="Overrides the Host header sent with all RPCs.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   380
group.add_option("--no_cookies", action="store_false",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   381
                 dest="save_cookies", default=True,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   382
                 help="Do not save authentication cookies to local disk.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   383
# Issue
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   384
group = parser.add_option_group("Issue options")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   385
group.add_option("-d", "--description", action="store", dest="description",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   386
                 metavar="DESCRIPTION", default=None,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   387
                 help="Optional description when creating an issue.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   388
group.add_option("-f", "--description_file", action="store",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   389
                 dest="description_file", metavar="DESCRIPTION_FILE",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   390
                 default=None,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   391
                 help="Optional path of a file that contains "
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   392
                      "the description when creating an issue.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   393
group.add_option("-r", "--reviewers", action="store", dest="reviewers",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   394
                 metavar="REVIEWERS", default=None,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   395
                 help="Add reviewers (comma separated email addresses).")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   396
group.add_option("--cc", action="store", dest="cc",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   397
                 metavar="CC", default=None,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   398
                 help="Add CC (comma separated email addresses).")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   399
# Upload options
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   400
group = parser.add_option_group("Patch options")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   401
group.add_option("-m", "--message", action="store", dest="message",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   402
                 metavar="MESSAGE", default=None,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   403
                 help="A message to identify the patch. "
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   404
                      "Will prompt if omitted.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   405
group.add_option("-i", "--issue", type="int", action="store",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   406
                 metavar="ISSUE", default=None,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   407
                 help="Issue number to which to add. Defaults to new issue.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   408
group.add_option("-l", "--local_base", action="store_true",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   409
                 dest="local_base", default=False,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   410
                 help="Base files will be uploaded.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   411
group.add_option("--send_mail", action="store_true",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   412
                 dest="send_mail", default=False,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   413
                 help="Send notification email to reviewers.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   414
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   415
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   416
def GetRpcServer(options):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   417
  """Returns an instance of an AbstractRpcServer.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   418
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   419
  Returns:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   420
    A new AbstractRpcServer, on which RPC calls can be made.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   421
  """
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   422
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   423
  rpc_server_class = HttpRpcServer
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   424
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   425
  def GetUserCredentials():
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   426
    """Prompts the user for a username and password."""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   427
    email = options.email
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   428
    if email is None:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   429
      email = raw_input("Email: ").strip()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   430
    password = getpass.getpass("Password for %s: " % email)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   431
    return (email, password)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   432
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   433
  # If this is the dev_appserver, use fake authentication.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   434
  host = (options.host or options.server).lower()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   435
  if host == "localhost" or host.startswith("localhost:"):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   436
    email = options.email
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   437
    if email is None:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   438
      email = "test@example.com"
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   439
      logging.info("Using debug user %s.  Override with --email" % email)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   440
    server = rpc_server_class(
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   441
        options.server,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   442
        lambda: (email, "password"),
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   443
        host_override=options.host,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   444
        extra_headers={"Cookie":
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   445
                       'dev_appserver_login="%s:False"' % email},
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   446
        save_cookies=options.save_cookies)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   447
    # Don't try to talk to ClientLogin.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   448
    server.authenticated = True
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   449
    return server
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   450
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   451
  return rpc_server_class(options.server, GetUserCredentials,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   452
                          host_override=options.host,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   453
                          save_cookies=options.save_cookies)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   454
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   455
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   456
def EncodeMultipartFormData(fields, files):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   457
  """Encode form fields for multipart/form-data.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   458
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   459
  Args:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   460
    fields: A sequence of (name, value) elements for regular form fields.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   461
    files: A sequence of (name, filename, value) elements for data to be
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   462
           uploaded as files.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   463
  Returns:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   464
    (content_type, body) ready for httplib.HTTP instance.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   465
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   466
  Source:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   467
    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   468
  """
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   469
  BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-'
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   470
  CRLF = '\r\n'
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   471
  lines = []
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   472
  for (key, value) in fields:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   473
    lines.append('--' + BOUNDARY)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   474
    lines.append('Content-Disposition: form-data; name="%s"' % key)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   475
    lines.append('')
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   476
    lines.append(value)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   477
  for (key, filename, value) in files:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   478
    lines.append('--' + BOUNDARY)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   479
    lines.append('Content-Disposition: form-data; name="%s"; filename="%s"' %
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   480
             (key, filename))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   481
    lines.append('Content-Type: %s' % GetContentType(filename))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   482
    lines.append('')
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   483
    lines.append(value)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   484
  lines.append('--' + BOUNDARY + '--')
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   485
  lines.append('')
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   486
  body = CRLF.join(lines)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   487
  content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   488
  return content_type, body
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   489
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   490
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   491
def GetContentType(filename):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   492
  """Helper to guess the content-type from the filename."""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   493
  return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   494
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   495
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   496
# Use a shell for subcommands on Windows to get a PATH search.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   497
use_shell = sys.platform.startswith("win")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   498
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   499
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   500
def RunShell(command, silent_ok=False, universal_newlines=False):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   501
  logging.info("Running %s", command)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   502
  p = subprocess.Popen(command, stdout=subprocess.PIPE,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   503
                       stderr=subprocess.STDOUT, shell=use_shell,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   504
                       universal_newlines=universal_newlines)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   505
  data = p.stdout.read()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   506
  p.wait()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   507
  p.stdout.close()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   508
  if p.returncode:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   509
    ErrorExit("Got error status from %s" % command)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   510
  if not silent_ok and not data:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   511
    ErrorExit("No output from %s" % command)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   512
  return data
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   513
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   514
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   515
class VersionControlSystem(object):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   516
  """Abstract base class providing an interface to the VCS."""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   517
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   518
  def GenerateDiff(self, args):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   519
    """Return the current diff as a string.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   520
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   521
    Args:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   522
      args: Extra arguments to pass to the diff command.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   523
    """
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   524
    raise NotImplementedError(
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   525
        "abstract method -- subclass %s must override" % self.__class__)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   526
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   527
  def GetUnknownFiles(self):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   528
    """Return a list of files unknown to the VCS."""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   529
    raise NotImplementedError(
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   530
        "abstract method -- subclass %s must override" % self.__class__)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   531
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   532
  def CheckForUnknownFiles(self):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   533
    """Show an "are you sure?" prompt if there are unknown files."""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   534
    unknown_files = self.GetUnknownFiles()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   535
    if unknown_files:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   536
      print "The following files are not added to version control:"
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   537
      for line in unknown_files:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   538
        print line
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   539
      prompt = "Are you sure to continue?(y/N) "
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   540
      answer = raw_input(prompt).strip()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   541
      if answer != "y":
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   542
        ErrorExit("User aborted")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   543
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   544
  def GetBaseFile(self, filename):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   545
    """Get the content of the upstream version of a file.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   546
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   547
    Returns:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   548
      A tuple (content, status) representing the file content and the status of
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   549
      the file.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   550
    """
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   551
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   552
    raise NotImplementedError(
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   553
        "abstract method -- subclass %s must override" % self.__class__)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   554
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   555
  def UploadBaseFiles(self, issue, rpc_server, patch_list, patchset, options):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   556
    """Uploads the base files."""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   557
    patches = dict()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   558
    [patches.setdefault(v, k) for k, v in patch_list]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   559
    for filename in patches.keys():
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   560
      content, status = self.GetBaseFile(filename)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   561
      no_base_file = False
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   562
      if len(content) > MAX_UPLOAD_SIZE:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   563
        print ("Not uploading the base file for " + filename +
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   564
               " because the file is too large.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   565
        no_base_file = True
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   566
        content = ""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   567
      checksum = md5.new(content).hexdigest()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   568
      if options.verbose > 0:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   569
        print "Uploading %s" % filename
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   570
      url = "/%d/upload_content/%d/%d" % (int(issue), int(patchset),
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   571
                                          int(patches.get(filename)))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   572
      form_fields = [("filename", filename),
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   573
                     ("status", status),
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   574
                     ("checksum", checksum),]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   575
      if no_base_file:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   576
        form_fields.append(("no_base_file", "1"))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   577
      if options.email:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   578
        form_fields.append(("user", options.email))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   579
      ctype, body = EncodeMultipartFormData(form_fields,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   580
                                            [("data", filename, content)])
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   581
      response_body = rpc_server.Send(url, body, content_type=ctype)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   582
      if not response_body.startswith("OK"):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   583
        StatusUpdate("  --> %s" % response_body)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   584
        sys.exit(False)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   585
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   586
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   587
class SubversionVCS(VersionControlSystem):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   588
  """Implementation of the VersionControlSystem interface for Subversion."""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   589
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   590
  def GuessBase(self, required):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   591
    """Returns the SVN base URL.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   592
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   593
    Args:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   594
      required: If true, exits if the url can't be guessed, otherwise None is
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   595
        returned.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   596
    """
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   597
    info = RunShell(["svn", "info"])
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   598
    for line in info.splitlines():
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   599
      words = line.split()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   600
      if len(words) == 2 and words[0] == "URL:":
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   601
        url = words[1]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   602
        scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   603
        username, netloc = urllib.splituser(netloc)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   604
        if username:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   605
          logging.info("Removed username from base URL")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   606
        if netloc.endswith("svn.python.org"):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   607
          if netloc == "svn.python.org":
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   608
            if path.startswith("/projects/"):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   609
              path = path[9:]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   610
          elif netloc != "pythondev@svn.python.org":
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   611
            ErrorExit("Unrecognized Python URL: %s" % url)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   612
          base = "http://svn.python.org/view/*checkout*%s/" % path
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   613
          logging.info("Guessed Python base = %s", base)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   614
        elif netloc.endswith("svn.collab.net"):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   615
          if path.startswith("/repos/"):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   616
            path = path[6:]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   617
          base = "http://svn.collab.net/viewvc/*checkout*%s/" % path
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   618
          logging.info("Guessed CollabNet base = %s", base)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   619
        elif netloc.endswith(".googlecode.com"):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   620
          path = path + "/"
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   621
          base = urlparse.urlunparse(("http", netloc, path, params,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   622
                                      query, fragment))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   623
          logging.info("Guessed Google Code base = %s", base)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   624
        else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   625
          path = path + "/"
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   626
          base = urlparse.urlunparse((scheme, netloc, path, params,
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   627
                                      query, fragment))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   628
          logging.info("Guessed base = %s", base)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   629
        return base
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   630
    if required:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   631
      ErrorExit("Can't find URL in output from svn info")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   632
    return None
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   633
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   634
  def GenerateDiff(self, args):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   635
    cmd = ["svn", "diff"]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   636
    if not sys.platform.startswith("win"):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   637
      cmd.append("--diff-cmd=diff")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   638
    cmd.extend(args)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   639
    data = RunShell(cmd)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   640
    count = 0
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   641
    for line in data.splitlines():
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   642
      if line.startswith("Index:") or line.startswith("Property changes on:"):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   643
        count += 1
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   644
        logging.info(line)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   645
    if not count:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   646
      ErrorExit("No valid patches found in output from svn diff")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   647
    return data
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   648
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   649
  def _CollapseKeywords(self, content, keyword_str):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   650
    """Collapses SVN keywords."""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   651
    # svn cat translates keywords but svn diff doesn't. As a result of this
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   652
    # behavior patching.PatchChunks() fails with a chunk mismatch error.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   653
    # This part was originally written by the Review Board development team
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   654
    # who had the same problem (http://reviews.review-board.org/r/276/).
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   655
    # Mapping of keywords to known aliases
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   656
    svn_keywords = {
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   657
      # Standard keywords
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   658
      'Date':                ['Date', 'LastChangedDate'],
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   659
      'Revision':            ['Revision', 'LastChangedRevision', 'Rev'],
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   660
      'Author':              ['Author', 'LastChangedBy'],
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   661
      'HeadURL':             ['HeadURL', 'URL'],
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   662
      'Id':                  ['Id'],
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   663
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   664
      # Aliases
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   665
      'LastChangedDate':     ['LastChangedDate', 'Date'],
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   666
      'LastChangedRevision': ['LastChangedRevision', 'Rev', 'Revision'],
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   667
      'LastChangedBy':       ['LastChangedBy', 'Author'],
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   668
      'URL':                 ['URL', 'HeadURL'],
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   669
    }
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   670
    def repl(m):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   671
       if m.group(2):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   672
         return "$%s::%s$" % (m.group(1), " " * len(m.group(3)))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   673
       return "$%s$" % m.group(1)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   674
    keywords = [keyword
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   675
                for name in keyword_str.split(" ")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   676
                for keyword in svn_keywords.get(name, [])]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   677
    return re.sub(r"\$(%s):(:?)([^\$]+)\$" % '|'.join(keywords), repl, content)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   678
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   679
  def GetUnknownFiles(self):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   680
    status = RunShell(["svn", "status", "--ignore-externals"], silent_ok=True)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   681
    unknown_files = []
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   682
    for line in status.split("\n"):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   683
      if line and line[0] == "?":
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   684
        unknown_files.append(line)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   685
    return unknown_files
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   686
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   687
  def GetBaseFile(self, filename):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   688
    status = RunShell(["svn", "status", "--ignore-externals", filename])
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   689
    if not status:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   690
      StatusUpdate("svn status returned no output for %s" % filename)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   691
      sys.exit(False)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   692
    status_lines = status.splitlines()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   693
    # If file is in a cl, the output will begin with
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   694
    # "\n--- Changelist 'cl_name':\n".  See
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   695
    # http://svn.collab.net/repos/svn/trunk/notes/changelist-design.txt
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   696
    if (len(status_lines) == 3 and
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   697
        not status_lines[0] and
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   698
        status_lines[1].startswith("--- Changelist")):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   699
      status = status_lines[2]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   700
    else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   701
      status = status_lines[0]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   702
    # If a file is copied its status will be "A  +", which signifies
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   703
    # "addition-with-history".  See "svn st" for more information.  We need to
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   704
    # upload the original file or else diff parsing will fail if the file was
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   705
    # edited.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   706
    if ((status[0] == "A" and status[3] != "+") or
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   707
        (status[0] == " " and status[1] == "M")):  # property changed
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   708
      content = ""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   709
    elif (status[0] in ("M", "D", "R") or
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   710
          (status[0] == "A" and status[3] == "+")):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   711
      mimetype = RunShell(["svn", "-rBASE", "propget", "svn:mime-type",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   712
                           filename],
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   713
                          silent_ok=True)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   714
      if mimetype.startswith("application/octet-stream"):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   715
        content = ""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   716
      else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   717
        # On Windows svn cat gives \r\n, and calling subprocess.Popen turns
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   718
        # them into \r\r\n, so use universal newlines to avoid the extra \r.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   719
        if sys.platform.startswith("win"):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   720
          nl = True
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   721
        else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   722
          nl = False
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   723
        content = RunShell(["svn", "cat", filename], universal_newlines=nl)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   724
      keywords = RunShell(["svn", "-rBASE", "propget", "svn:keywords",
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   725
                           filename],
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   726
                          silent_ok=True)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   727
      if keywords:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   728
        content = self._CollapseKeywords(content, keywords)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   729
    else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   730
      StatusUpdate("svn status returned unexpected output: %s" % status)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   731
      sys.exit(False)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   732
    return content, status[0:5]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   733
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   734
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   735
class GitVCS(VersionControlSystem):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   736
  """Implementation of the VersionControlSystem interface for Git."""
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   737
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   738
  def __init__(self):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   739
    # Map of filename -> hash of base file.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   740
    self.base_hashes = {}
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   741
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   742
  def GenerateDiff(self, extra_args):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   743
    # This is more complicated than svn's GenerateDiff because we must convert
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   744
    # the diff output to include an svn-style "Index:" line as well as record
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   745
    # the hashes of the base files, so we can upload them along with our diff.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   746
    gitdiff = RunShell(["git", "diff", "--full-index"] + extra_args)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   747
    svndiff = []
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   748
    filecount = 0
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   749
    filename = None
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   750
    for line in gitdiff.splitlines():
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   751
      match = re.match(r"diff --git a/(.*) b/.*$", line)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   752
      if match:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   753
        filecount += 1
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   754
        filename = match.group(1)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   755
        svndiff.append("Index: %s\n" % filename)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   756
      else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   757
        # The "index" line in a git diff looks like this (long hashes elided):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   758
        #   index 82c0d44..b2cee3f 100755
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   759
        # We want to save the left hash, as that identifies the base file.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   760
        match = re.match(r"index (\w+)\.\.", line)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   761
        if match:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   762
          self.base_hashes[filename] = match.group(1)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   763
      svndiff.append(line + "\n")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   764
    if not filecount:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   765
      ErrorExit("No valid patches found in output from git diff")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   766
    return "".join(svndiff)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   767
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   768
  def GetUnknownFiles(self):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   769
    status = RunShell(["git", "ls-files", "--exclude-standard", "--others"],
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   770
                      silent_ok=True)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   771
    return status.splitlines()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   772
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   773
  def GetBaseFile(self, filename):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   774
    hash = self.base_hashes[filename]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   775
    if hash == "0" * 40:  # All-zero hash indicates no base file.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   776
      return ("", "A")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   777
    else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   778
      return (RunShell(["git", "show", hash]), "M")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   779
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   780
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   781
# NOTE: this function is duplicated in engine.py, keep them in sync.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   782
def SplitPatch(data):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   783
  """Splits a patch into separate pieces for each file.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   784
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   785
  Args:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   786
    data: A string containing the output of svn diff.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   787
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   788
  Returns:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   789
    A list of 2-tuple (filename, text) where text is the svn diff output
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   790
      pertaining to filename.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   791
  """
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   792
  patches = []
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   793
  filename = None
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   794
  diff = []
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   795
  for line in data.splitlines(True):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   796
    new_filename = None
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   797
    if line.startswith('Index:'):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   798
      unused, new_filename = line.split(':', 1)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   799
      new_filename = new_filename.strip()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   800
    elif line.startswith('Property changes on:'):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   801
      unused, temp_filename = line.split(':', 1)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   802
      # When a file is modified, paths use '/' between directories, however
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   803
      # when a property is modified '\' is used on Windows.  Make them the same
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   804
      # otherwise the file shows up twice.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   805
      temp_filename = temp_filename.strip().replace('\\', '/')
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   806
      if temp_filename != filename:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   807
        # File has property changes but no modifications, create a new diff.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   808
        new_filename = temp_filename
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   809
    if new_filename:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   810
      if filename and diff:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   811
        patches.append((filename, ''.join(diff)))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   812
      filename = new_filename
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   813
      diff = [line]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   814
      continue
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   815
    if diff is not None:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   816
      diff.append(line)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   817
  if filename and diff:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   818
    patches.append((filename, ''.join(diff)))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   819
  return patches
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   820
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   821
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   822
def UploadSeparatePatches(issue, rpc_server, patchset, data, options):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   823
  """Uploads a separate patch for each file in the diff output.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   824
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   825
  Returns a list of [patch_key, filename] for each file.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   826
  """
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   827
  patches = SplitPatch(data)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   828
  rv = []
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   829
  for patch in patches:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   830
    if len(patch[1]) > MAX_UPLOAD_SIZE:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   831
      print ("Not uploading the patch for " + patch[0] +
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   832
             " because the file is too large.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   833
      continue
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   834
    form_fields = [("filename", patch[0])]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   835
    if options.local_base:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   836
      form_fields.append(("content_upload", "1"))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   837
    files = [("data", "data.diff", patch[1])]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   838
    ctype, body = EncodeMultipartFormData(form_fields, files)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   839
    url = "/%d/upload_patch/%d" % (int(issue), int(patchset))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   840
    print "Uploading patch for " + patch[0]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   841
    response_body = rpc_server.Send(url, body, content_type=ctype)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   842
    lines = response_body.splitlines()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   843
    if not lines or lines[0] != "OK":
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   844
      StatusUpdate("  --> %s" % response_body)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   845
      sys.exit(False)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   846
    rv.append([lines[1], patch[0]])
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   847
  return rv
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   848
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   849
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   850
def GuessVCS():
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   851
  """Helper to guess the version control system.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   852
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   853
  This examines the current directory, guesses which VersionControlSystem
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   854
  we're using, and returns an instance of the appropriate class.  Exit with an
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   855
  error if we can't figure it out.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   856
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   857
  Returns:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   858
    A VersionControlSystem instance. Exits if the VCS can't be guessed.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   859
  """
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   860
  # Subversion has a .svn in all working directories.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   861
  if os.path.isdir('.svn'):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   862
    logging.info("Guessed VCS = Subversion")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   863
    return SubversionVCS()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   864
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   865
  # Git has a command to test if you're in a git tree.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   866
  # Try running it, but don't die if we don't have git installed.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   867
  try:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   868
    subproc = subprocess.Popen(["git", "rev-parse", "--is-inside-work-tree"],
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   869
                               stdout=subprocess.PIPE, stderr=subprocess.PIPE)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   870
    if subproc.wait() == 0:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   871
      return GitVCS()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   872
  except OSError, (errno, message):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   873
    if errno != 2:  # ENOENT -- they don't have git installed.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   874
      raise
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   875
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   876
  ErrorExit(("Could not guess version control system. "
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   877
             "Are you in a working copy directory?"))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   878
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   879
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   880
def RealMain(argv, data=None):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   881
  logging.basicConfig(format=("%(asctime).19s %(levelname)s %(filename)s:"
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   882
                              "%(lineno)s %(message)s "))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   883
  os.environ['LC_ALL'] = 'C'
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   884
  options, args = parser.parse_args(argv[1:])
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   885
  global verbosity
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   886
  verbosity = options.verbose
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   887
  if verbosity >= 3:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   888
    logging.getLogger().setLevel(logging.DEBUG)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   889
  elif verbosity >= 2:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   890
    logging.getLogger().setLevel(logging.INFO)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   891
  vcs = GuessVCS()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   892
  if isinstance(vcs, SubversionVCS):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   893
    # base field is only allowed for Subversion.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   894
    # Note: Fetching base files may become deprecated in future releases.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   895
    base = vcs.GuessBase(not options.local_base)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   896
  else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   897
    base = None
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   898
  if not base and not options.local_base:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   899
    options.local_base = True
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   900
    logging.info("Enabled upload of base file")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   901
  if not options.assume_yes:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   902
    vcs.CheckForUnknownFiles()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   903
  if data is None:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   904
    data = vcs.GenerateDiff(args)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   905
  if verbosity >= 1:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   906
    print "Upload server:", options.server, "(change with -s/--server)"
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   907
  if options.issue:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   908
    prompt = "Message describing this patch set: "
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   909
  else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   910
    prompt = "New issue subject: "
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   911
  message = options.message or raw_input(prompt).strip()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   912
  if not message:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   913
    ErrorExit("A non-empty message is required")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   914
  rpc_server = GetRpcServer(options)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   915
  form_fields = [("subject", message)]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   916
  if base:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   917
    form_fields.append(("base", base))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   918
  if options.issue:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   919
    form_fields.append(("issue", str(options.issue)))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   920
  if options.email:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   921
    form_fields.append(("user", options.email))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   922
  if options.reviewers:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   923
    for reviewer in options.reviewers.split(','):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   924
      if reviewer.count("@") != 1 or "." not in reviewer.split("@")[1]:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   925
        ErrorExit("Invalid email address: %s" % reviewer)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   926
    form_fields.append(("reviewers", options.reviewers))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   927
  if options.cc:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   928
    for cc in options.cc.split(','):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   929
      if cc.count("@") != 1 or "." not in cc.split("@")[1]:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   930
        ErrorExit("Invalid email address: %s" % cc)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   931
    form_fields.append(("cc", options.cc))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   932
  description = options.description
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   933
  if options.description_file:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   934
    if options.description:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   935
      ErrorExit("Can't specify description and description_file")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   936
    file = open(options.description_file, 'r')
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   937
    description = file.read()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   938
    file.close()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   939
  if description:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   940
    form_fields.append(("description", description))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   941
  # If we're uploading base files, don't send the email before the uploads, so
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   942
  # that it contains the file status.
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   943
  if options.send_mail and not options.local_base:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   944
    form_fields.append(("send_mail", "1"))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   945
  if options.local_base:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   946
    form_fields.append(("content_upload", "1"))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   947
  if len(data) > MAX_UPLOAD_SIZE:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   948
    print "Patch is large, so uploading file patches separately."
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   949
    files = []
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   950
    form_fields.append(("separate_patches", "1"))
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   951
  else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   952
    files = [("data", "data.diff", data)]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   953
  ctype, body = EncodeMultipartFormData(form_fields, files)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   954
  response_body = rpc_server.Send("/upload", body, content_type=ctype)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   955
  if options.local_base or not files:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   956
    lines = response_body.splitlines()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   957
    if len(lines) >= 2:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   958
      msg = lines[0]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   959
      patchset = lines[1].strip()
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   960
      patches = [x.split(" ", 1) for x in lines[2:]]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   961
    else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   962
      msg = response_body
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   963
  else:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   964
    msg = response_body
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   965
  StatusUpdate(msg)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   966
  if not response_body.startswith("Issue created.") and \
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   967
  not response_body.startswith("Issue updated."):
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   968
    sys.exit(0)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   969
  issue = msg[msg.rfind("/")+1:]
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   970
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   971
  if not files:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   972
    result = UploadSeparatePatches(issue, rpc_server, patchset, data, options)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   973
    if options.local_base:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   974
      patches = result
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   975
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   976
  if options.local_base:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   977
    vcs.UploadBaseFiles(issue, rpc_server, patches, patchset, options)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   978
    if options.send_mail:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   979
      rpc_server.Send("/" + issue + "/mail", payload="")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   980
  return issue
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   981
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   982
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   983
def main():
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   984
  try:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   985
    RealMain(sys.argv)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   986
  except KeyboardInterrupt:
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   987
    print
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   988
    StatusUpdate("Interrupted.")
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   989
    sys.exit(1)
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   990
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   991
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   992
if __name__ == "__main__":
cf9f7d81edec Pristine initial commit of upload.py script from
Todd Larsen <tlarsen@google.com>
parents:
diff changeset
   993
  main()