Turns out that even in its unmaintained state, tailor is the best option for svn-to-svn copies out there, if you don't have svnadmin access to the destination... I did a recent project where I massaged the dump from the source (the key bit was the Lump-handling code from svndumpfilter, but replace the broken prop-handling there), loaded it into a scratch repo, and then tailor that into the destination.
Problem was that this (like git-svn and some others) ignores properties entirely. Since svn:keywords and svn:eol-style (among others) change what the content is checked out as, that wasn't good enough... The resulting hook is kind of evil, and incomplete, but useful enough that I thought I'd share it with other tailor users. The key bit of evil is monkey-patching SvnWorkingDir._commit to run a list of just-before-commit jobs -- before-commit is actually *too* soon, we need to apply properties after all svn "add" and "mv" operations have been done, but before the commit itself. (See force_decorate_once below.) The "incomplete" bits include * no support for *deletion* of properties - that would require looking at the destination tree and seeing what props are present only on the destination files/dirs (and handling renames within the same commit sanely.) In my use case, the only deletion was a typo that didn't have any impact on the files, so deleting it by hand afterwards was acceptable. * assumes that you're using svn on both sides - which is why this isn't suitable as a *patch*, only as a config-file hook (though adding a new just-before-commit-hook would be a useful patch, which would simplify this code.) * the svn hooks are just ad-hoc Popen calls; at very least they should use --xml to avoid quoting issues (but I knew in advance, from the dump, that there had never been any terribly interesting characters in prop names or values.) I think this gives tailor a bit of a leg up over git-svn (which is otherwise the "runner-up" in the comparison among the tools...) #!/usr/bin/env tailor # -*- python -*- """ ... [project] ... before-commit = before ... """ def svn_proplist(path): from subprocess import Popen, PIPE svn = Popen(["svn", "proplist", "-q", path], stdout=PIPE) props, _ = svn.communicate() if svn.wait() != 0: sys.exit("proplist failed with %s" % svn.returncode) return [prop.strip() for prop in props.split()] def svn_propget(path, propname): from subprocess import Popen, PIPE svn = Popen(["svn", "propget", propname, path], stdout=PIPE) propvalue, _ = svn.communicate() if svn.wait() != 0: sys.exit("propget failed with %s" % svn.returncode) assert propvalue.endswith("\n") propvalue = propvalue[:-1] # strip only the newline added by propget itself # we *could* use --xml for this, but the set of values we actually have is pretty limited return propvalue def svn_propset(path, propname, propvalue): from subprocess import check_call check_call(["svn", "propset", propname, propvalue, path]) # actually we want a list of things to do pre-commit, and then make repository.svn.SvnWorkingDir._commit do them def force_decorate_once(wd): if hasattr(wd.__class__, "_orig_commit"): return wd.__class__._orig_commit = wd.__class__._commit def wrapper(self, *args, **kwargs): for work in self.work_for_this_rev: work() self._orig_commit(*args, **kwargs) wd.__class__._commit = wrapper def before(wd, changeset): import sys, os import functools # the runnable-config-file hack does something weird/wrong with scoping, but this works around it global svn_proplist, svn_propget, svn_propset, force_decorate_once proj = wd.repository.projectref() repo_root = wd.repository.rootdir srcdir = proj.source.subdir targdir = proj.target.subdir work_for_this_rev = [] force_decorate_once(wd) for cs_entry in changeset.entries: if cs_entry.action_kind != cs_entry.DELETED: changed_src = os.path.join(repo_root, srcdir, cs_entry.name) changed_targ = os.path.join(repo_root, targdir, cs_entry.name) for propname in svn_proplist(changed_src): propvalue = svn_propget(changed_src, propname) work_for_this_rev.append(functools.partial(svn_propset, changed_targ, propname, propvalue)) setattr(wd, "work_for_this_rev", work_for_this_rev) return True _______________________________________________ Tailor mailing list Tailor@lists.zooko.com http://lists.zooko.com/mailman/listinfo/tailor