OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # coding: utf-8 | 2 # coding: utf-8 |
3 # | 3 # |
4 # Copyright 2007 Google Inc. | 4 # Copyright 2007 Google Inc. |
5 # | 5 # |
6 # Licensed under the Apache License, Version 2.0 (the "License"); | 6 # Licensed under the Apache License, Version 2.0 (the "License"); |
7 # 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. |
8 # You may obtain a copy of the License at | 8 # You may obtain a copy of the License at |
9 # | 9 # |
10 # http://www.apache.org/licenses/LICENSE-2.0 | 10 # http://www.apache.org/licenses/LICENSE-2.0 |
(...skipping 926 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
937 new_content: For text files, this is empty. For binary files, this is | 937 new_content: For text files, this is empty. For binary files, this is |
938 the contents of the new file, since the diff output won't contain | 938 the contents of the new file, since the diff output won't contain |
939 information to reconstruct the current file. | 939 information to reconstruct the current file. |
940 is_binary: True iff the file is binary. | 940 is_binary: True iff the file is binary. |
941 status: The status of the file. | 941 status: The status of the file. |
942 """ | 942 """ |
943 | 943 |
944 raise NotImplementedError( | 944 raise NotImplementedError( |
945 "abstract method -- subclass %s must override" % self.__class__) | 945 "abstract method -- subclass %s must override" % self.__class__) |
946 | 946 |
947 | |
948 def GetBaseFiles(self, diff): | 947 def GetBaseFiles(self, diff): |
949 """Helper that calls GetBase file for each file in the patch. | 948 """Helper that calls GetBase file for each file in the patch. |
950 | 949 |
951 Returns: | 950 Returns: |
952 A dictionary that maps from filename to GetBaseFile's tuple. Filenames | 951 A dictionary that maps from filename to GetBaseFile's tuple. Filenames |
953 are retrieved based on lines that start with "Index:" or | 952 are retrieved based on lines that start with "Index:" or |
954 "Property changes on:". | 953 "Property changes on:". |
955 """ | 954 """ |
956 files = {} | 955 files = {} |
957 for line in diff.splitlines(True): | 956 for line in diff.splitlines(True): |
958 if line.startswith('Index:') or line.startswith('Property changes on:'): | 957 if line.startswith('Index:') or line.startswith('Property changes on:'): |
959 unused, filename = line.split(':', 1) | 958 unused, filename = line.split(':', 1) |
960 # On Windows if a file has property changes its filename uses '\' | 959 # On Windows if a file has property changes its filename uses '\' |
961 # instead of '/'. | 960 # instead of '/'. |
962 filename = filename.strip().replace('\\', '/') | 961 filename = filename.strip().replace('\\', '/') |
963 files[filename] = self.GetBaseFile(filename) | 962 files[filename] = self.GetBaseFile(filename) |
964 return files | 963 return files |
965 | 964 |
966 | |
967 def UploadBaseFiles(self, issue, rpc_server, patch_list, patchset, options, | 965 def UploadBaseFiles(self, issue, rpc_server, patch_list, patchset, options, |
968 files): | 966 files): |
969 """Uploads the base files (and if necessary, the current ones as well).""" | 967 """Uploads the base files (and if necessary, the current ones as well).""" |
970 | 968 |
971 def UploadFile(filename, file_id, content, is_binary, status, is_base): | 969 def UploadFile(filename, file_id, content, is_binary, status, is_base): |
972 """Uploads a file to the server.""" | 970 """Uploads a file to the server.""" |
973 file_too_large = False | 971 file_too_large = False |
974 if is_base: | 972 if is_base: |
975 type = "base" | 973 type = "base" |
976 else: | 974 else: |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1026 file_id, base_content, is_binary, status, True)) | 1024 file_id, base_content, is_binary, status, True)) |
1027 threads.append(t) | 1025 threads.append(t) |
1028 if new_content != None: | 1026 if new_content != None: |
1029 t = thread_pool.apply_async(UploadFile, args=(filename, | 1027 t = thread_pool.apply_async(UploadFile, args=(filename, |
1030 file_id, new_content, is_binary, status, False)) | 1028 file_id, new_content, is_binary, status, False)) |
1031 threads.append(t) | 1029 threads.append(t) |
1032 | 1030 |
1033 for t in threads: | 1031 for t in threads: |
1034 print t.get(timeout=60) | 1032 print t.get(timeout=60) |
1035 | 1033 |
1036 | |
1037 def IsImage(self, filename): | 1034 def IsImage(self, filename): |
1038 """Returns true if the filename has an image extension.""" | 1035 """Returns true if the filename has an image extension.""" |
1039 mimetype = mimetypes.guess_type(filename)[0] | 1036 mimetype = mimetypes.guess_type(filename)[0] |
1040 if not mimetype: | 1037 if not mimetype: |
1041 return False | 1038 return False |
1042 return (mimetype.startswith("image/") and | 1039 return (mimetype.startswith("image/") and |
1043 not mimetype.startswith("image/svg")) | 1040 not mimetype.startswith("image/svg")) |
1044 | 1041 |
1045 def IsBinaryData(self, data): | 1042 def IsBinaryData(self, data): |
1046 """Returns true if data contains a null byte.""" | 1043 """Returns true if data contains a null byte.""" |
1047 # Derived from how Mercurial's heuristic, see | 1044 # Derived from how Mercurial's heuristic, see |
1048 # http://selenic.com/hg/file/848a6658069e/mercurial/util.py#l229 | 1045 # http://selenic.com/hg/file/848a6658069e/mercurial/util.py#l229 |
1049 return bool(data and "\0" in data) | 1046 return bool(data and "\0" in data) |
1050 | 1047 |
| 1048 def GetMostRecentCommitSummary(self): |
| 1049 """Returns a one line summary of the current commit.""" |
| 1050 return "" |
| 1051 |
1051 | 1052 |
1052 class SubversionVCS(VersionControlSystem): | 1053 class SubversionVCS(VersionControlSystem): |
1053 """Implementation of the VersionControlSystem interface for Subversion.""" | 1054 """Implementation of the VersionControlSystem interface for Subversion.""" |
1054 | 1055 |
1055 def __init__(self, options): | 1056 def __init__(self, options): |
1056 super(SubversionVCS, self).__init__(options) | 1057 super(SubversionVCS, self).__init__(options) |
1057 if self.options.revision: | 1058 if self.options.revision: |
1058 match = re.match(r"(\d+)(:(\d+))?", self.options.revision) | 1059 match = re.match(r"(\d+)(:(\d+))?", self.options.revision) |
1059 if not match: | 1060 if not match: |
1060 ErrorExit("Invalid Subversion revision %s." % self.options.revision) | 1061 ErrorExit("Invalid Subversion revision %s." % self.options.revision) |
(...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1504 | 1505 |
1505 # Only include the "after" file if it's an image; otherwise it | 1506 # Only include the "after" file if it's an image; otherwise it |
1506 # it is reconstructed from the diff. | 1507 # it is reconstructed from the diff. |
1507 if hash_after: | 1508 if hash_after: |
1508 new_content = self.GetFileContent(hash_after) | 1509 new_content = self.GetFileContent(hash_after) |
1509 is_binary = is_binary or self.IsBinaryData(new_content) | 1510 is_binary = is_binary or self.IsBinaryData(new_content) |
1510 if not is_binary: | 1511 if not is_binary: |
1511 new_content = None | 1512 new_content = None |
1512 return (base_content, new_content, is_binary, status) | 1513 return (base_content, new_content, is_binary, status) |
1513 | 1514 |
| 1515 def GetMostRecentCommitSummary(self): |
| 1516 return RunShell(["git", "log", "-1", "--format=%s"], silent_ok=True).strip() |
| 1517 |
1514 | 1518 |
1515 class CVSVCS(VersionControlSystem): | 1519 class CVSVCS(VersionControlSystem): |
1516 """Implementation of the VersionControlSystem interface for CVS.""" | 1520 """Implementation of the VersionControlSystem interface for CVS.""" |
1517 | 1521 |
1518 def __init__(self, options): | 1522 def __init__(self, options): |
1519 super(CVSVCS, self).__init__(options) | 1523 super(CVSVCS, self).__init__(options) |
1520 | 1524 |
1521 def GetGUID(self): | 1525 def GetGUID(self): |
1522 """For now we don't know how to get repository ID for CVS""" | 1526 """For now we don't know how to get repository ID for CVS""" |
1523 return | 1527 return |
(...skipping 904 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2428 | 2432 |
2429 # Process --message, --title and --file. | 2433 # Process --message, --title and --file. |
2430 message = options.message or "" | 2434 message = options.message or "" |
2431 title = options.title or "" | 2435 title = options.title or "" |
2432 if options.file: | 2436 if options.file: |
2433 if options.message: | 2437 if options.message: |
2434 ErrorExit("Can't specify both message and message file options") | 2438 ErrorExit("Can't specify both message and message file options") |
2435 file = open(options.file, 'r') | 2439 file = open(options.file, 'r') |
2436 message = file.read() | 2440 message = file.read() |
2437 file.close() | 2441 file.close() |
2438 if options.issue: | 2442 title = title or message.split('\n', 1)[0].strip() |
2439 prompt = "Title describing this patch set: " | 2443 if not title: |
2440 else: | 2444 if options.issue: |
2441 prompt = "New issue subject: " | 2445 prompt = "Title describing this patch set" |
2442 title = ( | 2446 else: |
2443 title or message.split('\n', 1)[0].strip() or raw_input(prompt).strip()) | 2447 prompt = "New issue subject" |
| 2448 title_default = vcs.GetMostRecentCommitSummary() |
| 2449 if title_default: |
| 2450 prompt += " [%s]" % title_default |
| 2451 title = raw_input(prompt + ": ").strip() or title_default |
2444 if not title and not options.issue: | 2452 if not title and not options.issue: |
2445 ErrorExit("A non-empty title is required for a new issue") | 2453 ErrorExit("A non-empty title is required for a new issue") |
2446 # For existing issues, it's fine to give a patchset an empty name. Rietveld | 2454 # For existing issues, it's fine to give a patchset an empty name. Rietveld |
2447 # doesn't accept that so use a whitespace. | 2455 # doesn't accept that so use a whitespace. |
2448 title = title or " " | 2456 title = title or " " |
2449 if len(title) > 100: | 2457 if len(title) > 100: |
2450 title = title[:99] + '…' | 2458 title = title[:99] + '…' |
2451 if title and not options.issue: | 2459 if title and not options.issue: |
2452 message = message or title | 2460 message = message or title |
2453 | 2461 |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2535 print | 2543 print |
2536 StatusUpdate("Interrupted.") | 2544 StatusUpdate("Interrupted.") |
2537 sys.exit(1) | 2545 sys.exit(1) |
2538 except auth.AuthenticationError as e: | 2546 except auth.AuthenticationError as e: |
2539 print >> sys.stderr, e | 2547 print >> sys.stderr, e |
2540 sys.exit(1) | 2548 sys.exit(1) |
2541 | 2549 |
2542 | 2550 |
2543 if __name__ == "__main__": | 2551 if __name__ == "__main__": |
2544 main() | 2552 main() |
OLD | NEW |