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

Side by Side Diff: gcl.py

Issue 100095: Convert gcl.GetSVNFileInfo() to xml format. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools/
Patch Set: '' Created 11 years, 8 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 | « no previous file | revert.py » ('j') | 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/python 1 #!/usr/bin/python
2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 # 5 #
6 # Wrapper script around Rietveld's upload.py that groups files into 6 # Wrapper script around Rietveld's upload.py that groups files into
7 # changelists. 7 # changelists.
8 8
9 import getpass 9 import getpass
10 import os 10 import os
11 import random 11 import random
12 import re 12 import re
13 import string 13 import string
14 import subprocess 14 import subprocess
15 import sys 15 import sys
16 import tempfile 16 import tempfile
17 import upload 17 import upload
18 import urllib2 18 import urllib2
19 import xml.dom.minidom
19 20
20 21
21 __version__ = '1.0' 22 __version__ = '1.0'
22 23
23 24
24 CODEREVIEW_SETTINGS = { 25 CODEREVIEW_SETTINGS = {
25 # Default values. 26 # Default values.
26 "CODE_REVIEW_SERVER": "codereview.chromium.org", 27 "CODE_REVIEW_SERVER": "codereview.chromium.org",
27 "CC_LIST": "chromium-reviews@googlegroups.com", 28 "CC_LIST": "chromium-reviews@googlegroups.com",
28 "VIEW_VC": "http://src.chromium.org/viewvc/chrome?view=rev&revision=", 29 "VIEW_VC": "http://src.chromium.org/viewvc/chrome?view=rev&revision=",
(...skipping 11 matching lines...) Expand all
40 # Filename where we store repository specific information for gcl. 41 # Filename where we store repository specific information for gcl.
41 CODEREVIEW_SETTINGS_FILE = "codereview.settings" 42 CODEREVIEW_SETTINGS_FILE = "codereview.settings"
42 43
43 # Warning message when the change appears to be missing tests. 44 # Warning message when the change appears to be missing tests.
44 MISSING_TEST_MSG = "Change contains new or modified methods, but no new tests!" 45 MISSING_TEST_MSG = "Change contains new or modified methods, but no new tests!"
45 46
46 # Caches whether we read the codereview.settings file yet or not. 47 # Caches whether we read the codereview.settings file yet or not.
47 read_gcl_info = False 48 read_gcl_info = False
48 49
49 50
51 ### Simplified XML processing functions.
52
53 def ParseXML(output):
54 try:
55 return xml.dom.minidom.parseString(output)
56 except xml.parsers.expat.ExpatError:
57 return None
58
59 def GetNamedNodeText(node, node_name):
60 child_nodes = node.getElementsByTagName(node_name)
61 if not child_nodes:
62 return None
63 assert len(child_nodes) == 1 and child_nodes[0].childNodes.length == 1
64 return child_nodes[0].firstChild.nodeValue
65
66
67 def GetNodeNamedAttributeText(node, node_name, attribute_name):
68 child_nodes = node.getElementsByTagName(node_name)
69 if not child_nodes:
70 return None
71 assert len(child_nodes) == 1
72 return child_nodes[0].getAttribute(attribute_name)
73
74
75 ### SVN Functions
76
50 def IsSVNMoved(filename): 77 def IsSVNMoved(filename):
51 """Determine if a file has been added through svn mv""" 78 """Determine if a file has been added through svn mv"""
52 info = GetSVNFileInfo(filename) 79 info = GetSVNFileInfo(filename)
53 return (info.get('Copied From URL') and 80 return (info.get('Copied From URL') and
54 info.get('Copied From Rev') and 81 info.get('Copied From Rev') and
55 info.get('Schedule') == 'add') 82 info.get('Schedule') == 'add')
56 83
57 84
58 def GetSVNFileInfo(file): 85 def GetSVNFileInfo(file):
59 """Returns a dictionary from the svn info output for the given file.""" 86 """Returns a dictionary from the svn info output for the given file."""
60 output = RunShell(["svn", "info", file]) 87 dom = ParseXML(RunShell(["svn", "info", "--xml", file]))
61 result = {} 88 result = {}
62 re_key_value_pair = re.compile('^(.*)\: (.*)$') 89 if dom:
63 for line in output.splitlines(): 90 # /info/entry/
64 key_value_pair = re_key_value_pair.match(line) 91 # url
65 if key_value_pair: 92 # reposityory/(root|uuid)
66 result[key_value_pair.group(1)] = key_value_pair.group(2) 93 # wc-info/(schedule|depth)
94 # commit/(author|date)
95 result['Node Kind'] = GetNodeNamedAttributeText(dom, 'entry', 'kind')
96 result['Repository Root'] = GetNamedNodeText(dom, 'root')
97 result['Schedule'] = GetNamedNodeText(dom, 'schedule')
98 result['URL'] = GetNamedNodeText(dom, 'url')
99 result['Path'] = GetNodeNamedAttributeText(dom, 'entry', 'path')
100 result['Copied From URL'] = GetNamedNodeText(dom, 'copy-from-url')
101 result['Copied From Rev'] = GetNamedNodeText(dom, 'copy-from-rev')
67 return result 102 return result
68 103
69 104
70 def GetSVNFileProperty(file, property_name): 105 def GetSVNFileProperty(file, property_name):
71 """Returns the value of an SVN property for the given file. 106 """Returns the value of an SVN property for the given file.
72 107
73 Args: 108 Args:
74 file: The file to check 109 file: The file to check
75 property_name: The name of the SVN property, e.g. "svn:mime-type" 110 property_name: The name of the SVN property, e.g. "svn:mime-type"
76 111
77 Returns: 112 Returns:
78 The value of the property, which will be the empty string if the property 113 The value of the property, which will be the empty string if the property
79 is not set on the file. If the file is not under version control, the 114 is not set on the file. If the file is not under version control, the
80 empty string is also returned. 115 empty string is also returned.
81 """ 116 """
82 output = RunShell(["svn", "propget", property_name, file]) 117 output = RunShell(["svn", "propget", property_name, file])
83 if (output.startswith("svn: ") and 118 if (output.startswith("svn: ") and
84 output.endswith("is not under version control")): 119 output.endswith("is not under version control")):
85 return "" 120 return ""
86 else: 121 else:
87 return output 122 return output
88 123
89 124
125 def GetSVNStatus(file):
126 """Returns the svn 1.5 svn status emulated output.
127
128 @file can be a string (one file) or a list of files."""
129 command = ["svn", "status", "--xml"]
130 if file is None:
131 pass
132 elif isinstance(file, basestring):
133 command.append(file)
134 else:
135 command.extend(file)
136
137 status_letter = {
138 '': ' ',
139 'unversioned': '?',
140 'modified': 'M',
141 'added': 'A',
142 'conflicted': 'C',
143 'deleted': 'D',
144 'ignored': 'I',
145 'replaced': 'R',
146 # TODO(maruel): Find the corresponding strings for X, !, ~
147 }
148 dom = ParseXML(RunShell(command))
149 results = []
150 if dom:
151 # /status/target/entry/(wc-status|commit|author|date)
152 for target in dom.getElementsByTagName('target'):
153 base_path = target.getAttribute('path')
154 for entry in target.getElementsByTagName('entry'):
155 file = entry.getAttribute('path')
156 wc_status = entry.getElementsByTagName('wc-status')
157 assert len(wc_status) == 1
158 # Emulate svn 1.5 status ouput...
159 statuses = [' ' for i in range(7)]
160 # Col 0
161 xml_item_status = wc_status[0].getAttribute('item')
162 if xml_item_status in status_letter:
163 statuses[0] = status_letter[xml_item_status]
164 else:
165 raise Exception('Unknown item status "%s"; please implement me!' %
166 xml_item_status)
167 # Col 1
168 xml_props_status = wc_status[0].getAttribute('props')
169 if xml_props_status == 'modified':
170 statuses[1] = 'M'
171 elif xml_props_status == 'conflicted':
172 statuses[1] = 'C'
173 elif (not xml_props_status or xml_props_status == 'none' or
174 xml_props_status == 'normal'):
175 pass
176 else:
177 raise Exception('Unknown props status "%s"; please implement me!' %
178 xml_props_status)
179 # Col 3
180 if wc_status[0].getAttribute('copied') == 'true':
181 statuses[3] = '+'
182 item = (''.join(statuses), file)
183 results.append(item)
184 return results
185
186
187 def UnknownFiles(extra_args):
188 """Runs svn status and prints unknown files.
189
190 Any args in |extra_args| are passed to the tool to support giving alternate
191 code locations.
192 """
193 return [item[1] for item in GetSVNStatus(extra_args) if item[0][0] == '?']
194
195
90 def GetRepositoryRoot(): 196 def GetRepositoryRoot():
91 """Returns the top level directory of the current repository. 197 """Returns the top level directory of the current repository.
92 198
93 The directory is returned as an absolute path. 199 The directory is returned as an absolute path.
94 """ 200 """
95 global repository_root 201 global repository_root
96 if not repository_root: 202 if not repository_root:
97 cur_dir_repo_root = GetSVNFileInfo(os.getcwd()).get("Repository Root") 203 cur_dir_repo_root = GetSVNFileInfo(os.getcwd()).get("Repository Root")
98 if not cur_dir_repo_root: 204 if not cur_dir_repo_root:
99 raise Exception("gcl run outside of repository") 205 raise Exception("gcl run outside of repository")
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 files = [] 517 files = []
412 for line in split_data[1].splitlines(): 518 for line in split_data[1].splitlines():
413 status = line[:7] 519 status = line[:7]
414 file = line[7:] 520 file = line[7:]
415 files.append((status, file)) 521 files.append((status, file))
416 description = split_data[2] 522 description = split_data[2]
417 save = False 523 save = False
418 if update_status: 524 if update_status:
419 for file in files: 525 for file in files:
420 filename = os.path.join(GetRepositoryRoot(), file[1]) 526 filename = os.path.join(GetRepositoryRoot(), file[1])
421 status = RunShell(["svn", "status", filename])[:7] 527 status_result = GetSVNStatus(filename)
422 if not status: # File has been reverted. 528 if not status_result or not status_result[0][0]:
529 # File has been reverted.
423 save = True 530 save = True
424 files.remove(file) 531 files.remove(file)
425 elif status != file[0]: 532 elif status != file[0]:
426 save = True 533 save = True
427 files[files.index(file)] = (status, file[1]) 534 files[files.index(file)] = (status, file[1])
428 change_info = ChangeInfo(changename, issue, description, files) 535 change_info = ChangeInfo(changename, issue, description, files)
429 if save: 536 if save:
430 change_info.Save() 537 change_info.Save()
431 return change_info 538 return change_info
432 539
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 dir_prefix = os.getcwd()[len(GetRepositoryRoot()):].strip(os.sep) 574 dir_prefix = os.getcwd()[len(GetRepositoryRoot()):].strip(os.sep)
468 575
469 # Get a list of all files in changelists. 576 # Get a list of all files in changelists.
470 files_in_cl = {} 577 files_in_cl = {}
471 for cl in GetCLs(): 578 for cl in GetCLs():
472 change_info = LoadChangelistInfo(cl) 579 change_info = LoadChangelistInfo(cl)
473 for status, filename in change_info.files: 580 for status, filename in change_info.files:
474 files_in_cl[filename] = change_info.name 581 files_in_cl[filename] = change_info.name
475 582
476 # Get all the modified files. 583 # Get all the modified files.
477 status = RunShell(["svn", "status"]) 584 status_result = GetSVNStatus(None)
478 for line in status.splitlines(): 585 for line in status_result:
479 if not len(line) or line[0] == "?": 586 status = line[0]
587 filename = line[1]
588 if status[0] == "?":
480 continue 589 continue
481 status = line[:7]
482 filename = line[7:].strip()
483 if dir_prefix: 590 if dir_prefix:
484 filename = os.path.join(dir_prefix, filename) 591 filename = os.path.join(dir_prefix, filename)
485 change_list_name = "" 592 change_list_name = ""
486 if filename in files_in_cl: 593 if filename in files_in_cl:
487 change_list_name = files_in_cl[filename] 594 change_list_name = files_in_cl[filename]
488 files.setdefault(change_list_name, []).append((status, filename)) 595 files.setdefault(change_list_name, []).append((status, filename))
489 596
490 return files 597 return files
491 598
492 599
(...skipping 30 matching lines...) Expand all
523 ErrorExit("Error accessing url %s" % request_path) 630 ErrorExit("Error accessing url %s" % request_path)
524 else: 631 else:
525 return None 632 return None
526 633
527 634
528 def GetIssueDescription(issue): 635 def GetIssueDescription(issue):
529 """Returns the issue description from Rietveld.""" 636 """Returns the issue description from Rietveld."""
530 return SendToRietveld("/" + issue + "/description") 637 return SendToRietveld("/" + issue + "/description")
531 638
532 639
533 def UnknownFiles(extra_args):
534 """Runs svn status and prints unknown files.
535
536 Any args in |extra_args| are passed to the tool to support giving alternate
537 code locations.
538 """
539 args = ["svn", "status"]
540 args += extra_args
541 p = subprocess.Popen(args, stdout = subprocess.PIPE,
542 stderr = subprocess.STDOUT, shell = use_shell)
543 while 1:
544 line = p.stdout.readline()
545 if not line:
546 break
547 if line[0] != '?':
548 continue # Not an unknown file to svn.
549 # The lines look like this:
550 # "? foo.txt"
551 # and we want just "foo.txt"
552 print line[7:].strip()
553 p.wait()
554 p.stdout.close()
555
556
557 def Opened(): 640 def Opened():
558 """Prints a list of modified files in the current directory down.""" 641 """Prints a list of modified files in the current directory down."""
559 files = GetModifiedFiles() 642 files = GetModifiedFiles()
560 cl_keys = files.keys() 643 cl_keys = files.keys()
561 cl_keys.sort() 644 cl_keys.sort()
562 for cl_name in cl_keys: 645 for cl_name in cl_keys:
563 if cl_name: 646 if cl_name:
564 note = "" 647 note = ""
565 if len(LoadChangelistInfo(cl_name).files) != len(files[cl_name]): 648 if len(LoadChangelistInfo(cl_name).files) != len(files[cl_name]):
566 note = " (Note: this changelist contains files outside this directory)" 649 note = " (Note: this changelist contains files outside this directory)"
(...skipping 530 matching lines...) Expand 10 before | Expand all | Expand 10 after
1097 # the files. This allows commands such as 'gcl diff xxx' to work. 1180 # the files. This allows commands such as 'gcl diff xxx' to work.
1098 args =["svn", command] 1181 args =["svn", command]
1099 root = GetRepositoryRoot() 1182 root = GetRepositoryRoot()
1100 args.extend([os.path.join(root, x) for x in change_info.FileList()]) 1183 args.extend([os.path.join(root, x) for x in change_info.FileList()])
1101 RunShell(args, True) 1184 RunShell(args, True)
1102 return 0 1185 return 0
1103 1186
1104 1187
1105 if __name__ == "__main__": 1188 if __name__ == "__main__":
1106 sys.exit(main()) 1189 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | revert.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698