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

Side by Side Diff: scm.py

Issue 391075: Revert 32057, 32058, 32059, 32062 because they still have unwanted side-effects. (Closed)
Patch Set: Created 11 years, 1 month 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
« no previous file with comments | « revert.py ('k') | 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 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """SCM-specific utility classes.""" 5 """SCM-specific functions."""
6 6
7 import os 7 import os
8 import re 8 import re
9 import subprocess 9 import subprocess
10 import sys 10 import sys
11 import tempfile
12 import xml.dom.minidom 11 import xml.dom.minidom
13 12
14 import gclient_utils 13 import gclient_utils
15 14
16 15
17 class GIT(object): 16 SVN_COMMAND = "svn"
18 COMMAND = "git" 17 GIT_COMMAND = "git"
19 18
20 @staticmethod 19 # -----------------------------------------------------------------------------
21 def Capture(args, in_directory=None, print_error=True): 20 # Git utils:
22 """Runs git, capturing output sent to stdout as a string. 21
23 22
24 Args: 23 def CaptureGit(args, in_directory=None, print_error=True):
25 args: A sequence of command line parameters to be passed to git. 24 """Runs git, capturing output sent to stdout as a string.
26 in_directory: The directory where git is to be run. 25
27 26 Args:
28 Returns: 27 args: A sequence of command line parameters to be passed to git.
29 The output sent to stdout as a string. 28 in_directory: The directory where git is to be run.
30 """ 29
31 c = [GIT.COMMAND] 30 Returns:
32 c.extend(args) 31 The output sent to stdout as a string.
33 32 """
34 # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for 33 c = [GIT_COMMAND]
35 # the git.exe executable, but shell=True makes subprocess on Linux fail 34 c.extend(args)
36 # when it's called with a list because it only tries to execute the 35
37 # first string ("git"). 36 # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for
38 stderr = None 37 # the git.exe executable, but shell=True makes subprocess on Linux fail
39 if not print_error: 38 # when it's called with a list because it only tries to execute the
40 stderr = subprocess.PIPE 39 # first string ("git").
41 return subprocess.Popen(c, 40 stderr = None
42 cwd=in_directory, 41 if not print_error:
43 shell=sys.platform.startswith('win'), 42 stderr = subprocess.PIPE
44 stdout=subprocess.PIPE, 43 return subprocess.Popen(c,
45 stderr=stderr).communicate()[0] 44 cwd=in_directory,
46 45 shell=sys.platform.startswith('win'),
47 46 stdout=subprocess.PIPE,
48 @staticmethod 47 stderr=stderr).communicate()[0]
49 def CaptureStatus(files, upstream_branch='origin'): 48
50 """Returns git status. 49
51 50 def CaptureGitStatus(files, upstream_branch='origin'):
52 @files can be a string (one file) or a list of files. 51 """Returns git status.
53 52
54 Returns an array of (status, file) tuples.""" 53 @files can be a string (one file) or a list of files.
55 command = ["diff", "--name-status", "-r", "%s.." % upstream_branch] 54
56 if not files: 55 Returns an array of (status, file) tuples."""
57 pass 56 command = ["diff", "--name-status", "-r", "%s.." % upstream_branch]
58 elif isinstance(files, basestring): 57 if not files:
59 command.append(files) 58 pass
60 else: 59 elif isinstance(files, basestring):
61 command.extend(files) 60 command.append(files)
62 61 else:
63 status = GIT.Capture(command).rstrip() 62 command.extend(files)
64 results = [] 63
65 if status: 64 status = CaptureGit(command).rstrip()
66 for statusline in status.split('\n'): 65 results = []
67 m = re.match('^(\w)\t(.+)$', statusline) 66 if status:
68 if not m: 67 for statusline in status.split('\n'):
69 raise Exception("status currently unsupported: %s" % statusline) 68 m = re.match('^(\w)\t(.+)$', statusline)
70 results.append(('%s ' % m.group(1), m.group(2))) 69 if not m:
71 return results 70 raise Exception("status currently unsupported: %s" % statusline)
72 71 results.append(('%s ' % m.group(1), m.group(2)))
73 72 return results
74 class SVN(object): 73
75 COMMAND = "svn" 74
76 75 # -----------------------------------------------------------------------------
77 @staticmethod 76 # SVN utils:
78 def Run(args, in_directory): 77
79 """Runs svn, sending output to stdout. 78
80 79 def RunSVN(args, in_directory):
81 Args: 80 """Runs svn, sending output to stdout.
82 args: A sequence of command line parameters to be passed to svn. 81
83 in_directory: The directory where svn is to be run. 82 Args:
84 83 args: A sequence of command line parameters to be passed to svn.
85 Raises: 84 in_directory: The directory where svn is to be run.
86 Error: An error occurred while running the svn command. 85
87 """ 86 Raises:
88 c = [SVN.COMMAND] 87 Error: An error occurred while running the svn command.
89 c.extend(args) 88 """
90 89 c = [SVN_COMMAND]
91 gclient_utils.SubprocessCall(c, in_directory) 90 c.extend(args)
92 91
93 @staticmethod 92 gclient_utils.SubprocessCall(c, in_directory)
94 def Capture(args, in_directory=None, print_error=True): 93
95 """Runs svn, capturing output sent to stdout as a string. 94
96 95 def CaptureSVN(args, in_directory=None, print_error=True):
97 Args: 96 """Runs svn, capturing output sent to stdout as a string.
98 args: A sequence of command line parameters to be passed to svn. 97
99 in_directory: The directory where svn is to be run. 98 Args:
100 99 args: A sequence of command line parameters to be passed to svn.
101 Returns: 100 in_directory: The directory where svn is to be run.
102 The output sent to stdout as a string. 101
103 """ 102 Returns:
104 c = [SVN.COMMAND] 103 The output sent to stdout as a string.
105 c.extend(args) 104 """
106 105 c = [SVN_COMMAND]
107 # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for 106 c.extend(args)
108 # the svn.exe executable, but shell=True makes subprocess on Linux fail 107
109 # when it's called with a list because it only tries to execute the 108 # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for
110 # first string ("svn"). 109 # the svn.exe executable, but shell=True makes subprocess on Linux fail
111 stderr = None 110 # when it's called with a list because it only tries to execute the
112 if not print_error: 111 # first string ("svn").
113 stderr = subprocess.PIPE 112 stderr = None
114 return subprocess.Popen(c, 113 if not print_error:
115 cwd=in_directory, 114 stderr = subprocess.PIPE
116 shell=(sys.platform == 'win32'), 115 return subprocess.Popen(c,
117 stdout=subprocess.PIPE, 116 cwd=in_directory,
118 stderr=stderr).communicate()[0] 117 shell=(sys.platform == 'win32'),
119 118 stdout=subprocess.PIPE,
120 @staticmethod 119 stderr=stderr).communicate()[0]
121 def RunAndGetFileList(options, args, in_directory, file_list): 120
122 """Runs svn checkout, update, or status, output to stdout. 121
123 122 def RunSVNAndGetFileList(options, args, in_directory, file_list):
124 The first item in args must be either "checkout", "update", or "status". 123 """Runs svn checkout, update, or status, output to stdout.
125 124
126 svn's stdout is parsed to collect a list of files checked out or updated. 125 The first item in args must be either "checkout", "update", or "status".
127 These files are appended to file_list. svn's stdout is also printed to 126
128 sys.stdout as in Run. 127 svn's stdout is parsed to collect a list of files checked out or updated.
129 128 These files are appended to file_list. svn's stdout is also printed to
130 Args: 129 sys.stdout as in RunSVN.
131 options: command line options to gclient 130
132 args: A sequence of command line parameters to be passed to svn. 131 Args:
133 in_directory: The directory where svn is to be run. 132 options: command line options to gclient
134 133 args: A sequence of command line parameters to be passed to svn.
135 Raises: 134 in_directory: The directory where svn is to be run.
136 Error: An error occurred while running the svn command. 135
137 """ 136 Raises:
138 command = [SVN.COMMAND] 137 Error: An error occurred while running the svn command.
139 command.extend(args) 138 """
140 139 command = [SVN_COMMAND]
141 # svn update and svn checkout use the same pattern: the first three columns 140 command.extend(args)
142 # are for file status, property status, and lock status. This is followed 141
143 # by two spaces, and then the path to the file. 142 # svn update and svn checkout use the same pattern: the first three columns
144 update_pattern = '^... (.*)$' 143 # are for file status, property status, and lock status. This is followed
145 144 # by two spaces, and then the path to the file.
146 # The first three columns of svn status are the same as for svn update and 145 update_pattern = '^... (.*)$'
147 # svn checkout. The next three columns indicate addition-with-history, 146
148 # switch, and remote lock status. This is followed by one space, and then 147 # The first three columns of svn status are the same as for svn update and
149 # the path to the file. 148 # svn checkout. The next three columns indicate addition-with-history,
150 status_pattern = '^...... (.*)$' 149 # switch, and remote lock status. This is followed by one space, and then
151 150 # the path to the file.
152 # args[0] must be a supported command. This will blow up if it's something 151 status_pattern = '^...... (.*)$'
153 # else, which is good. Note that the patterns are only effective when 152
154 # these commands are used in their ordinary forms, the patterns are invalid 153 # args[0] must be a supported command. This will blow up if it's something
155 # for "svn status --show-updates", for example. 154 # else, which is good. Note that the patterns are only effective when
156 pattern = { 155 # these commands are used in their ordinary forms, the patterns are invalid
157 'checkout': update_pattern, 156 # for "svn status --show-updates", for example.
158 'status': status_pattern, 157 pattern = {
159 'update': update_pattern, 158 'checkout': update_pattern,
160 }[args[0]] 159 'status': status_pattern,
161 160 'update': update_pattern,
162 compiled_pattern = re.compile(pattern) 161 }[args[0]]
163 162
164 def CaptureMatchingLines(line): 163 compiled_pattern = re.compile(pattern)
165 match = compiled_pattern.search(line) 164
166 if match: 165 def CaptureMatchingLines(line):
167 file_list.append(match.group(1)) 166 match = compiled_pattern.search(line)
168 167 if match:
169 SVN.RunAndFilterOutput(args, 168 file_list.append(match.group(1))
170 in_directory, 169
171 options.verbose, 170 RunSVNAndFilterOutput(args,
172 True, 171 in_directory,
173 CaptureMatchingLines) 172 options.verbose,
174 173 True,
175 @staticmethod 174 CaptureMatchingLines)
176 def RunAndFilterOutput(args, 175
177 in_directory, 176 def RunSVNAndFilterOutput(args,
178 print_messages, 177 in_directory,
179 print_stdout, 178 print_messages,
180 filter): 179 print_stdout,
181 """Runs svn checkout, update, status, or diff, optionally outputting 180 filter):
182 to stdout. 181 """Runs svn checkout, update, status, or diff, optionally outputting
183 182 to stdout.
184 The first item in args must be either "checkout", "update", 183
185 "status", or "diff". 184 The first item in args must be either "checkout", "update",
186 185 "status", or "diff".
187 svn's stdout is passed line-by-line to the given filter function. If 186
188 print_stdout is true, it is also printed to sys.stdout as in Run. 187 svn's stdout is passed line-by-line to the given filter function. If
189 188 print_stdout is true, it is also printed to sys.stdout as in RunSVN.
190 Args: 189
191 args: A sequence of command line parameters to be passed to svn. 190 Args:
192 in_directory: The directory where svn is to be run. 191 args: A sequence of command line parameters to be passed to svn.
193 print_messages: Whether to print status messages to stdout about 192 in_directory: The directory where svn is to be run.
194 which Subversion commands are being run. 193 print_messages: Whether to print status messages to stdout about
195 print_stdout: Whether to forward Subversion's output to stdout. 194 which Subversion commands are being run.
196 filter: A function taking one argument (a string) which will be 195 print_stdout: Whether to forward Subversion's output to stdout.
197 passed each line (with the ending newline character removed) of 196 filter: A function taking one argument (a string) which will be
198 Subversion's output for filtering. 197 passed each line (with the ending newline character removed) of
199 198 Subversion's output for filtering.
200 Raises: 199
201 Error: An error occurred while running the svn command. 200 Raises:
202 """ 201 Error: An error occurred while running the svn command.
203 command = [SVN.COMMAND] 202 """
204 command.extend(args) 203 command = [SVN_COMMAND]
205 204 command.extend(args)
206 gclient_utils.SubprocessCallAndFilter(command, 205
207 in_directory, 206 gclient_utils.SubprocessCallAndFilter(command,
208 print_messages, 207 in_directory,
209 print_stdout, 208 print_messages,
210 filter=filter) 209 print_stdout,
211 210 filter=filter)
212 @staticmethod 211
213 def CaptureInfo(relpath, in_directory=None, print_error=True): 212 def CaptureSVNInfo(relpath, in_directory=None, print_error=True):
214 """Returns a dictionary from the svn info output for the given file. 213 """Returns a dictionary from the svn info output for the given file.
215 214
216 Args: 215 Args:
217 relpath: The directory where the working copy resides relative to 216 relpath: The directory where the working copy resides relative to
218 the directory given by in_directory. 217 the directory given by in_directory.
219 in_directory: The directory where svn is to be run. 218 in_directory: The directory where svn is to be run.
220 """ 219 """
221 output = SVN.Capture(["info", "--xml", relpath], in_directory, print_error) 220 output = CaptureSVN(["info", "--xml", relpath], in_directory, print_error)
222 dom = gclient_utils.ParseXML(output) 221 dom = gclient_utils.ParseXML(output)
223 result = {} 222 result = {}
224 if dom: 223 if dom:
225 GetNamedNodeText = gclient_utils.GetNamedNodeText 224 GetNamedNodeText = gclient_utils.GetNamedNodeText
226 GetNodeNamedAttributeText = gclient_utils.GetNodeNamedAttributeText 225 GetNodeNamedAttributeText = gclient_utils.GetNodeNamedAttributeText
227 def C(item, f): 226 def C(item, f):
228 if item is not None: return f(item) 227 if item is not None: return f(item)
229 # /info/entry/ 228 # /info/entry/
230 # url 229 # url
231 # reposityory/(root|uuid) 230 # reposityory/(root|uuid)
232 # wc-info/(schedule|depth) 231 # wc-info/(schedule|depth)
233 # commit/(author|date) 232 # commit/(author|date)
234 # str() the results because they may be returned as Unicode, which 233 # str() the results because they may be returned as Unicode, which
235 # interferes with the higher layers matching up things in the deps 234 # interferes with the higher layers matching up things in the deps
236 # dictionary. 235 # dictionary.
237 # TODO(maruel): Fix at higher level instead (!) 236 # TODO(maruel): Fix at higher level instead (!)
238 result['Repository Root'] = C(GetNamedNodeText(dom, 'root'), str) 237 result['Repository Root'] = C(GetNamedNodeText(dom, 'root'), str)
239 result['URL'] = C(GetNamedNodeText(dom, 'url'), str) 238 result['URL'] = C(GetNamedNodeText(dom, 'url'), str)
240 result['UUID'] = C(GetNamedNodeText(dom, 'uuid'), str) 239 result['UUID'] = C(GetNamedNodeText(dom, 'uuid'), str)
241 result['Revision'] = C(GetNodeNamedAttributeText(dom, 'entry', 240 result['Revision'] = C(GetNodeNamedAttributeText(dom, 'entry', 'revision'),
242 'revision'), 241 int)
243 int) 242 result['Node Kind'] = C(GetNodeNamedAttributeText(dom, 'entry', 'kind'),
244 result['Node Kind'] = C(GetNodeNamedAttributeText(dom, 'entry', 'kind'), 243 str)
245 str) 244 result['Schedule'] = C(GetNamedNodeText(dom, 'schedule'), str)
246 # Differs across versions. 245 result['Path'] = C(GetNodeNamedAttributeText(dom, 'entry', 'path'), str)
247 if result['Node Kind'] == 'dir': 246 result['Copied From URL'] = C(GetNamedNodeText(dom, 'copy-from-url'), str)
248 result['Node Kind'] = 'directory' 247 result['Copied From Rev'] = C(GetNamedNodeText(dom, 'copy-from-rev'), str)
249 result['Schedule'] = C(GetNamedNodeText(dom, 'schedule'), str) 248 return result
250 result['Path'] = C(GetNodeNamedAttributeText(dom, 'entry', 'path'), str) 249
251 result['Copied From URL'] = C(GetNamedNodeText(dom, 'copy-from-url'), str) 250
252 result['Copied From Rev'] = C(GetNamedNodeText(dom, 'copy-from-rev'), str) 251 def CaptureSVNHeadRevision(url):
253 return result 252 """Get the head revision of a SVN repository.
254 253
255 @staticmethod 254 Returns:
256 def CaptureHeadRevision(url): 255 Int head revision
257 """Get the head revision of a SVN repository. 256 """
258 257 info = CaptureSVN(["info", "--xml", url], os.getcwd())
259 Returns: 258 dom = xml.dom.minidom.parseString(info)
260 Int head revision 259 return dom.getElementsByTagName('entry')[0].getAttribute('revision')
261 """ 260
262 info = SVN.Capture(["info", "--xml", url], os.getcwd()) 261
263 dom = xml.dom.minidom.parseString(info) 262 def CaptureSVNStatus(files):
264 return dom.getElementsByTagName('entry')[0].getAttribute('revision') 263 """Returns the svn 1.5 svn status emulated output.
265 264
266 @staticmethod 265 @files can be a string (one file) or a list of files.
267 def CaptureStatus(files): 266
268 """Returns the svn 1.5 svn status emulated output. 267 Returns an array of (status, file) tuples."""
269 268 command = ["status", "--xml"]
270 @files can be a string (one file) or a list of files. 269 if not files:
271 270 pass
272 Returns an array of (status, file) tuples.""" 271 elif isinstance(files, basestring):
273 command = ["status", "--xml"] 272 command.append(files)
274 if not files: 273 else:
275 pass 274 command.extend(files)
276 elif isinstance(files, basestring): 275
277 command.append(files) 276 status_letter = {
278 else: 277 None: ' ',
279 command.extend(files) 278 '': ' ',
280 279 'added': 'A',
281 status_letter = { 280 'conflicted': 'C',
282 None: ' ', 281 'deleted': 'D',
283 '': ' ', 282 'external': 'X',
284 'added': 'A', 283 'ignored': 'I',
285 'conflicted': 'C', 284 'incomplete': '!',
286 'deleted': 'D', 285 'merged': 'G',
287 'external': 'X', 286 'missing': '!',
288 'ignored': 'I', 287 'modified': 'M',
289 'incomplete': '!', 288 'none': ' ',
290 'merged': 'G', 289 'normal': ' ',
291 'missing': '!', 290 'obstructed': '~',
292 'modified': 'M', 291 'replaced': 'R',
293 'none': ' ', 292 'unversioned': '?',
294 'normal': ' ', 293 }
295 'obstructed': '~', 294 dom = gclient_utils.ParseXML(CaptureSVN(command))
296 'replaced': 'R', 295 results = []
297 'unversioned': '?', 296 if dom:
298 } 297 # /status/target/entry/(wc-status|commit|author|date)
299 dom = gclient_utils.ParseXML(SVN.Capture(command)) 298 for target in dom.getElementsByTagName('target'):
300 results = [] 299 for entry in target.getElementsByTagName('entry'):
301 if dom: 300 file_path = entry.getAttribute('path')
302 # /status/target/entry/(wc-status|commit|author|date) 301 wc_status = entry.getElementsByTagName('wc-status')
303 for target in dom.getElementsByTagName('target'): 302 assert len(wc_status) == 1
304 #base_path = target.getAttribute('path') 303 # Emulate svn 1.5 status ouput...
305 for entry in target.getElementsByTagName('entry'): 304 statuses = [' '] * 7
306 file_path = entry.getAttribute('path') 305 # Col 0
307 wc_status = entry.getElementsByTagName('wc-status') 306 xml_item_status = wc_status[0].getAttribute('item')
308 assert len(wc_status) == 1 307 if xml_item_status in status_letter:
309 # Emulate svn 1.5 status ouput... 308 statuses[0] = status_letter[xml_item_status]
310 statuses = [' '] * 7 309 else:
311 # Col 0 310 raise Exception('Unknown item status "%s"; please implement me!' %
312 xml_item_status = wc_status[0].getAttribute('item') 311 xml_item_status)
313 if xml_item_status in status_letter: 312 # Col 1
314 statuses[0] = status_letter[xml_item_status] 313 xml_props_status = wc_status[0].getAttribute('props')
315 else: 314 if xml_props_status == 'modified':
316 raise Exception('Unknown item status "%s"; please implement me!' % 315 statuses[1] = 'M'
317 xml_item_status) 316 elif xml_props_status == 'conflicted':
318 # Col 1 317 statuses[1] = 'C'
319 xml_props_status = wc_status[0].getAttribute('props') 318 elif (not xml_props_status or xml_props_status == 'none' or
320 if xml_props_status == 'modified': 319 xml_props_status == 'normal'):
321 statuses[1] = 'M' 320 pass
322 elif xml_props_status == 'conflicted': 321 else:
323 statuses[1] = 'C' 322 raise Exception('Unknown props status "%s"; please implement me!' %
324 elif (not xml_props_status or xml_props_status == 'none' or 323 xml_props_status)
325 xml_props_status == 'normal'): 324 # Col 2
326 pass 325 if wc_status[0].getAttribute('wc-locked') == 'true':
327 else: 326 statuses[2] = 'L'
328 raise Exception('Unknown props status "%s"; please implement me!' % 327 # Col 3
329 xml_props_status) 328 if wc_status[0].getAttribute('copied') == 'true':
330 # Col 2 329 statuses[3] = '+'
331 if wc_status[0].getAttribute('wc-locked') == 'true': 330 # Col 4
332 statuses[2] = 'L' 331 if wc_status[0].getAttribute('switched') == 'true':
333 # Col 3 332 statuses[4] = 'S'
334 if wc_status[0].getAttribute('copied') == 'true': 333 # TODO(maruel): Col 5 and 6
335 statuses[3] = '+' 334 item = (''.join(statuses), file_path)
336 # Col 4 335 results.append(item)
337 if wc_status[0].getAttribute('switched') == 'true': 336 return results
338 statuses[4] = 'S'
339 # TODO(maruel): Col 5 and 6
340 item = (''.join(statuses), file_path)
341 results.append(item)
342 return results
343
344 @staticmethod
345 def IsMoved(filename):
346 """Determine if a file has been added through svn mv"""
347 info = SVN.CaptureInfo(filename)
348 return (info.get('Copied From URL') and
349 info.get('Copied From Rev') and
350 info.get('Schedule') == 'add')
351
352 @staticmethod
353 def GetFileProperty(file, property_name):
354 """Returns the value of an SVN property for the given file.
355
356 Args:
357 file: The file to check
358 property_name: The name of the SVN property, e.g. "svn:mime-type"
359
360 Returns:
361 The value of the property, which will be the empty string if the property
362 is not set on the file. If the file is not under version control, the
363 empty string is also returned.
364 """
365 output = SVN.Run(["propget", property_name, file], None)
366 if (output and
367 output.startswith("svn: ") and
368 output.endswith("is not under version control")):
369 return ""
370 else:
371 return output
372
373 @staticmethod
374 def DiffItem(filename):
375 """Diff a single file"""
376 # Use svn info output instead of os.path.isdir because the latter fails
377 # when the file is deleted.
378 if SVN.CaptureInfo(filename).get("Node Kind") == "directory":
379 return None
380 # If the user specified a custom diff command in their svn config file,
381 # then it'll be used when we do svn diff, which we don't want to happen
382 # since we want the unified diff. Using --diff-cmd=diff doesn't always
383 # work, since they can have another diff executable in their path that
384 # gives different line endings. So we use a bogus temp directory as the
385 # config directory, which gets around these problems.
386 if sys.platform.startswith("win"):
387 parent_dir = tempfile.gettempdir()
388 else:
389 parent_dir = sys.path[0] # tempdir is not secure.
390 bogus_dir = os.path.join(parent_dir, "temp_svn_config")
391 if not os.path.exists(bogus_dir):
392 os.mkdir(bogus_dir)
393 # Grabs the diff data.
394 data = SVN.Capture(["diff", "--config-dir", bogus_dir, filename], None)
395
396 # We know the diff will be incorrectly formatted. Fix it.
397 if SVN.IsMoved(filename):
398 # The file is "new" in the patch sense. Generate a homebrew diff.
399 # We can't use ReadFile() since it's not using binary mode.
400 file_handle = open(filename, 'rb')
401 file_content = file_handle.read()
402 file_handle.close()
403 # Prepend '+' to every lines.
404 file_content = ['+' + i for i in file_content.splitlines(True)]
405 nb_lines = len(file_content)
406 # We need to use / since patch on unix will fail otherwise.
407 filename = filename.replace('\\', '/')
408 data = "Index: %s\n" % filename
409 data += ("============================================================="
410 "======\n")
411 # Note: Should we use /dev/null instead?
412 data += "--- %s\n" % filename
413 data += "+++ %s\n" % filename
414 data += "@@ -0,0 +1,%d @@\n" % nb_lines
415 data += ''.join(file_content)
416 return data
OLDNEW
« no previous file with comments | « revert.py ('k') | tests/gcl_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698