1 | #!/usr/bin/env python |
---|
2 | |
---|
3 | # This script reads the auto-properties defined in the |
---|
4 | # $HOME/.subversion/config file and applies them recursively to all |
---|
5 | # the files and directories in the current working copy. It may |
---|
6 | # behave differently than the Subversion command line; where the |
---|
7 | # subversion command line may only apply a single matching |
---|
8 | # auto-property to a single pathname, this script will apply all |
---|
9 | # matching lines to a single pathname. |
---|
10 | # |
---|
11 | # To do: |
---|
12 | # 1) Switch to using the Subversion Python bindings. |
---|
13 | # 2) Allow a command line option to specify the configuration file to |
---|
14 | # load the auto-properties from. |
---|
15 | # |
---|
16 | # $HeadURL: http://svn.collab.net/repos/svn/branches/1.6.x/contrib/client-side/svn_apply_autoprops.py $ |
---|
17 | # $LastChangedRevision: 20787 $ |
---|
18 | # $LastChangedDate: 2006-07-20 03:41:28 +0000 (Thu, 20 Jul 2006) $ |
---|
19 | # $LastChangedBy: blair $ |
---|
20 | # |
---|
21 | # Copyright (C) 2005,2006 Blair Zajac <blair@orcaware.com> |
---|
22 | # |
---|
23 | # This script is free software; you can redistribute it and/or modify |
---|
24 | # it under the terms of the GNU General Public License as published by |
---|
25 | # the Free Software Foundation; either version 2 of the License, or |
---|
26 | # (at your option) any later version. |
---|
27 | # |
---|
28 | # This script is distributed in the hope that it will be useful, but |
---|
29 | # WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
30 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
31 | # General Public License for more details. |
---|
32 | # |
---|
33 | # A copy of the GNU General Public License can be obtained by writing |
---|
34 | # to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
---|
35 | # Boston, MA 02111-1307 USA. |
---|
36 | |
---|
37 | import fnmatch |
---|
38 | import os |
---|
39 | import re |
---|
40 | import sys |
---|
41 | |
---|
42 | # The path to the Subversion configuration file. |
---|
43 | SVN_CONFIG_FILENAME = '$HOME/.subversion/config' |
---|
44 | |
---|
45 | # The name of Subversion's private directory in working copies. |
---|
46 | SVN_WC_ADM_DIR_NAME = '.svn' |
---|
47 | |
---|
48 | def get_autoprop_lines(fd): |
---|
49 | lines = [] |
---|
50 | reading_autoprops = 0 |
---|
51 | |
---|
52 | re_start_autoprops = re.compile('^\s*\[auto-props\]\s*') |
---|
53 | re_end_autoprops = re.compile('^\s*\[\w+\]\s*') |
---|
54 | |
---|
55 | for line in fd.xreadlines(): |
---|
56 | if reading_autoprops: |
---|
57 | if re_end_autoprops.match(line): |
---|
58 | reading_autoprops = 0 |
---|
59 | continue |
---|
60 | else: |
---|
61 | if re_start_autoprops.match(line): |
---|
62 | reading_autoprops = 1 |
---|
63 | continue |
---|
64 | |
---|
65 | if reading_autoprops: |
---|
66 | lines += [line] |
---|
67 | |
---|
68 | return lines |
---|
69 | |
---|
70 | def process_autoprop_lines(lines): |
---|
71 | result = [] |
---|
72 | |
---|
73 | for line in lines: |
---|
74 | # Split the line on the = separating the fnmatch string from the |
---|
75 | # properties. |
---|
76 | try: |
---|
77 | (fnmatch, props) = line.split('=', 1) |
---|
78 | except ValueError: |
---|
79 | continue |
---|
80 | |
---|
81 | # Remove leading and trailing whitespace from the fnmatch and |
---|
82 | # properties. |
---|
83 | fnmatch = fnmatch.strip() |
---|
84 | props = props.strip() |
---|
85 | |
---|
86 | # Create a list of property name and property values. Remove all |
---|
87 | # leading and trailing whitespce from the propery names and |
---|
88 | # values. |
---|
89 | props_list = [] |
---|
90 | for prop in props.split(';'): |
---|
91 | prop = prop.strip() |
---|
92 | if not len(prop): |
---|
93 | continue |
---|
94 | try: |
---|
95 | (prop_name, prop_value) = prop.split('=', 1) |
---|
96 | prop_name = prop_name.strip() |
---|
97 | prop_value = prop_value.strip() |
---|
98 | except ValueError: |
---|
99 | prop_name = prop |
---|
100 | prop_value = '*' |
---|
101 | if len(prop_name): |
---|
102 | props_list += [(prop_name, prop_value)] |
---|
103 | |
---|
104 | result += [(fnmatch, props_list)] |
---|
105 | |
---|
106 | return result |
---|
107 | |
---|
108 | def filter_walk(autoprop_lines, dirname, filenames): |
---|
109 | # Do no descend into directories that do not have a .svn directory. |
---|
110 | try: |
---|
111 | filenames.remove(SVN_WC_ADM_DIR_NAME) |
---|
112 | except ValueError: |
---|
113 | filenames = [] |
---|
114 | print "Will not process files in '%s' because it does not have a '%s' " \ |
---|
115 | "directory." \ |
---|
116 | % (dirname, SVN_WC_ADM_DIR_NAME) |
---|
117 | return |
---|
118 | |
---|
119 | filenames.sort() |
---|
120 | |
---|
121 | # Find those filenames that match each fnmatch. |
---|
122 | for autoprops_line in autoprop_lines: |
---|
123 | fnmatch_str = autoprops_line[0] |
---|
124 | prop_list = autoprops_line[1] |
---|
125 | |
---|
126 | matching_filenames = fnmatch.filter(filenames, fnmatch_str) |
---|
127 | if not matching_filenames: |
---|
128 | continue |
---|
129 | |
---|
130 | for prop in prop_list: |
---|
131 | command = ['svn', 'propset', prop[0], prop[1]] |
---|
132 | for f in matching_filenames: |
---|
133 | command += ["%s/%s" % (dirname, f)] |
---|
134 | |
---|
135 | status = os.spawnvp(os.P_WAIT, 'svn', command) |
---|
136 | if status: |
---|
137 | print 'Command "%s" failed with exit status %s' \ |
---|
138 | % (command, status) |
---|
139 | sys.exit(1) |
---|
140 | |
---|
141 | def main(): |
---|
142 | config_filename = os.path.expandvars(SVN_CONFIG_FILENAME) |
---|
143 | try: |
---|
144 | fd = file(config_filename) |
---|
145 | except IOError: |
---|
146 | print "Cannot open svn configuration file '%s' for reading: %s" \ |
---|
147 | % (config_filename, sys.exc_value.strerror) |
---|
148 | |
---|
149 | autoprop_lines = get_autoprop_lines(fd) |
---|
150 | |
---|
151 | fd.close() |
---|
152 | |
---|
153 | autoprop_lines = process_autoprop_lines(autoprop_lines) |
---|
154 | |
---|
155 | os.path.walk('.', filter_walk, autoprop_lines) |
---|
156 | |
---|
157 | if __name__ == '__main__': |
---|
158 | sys.exit(main()) |
---|