OLD | NEW |
1 ''' | 1 ''' |
2 Copyright 2011 Google Inc. | 2 Copyright 2011 Google Inc. |
3 | 3 |
4 Use of this source code is governed by a BSD-style license that can be | 4 Use of this source code is governed by a BSD-style license that can be |
5 found in the LICENSE file. | 5 found in the LICENSE file. |
6 ''' | 6 ''' |
7 | 7 |
8 import fnmatch | 8 import fnmatch |
9 import os | 9 import os |
10 import re | 10 import re |
11 import subprocess | 11 import subprocess |
| 12 import threading |
12 | 13 |
13 PROPERTY_MIMETYPE = 'svn:mime-type' | 14 PROPERTY_MIMETYPE = 'svn:mime-type' |
14 | 15 |
15 # Status types for GetFilesWithStatus() | 16 # Status types for GetFilesWithStatus() |
16 STATUS_ADDED = 0x01 | 17 STATUS_ADDED = 0x01 |
17 STATUS_DELETED = 0x02 | 18 STATUS_DELETED = 0x02 |
18 STATUS_MODIFIED = 0x04 | 19 STATUS_MODIFIED = 0x04 |
19 STATUS_NOT_UNDER_SVN_CONTROL = 0x08 | 20 STATUS_NOT_UNDER_SVN_CONTROL = 0x08 |
20 | 21 |
21 | 22 |
(...skipping 16 matching lines...) Expand all Loading... |
38 raise Exception('Could not retrieve %s. Verify that the URL is valid ' | 39 raise Exception('Could not retrieve %s. Verify that the URL is valid ' |
39 'and check your connection.' % svn_url) | 40 'and check your connection.' % svn_url) |
40 return proc.communicate()[0] | 41 return proc.communicate()[0] |
41 | 42 |
42 | 43 |
43 class Svn: | 44 class Svn: |
44 | 45 |
45 def __init__(self, directory): | 46 def __init__(self, directory): |
46 """Set up to manipulate SVN control within the given directory. | 47 """Set up to manipulate SVN control within the given directory. |
47 | 48 |
| 49 The resulting object is thread-safe: access to all methods is |
| 50 synchronized (if one thread is currently executing any of its methods, |
| 51 all other threads must wait before executing any of its methods). |
| 52 |
48 @param directory | 53 @param directory |
49 """ | 54 """ |
50 self._directory = directory | 55 self._directory = directory |
| 56 # This must be a reentrant lock, so that it can be held by both |
| 57 # _RunCommand() and (some of) the methods that call it. |
| 58 self._rlock = threading.RLock() |
51 | 59 |
52 def _RunCommand(self, args): | 60 def _RunCommand(self, args): |
53 """Run a command (from self._directory) and return stdout as a single | 61 """Run a command (from self._directory) and return stdout as a single |
54 string. | 62 string. |
55 | 63 |
56 @param args a list of arguments | 64 @param args a list of arguments |
57 """ | 65 """ |
58 print 'RunCommand: %s' % args | 66 with self._rlock: |
59 proc = subprocess.Popen(args, cwd=self._directory, | 67 print 'RunCommand: %s' % args |
60 stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 68 proc = subprocess.Popen(args, cwd=self._directory, |
61 (stdout, stderr) = proc.communicate() | 69 stdout=subprocess.PIPE, |
62 if proc.returncode is not 0: | 70 stderr=subprocess.PIPE) |
63 raise Exception('command "%s" failed in dir "%s": %s' % | 71 (stdout, stderr) = proc.communicate() |
64 (args, self._directory, stderr)) | 72 if proc.returncode is not 0: |
65 return stdout | 73 raise Exception('command "%s" failed in dir "%s": %s' % |
| 74 (args, self._directory, stderr)) |
| 75 return stdout |
66 | 76 |
67 def GetInfo(self): | 77 def GetInfo(self): |
68 """Run "svn info" and return a dictionary containing its output. | 78 """Run "svn info" and return a dictionary containing its output. |
69 """ | 79 """ |
70 output = self._RunCommand([SVN, 'info']) | 80 output = self._RunCommand([SVN, 'info']) |
71 svn_info = {} | 81 svn_info = {} |
72 for line in output.split('\n'): | 82 for line in output.split('\n'): |
73 if ':' in line: | 83 if ':' in line: |
74 (key, value) = line.split(':', 1) | 84 (key, value) = line.split(':', 1) |
75 svn_info[key.strip()] = value.strip() | 85 svn_info[key.strip()] = value.strip() |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 | 170 |
161 def SetPropertyByFilenamePattern(self, filename_pattern, | 171 def SetPropertyByFilenamePattern(self, filename_pattern, |
162 property_name, property_value): | 172 property_name, property_value): |
163 """Sets a svn property for all files matching filename_pattern. | 173 """Sets a svn property for all files matching filename_pattern. |
164 | 174 |
165 @param filename_pattern set the property for all files whose names match | 175 @param filename_pattern set the property for all files whose names match |
166 this Unix-style filename pattern (e.g., '*.jpg') | 176 this Unix-style filename pattern (e.g., '*.jpg') |
167 @param property_name property_name to set for each file | 177 @param property_name property_name to set for each file |
168 @param property_value what to set the property_name to | 178 @param property_value what to set the property_name to |
169 """ | 179 """ |
170 all_files = os.listdir(self._directory) | 180 with self._rlock: |
171 matching_files = sorted(fnmatch.filter(all_files, filename_pattern)) | 181 all_files = os.listdir(self._directory) |
172 self.SetProperty(matching_files, property_name, property_value) | 182 matching_files = sorted(fnmatch.filter(all_files, filename_pattern)) |
| 183 self.SetProperty(matching_files, property_name, property_value) |
173 | 184 |
174 def ExportBaseVersionOfFile(self, file_within_repo, dest_path): | 185 def ExportBaseVersionOfFile(self, file_within_repo, dest_path): |
175 """Retrieves a copy of the base version (what you would get if you ran | 186 """Retrieves a copy of the base version (what you would get if you ran |
176 'svn revert') of a file within the repository. | 187 'svn revert') of a file within the repository. |
177 | 188 |
178 @param file_within_repo path to the file within the repo whose base | 189 @param file_within_repo path to the file within the repo whose base |
179 version you wish to obtain | 190 version you wish to obtain |
180 @param dest_path destination to which to write the base content | 191 @param dest_path destination to which to write the base content |
181 """ | 192 """ |
182 self._RunCommand([SVN, 'export', '--revision', 'BASE', '--force', | 193 self._RunCommand([SVN, 'export', '--revision', 'BASE', '--force', |
183 file_within_repo, dest_path]) | 194 file_within_repo, dest_path]) |
OLD | NEW |