OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2007 Google Inc. | 3 # Copyright 2007 Google Inc. |
4 # | 4 # |
5 # Licensed under the Apache License, Version 2.0 (the "License"); | 5 # Licensed under the Apache License, Version 2.0 (the "License"); |
6 # you may not use this file except in compliance with the License. | 6 # you may not use this file except in compliance with the License. |
7 # You may obtain a copy of the License at | 7 # You may obtain a copy of the License at |
8 # | 8 # |
9 # http://www.apache.org/licenses/LICENSE-2.0 | 9 # http://www.apache.org/licenses/LICENSE-2.0 |
10 # | 10 # |
(...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
454 os.close(fd) | 454 os.close(fd) |
455 # Always chmod the cookie file | 455 # Always chmod the cookie file |
456 os.chmod(self.cookie_file, 0600) | 456 os.chmod(self.cookie_file, 0600) |
457 else: | 457 else: |
458 # Don't save cookies across runs of update.py. | 458 # Don't save cookies across runs of update.py. |
459 self.cookie_jar = cookielib.CookieJar() | 459 self.cookie_jar = cookielib.CookieJar() |
460 opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar)) | 460 opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar)) |
461 return opener | 461 return opener |
462 | 462 |
463 | 463 |
| 464 class CondensedHelpFormatter(optparse.IndentedHelpFormatter): |
| 465 """Frees more horizontal space by removing indentation from group |
| 466 options and collapsing arguments between short and long, e.g. |
| 467 '-o ARG, --opt=ARG' to -o --opt ARG""" |
| 468 |
| 469 def format_heading(self, heading): |
| 470 return "%s:\n" % heading |
| 471 |
| 472 def format_option(self, option): |
| 473 self.dedent() |
| 474 res = optparse.HelpFormatter.format_option(self, option) |
| 475 self.indent() |
| 476 return res |
| 477 |
| 478 def format_option_strings(self, option): |
| 479 self.set_long_opt_delimiter(" ") |
| 480 optstr = optparse.HelpFormatter.format_option_strings(self, option) |
| 481 optlist = optstr.split(", ") |
| 482 if len(optlist) > 1: |
| 483 if option.takes_value(): |
| 484 # strip METAVAR from all but the last option |
| 485 optlist = [x.split()[0] for x in optlist[:-1]] + optlist[-1:] |
| 486 optstr = " ".join(optlist) |
| 487 return optstr |
| 488 |
| 489 |
464 parser = optparse.OptionParser( | 490 parser = optparse.OptionParser( |
465 usage="%prog [options] [-- diff_options] [path...]") | 491 usage="%prog [options] [-- diff_options] [path...]", |
| 492 add_help_option=False, |
| 493 formatter=CondensedHelpFormatter() |
| 494 ) |
| 495 parser.add_option("-h", "--help", action="store_true", |
| 496 help="Show this help message and exit.") |
466 parser.add_option("-y", "--assume_yes", action="store_true", | 497 parser.add_option("-y", "--assume_yes", action="store_true", |
467 dest="assume_yes", default=False, | 498 dest="assume_yes", default=False, |
468 help="Assume that the answer to yes/no questions is 'yes'.") | 499 help="Assume that the answer to yes/no questions is 'yes'.") |
469 # Logging | 500 # Logging |
470 group = parser.add_option_group("Logging options") | 501 group = parser.add_option_group("Logging options") |
471 group.add_option("-q", "--quiet", action="store_const", const=0, | 502 group.add_option("-q", "--quiet", action="store_const", const=0, |
472 dest="verbose", help="Print errors only.") | 503 dest="verbose", help="Print errors only.") |
473 group.add_option("-v", "--verbose", action="store_const", const=2, | 504 group.add_option("-v", "--verbose", action="store_const", const=2, |
474 dest="verbose", default=1, | 505 dest="verbose", default=1, |
475 help="Print info level logs.") | 506 help="Print info level logs.") |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
521 # Upload options | 552 # Upload options |
522 group = parser.add_option_group("Patch options") | 553 group = parser.add_option_group("Patch options") |
523 group.add_option("-m", "--message", action="store", dest="message", | 554 group.add_option("-m", "--message", action="store", dest="message", |
524 metavar="MESSAGE", default=None, | 555 metavar="MESSAGE", default=None, |
525 help="A message to identify the patch. " | 556 help="A message to identify the patch. " |
526 "Will prompt if omitted.") | 557 "Will prompt if omitted.") |
527 group.add_option("-i", "--issue", type="int", action="store", | 558 group.add_option("-i", "--issue", type="int", action="store", |
528 metavar="ISSUE", default=None, | 559 metavar="ISSUE", default=None, |
529 help="Issue number to which to add. Defaults to new issue.") | 560 help="Issue number to which to add. Defaults to new issue.") |
530 group.add_option("--base_url", action="store", dest="base_url", default=None, | 561 group.add_option("--base_url", action="store", dest="base_url", default=None, |
531 help="Base repository URL (listed as \"Base URL\" when " | 562 help="Base URL path for files (listed as \"Base URL\" when " |
532 "viewing issue). If omitted, will be guessed automatically " | 563 "viewing issue). If omitted, will be guessed automatically " |
533 "for SVN repos and left blank for others.") | 564 "for SVN repos and left blank for others.") |
534 group.add_option("--download_base", action="store_true", | 565 group.add_option("--download_base", action="store_true", |
535 dest="download_base", default=False, | 566 dest="download_base", default=False, |
536 help="Base files will be downloaded by the server " | 567 help="Base files will be downloaded by the server " |
537 "(side-by-side diffs may not work on files with CRs).") | 568 "(side-by-side diffs may not work on files with CRs).") |
538 group.add_option("--rev", action="store", dest="revision", | 569 group.add_option("--rev", action="store", dest="revision", |
539 metavar="REV", default=None, | 570 metavar="REV", default=None, |
540 help="Base revision/branch/tree to diff against. Use " | 571 help="Base revision/branch/tree to diff against. Use " |
541 "rev1:rev2 range to review already committed changeset.") | 572 "rev1:rev2 range to review already committed changeset.") |
542 group.add_option("--send_mail", action="store_true", | 573 group.add_option("--send_mail", action="store_true", |
543 dest="send_mail", default=False, | 574 dest="send_mail", default=False, |
544 help="Send notification email to reviewers.") | 575 help="Send notification email to reviewers.") |
545 group.add_option("-p", "--send_patch", action="store_true", | 576 group.add_option("-p", "--send_patch", action="store_true", |
546 dest="send_patch", default=False, | 577 dest="send_patch", default=False, |
547 help="Send notification email to reviewers, with a diff of " | 578 help="Same as --send_mail, but include diff as an " |
548 "the changes included as an attachment instead of " | 579 "attachment, and prepend email subject with 'PATCH:'.") |
549 "inline. Also prepends 'PATCH:' to the email subject. " | |
550 "(implies --send_mail)") | |
551 group.add_option("--vcs", action="store", dest="vcs", | 580 group.add_option("--vcs", action="store", dest="vcs", |
552 metavar="VCS", default=None, | 581 metavar="VCS", default=None, |
553 help=("Version control system (optional, usually upload.py " | 582 help=("Version control system (optional, usually upload.py " |
554 "already guesses the right VCS).")) | 583 "already guesses the right VCS).")) |
555 group.add_option("--emulate_svn_auto_props", action="store_true", | 584 group.add_option("--emulate_svn_auto_props", action="store_true", |
556 dest="emulate_svn_auto_props", default=False, | 585 dest="emulate_svn_auto_props", default=False, |
557 help=("Emulate Subversion's auto properties feature.")) | 586 help=("Emulate Subversion's auto properties feature.")) |
558 # Perforce-specific | 587 # Perforce-specific |
559 group = parser.add_option_group("Perforce-specific options " | 588 group = parser.add_option_group("Perforce-specific options " |
560 "(overrides P4 environment variables)") | 589 "(overrides P4 environment variables)") |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
749 class VersionControlSystem(object): | 778 class VersionControlSystem(object): |
750 """Abstract base class providing an interface to the VCS.""" | 779 """Abstract base class providing an interface to the VCS.""" |
751 | 780 |
752 def __init__(self, options): | 781 def __init__(self, options): |
753 """Constructor. | 782 """Constructor. |
754 | 783 |
755 Args: | 784 Args: |
756 options: Command line options. | 785 options: Command line options. |
757 """ | 786 """ |
758 self.options = options | 787 self.options = options |
| 788 |
| 789 def GetGUID(self): |
| 790 """Return string to distinguish the repository from others, for example to |
| 791 query all opened review issues for it""" |
| 792 raise NotImplementedError( |
| 793 "abstract method -- subclass %s must override" % self.__class__) |
759 | 794 |
760 def PostProcessDiff(self, diff): | 795 def PostProcessDiff(self, diff): |
761 """Return the diff with any special post processing this VCS needs, e.g. | 796 """Return the diff with any special post processing this VCS needs, e.g. |
762 to include an svn-style "Index:".""" | 797 to include an svn-style "Index:".""" |
763 return diff | 798 return diff |
764 | 799 |
765 def GenerateDiff(self, args): | 800 def GenerateDiff(self, args): |
766 """Return the current diff as a string. | 801 """Return the current diff as a string. |
767 | 802 |
768 Args: | 803 Args: |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
903 self.rev_end = match.group(3) | 938 self.rev_end = match.group(3) |
904 else: | 939 else: |
905 self.rev_start = self.rev_end = None | 940 self.rev_start = self.rev_end = None |
906 # Cache output from "svn list -r REVNO dirname". | 941 # Cache output from "svn list -r REVNO dirname". |
907 # Keys: dirname, Values: 2-tuple (ouput for start rev and end rev). | 942 # Keys: dirname, Values: 2-tuple (ouput for start rev and end rev). |
908 self.svnls_cache = {} | 943 self.svnls_cache = {} |
909 # Base URL is required to fetch files deleted in an older revision. | 944 # Base URL is required to fetch files deleted in an older revision. |
910 # Result is cached to not guess it over and over again in GetBaseFile(). | 945 # Result is cached to not guess it over and over again in GetBaseFile(). |
911 required = self.options.download_base or self.options.revision is not None | 946 required = self.options.download_base or self.options.revision is not None |
912 self.svn_base = self._GuessBase(required) | 947 self.svn_base = self._GuessBase(required) |
| 948 |
| 949 def GetGUID(self): |
| 950 return self._GetInfo("Repository UUID") |
913 | 951 |
914 def GuessBase(self, required): | 952 def GuessBase(self, required): |
915 """Wrapper for _GuessBase.""" | 953 """Wrapper for _GuessBase.""" |
916 return self.svn_base | 954 return self.svn_base |
917 | 955 |
918 def _GuessBase(self, required): | 956 def _GuessBase(self, required): |
919 """Returns base URL for current diff. | 957 """Returns base URL for current diff. |
920 | 958 |
921 Args: | 959 Args: |
922 required: If true, exits if the url can't be guessed, otherwise None is | 960 required: If true, exits if the url can't be guessed, otherwise None is |
923 returned. | 961 returned. |
924 """ | 962 """ |
925 info = RunShell(["svn", "info"]) | 963 url = self._GetInfo("URL") |
926 for line in info.splitlines(): | 964 if url: |
927 if line.startswith("URL: "): | |
928 url = line.split()[1] | |
929 scheme, netloc, path, params, query, fragment = urlparse.urlparse(url) | 965 scheme, netloc, path, params, query, fragment = urlparse.urlparse(url) |
930 guess = "" | 966 guess = "" |
| 967 # TODO(anatoli) - repository specific hacks should be handled by server |
931 if netloc == "svn.python.org" and scheme == "svn+ssh": | 968 if netloc == "svn.python.org" and scheme == "svn+ssh": |
932 path = "projects" + path | 969 path = "projects" + path |
933 scheme = "http" | 970 scheme = "http" |
934 guess = "Python " | 971 guess = "Python " |
935 elif netloc.endswith(".googlecode.com"): | 972 elif netloc.endswith(".googlecode.com"): |
936 scheme = "http" | 973 scheme = "http" |
937 guess = "Google Code " | 974 guess = "Google Code " |
938 path = path + "/" | 975 path = path + "/" |
939 base = urlparse.urlunparse((scheme, netloc, path, params, | 976 base = urlparse.urlunparse((scheme, netloc, path, params, |
940 query, fragment)) | 977 query, fragment)) |
941 logging.info("Guessed %sbase = %s", guess, base) | 978 logging.info("Guessed %sbase = %s", guess, base) |
942 return base | 979 return base |
943 if required: | 980 if required: |
944 ErrorExit("Can't find URL in output from svn info") | 981 ErrorExit("Can't find URL in output from svn info") |
945 return None | 982 return None |
| 983 |
| 984 def _GetInfo(self, key): |
| 985 """Parses 'svn info' for current dir. Returns value for key or None""" |
| 986 for line in RunShell(["svn", "info"]).splitlines(): |
| 987 if line.startswith(key + ": "): |
| 988 return line.split(":", 1)[1].strip() |
946 | 989 |
947 def _EscapeFilename(self, filename): | 990 def _EscapeFilename(self, filename): |
948 """Escapes filename for SVN commands.""" | 991 """Escapes filename for SVN commands.""" |
949 if "@" in filename and not filename.endswith("@"): | 992 if "@" in filename and not filename.endswith("@"): |
950 filename = "%s@" % filename | 993 filename = "%s@" % filename |
951 return filename | 994 return filename |
952 | 995 |
953 def GenerateDiff(self, args): | 996 def GenerateDiff(self, args): |
954 cmd = ["svn", "diff"] | 997 cmd = ["svn", "diff"] |
955 if self.options.revision: | 998 if self.options.revision: |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1173 class GitVCS(VersionControlSystem): | 1216 class GitVCS(VersionControlSystem): |
1174 """Implementation of the VersionControlSystem interface for Git.""" | 1217 """Implementation of the VersionControlSystem interface for Git.""" |
1175 | 1218 |
1176 def __init__(self, options): | 1219 def __init__(self, options): |
1177 super(GitVCS, self).__init__(options) | 1220 super(GitVCS, self).__init__(options) |
1178 # Map of filename -> (hash before, hash after) of base file. | 1221 # Map of filename -> (hash before, hash after) of base file. |
1179 # Hashes for "no such file" are represented as None. | 1222 # Hashes for "no such file" are represented as None. |
1180 self.hashes = {} | 1223 self.hashes = {} |
1181 # Map of new filename -> old filename for renames. | 1224 # Map of new filename -> old filename for renames. |
1182 self.renames = {} | 1225 self.renames = {} |
| 1226 |
| 1227 def GetGUID(self): |
| 1228 revlist = RunShell("git rev-list --parents HEAD".split()).splitlines() |
| 1229 # 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 |
| 1231 # be done to figure out which HEAD is the 'most representative'. |
| 1232 for r in revlist: |
| 1233 if ' ' not in r: |
| 1234 return r |
1183 | 1235 |
1184 def PostProcessDiff(self, gitdiff): | 1236 def PostProcessDiff(self, gitdiff): |
1185 """Converts the diff output to include an svn-style "Index:" line as well | 1237 """Converts the diff output to include an svn-style "Index:" line as well |
1186 as record the hashes of the files, so we can upload them along with our | 1238 as record the hashes of the files, so we can upload them along with our |
1187 diff.""" | 1239 diff.""" |
1188 # Special used by git to indicate "no such content". | 1240 # Special used by git to indicate "no such content". |
1189 NULL_HASH = "0"*40 | 1241 NULL_HASH = "0"*40 |
1190 | 1242 |
1191 def IsFileNew(filename): | 1243 def IsFileNew(filename): |
1192 return filename in self.hashes and self.hashes[filename][0] is None | 1244 return filename in self.hashes and self.hashes[filename][0] is None |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1284 def GetBaseFile(self, filename): | 1336 def GetBaseFile(self, filename): |
1285 hash_before, hash_after = self.hashes.get(filename, (None,None)) | 1337 hash_before, hash_after = self.hashes.get(filename, (None,None)) |
1286 base_content = None | 1338 base_content = None |
1287 new_content = None | 1339 new_content = None |
1288 status = None | 1340 status = None |
1289 | 1341 |
1290 if filename in self.renames: | 1342 if filename in self.renames: |
1291 status = "A +" # Match svn attribute name for renames. | 1343 status = "A +" # Match svn attribute name for renames. |
1292 if filename not in self.hashes: | 1344 if filename not in self.hashes: |
1293 # If a rename doesn't change the content, we never get a hash. | 1345 # If a rename doesn't change the content, we never get a hash. |
1294 base_content = RunShell(["git", "show", "HEAD:" + filename]) | 1346 base_content = RunShell( |
| 1347 ["git", "show", "HEAD:" + filename], silent_ok=True) |
1295 elif not hash_before: | 1348 elif not hash_before: |
1296 status = "A" | 1349 status = "A" |
1297 base_content = "" | 1350 base_content = "" |
1298 elif not hash_after: | 1351 elif not hash_after: |
1299 status = "D" | 1352 status = "D" |
1300 else: | 1353 else: |
1301 status = "M" | 1354 status = "M" |
1302 | 1355 |
1303 is_binary = self.IsBinaryData(base_content) | 1356 is_binary = self.IsBinaryData(base_content) |
1304 is_image = self.IsImage(filename) | 1357 is_image = self.IsImage(filename) |
(...skipping 11 matching lines...) Expand all Loading... |
1316 | 1369 |
1317 return (base_content, new_content, is_binary, status) | 1370 return (base_content, new_content, is_binary, status) |
1318 | 1371 |
1319 | 1372 |
1320 class CVSVCS(VersionControlSystem): | 1373 class CVSVCS(VersionControlSystem): |
1321 """Implementation of the VersionControlSystem interface for CVS.""" | 1374 """Implementation of the VersionControlSystem interface for CVS.""" |
1322 | 1375 |
1323 def __init__(self, options): | 1376 def __init__(self, options): |
1324 super(CVSVCS, self).__init__(options) | 1377 super(CVSVCS, self).__init__(options) |
1325 | 1378 |
| 1379 def GetGUID(self): |
| 1380 """For now we don't know how to get repository ID for CVS""" |
| 1381 return |
| 1382 |
1326 def GetOriginalContent_(self, filename): | 1383 def GetOriginalContent_(self, filename): |
1327 RunShell(["cvs", "up", filename], silent_ok=True) | 1384 RunShell(["cvs", "up", filename], silent_ok=True) |
1328 # TODO need detect file content encoding | 1385 # TODO need detect file content encoding |
1329 content = open(filename).read() | 1386 content = open(filename).read() |
1330 return content.replace("\r\n", "\n") | 1387 return content.replace("\r\n", "\n") |
1331 | 1388 |
1332 def GetBaseFile(self, filename): | 1389 def GetBaseFile(self, filename): |
1333 base_content = None | 1390 base_content = None |
1334 new_content = None | 1391 new_content = None |
1335 status = "A" | 1392 status = "A" |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1391 self.repo_dir = os.path.normpath(repo_dir) | 1448 self.repo_dir = os.path.normpath(repo_dir) |
1392 # Compute the subdir | 1449 # Compute the subdir |
1393 cwd = os.path.normpath(os.getcwd()) | 1450 cwd = os.path.normpath(os.getcwd()) |
1394 assert cwd.startswith(self.repo_dir) | 1451 assert cwd.startswith(self.repo_dir) |
1395 self.subdir = cwd[len(self.repo_dir):].lstrip(r"\/") | 1452 self.subdir = cwd[len(self.repo_dir):].lstrip(r"\/") |
1396 if self.options.revision: | 1453 if self.options.revision: |
1397 self.base_rev = self.options.revision | 1454 self.base_rev = self.options.revision |
1398 else: | 1455 else: |
1399 self.base_rev = RunShell(["hg", "parent", "-q"]).split(':')[1].strip() | 1456 self.base_rev = RunShell(["hg", "parent", "-q"]).split(':')[1].strip() |
1400 | 1457 |
| 1458 def GetGUID(self): |
| 1459 # See chapter "Uniquely identifying a repository" |
| 1460 # http://hgbook.red-bean.com/read/customizing-the-output-of-mercurial.html |
| 1461 info = RunShell("hg log -r0 --template {node}".split()) |
| 1462 return info.strip() |
| 1463 |
1401 def _GetRelPath(self, filename): | 1464 def _GetRelPath(self, filename): |
1402 """Get relative path of a file according to the current directory, | 1465 """Get relative path of a file according to the current directory, |
1403 given its logical path in the repo.""" | 1466 given its logical path in the repo.""" |
1404 assert filename.startswith(self.subdir), (filename, self.subdir) | 1467 assert filename.startswith(self.subdir), (filename, self.subdir) |
1405 return filename[len(self.subdir):].lstrip(r"\/") | 1468 return filename[len(self.subdir):].lstrip(r"\/") |
1406 | 1469 |
1407 def GenerateDiff(self, extra_args): | 1470 def GenerateDiff(self, extra_args): |
1408 cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args | 1471 cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args |
1409 data = RunShell(cmd, silent_ok=True) | 1472 data = RunShell(cmd, silent_ok=True) |
1410 svndiff = [] | 1473 svndiff = [] |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1515 if not options.message: | 1578 if not options.message: |
1516 description = self.RunPerforceCommand(["describe", self.p4_changelist], | 1579 description = self.RunPerforceCommand(["describe", self.p4_changelist], |
1517 marshal_output=True) | 1580 marshal_output=True) |
1518 if description and "desc" in description: | 1581 if description and "desc" in description: |
1519 # Rietveld doesn't support multi-line descriptions | 1582 # Rietveld doesn't support multi-line descriptions |
1520 raw_message = description["desc"].strip() | 1583 raw_message = description["desc"].strip() |
1521 lines = raw_message.splitlines() | 1584 lines = raw_message.splitlines() |
1522 if len(lines): | 1585 if len(lines): |
1523 options.message = lines[0] | 1586 options.message = lines[0] |
1524 | 1587 |
| 1588 def GetGUID(self): |
| 1589 """For now we don't know how to get repository ID for Perforce""" |
| 1590 return |
| 1591 |
1525 def RunPerforceCommandWithReturnCode(self, extra_args, marshal_output=False, | 1592 def RunPerforceCommandWithReturnCode(self, extra_args, marshal_output=False, |
1526 universal_newlines=True): | 1593 universal_newlines=True): |
1527 args = ["p4"] | 1594 args = ["p4"] |
1528 if marshal_output: | 1595 if marshal_output: |
1529 # -G makes perforce format its output as marshalled python objects | 1596 # -G makes perforce format its output as marshalled python objects |
1530 args.extend(["-G"]) | 1597 args.extend(["-G"]) |
1531 if self.p4_port: | 1598 if self.p4_port: |
1532 args.extend(["-p", self.p4_port]) | 1599 args.extend(["-p", self.p4_port]) |
1533 if self.p4_client: | 1600 if self.p4_client: |
1534 args.extend(["-c", self.p4_client]) | 1601 args.extend(["-c", self.p4_client]) |
(...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2101 argv: Command line arguments. | 2168 argv: Command line arguments. |
2102 data: Diff contents. If None (default) the diff is generated by | 2169 data: Diff contents. If None (default) the diff is generated by |
2103 the VersionControlSystem implementation returned by GuessVCS(). | 2170 the VersionControlSystem implementation returned by GuessVCS(). |
2104 | 2171 |
2105 Returns: | 2172 Returns: |
2106 A 2-tuple (issue id, patchset id). | 2173 A 2-tuple (issue id, patchset id). |
2107 The patchset id is None if the base files are not uploaded by this | 2174 The patchset id is None if the base files are not uploaded by this |
2108 script (applies only to SVN checkouts). | 2175 script (applies only to SVN checkouts). |
2109 """ | 2176 """ |
2110 options, args = parser.parse_args(argv[1:]) | 2177 options, args = parser.parse_args(argv[1:]) |
| 2178 if options.help: |
| 2179 if options.verbose < 2: |
| 2180 # hide Perforce options |
| 2181 parser.epilog = "Use '--help -v' to show additional Perforce options." |
| 2182 parser.option_groups.remove(parser.get_option_group('--p4_port')) |
| 2183 parser.print_help() |
| 2184 sys.exit(0) |
| 2185 |
2111 global verbosity | 2186 global verbosity |
2112 verbosity = options.verbose | 2187 verbosity = options.verbose |
2113 if verbosity >= 3: | 2188 if verbosity >= 3: |
2114 logging.getLogger().setLevel(logging.DEBUG) | 2189 logging.getLogger().setLevel(logging.DEBUG) |
2115 elif verbosity >= 2: | 2190 elif verbosity >= 2: |
2116 logging.getLogger().setLevel(logging.INFO) | 2191 logging.getLogger().setLevel(logging.INFO) |
2117 | 2192 |
2118 vcs = GuessVCS(options) | 2193 vcs = GuessVCS(options) |
2119 | 2194 |
2120 base = options.base_url | 2195 base = options.base_url |
(...skipping 29 matching lines...) Expand all Loading... |
2150 prompt = "New issue subject: " | 2225 prompt = "New issue subject: " |
2151 message = options.message or raw_input(prompt).strip() | 2226 message = options.message or raw_input(prompt).strip() |
2152 if not message: | 2227 if not message: |
2153 ErrorExit("A non-empty message is required") | 2228 ErrorExit("A non-empty message is required") |
2154 rpc_server = GetRpcServer(options.server, | 2229 rpc_server = GetRpcServer(options.server, |
2155 options.email, | 2230 options.email, |
2156 options.host, | 2231 options.host, |
2157 options.save_cookies, | 2232 options.save_cookies, |
2158 options.account_type) | 2233 options.account_type) |
2159 form_fields = [("subject", message)] | 2234 form_fields = [("subject", message)] |
| 2235 |
| 2236 repo_guid = vcs.GetGUID() |
| 2237 if repo_guid: |
| 2238 form_fields.append(("repo_guid", repo_guid)) |
2160 if base: | 2239 if base: |
2161 b = urlparse.urlparse(base) | 2240 b = urlparse.urlparse(base) |
2162 username, netloc = urllib.splituser(b.netloc) | 2241 username, netloc = urllib.splituser(b.netloc) |
2163 if username: | 2242 if username: |
2164 logging.info("Removed username from base URL") | 2243 logging.info("Removed username from base URL") |
2165 base = urlparse.urlunparse((b.scheme, netloc, b.path, b.params, | 2244 base = urlparse.urlunparse((b.scheme, netloc, b.path, b.params, |
2166 b.query, b.fragment)) | 2245 b.query, b.fragment)) |
2167 form_fields.append(("base", base)) | 2246 form_fields.append(("base", base)) |
2168 if options.issue: | 2247 if options.issue: |
2169 form_fields.append(("issue", str(options.issue))) | 2248 form_fields.append(("issue", str(options.issue))) |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2256 os.environ['LC_ALL'] = 'C' | 2335 os.environ['LC_ALL'] = 'C' |
2257 RealMain(sys.argv) | 2336 RealMain(sys.argv) |
2258 except KeyboardInterrupt: | 2337 except KeyboardInterrupt: |
2259 print | 2338 print |
2260 StatusUpdate("Interrupted.") | 2339 StatusUpdate("Interrupted.") |
2261 sys.exit(1) | 2340 sys.exit(1) |
2262 | 2341 |
2263 | 2342 |
2264 if __name__ == "__main__": | 2343 if __name__ == "__main__": |
2265 main() | 2344 main() |
OLD | NEW |