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

Side by Side Diff: gcl.py

Issue 115217: Revert changes 15823 and 15824 because they broke gclient revert. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools/
Patch Set: Created 11 years, 7 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 | gclient.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 import xml.dom.minidom
20 20
21 # gcl now depends on gclient.
22 import gclient
23 21
24 __version__ = '1.0' 22 __version__ = '1.0'
25 23
26 24
27 CODEREVIEW_SETTINGS = { 25 CODEREVIEW_SETTINGS = {
28 # Default values. 26 # Default values.
29 "CODE_REVIEW_SERVER": "codereview.chromium.org", 27 "CODE_REVIEW_SERVER": "codereview.chromium.org",
30 "CC_LIST": "chromium-reviews@googlegroups.com", 28 "CC_LIST": "chromium-reviews@googlegroups.com",
31 "VIEW_VC": "http://src.chromium.org/viewvc/chrome?view=rev&revision=", 29 "VIEW_VC": "http://src.chromium.org/viewvc/chrome?view=rev&revision=",
32 } 30 }
(...skipping 10 matching lines...) Expand all
43 # Filename where we store repository specific information for gcl. 41 # Filename where we store repository specific information for gcl.
44 CODEREVIEW_SETTINGS_FILE = "codereview.settings" 42 CODEREVIEW_SETTINGS_FILE = "codereview.settings"
45 43
46 # Warning message when the change appears to be missing tests. 44 # Warning message when the change appears to be missing tests.
47 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!"
48 46
49 # Caches whether we read the codereview.settings file yet or not. 47 # Caches whether we read the codereview.settings file yet or not.
50 read_gcl_info = False 48 read_gcl_info = False
51 49
52 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
53 ### SVN Functions 75 ### SVN Functions
54 76
55 def IsSVNMoved(filename): 77 def IsSVNMoved(filename):
56 """Determine if a file has been added through svn mv""" 78 """Determine if a file has been added through svn mv"""
57 info = gclient.CaptureSVNInfo(filename) 79 info = GetSVNFileInfo(filename)
58 return (info.get('Copied From URL') and 80 return (info.get('Copied From URL') and
59 info.get('Copied From Rev') and 81 info.get('Copied From Rev') and
60 info.get('Schedule') == 'add') 82 info.get('Schedule') == 'add')
61 83
62 84
85 def GetSVNFileInfo(file):
86 """Returns a dictionary from the svn info output for the given file."""
87 dom = ParseXML(RunShell(["svn", "info", "--xml", file]))
88 result = {}
89 if dom:
90 # /info/entry/
91 # url
92 # reposityory/(root|uuid)
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')
102 return result
103
104
63 def GetSVNFileProperty(file, property_name): 105 def GetSVNFileProperty(file, property_name):
64 """Returns the value of an SVN property for the given file. 106 """Returns the value of an SVN property for the given file.
65 107
66 Args: 108 Args:
67 file: The file to check 109 file: The file to check
68 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"
69 111
70 Returns: 112 Returns:
71 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
72 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
(...skipping 25 matching lines...) Expand all
98 'conflicted': 'C', 140 'conflicted': 'C',
99 'deleted': 'D', 141 'deleted': 'D',
100 'ignored': 'I', 142 'ignored': 'I',
101 'missing': '!', 143 'missing': '!',
102 'modified': 'M', 144 'modified': 'M',
103 'normal': ' ', 145 'normal': ' ',
104 'replaced': 'R', 146 'replaced': 'R',
105 'unversioned': '?', 147 'unversioned': '?',
106 # TODO(maruel): Find the corresponding strings for X, ~ 148 # TODO(maruel): Find the corresponding strings for X, ~
107 } 149 }
108 dom = gclient.ParseXML(RunShell(command)) 150 dom = ParseXML(RunShell(command))
109 results = [] 151 results = []
110 if dom: 152 if dom:
111 # /status/target/entry/(wc-status|commit|author|date) 153 # /status/target/entry/(wc-status|commit|author|date)
112 for target in dom.getElementsByTagName('target'): 154 for target in dom.getElementsByTagName('target'):
113 base_path = target.getAttribute('path') 155 base_path = target.getAttribute('path')
114 for entry in target.getElementsByTagName('entry'): 156 for entry in target.getElementsByTagName('entry'):
115 file = entry.getAttribute('path') 157 file = entry.getAttribute('path')
116 wc_status = entry.getElementsByTagName('wc-status') 158 wc_status = entry.getElementsByTagName('wc-status')
117 assert len(wc_status) == 1 159 assert len(wc_status) == 1
118 # Emulate svn 1.5 status ouput... 160 # Emulate svn 1.5 status ouput...
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 return [item[1] for item in GetSVNStatus(extra_args) if item[0][0] == '?'] 195 return [item[1] for item in GetSVNStatus(extra_args) if item[0][0] == '?']
154 196
155 197
156 def GetRepositoryRoot(): 198 def GetRepositoryRoot():
157 """Returns the top level directory of the current repository. 199 """Returns the top level directory of the current repository.
158 200
159 The directory is returned as an absolute path. 201 The directory is returned as an absolute path.
160 """ 202 """
161 global repository_root 203 global repository_root
162 if not repository_root: 204 if not repository_root:
163 infos = gclient.CaptureSVNInfo(os.getcwd(), print_error=False) 205 cur_dir_repo_root = GetSVNFileInfo(os.getcwd()).get("Repository Root")
164 cur_dir_repo_root = infos.get("Repository Root")
165 if not cur_dir_repo_root: 206 if not cur_dir_repo_root:
166 raise Exception("gcl run outside of repository") 207 raise Exception("gcl run outside of repository")
167 208
168 repository_root = os.getcwd() 209 repository_root = os.getcwd()
169 while True: 210 while True:
170 parent = os.path.dirname(repository_root) 211 parent = os.path.dirname(repository_root)
171 if (gclient.CaptureSVNInfo(parent).get("Repository Root") != 212 if GetSVNFileInfo(parent).get("Repository Root") != cur_dir_repo_root:
172 cur_dir_repo_root):
173 break 213 break
174 repository_root = parent 214 repository_root = parent
175 return repository_root 215 return repository_root
176 216
177 217
178 def GetInfoDir(): 218 def GetInfoDir():
179 """Returns the directory where gcl info files are stored.""" 219 """Returns the directory where gcl info files are stored."""
180 global gcl_info_dir 220 global gcl_info_dir
181 if not gcl_info_dir: 221 if not gcl_info_dir:
182 gcl_info_dir = os.path.join(GetRepositoryRoot(), '.svn', 'gcl_info') 222 gcl_info_dir = os.path.join(GetRepositoryRoot(), '.svn', 'gcl_info')
183 return gcl_info_dir 223 return gcl_info_dir
184 224
185 225
186 def GetCodeReviewSetting(key): 226 def GetCodeReviewSetting(key):
187 """Returns a value for the given key for this repository.""" 227 """Returns a value for the given key for this repository."""
188 global read_gcl_info 228 global read_gcl_info
189 if not read_gcl_info: 229 if not read_gcl_info:
190 read_gcl_info = True 230 read_gcl_info = True
191 # First we check if we have a cached version. 231 # First we check if we have a cached version.
192 cached_settings_file = os.path.join(GetInfoDir(), CODEREVIEW_SETTINGS_FILE) 232 cached_settings_file = os.path.join(GetInfoDir(), CODEREVIEW_SETTINGS_FILE)
193 if (not os.path.exists(cached_settings_file) or 233 if (not os.path.exists(cached_settings_file) or
194 os.stat(cached_settings_file).st_mtime > 60*60*24*3): 234 os.stat(cached_settings_file).st_mtime > 60*60*24*3):
195 dir_info = gclient.CaptureSVNInfo(".") 235 dir_info = GetSVNFileInfo(".")
196 repo_root = dir_info["Repository Root"] 236 repo_root = dir_info["Repository Root"]
197 url_path = dir_info["URL"] 237 url_path = dir_info["URL"]
198 settings = "" 238 settings = ""
199 while True: 239 while True:
200 # Look for the codereview.settings file at the current level. 240 # Look for the codereview.settings file at the current level.
201 svn_path = url_path + "/" + CODEREVIEW_SETTINGS_FILE 241 svn_path = url_path + "/" + CODEREVIEW_SETTINGS_FILE
202 settings, rc = RunShellWithReturnCode(["svn", "cat", svn_path]) 242 settings, rc = RunShellWithReturnCode(["svn", "cat", svn_path])
203 if not rc: 243 if not rc:
204 # Exit the loop if the file was found. 244 # Exit the loop if the file was found.
205 break 245 break
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
287 327
288 328
289 class ChangeInfo: 329 class ChangeInfo:
290 """Holds information about a changelist. 330 """Holds information about a changelist.
291 331
292 issue: the Rietveld issue number, of "" if it hasn't been uploaded yet. 332 issue: the Rietveld issue number, of "" if it hasn't been uploaded yet.
293 description: the description. 333 description: the description.
294 files: a list of 2 tuple containing (status, filename) of changed files, 334 files: a list of 2 tuple containing (status, filename) of changed files,
295 with paths being relative to the top repository directory. 335 with paths being relative to the top repository directory.
296 """ 336 """
297 def __init__(self, name="", issue="", description="", files=None): 337 def __init__(self, name="", issue="", description="", files=[]):
298 self.name = name 338 self.name = name
299 self.issue = issue 339 self.issue = issue
300 self.description = description 340 self.description = description
301 self.files = files 341 self.files = files
302 if self.files is None:
303 self.files = []
304 self.patch = None 342 self.patch = None
305 343
306 def FileList(self): 344 def FileList(self):
307 """Returns a list of files.""" 345 """Returns a list of files."""
308 return [file[1] for file in self.files] 346 return [file[1] for file in self.files]
309 347
310 def _NonDeletedFileList(self): 348 def _NonDeletedFileList(self):
311 """Returns a list of files in this change, not including deleted files.""" 349 """Returns a list of files in this change, not including deleted files."""
312 return [file[1] for file in self.files if not file[0].startswith("D")] 350 return [file[1] for file in self.files if not file[0].startswith("D")]
313 351
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after
705 previous_cwd = os.getcwd() 743 previous_cwd = os.getcwd()
706 if root is None: 744 if root is None:
707 os.chdir(GetRepositoryRoot()) 745 os.chdir(GetRepositoryRoot())
708 else: 746 else:
709 os.chdir(root) 747 os.chdir(root)
710 748
711 diff = [] 749 diff = []
712 for file in files: 750 for file in files:
713 # Use svn info output instead of os.path.isdir because the latter fails 751 # Use svn info output instead of os.path.isdir because the latter fails
714 # when the file is deleted. 752 # when the file is deleted.
715 if gclient.CaptureSVNInfo(file).get("Node Kind") in ("dir", "directory"): 753 if GetSVNFileInfo(file).get("Node Kind") in ("dir", "directory"):
716 continue 754 continue
717 # If the user specified a custom diff command in their svn config file, 755 # If the user specified a custom diff command in their svn config file,
718 # then it'll be used when we do svn diff, which we don't want to happen 756 # then it'll be used when we do svn diff, which we don't want to happen
719 # since we want the unified diff. Using --diff-cmd=diff doesn't always 757 # since we want the unified diff. Using --diff-cmd=diff doesn't always
720 # work, since they can have another diff executable in their path that 758 # work, since they can have another diff executable in their path that
721 # gives different line endings. So we use a bogus temp directory as the 759 # gives different line endings. So we use a bogus temp directory as the
722 # config directory, which gets around these problems. 760 # config directory, which gets around these problems.
723 if sys.platform.startswith("win"): 761 if sys.platform.startswith("win"):
724 parent_dir = tempfile.gettempdir() 762 parent_dir = tempfile.gettempdir()
725 else: 763 else:
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after
1146 # the files. This allows commands such as 'gcl diff xxx' to work. 1184 # the files. This allows commands such as 'gcl diff xxx' to work.
1147 args =["svn", command] 1185 args =["svn", command]
1148 root = GetRepositoryRoot() 1186 root = GetRepositoryRoot()
1149 args.extend([os.path.join(root, x) for x in change_info.FileList()]) 1187 args.extend([os.path.join(root, x) for x in change_info.FileList()])
1150 RunShell(args, True) 1188 RunShell(args, True)
1151 return 0 1189 return 0
1152 1190
1153 1191
1154 if __name__ == "__main__": 1192 if __name__ == "__main__":
1155 sys.exit(main()) 1193 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | gclient.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698