#!/usr/bin/env python # To do: # 1) Switch to using the Subversion Python bindings. # # $HeadURL: https://svn.apache.org/repos/asf/subversion/trunk/contrib/client-side/svn_apply_autoprops.py $ # $LastChangedRevision: 1741723 $ # $LastChangedDate: 2016-04-30 04:16:53 -0400 (Sat, 30 Apr 2016) $ # $LastChangedBy: stefan2 $ # # Copyright (C) 2005,2006 Blair Zajac # # This script is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This script is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # A copy of the GNU General Public License can be obtained by writing # to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, # Boston, MA 02111-1307 USA. import getopt import fnmatch import os import re import sys # The default path to the Subversion configuration file. SVN_CONFIG_FILENAME = os.path.expandvars('$HOME/.subversion/config') # The name of Subversion's private directory in working copies. SVN_WC_ADM_DIR_NAME = '.svn' # The name this script was invoked as. PROGNAME = os.path.basename(sys.argv[0]) def usage(): print("""This script reads the auto-properties defined in the file '%s' and applies them recursively to all the files and directories in the current working copy. It may behave differently than the Subversion command line; where the subversion command line may only apply a single matching auto-property to a single pathname, this script will apply all matching lines to a single pathname. Usage: %s [options] [WC_PATH] where WC_PATH is the path to a working copy. If WC_PATH is not specified, '.' is assumed. Valid options are: --help, -h : Print this help text. --config ARG : Read the Subversion config file at path ARG instead of '%s'. """ % (SVN_CONFIG_FILENAME, PROGNAME, SVN_CONFIG_FILENAME)) def get_autoprop_lines(fd): lines = [] reading_autoprops = 0 re_start_autoprops = re.compile('^\s*\[auto-props\]\s*') re_end_autoprops = re.compile('^\s*\[\w+\]\s*') for line in fd.xreadlines(): if reading_autoprops: if re_end_autoprops.match(line): reading_autoprops = 0 continue else: if re_start_autoprops.match(line): reading_autoprops = 1 continue if reading_autoprops: lines += [line] return lines def process_autoprop_lines(lines): result = [] for line in lines: # Split the line on the = separating the fnmatch string from the # properties. try: (fnmatch, props) = line.split('=', 1) except ValueError: continue # Remove leading and trailing whitespace from the fnmatch and # properties. fnmatch = fnmatch.strip() props = props.strip() # Create a list of property name and property values. Remove all # leading and trailing whitespce from the propery names and # values. props_list = [] for prop in props.split(';'): prop = prop.strip() if not len(prop): continue try: (prop_name, prop_value) = prop.split('=', 1) prop_name = prop_name.strip() prop_value = prop_value.strip() except ValueError: prop_name = prop prop_value = '*' if len(prop_name): props_list += [(prop_name, prop_value)] result += [(fnmatch, props_list)] return result def filter_walk(autoprop_lines, dirname, filenames): # Do not descend into a .svn directory. try: filenames.remove(SVN_WC_ADM_DIR_NAME) except ValueError: pass filenames.sort() # Find those filenames that match each fnmatch. for autoprops_line in autoprop_lines: fnmatch_str = autoprops_line[0] prop_list = autoprops_line[1] matching_filenames = fnmatch.filter(filenames, fnmatch_str) matching_filenames = [f for f in matching_filenames \ if not os.path.islink(os.path.join(dirname, f))] if not matching_filenames: continue for prop in prop_list: command = ['svn', 'propset', prop[0], prop[1]] for f in matching_filenames: command += ["%s/%s" % (dirname, f)] status = os.spawnvp(os.P_WAIT, 'svn', command) if status: print('Command %s failed with exit status %s' \ % (command, status)) def main(): try: opts, args = getopt.getopt(sys.argv[1:], 'h', ['help', 'config=']) except getopt.GetoptError as e: usage() return 1 config_filename = None for (o, a) in opts: if o == '-h' or o == '--help': usage() return 0 elif o == '--config': config_filename = os.path.abspath(a) if not config_filename: config_filename = SVN_CONFIG_FILENAME if len(args) == 0: wc_path = '.' elif len(args) == 1: wc_path = args[0] else: usage() print("Too many arguments: %s" % ' '.join(args)) return 1 try: fd = file(config_filename) except IOError: print("Cannot open svn configuration file '%s' for reading: %s" \ % (config_filename, sys.exc_value.strerror)) return 1 autoprop_lines = get_autoprop_lines(fd) fd.close() autoprop_lines = process_autoprop_lines(autoprop_lines) os.path.walk(wc_path, filter_walk, autoprop_lines) if __name__ == '__main__': sys.exit(main())