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

Side by Side Diff: gcl.py

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

Powered by Google App Engine
This is Rietveld 408576698