On Wed, Dec 08, 2010 at 11:59:16PM -0800, JamieEchlin wrote:
>
> Daniel, thank you very much for that, that's incredibly helpful. It
> definitely gives me somewhere to start.
Hope, you'll be able to solve your problem. Here's a script that's a bit
more clean than the previous one. I haven't tested it much at all but it
appears to be able to display added, modified and deleted properties set
on both dirs and files. The '###' lines represents TODO's.
Daniel
#!/usr/bin/env python
import sys
import os
import getopt
try:
my_getopt = getopt.gnu_getop
except AttributeError:
my_getopt = getopt.getopt
import svn.wc
import svn.core
EQUAL_STRING = (
"========================================================================")
UNDER_STRING = (
"------------------------------------------------------------------------")
def usage_and_exit(retval):
if retval:
out = sys.stderr
else:
out = sys.stdout
out.write("""Usage: %s TARGET
Options:
--help (-h) : Show this usage message
Display the difference between the BASE revision and the changes made in the
working copy. This is just a very basic example script. It doesn't properly
handle revisions or the problems involved in adjusting diff labels. At
present it always prints one diff header for each file or dir that has
property changes. If we'd check for more than property changes - we need to
keep track of when we have printed a diff header. Some files can have both
property and text changes.
""" % (os.path.basename(sys.argv[0])))
sys.exit(retval)
def print_diff_headers(path, rev):
print "Index: %s" % path
print EQUAL_STRING
print "--- %s\t (revision %d)" % (path, rev)
### Here we'd check rev2 against some constant that represents the "working
### copy revision" - it's probably -1.
print "+++ %s\t (working copy)" % path
def props_changed(path, propchanges, originalprops):
print "\nProperty changes on %s" % path
print UNDER_STRING
for (name, value) in propchanges.items():
if originalprops is not None and name in originalprops:
original_value = originalprops[name]
else:
original_value = None
if not (value or original_value) or (value == original_value):
continue
if not original_value:
print "Added: %s" % name
elif not value:
print "Deleted %s" % name
else:
print "Modified %s" % name
### We're ignoring special handling of svn:mergeinfo for now.
### Do we have to handle utf8 conversions here?
if original_value is not None:
print " - %s" % original_value
if value is not None:
print " + %s" % value
def content_changed(path, tmpfile1, tmpfile2, rev1, rev2, mimetype1,
mimetype2):
### TODO: Write this one
pass
def has_regular_prop_changes(props):
if not props:
return False
### For some reason, svn_categorize_props() segfaults
### Shouldn't we only pass the regular_props to props_changed?
for (name, value) in props.items():
(kind, unused_prefix_len) = svn.core.svn_property_kind(name)
if kind == svn.core.svn_prop_regular_kind:
return True
return False
class Callback(svn.wc.DiffCallbacks2):
def file_changed(self, adm_access, path,
tmpfile1, tmpfile2, rev1, rev2,
mimetype1, mimetype2, propchanges,
originalprops):
if has_regular_prop_changes(propchanges):
print_diff_headers(path, rev1)
props_changed(path, propchanges, originalprops)
return (svn.wc.notify_state_unknown, svn.wc.notify_state_unknown)
def file_added(self, adm_access, path, tmpfile1, tmpfile2,
rev1, rev2, mimetype1, mimetype2, propchanges,
originalprops):
return (svn.wc.notify_state_unknown, svn.wc.notify_state_unknown)
def file_deleted(self, adm_access, path, tmpfile1,
tmpfile2, mimetype1, mimetype2, originalprops):
return svn.wc.notify_state_unknown
def dir_added(self, adm_access, path, rev):
return svn.wc.notify_state_unknown
def dir_deleted(self, adm_access, path):
return svn.wc.notify_state_unknown
def dir_props_changed(self, adm_access, path,
propchanges, originalprops):
if has_regular_prop_changes(propchanges):
### How fetch the revision here?
rev = 42
print_diff_headers(path, rev)
props_changed(path, propchanges, originalprops)
return svn.wc.notify_state_unknown
def main():
diff_callbacks = Callback()
depth = svn.core.svn_depth_infinity
# Parse the options
optlist, args = my_getopt(sys.argv[1:], "h", ['help'])
for opt, arg in optlist:
if opt == '--help' or opt == '-h':
usage_and_exit(1)
if len(args) != 1:
usage_and_exit(1)
if os.path.isdir(args[0]):
target = ''
wc_dir = args[0]
else:
target = os.path.basename(args[0])
wc_dir = os.path.dirname(args[0])
try:
# Subversion wants all paths to be canonicalised, that involves
# collapsing redundant "/./" elements, removing multiple adjacent
# separator characters and removing trailing separator characters.
canon_wc_dir = svn.core.svn_path_canonicalize(wc_dir)
canon_target = svn.core.svn_path_canonicalize(target)
# The C code that Subversion consists of, uses apr pools for allocation of
# memory. The idea is that the pools in the swig bindings are
# (mostly) optional and auto-managed in accordance with the lifetime
# of the python objects themselves. They are needed in the places
# I've used them, but later releases may not need them.
pool = svn.core.Pool()
# The wc, of svn_wc_adm_access_t type, is a data structure for
# coordinating the access to the working copy administrative area
# (the .svn folders). It is associated with the containing parent
# dir. I find the adm_access approach a bit messy - you can specify
# how far you wanna lock and multiple access_batons can form sets.
# The 1.7 release will introduce a more intuitive way of accessing
# the wc administrative area.
wc = svn.wc.adm_open3(None, canon_wc_dir,
True, # write_lock
-1, # levels_to_lock,
None)
svn.wc.svn_wc_diff4(wc, canon_target, diff_callbacks, depth, False,
None, pool)
except svn.core.SubversionException, ex:
sys.stderr.write("ERROR: %s\n" % ex.message)
if __name__ == '__main__':
main()
Received on 2010-12-09 22:26:08 CET