| epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 1 | ''' | 
 | 2 | Copyright 2011 Google Inc. | 
 | 3 |  | 
 | 4 | Use of this source code is governed by a BSD-style license that can be | 
 | 5 | found in the LICENSE file. | 
 | 6 | ''' | 
 | 7 |  | 
| epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 8 | import fnmatch | 
 | 9 | import os | 
| epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 10 | import re | 
 | 11 | import subprocess | 
 | 12 |  | 
 | 13 | PROPERTY_MIMETYPE = 'svn:mime-type' | 
 | 14 |  | 
 | 15 | class Svn: | 
 | 16 |  | 
 | 17 |     def __init__(self, directory): | 
 | 18 |         """Set up to manipulate SVN control within the given directory. | 
 | 19 |  | 
 | 20 |         @param directory | 
 | 21 |         """ | 
 | 22 |         self._directory = directory | 
 | 23 |  | 
 | 24 |     def _RunCommand(self, args): | 
 | 25 |         """Run a command (from self._directory) and return stdout as a single | 
 | 26 |         string. | 
 | 27 |  | 
 | 28 |         @param args a list of arguments | 
 | 29 |         """ | 
| epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 30 |         print 'RunCommand: %s' % args | 
| epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 31 |         proc = subprocess.Popen(args, cwd=self._directory, | 
| epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 32 |                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 
 | 33 |         (stdout, stderr) = proc.communicate() | 
 | 34 |         if proc.returncode is not 0: | 
 | 35 |             raise Exception('command "%s" failed in dir "%s": %s' % | 
 | 36 |                             (args, self._directory, stderr)) | 
| epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 37 |         return stdout | 
 | 38 |  | 
| epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 39 |     def Checkout(self, url, path): | 
 | 40 |         """Check out a working copy from a repository. | 
 | 41 |         Returns stdout as a single string. | 
 | 42 |  | 
 | 43 |         @param url URL from which to check out the working copy | 
 | 44 |         @param path path (within self._directory) where the local copy will be | 
 | 45 |         written | 
 | 46 |         """ | 
 | 47 |         return self._RunCommand(['svn', 'checkout', url, path]) | 
 | 48 |  | 
| epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 49 |     def GetNewFiles(self): | 
 | 50 |         """Return a list of files which are in this directory but NOT under | 
 | 51 |         SVN control. | 
 | 52 |         """ | 
 | 53 |         stdout = self._RunCommand(['svn', 'status']) | 
| epoger@google.com | d625655 | 2012-01-10 14:10:34 +0000 | [diff] [blame] | 54 |         new_regex = re.compile('^\?.....\s+(.+)$', re.MULTILINE) | 
 | 55 |         files = new_regex.findall(stdout) | 
 | 56 |         return files | 
 | 57 |  | 
 | 58 |     def GetNewAndModifiedFiles(self): | 
 | 59 |         """Return a list of files in this dir which are newly added or modified, | 
 | 60 |         including those that are not (yet) under SVN control. | 
 | 61 |         """ | 
 | 62 |         stdout = self._RunCommand(['svn', 'status']) | 
 | 63 |         new_regex = re.compile('^[AM\?].....\s+(.+)$', re.MULTILINE) | 
| epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 64 |         files = new_regex.findall(stdout) | 
 | 65 |         return files | 
 | 66 |  | 
 | 67 |     def AddFiles(self, filenames): | 
 | 68 |         """Adds these files to SVN control. | 
 | 69 |  | 
 | 70 |         @param filenames files to add to SVN control | 
 | 71 |         """ | 
| epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 72 |         self._RunCommand(['svn', 'add'] + filenames) | 
| epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 73 |  | 
 | 74 |     def SetProperty(self, filenames, property_name, property_value): | 
 | 75 |         """Sets a svn property for these files. | 
 | 76 |  | 
 | 77 |         @param filenames files to set property on | 
 | 78 |         @param property_name property_name to set for each file | 
 | 79 |         @param property_value what to set the property_name to | 
 | 80 |         """ | 
| epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 81 |         if filenames: | 
 | 82 |             self._RunCommand( | 
 | 83 |                 ['svn', 'propset', property_name, property_value] + filenames) | 
 | 84 |  | 
 | 85 |     def SetPropertyByFilenamePattern(self, filename_pattern, | 
 | 86 |                                      property_name, property_value): | 
 | 87 |         """Sets a svn property for all files matching filename_pattern. | 
 | 88 |  | 
 | 89 |         @param filename_pattern set the property for all files whose names match | 
 | 90 |                this Unix-style filename pattern (e.g., '*.jpg') | 
 | 91 |         @param property_name property_name to set for each file | 
 | 92 |         @param property_value what to set the property_name to | 
 | 93 |         """ | 
 | 94 |         all_files = os.listdir(self._directory) | 
 | 95 |         matching_files = fnmatch.filter(all_files, filename_pattern) | 
 | 96 |         self.SetProperty(matching_files, property_name, property_value) |