#!/usr/bin/env python # -*- coding:utf-8;mode:python;mode:font-lock -*- ## # Apply autoprops configuration to a working copy. # Requires python 2.3+ ## # Copyright (c) 2005 Wilfredo Sanchez Vega . # All rights reserved. # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE # AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL # DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR # PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. ## import sys import os import getopt import ConfigParser import fnmatch __doc__ = """ This program applies Subversion's configuration file (defaults to ~/.subversion/config), reads the autoprops settings, and applies them to all files in a working directory. The reason that this is useful is that the autoprops settings are only used by Subversion when new files are added to the repository. If you were, for example, to change the MIME type for a file extension already in use in the repository, and you want that change to apply to existing files, run this tool on a working copy to update those files, then commit the property changes. """ ## # Handle command line ## # Defaults verbose = True dry_run = False config_filename = os.path.join(os.environ["HOME"], ".subversion", "config") clear_nomatch = [] clear_noprop = [] program = sys.argv[0] # Need Python 2.3 if sys.version_info[0] < 2 or (sys.version_info[0] == 2 and sys.version_info[1] < 3): print "%s requires python version >= 2.3" % (program,) sys.exit(1) # Usage def usage(e=None): if e: print e print "" print "usage: %s [options]" % (program,) print "options:" print "\t-v, --verbose Be verbose" print "\t-q, --quiet Be quiet" print "\t-n, --dry-run Don't actually do anything (pretty boring with -q)" print "\t-f, --config file Specify config file [%s]" % (config_filename,) print "\t--clear-nomatch prop[;prop...] Clear properties on files with no matching pattern in config" print "\t--clear-noprop prop[;prop...] Clear properties on files with matching pattern but no props in config" if e: sys.exit(1) else: sys.exit(0) # Read options try: (optargs, args) = getopt.getopt( sys.argv[1:], "vqnf:", [ "quiet", "verbose", "dry-run", "config=", "clear-nomatch=", "clear-noprop=", ] ) except getopt.GetoptError, e: usage(e) for optarg in optargs: (opt, arg) = optarg if opt == "-v" or opt == "--verbose": verbose = True elif opt == "-q" or opt == "--quiet": verbose = False elif opt == "-n" or opt == "--dry-run": dry_run = True elif opt == "-f" or opt == "--config": config_filename = arg elif opt == "--clear-nomatch": clear_nomatch.extend(arg.split(";")) elif opt == "--clear-noprop": clear_noprop.extend(arg.split(";")) working_copies = args for wc in working_copies: if not os.path.isdir(wc) or not os.path.isdir(os.path.join(wc, ".svn")): print "Not a working copy: %r" % wc sys.exit(1) ## # Do The Right Thing ## # # Read Subversion config # if not os.path.isfile(config_filename): raise AssertionError("No config file %r" % config_filename) config_file = file(config_filename) try: parser = ConfigParser.SafeConfigParser() parser.readfp(config_file, config_filename) finally: config_file.close() if not parser.has_section("auto-props"): print "No auto props." sys.exit(0) # # Apply auto props # def run(cmd): input, output = os.popen4(cmd) try: input.close() if verbose: for line in output: sys.stdout.write(line) else: output.read() finally: output.close() def do_clear(path, names): for name in names: if dry_run: print "%s: delete %s" % (path, name) else: run(("svn", "propdel", name, path)) for wc in working_copies: for dir, subdirs, files in os.walk(wc): subdirs.remove(".svn") for subdir in subdirs: if not os.path.isdir(os.path.join(dir, subdir, ".svn")): subdirs.remove(subdir) for filename in files: path = os.path.join(dir, filename) pattern_count = 0 for pattern in parser.options("auto-props"): if fnmatch.fnmatch(filename, pattern): properties = parser.get("auto-props", pattern) for property in properties.split(";"): name, value = property.split("=") if dry_run: print "%s -> %s = %s" % (path, name, value) else: run(("svn", "propset", name, value, path)) do_clear(path, [p for p in clear_noprop if p not in properties]) pattern_count += 1 if pattern_count is 0: if clear_nomatch: do_clear(path, clear_nomatch) else: if verbose: print "%s: No pattern matches in config" % filename