Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(337)

Side by Side Diff: third_party/upload.py

Issue 9233057: Update upload.py @ fae51921ad9d (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Rebase against HEAD Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tests/git_cl_test.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # coding: utf-8
2 # 3 #
3 # Copyright 2007 Google Inc. 4 # Copyright 2007 Google Inc.
4 # 5 #
5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License. 7 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at 8 # You may obtain a copy of the License at
8 # 9 #
9 # http://www.apache.org/licenses/LICENSE-2.0 10 # http://www.apache.org/licenses/LICENSE-2.0
10 # 11 #
11 # Unless required by applicable law or agreed to in writing, software 12 # Unless required by applicable law or agreed to in writing, software
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 """Returns an OpenerDirector for making HTTP requests. 209 """Returns an OpenerDirector for making HTTP requests.
209 210
210 Returns: 211 Returns:
211 A urllib2.OpenerDirector object. 212 A urllib2.OpenerDirector object.
212 """ 213 """
213 raise NotImplementedError() 214 raise NotImplementedError()
214 215
215 def _CreateRequest(self, url, data=None): 216 def _CreateRequest(self, url, data=None):
216 """Creates a new urllib request.""" 217 """Creates a new urllib request."""
217 logging.debug("Creating request for: '%s' with payload:\n%s", url, data) 218 logging.debug("Creating request for: '%s' with payload:\n%s", url, data)
218 req = urllib2.Request(url, data=data) 219 req = urllib2.Request(url, data=data, headers={"Accept": "text/plain"})
219 if self.host_override: 220 if self.host_override:
220 req.add_header("Host", self.host_override) 221 req.add_header("Host", self.host_override)
221 for key, value in self.extra_headers.iteritems(): 222 for key, value in self.extra_headers.iteritems():
222 req.add_header(key, value) 223 req.add_header(key, value)
223 return req 224 return req
224 225
225 def _GetAuthToken(self, email, password): 226 def _GetAuthToken(self, email, password):
226 """Uses ClientLogin to authenticate the user, returning an auth token. 227 """Uses ClientLogin to authenticate the user, returning an auth token.
227 228
228 Args: 229 Args:
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 try: 393 try:
393 f = self.opener.open(req) 394 f = self.opener.open(req)
394 response = f.read() 395 response = f.read()
395 f.close() 396 f.close()
396 return response 397 return response
397 except urllib2.HTTPError, e: 398 except urllib2.HTTPError, e:
398 if tries > 3: 399 if tries > 3:
399 raise 400 raise
400 elif e.code == 401 or e.code == 302: 401 elif e.code == 401 or e.code == 302:
401 self._Authenticate() 402 self._Authenticate()
402 ## elif e.code >= 500 and e.code < 600:
403 ## # Server Error - try again.
404 ## continue
405 elif e.code == 301: 403 elif e.code == 301:
406 # Handle permanent redirect manually. 404 # Handle permanent redirect manually.
407 url = e.info()["location"] 405 url = e.info()["location"]
408 url_loc = urlparse.urlparse(url) 406 url_loc = urlparse.urlparse(url)
409 self.host = '%s://%s' % (url_loc[0], url_loc[1]) 407 self.host = '%s://%s' % (url_loc[0], url_loc[1])
408 elif e.code >= 500:
409 ErrorExit(e.read())
410 else: 410 else:
411 raise 411 raise
412 finally: 412 finally:
413 socket.setdefaulttimeout(old_timeout) 413 socket.setdefaulttimeout(old_timeout)
414 414
415 415
416 class HttpRpcServer(AbstractRpcServer): 416 class HttpRpcServer(AbstractRpcServer):
417 """Provides a simplified RPC-style interface for HTTP requests.""" 417 """Provides a simplified RPC-style interface for HTTP requests."""
418 418
419 def _Authenticate(self): 419 def _Authenticate(self):
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
525 dest="save_cookies", default=True, 525 dest="save_cookies", default=True,
526 help="Do not save authentication cookies to local disk.") 526 help="Do not save authentication cookies to local disk.")
527 group.add_option("--account_type", action="store", dest="account_type", 527 group.add_option("--account_type", action="store", dest="account_type",
528 metavar="TYPE", default=AUTH_ACCOUNT_TYPE, 528 metavar="TYPE", default=AUTH_ACCOUNT_TYPE,
529 choices=["GOOGLE", "HOSTED"], 529 choices=["GOOGLE", "HOSTED"],
530 help=("Override the default account type " 530 help=("Override the default account type "
531 "(defaults to '%default', " 531 "(defaults to '%default', "
532 "valid choices are 'GOOGLE' and 'HOSTED').")) 532 "valid choices are 'GOOGLE' and 'HOSTED')."))
533 # Issue 533 # Issue
534 group = parser.add_option_group("Issue options") 534 group = parser.add_option_group("Issue options")
535 group.add_option("-d", "--description", action="store", dest="description", 535 group.add_option("-t", "--title", action="store", dest="title",
536 metavar="DESCRIPTION", default=None, 536 help="New issue subject or new patch set title")
537 help="Optional description when creating an issue.") 537 group.add_option("-m", "--message", action="store", dest="message",
538 group.add_option("-f", "--description_file", action="store",
539 dest="description_file", metavar="DESCRIPTION_FILE",
540 default=None, 538 default=None,
541 help="Optional path of a file that contains " 539 help="New issue description or new patch set message")
542 "the description when creating an issue.") 540 group.add_option("-F", "--file", action="store", dest="file",
541 default=None, help="Read the message above from file.")
543 group.add_option("-r", "--reviewers", action="store", dest="reviewers", 542 group.add_option("-r", "--reviewers", action="store", dest="reviewers",
544 metavar="REVIEWERS", default=None, 543 metavar="REVIEWERS", default=None,
545 help="Add reviewers (comma separated email addresses).") 544 help="Add reviewers (comma separated email addresses).")
546 group.add_option("--cc", action="store", dest="cc", 545 group.add_option("--cc", action="store", dest="cc",
547 metavar="CC", default=None, 546 metavar="CC", default=None,
548 help="Add CC (comma separated email addresses).") 547 help="Add CC (comma separated email addresses).")
549 group.add_option("--private", action="store_true", dest="private", 548 group.add_option("--private", action="store_true", dest="private",
550 default=False, 549 default=False,
551 help="Make the issue restricted to reviewers and those CCed") 550 help="Make the issue restricted to reviewers and those CCed")
552 # Upload options 551 # Upload options
553 group = parser.add_option_group("Patch options") 552 group = parser.add_option_group("Patch options")
554 group.add_option("-m", "--message", action="store", dest="message",
555 metavar="MESSAGE", default=None,
556 help="A message to identify the patch. "
557 "Will prompt if omitted.")
558 group.add_option("-i", "--issue", type="int", action="store", 553 group.add_option("-i", "--issue", type="int", action="store",
559 metavar="ISSUE", default=None, 554 metavar="ISSUE", default=None,
560 help="Issue number to which to add. Defaults to new issue.") 555 help="Issue number to which to add. Defaults to new issue.")
561 group.add_option("--base_url", action="store", dest="base_url", default=None, 556 group.add_option("--base_url", action="store", dest="base_url", default=None,
562 help="Base URL path for files (listed as \"Base URL\" when " 557 help="Base URL path for files (listed as \"Base URL\" when "
563 "viewing issue). If omitted, will be guessed automatically " 558 "viewing issue). If omitted, will be guessed automatically "
564 "for SVN repos and left blank for others.") 559 "for SVN repos and left blank for others.")
565 group.add_option("--download_base", action="store_true", 560 group.add_option("--download_base", action="store_true",
566 dest="download_base", default=False, 561 dest="download_base", default=False,
567 help="Base files will be downloaded by the server " 562 help="Base files will be downloaded by the server "
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
778 class VersionControlSystem(object): 773 class VersionControlSystem(object):
779 """Abstract base class providing an interface to the VCS.""" 774 """Abstract base class providing an interface to the VCS."""
780 775
781 def __init__(self, options): 776 def __init__(self, options):
782 """Constructor. 777 """Constructor.
783 778
784 Args: 779 Args:
785 options: Command line options. 780 options: Command line options.
786 """ 781 """
787 self.options = options 782 self.options = options
788 783
789 def GetGUID(self): 784 def GetGUID(self):
790 """Return string to distinguish the repository from others, for example to 785 """Return string to distinguish the repository from others, for example to
791 query all opened review issues for it""" 786 query all opened review issues for it"""
792 raise NotImplementedError( 787 raise NotImplementedError(
793 "abstract method -- subclass %s must override" % self.__class__) 788 "abstract method -- subclass %s must override" % self.__class__)
794 789
795 def PostProcessDiff(self, diff): 790 def PostProcessDiff(self, diff):
796 """Return the diff with any special post processing this VCS needs, e.g. 791 """Return the diff with any special post processing this VCS needs, e.g.
797 to include an svn-style "Index:".""" 792 to include an svn-style "Index:"."""
798 return diff 793 return diff
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
938 self.rev_end = match.group(3) 933 self.rev_end = match.group(3)
939 else: 934 else:
940 self.rev_start = self.rev_end = None 935 self.rev_start = self.rev_end = None
941 # Cache output from "svn list -r REVNO dirname". 936 # Cache output from "svn list -r REVNO dirname".
942 # Keys: dirname, Values: 2-tuple (ouput for start rev and end rev). 937 # Keys: dirname, Values: 2-tuple (ouput for start rev and end rev).
943 self.svnls_cache = {} 938 self.svnls_cache = {}
944 # Base URL is required to fetch files deleted in an older revision. 939 # Base URL is required to fetch files deleted in an older revision.
945 # Result is cached to not guess it over and over again in GetBaseFile(). 940 # Result is cached to not guess it over and over again in GetBaseFile().
946 required = self.options.download_base or self.options.revision is not None 941 required = self.options.download_base or self.options.revision is not None
947 self.svn_base = self._GuessBase(required) 942 self.svn_base = self._GuessBase(required)
948 943
949 def GetGUID(self): 944 def GetGUID(self):
950 return self._GetInfo("Repository UUID") 945 return self._GetInfo("Repository UUID")
951 946
952 def GuessBase(self, required): 947 def GuessBase(self, required):
953 """Wrapper for _GuessBase.""" 948 """Wrapper for _GuessBase."""
954 return self.svn_base 949 return self.svn_base
955 950
956 def _GuessBase(self, required): 951 def _GuessBase(self, required):
957 """Returns base URL for current diff. 952 """Returns base URL for current diff.
958 953
(...skipping 14 matching lines...) Expand all
973 scheme = "http" 968 scheme = "http"
974 guess = "Google Code " 969 guess = "Google Code "
975 path = path + "/" 970 path = path + "/"
976 base = urlparse.urlunparse((scheme, netloc, path, params, 971 base = urlparse.urlunparse((scheme, netloc, path, params,
977 query, fragment)) 972 query, fragment))
978 logging.info("Guessed %sbase = %s", guess, base) 973 logging.info("Guessed %sbase = %s", guess, base)
979 return base 974 return base
980 if required: 975 if required:
981 ErrorExit("Can't find URL in output from svn info") 976 ErrorExit("Can't find URL in output from svn info")
982 return None 977 return None
983 978
984 def _GetInfo(self, key): 979 def _GetInfo(self, key):
985 """Parses 'svn info' for current dir. Returns value for key or None""" 980 """Parses 'svn info' for current dir. Returns value for key or None"""
986 for line in RunShell(["svn", "info"]).splitlines(): 981 for line in RunShell(["svn", "info"]).splitlines():
987 if line.startswith(key + ": "): 982 if line.startswith(key + ": "):
988 return line.split(":", 1)[1].strip() 983 return line.split(":", 1)[1].strip()
989 984
990 def _EscapeFilename(self, filename): 985 def _EscapeFilename(self, filename):
991 """Escapes filename for SVN commands.""" 986 """Escapes filename for SVN commands."""
992 if "@" in filename and not filename.endswith("@"): 987 if "@" in filename and not filename.endswith("@"):
993 filename = "%s@" % filename 988 filename = "%s@" % filename
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
1216 class GitVCS(VersionControlSystem): 1211 class GitVCS(VersionControlSystem):
1217 """Implementation of the VersionControlSystem interface for Git.""" 1212 """Implementation of the VersionControlSystem interface for Git."""
1218 1213
1219 def __init__(self, options): 1214 def __init__(self, options):
1220 super(GitVCS, self).__init__(options) 1215 super(GitVCS, self).__init__(options)
1221 # Map of filename -> (hash before, hash after) of base file. 1216 # Map of filename -> (hash before, hash after) of base file.
1222 # Hashes for "no such file" are represented as None. 1217 # Hashes for "no such file" are represented as None.
1223 self.hashes = {} 1218 self.hashes = {}
1224 # Map of new filename -> old filename for renames. 1219 # Map of new filename -> old filename for renames.
1225 self.renames = {} 1220 self.renames = {}
1226 1221
1227 def GetGUID(self): 1222 def GetGUID(self):
1228 revlist = RunShell("git rev-list --parents HEAD".split()).splitlines() 1223 revlist = RunShell("git rev-list --parents HEAD".split()).splitlines()
1229 # M-A: Return the 1st root hash, there could be multiple when a 1224 # M-A: Return the 1st root hash, there could be multiple when a
1230 # subtree is merged. In that case, more analysis would need to 1225 # subtree is merged. In that case, more analysis would need to
1231 # be done to figure out which HEAD is the 'most representative'. 1226 # be done to figure out which HEAD is the 'most representative'.
1232 for r in revlist: 1227 for r in revlist:
1233 if ' ' not in r: 1228 if ' ' not in r:
1234 return r 1229 return r
1235 1230
1236 def PostProcessDiff(self, gitdiff): 1231 def PostProcessDiff(self, gitdiff):
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
1303 # this by overriding the environment (but there is still a problem if the 1298 # this by overriding the environment (but there is still a problem if the
1304 # git config key "diff.external" is used). 1299 # git config key "diff.external" is used).
1305 env = os.environ.copy() 1300 env = os.environ.copy()
1306 if 'GIT_EXTERNAL_DIFF' in env: del env['GIT_EXTERNAL_DIFF'] 1301 if 'GIT_EXTERNAL_DIFF' in env: del env['GIT_EXTERNAL_DIFF']
1307 # -M/-C will not print the diff for the deleted file when a file is renamed. 1302 # -M/-C will not print the diff for the deleted file when a file is renamed.
1308 # This is confusing because the original file will not be shown on the 1303 # This is confusing because the original file will not be shown on the
1309 # review when a file is renamed. So first get the diff of all deleted files, 1304 # review when a file is renamed. So first get the diff of all deleted files,
1310 # then the diff of everything except deleted files with rename and copy 1305 # then the diff of everything except deleted files with rename and copy
1311 # support enabled. 1306 # support enabled.
1312 cmd = [ 1307 cmd = [
1313 "git", "diff", "--no-ext-diff", "--full-index", "--ignore-submodules" 1308 "git", "diff", "--no-color", "--no-ext-diff", "--full-index", "--ignore- submodules"
1314 ] 1309 ]
1315 diff = RunShell(cmd + ["--diff-filter=D"] + extra_args, env=env, 1310 diff = RunShell(cmd + ["--diff-filter=D"] + extra_args, env=env,
1316 silent_ok=True) 1311 silent_ok=True)
1317 diff += RunShell(cmd + ["-C", "--diff-filter=ACMRT"] + extra_args, env=env, 1312 diff += RunShell(cmd + ["-C", "--diff-filter=ACMRT"] + extra_args, env=env,
1318 silent_ok=True) 1313 silent_ok=True)
1319 if not diff: 1314 if not diff:
1320 ErrorExit("No output from %s" % (cmd + extra_args)) 1315 ErrorExit("No output from %s" % (cmd + extra_args))
1321 return diff 1316 return diff
1322 1317
1323 def GetUnknownFiles(self): 1318 def GetUnknownFiles(self):
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
1457 1452
1458 def GetGUID(self): 1453 def GetGUID(self):
1459 # See chapter "Uniquely identifying a repository" 1454 # See chapter "Uniquely identifying a repository"
1460 # http://hgbook.red-bean.com/read/customizing-the-output-of-mercurial.html 1455 # http://hgbook.red-bean.com/read/customizing-the-output-of-mercurial.html
1461 info = RunShell("hg log -r0 --template {node}".split()) 1456 info = RunShell("hg log -r0 --template {node}".split())
1462 return info.strip() 1457 return info.strip()
1463 1458
1464 def _GetRelPath(self, filename): 1459 def _GetRelPath(self, filename):
1465 """Get relative path of a file according to the current directory, 1460 """Get relative path of a file according to the current directory,
1466 given its logical path in the repo.""" 1461 given its logical path in the repo."""
1467 assert filename.startswith(self.subdir), (filename, self.subdir) 1462 absname = os.path.join(self.repo_dir, filename)
1468 return filename[len(self.subdir):].lstrip(r"\/") 1463 return os.path.relpath(absname)
1469 1464
1470 def GenerateDiff(self, extra_args): 1465 def GenerateDiff(self, extra_args):
1471 cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args 1466 cmd = [
1467 "hg", "diff", "--color", "never", "--git", "-r", self.base_rev
1468 ] + extra_args
1472 data = RunShell(cmd, silent_ok=True) 1469 data = RunShell(cmd, silent_ok=True)
1473 svndiff = [] 1470 svndiff = []
1474 filecount = 0 1471 filecount = 0
1475 for line in data.splitlines(): 1472 for line in data.splitlines():
1476 m = re.match("diff --git a/(\S+) b/(\S+)", line) 1473 m = re.match("diff --git a/(\S+) b/(\S+)", line)
1477 if m: 1474 if m:
1478 # Modify line to make it look like as it comes from svn diff. 1475 # Modify line to make it look like as it comes from svn diff.
1479 # With this modification no changes on the server side are required 1476 # With this modification no changes on the server side are required
1480 # to make upload.py work with Mercurial repos. 1477 # to make upload.py work with Mercurial repos.
1481 # NOTE: for proper handling of moved/copied files, we have to use 1478 # NOTE: for proper handling of moved/copied files, we have to use
1482 # the second filename. 1479 # the second filename.
1483 filename = m.group(2) 1480 filename = m.group(2)
1484 svndiff.append("Index: %s" % filename) 1481 svndiff.append("Index: %s" % filename)
1485 svndiff.append("=" * 67) 1482 svndiff.append("=" * 67)
1486 filecount += 1 1483 filecount += 1
1487 logging.info(line) 1484 logging.info(line)
1488 else: 1485 else:
1489 svndiff.append(line) 1486 svndiff.append(line)
1490 if not filecount: 1487 if not filecount:
1491 ErrorExit("No valid patches found in output from hg diff") 1488 ErrorExit("No valid patches found in output from hg diff")
1492 return "\n".join(svndiff) + "\n" 1489 return "\n".join(svndiff) + "\n"
1493 1490
1494 def GetUnknownFiles(self): 1491 def GetUnknownFiles(self):
1495 """Return a list of files unknown to the VCS.""" 1492 """Return a list of files unknown to the VCS."""
1496 args = [] 1493 args = []
1497 status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."], 1494 status = RunShell(
1495 ["hg", "status", "--color", "never", "--rev", self.base_rev, "-u", "."],
1498 silent_ok=True) 1496 silent_ok=True)
1499 unknown_files = [] 1497 unknown_files = []
1500 for line in status.splitlines(): 1498 for line in status.splitlines():
1501 st, fn = line.split(" ", 1) 1499 st, fn = line.split(" ", 1)
1502 if st == "?": 1500 if st == "?":
1503 unknown_files.append(fn) 1501 unknown_files.append(fn)
1504 return unknown_files 1502 return unknown_files
1505 1503
1506 def GetBaseFile(self, filename): 1504 def GetBaseFile(self, filename):
1507 # "hg status" and "hg cat" both take a path relative to the current subdir 1505 # "hg status" and "hg cat" both take a path relative to the current subdir,
1508 # rather than to the repo root, but "hg diff" has given us the full path 1506 # but "hg diff" has given us the path relative to the repo root.
1509 # to the repo root.
1510 base_content = "" 1507 base_content = ""
1511 new_content = None 1508 new_content = None
1512 is_binary = False 1509 is_binary = False
1513 oldrelpath = relpath = self._GetRelPath(filename) 1510 oldrelpath = relpath = self._GetRelPath(filename)
1514 # "hg status -C" returns two lines for moved/copied files, one otherwise 1511 # "hg status -C" returns two lines for moved/copied files, one otherwise
1515 out = RunShell(["hg", "status", "-C", "--rev", self.base_rev, relpath]) 1512 out = RunShell(
1513 [ "hg", "status", "--color", "never", "-C", "--rev", self.base_rev,
1514 relpath])
1516 out = out.splitlines() 1515 out = out.splitlines()
1517 # HACK: strip error message about missing file/directory if it isn't in 1516 # HACK: strip error message about missing file/directory if it isn't in
1518 # the working copy 1517 # the working copy
1519 if out[0].startswith('%s: ' % relpath): 1518 if out[0].startswith('%s: ' % relpath):
1520 out = out[1:] 1519 out = out[1:]
1521 status, _ = out[0].split(' ', 1) 1520 status, _ = out[0].split(' ', 1)
1522 if len(out) > 1 and status == "A": 1521 if len(out) > 1 and status == "A":
1523 # Moved/copied => considered as modified, use old filename to 1522 # Moved/copied => considered as modified, use old filename to
1524 # retrieve base contents 1523 # retrieve base contents
1525 oldrelpath = out[1].strip() 1524 oldrelpath = out[1].strip()
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1568 ErrorExit("A changelist id is required") 1567 ErrorExit("A changelist id is required")
1569 if (options.revision): 1568 if (options.revision):
1570 ErrorExit("--rev is not supported for perforce") 1569 ErrorExit("--rev is not supported for perforce")
1571 1570
1572 self.p4_port = options.p4_port 1571 self.p4_port = options.p4_port
1573 self.p4_client = options.p4_client 1572 self.p4_client = options.p4_client
1574 self.p4_user = options.p4_user 1573 self.p4_user = options.p4_user
1575 1574
1576 ConfirmLogin() 1575 ConfirmLogin()
1577 1576
1578 if not options.message: 1577 if not options.title:
1579 description = self.RunPerforceCommand(["describe", self.p4_changelist], 1578 description = self.RunPerforceCommand(["describe", self.p4_changelist],
1580 marshal_output=True) 1579 marshal_output=True)
1581 if description and "desc" in description: 1580 if description and "desc" in description:
1582 # Rietveld doesn't support multi-line descriptions 1581 # Rietveld doesn't support multi-line descriptions
1583 raw_message = description["desc"].strip() 1582 raw_title = description["desc"].strip()
1584 lines = raw_message.splitlines() 1583 lines = raw_title.splitlines()
1585 if len(lines): 1584 if len(lines):
1586 options.message = lines[0] 1585 options.title = lines[0]
1587 1586
1588 def GetGUID(self): 1587 def GetGUID(self):
1589 """For now we don't know how to get repository ID for Perforce""" 1588 """For now we don't know how to get repository ID for Perforce"""
1590 return 1589 return
1591 1590
1592 def RunPerforceCommandWithReturnCode(self, extra_args, marshal_output=False, 1591 def RunPerforceCommandWithReturnCode(self, extra_args, marshal_output=False,
1593 universal_newlines=True): 1592 universal_newlines=True):
1594 args = ["p4"] 1593 args = ["p4"]
1595 if marshal_output: 1594 if marshal_output:
1596 # -G makes perforce format its output as marshalled python objects 1595 # -G makes perforce format its output as marshalled python objects
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after
1967 if errcode != errno.ENOENT: # command not found code 1966 if errcode != errno.ENOENT: # command not found code
1968 raise 1967 raise
1969 1968
1970 # Mercurial has a command to get the base directory of a repository 1969 # Mercurial has a command to get the base directory of a repository
1971 # Try running it, but don't die if we don't have hg installed. 1970 # Try running it, but don't die if we don't have hg installed.
1972 # NOTE: we try Mercurial first as it can sit on top of an SVN working copy. 1971 # NOTE: we try Mercurial first as it can sit on top of an SVN working copy.
1973 res = RunDetectCommand(VCS_MERCURIAL, ["hg", "root"]) 1972 res = RunDetectCommand(VCS_MERCURIAL, ["hg", "root"])
1974 if res != None: 1973 if res != None:
1975 return res 1974 return res
1976 1975
1977 # Subversion has a .svn in all working directories. 1976 # Subversion from 1.7 has a single centralized .svn folder
1978 if os.path.isdir('.svn'): 1977 # ( see http://subversion.apache.org/docs/release-notes/1.7.html#wc-ng )
1979 logging.info("Guessed VCS = Subversion") 1978 # That's why we use 'svn info' instead of checking for .svn dir
1980 return (VCS_SUBVERSION, None) 1979 res = RunDetectCommand(VCS_SUBVERSION, ["svn", "info"])
1980 if res != None:
1981 return res
1981 1982
1982 # Git has a command to test if you're in a git tree. 1983 # Git has a command to test if you're in a git tree.
1983 # Try running it, but don't die if we don't have git installed. 1984 # Try running it, but don't die if we don't have git installed.
1984 res = RunDetectCommand(VCS_GIT, ["git", "rev-parse", 1985 res = RunDetectCommand(VCS_GIT, ["git", "rev-parse",
1985 "--is-inside-work-tree"]) 1986 "--is-inside-work-tree"])
1986 if res != None: 1987 if res != None:
1987 return res 1988 return res
1988 1989
1989 # detect CVS repos use `cvs status && $? == 0` rules 1990 # detect CVS repos use `cvs status && $? == 0` rules
1990 res = RunDetectCommand(VCS_CVS, ["cvs", "status"]) 1991 res = RunDetectCommand(VCS_CVS, ["cvs", "status"])
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
2212 if data is None: 2213 if data is None:
2213 data = vcs.GenerateDiff(args) 2214 data = vcs.GenerateDiff(args)
2214 data = vcs.PostProcessDiff(data) 2215 data = vcs.PostProcessDiff(data)
2215 if options.print_diffs: 2216 if options.print_diffs:
2216 print "Rietveld diff start:*****" 2217 print "Rietveld diff start:*****"
2217 print data 2218 print data
2218 print "Rietveld diff end:*****" 2219 print "Rietveld diff end:*****"
2219 files = vcs.GetBaseFiles(data) 2220 files = vcs.GetBaseFiles(data)
2220 if verbosity >= 1: 2221 if verbosity >= 1:
2221 print "Upload server:", options.server, "(change with -s/--server)" 2222 print "Upload server:", options.server, "(change with -s/--server)"
2222 if options.issue:
2223 prompt = "Message describing this patch set: "
2224 else:
2225 prompt = "New issue subject: "
2226 message = options.message or raw_input(prompt).strip()
2227 if not message:
2228 ErrorExit("A non-empty message is required")
2229 rpc_server = GetRpcServer(options.server, 2223 rpc_server = GetRpcServer(options.server,
2230 options.email, 2224 options.email,
2231 options.host, 2225 options.host,
2232 options.save_cookies, 2226 options.save_cookies,
2233 options.account_type) 2227 options.account_type)
2234 form_fields = [("subject", message)] 2228 form_fields = []
2235 2229
2236 repo_guid = vcs.GetGUID() 2230 repo_guid = vcs.GetGUID()
2237 if repo_guid: 2231 if repo_guid:
2238 form_fields.append(("repo_guid", repo_guid)) 2232 form_fields.append(("repo_guid", repo_guid))
2239 if base: 2233 if base:
2240 b = urlparse.urlparse(base) 2234 b = urlparse.urlparse(base)
2241 username, netloc = urllib.splituser(b.netloc) 2235 username, netloc = urllib.splituser(b.netloc)
2242 if username: 2236 if username:
2243 logging.info("Removed username from base URL") 2237 logging.info("Removed username from base URL")
2244 base = urlparse.urlunparse((b.scheme, netloc, b.path, b.params, 2238 base = urlparse.urlunparse((b.scheme, netloc, b.path, b.params,
2245 b.query, b.fragment)) 2239 b.query, b.fragment))
2246 form_fields.append(("base", base)) 2240 form_fields.append(("base", base))
2247 if options.issue: 2241 if options.issue:
2248 form_fields.append(("issue", str(options.issue))) 2242 form_fields.append(("issue", str(options.issue)))
2249 if options.email: 2243 if options.email:
2250 form_fields.append(("user", options.email)) 2244 form_fields.append(("user", options.email))
2251 if options.reviewers: 2245 if options.reviewers:
2252 for reviewer in options.reviewers.split(','): 2246 for reviewer in options.reviewers.split(','):
2253 CheckReviewer(reviewer) 2247 CheckReviewer(reviewer)
2254 form_fields.append(("reviewers", options.reviewers)) 2248 form_fields.append(("reviewers", options.reviewers))
2255 if options.cc: 2249 if options.cc:
2256 for cc in options.cc.split(','): 2250 for cc in options.cc.split(','):
2257 CheckReviewer(cc) 2251 CheckReviewer(cc)
2258 form_fields.append(("cc", options.cc)) 2252 form_fields.append(("cc", options.cc))
2259 description = options.description 2253
2260 if options.description_file: 2254 # Process --message, --title and --file.
2261 if options.description: 2255 message = options.message or ""
2262 ErrorExit("Can't specify description and description_file") 2256 title = options.title or ""
2263 file = open(options.description_file, 'r') 2257 if options.file:
2264 description = file.read() 2258 if options.message:
2259 ErrorExit("Can't specify both message and message file options")
2260 file = open(options.file, 'r')
2261 message = file.read()
2265 file.close() 2262 file.close()
2266 if description: 2263 if options.issue:
2267 form_fields.append(("description", description)) 2264 prompt = "Title describing this patch set: "
2265 else:
2266 prompt = "New issue subject: "
2267 title = (
2268 title or message.split('\n', 1)[0].strip() or raw_input(prompt).strip())
2269 if not title and not options.issue:
2270 ErrorExit("A non-empty title is required for a new issue")
2271 # For existing issues, it's fine to give a patchset an empty name. Rietveld
2272 # doesn't accept that so use a whitespace.
2273 title = title or " "
2274 if len(title) > 100:
2275 title = title[:99] + '…'
2276 if title and not options.issue:
2277 message = message or title
2278
2279 form_fields.append(("subject", title))
2280 if message:
2281 if not options.issue:
2282 form_fields.append(("description", message))
2283 else:
2284 # TODO: [ ] Use /<issue>/publish to add a comment.
2285 pass
2286
2268 # Send a hash of all the base file so the server can determine if a copy 2287 # Send a hash of all the base file so the server can determine if a copy
2269 # already exists in an earlier patchset. 2288 # already exists in an earlier patchset.
2270 base_hashes = "" 2289 base_hashes = ""
2271 for file, info in files.iteritems(): 2290 for file, info in files.iteritems():
2272 if not info[0] is None: 2291 if not info[0] is None:
2273 checksum = md5(info[0]).hexdigest() 2292 checksum = md5(info[0]).hexdigest()
2274 if base_hashes: 2293 if base_hashes:
2275 base_hashes += "|" 2294 base_hashes += "|"
2276 base_hashes += checksum + ":" + file 2295 base_hashes += checksum + ":" + file
2277 form_fields.append(("base_hashes", base_hashes)) 2296 form_fields.append(("base_hashes", base_hashes))
2278 if options.private: 2297 if options.private:
2279 if options.issue: 2298 if options.issue:
2280 print "Warning: Private flag ignored when updating an existing issue." 2299 print "Warning: Private flag ignored when updating an existing issue."
2281 else: 2300 else:
2282 form_fields.append(("private", "1")) 2301 form_fields.append(("private", "1"))
2283 if options.send_patch: 2302 if options.send_patch:
2284 options.send_mail = True 2303 options.send_mail = True
2285 # If we're uploading base files, don't send the email before the uploads, so
2286 # that it contains the file status.
2287 if options.send_mail and options.download_base:
2288 form_fields.append(("send_mail", "1"))
2289 if not options.download_base: 2304 if not options.download_base:
2290 form_fields.append(("content_upload", "1")) 2305 form_fields.append(("content_upload", "1"))
2291 if len(data) > MAX_UPLOAD_SIZE: 2306 if len(data) > MAX_UPLOAD_SIZE:
2292 print "Patch is large, so uploading file patches separately." 2307 print "Patch is large, so uploading file patches separately."
2293 uploaded_diff_file = [] 2308 uploaded_diff_file = []
2294 form_fields.append(("separate_patches", "1")) 2309 form_fields.append(("separate_patches", "1"))
2295 else: 2310 else:
2296 uploaded_diff_file = [("data", "data.diff", data)] 2311 uploaded_diff_file = [("data", "data.diff", data)]
2297 ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file) 2312 ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file)
2298 response_body = rpc_server.Send("/upload", body, content_type=ctype) 2313 response_body = rpc_server.Send("/upload", body, content_type=ctype)
(...skipping 14 matching lines...) Expand all
2313 sys.exit(0) 2328 sys.exit(0)
2314 issue = msg[msg.rfind("/")+1:] 2329 issue = msg[msg.rfind("/")+1:]
2315 2330
2316 if not uploaded_diff_file: 2331 if not uploaded_diff_file:
2317 result = UploadSeparatePatches(issue, rpc_server, patchset, data, options) 2332 result = UploadSeparatePatches(issue, rpc_server, patchset, data, options)
2318 if not options.download_base: 2333 if not options.download_base:
2319 patches = result 2334 patches = result
2320 2335
2321 if not options.download_base: 2336 if not options.download_base:
2322 vcs.UploadBaseFiles(issue, rpc_server, patches, patchset, options, files) 2337 vcs.UploadBaseFiles(issue, rpc_server, patches, patchset, options, files)
2323 if options.send_mail: 2338
2324 payload = "" 2339 payload = {} # payload for final request
2325 if options.send_patch: 2340 if options.send_mail:
2326 payload=urllib.urlencode({"attach_patch": "yes"}) 2341 payload["send_mail"] = "yes"
2327 rpc_server.Send("/" + issue + "/mail", payload=payload) 2342 if options.send_patch:
2343 payload["attach_patch"] = "yes"
2344 payload = urllib.urlencode(payload)
2345 rpc_server.Send("/" + issue + "/upload_complete/" + (patchset or ""),
2346 payload=payload)
2328 return issue, patchset 2347 return issue, patchset
2329 2348
2330 2349
2331 def main(): 2350 def main():
2332 try: 2351 try:
2333 logging.basicConfig(format=("%(asctime).19s %(levelname)s %(filename)s:" 2352 logging.basicConfig(format=("%(asctime).19s %(levelname)s %(filename)s:"
2334 "%(lineno)s %(message)s ")) 2353 "%(lineno)s %(message)s "))
2335 os.environ['LC_ALL'] = 'C' 2354 os.environ['LC_ALL'] = 'C'
2336 RealMain(sys.argv) 2355 RealMain(sys.argv)
2337 except KeyboardInterrupt: 2356 except KeyboardInterrupt:
2338 print 2357 print
2339 StatusUpdate("Interrupted.") 2358 StatusUpdate("Interrupted.")
2340 sys.exit(1) 2359 sys.exit(1)
2341 2360
2342 2361
2343 if __name__ == "__main__": 2362 if __name__ == "__main__":
2344 main() 2363 main()
OLDNEW
« no previous file with comments | « tests/git_cl_test.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698