160 lines
4.7 KiB
Python
Executable file
160 lines
4.7 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# -*- python -*-
|
|
|
|
"""
|
|
NAME
|
|
%(program)s - find a filename close to a given a SVN repository commit
|
|
|
|
SYNOPSIS
|
|
%(program)s [OPTIONS] REPO REV NAME
|
|
|
|
DESCRIPTION
|
|
Supposing we have a subversion repository containing a trunk and
|
|
various branches. Given the repository url and the revision number of
|
|
a commit, what is the top of the branch? $(program)s attempts to
|
|
answer this by letting you search for a specific file name which is
|
|
assumed to be unique within the branch and be situated at the top of
|
|
the branch subtree.
|
|
|
|
%(options)s
|
|
|
|
AUTHOR
|
|
Written by Henrik Levkowetz, <henrik@zinfandel.tools.ietf.org>
|
|
|
|
COPYRIGHT
|
|
Copyright 2015 Henrik Levkowetz
|
|
|
|
This program 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. There is NO WARRANTY; not even the
|
|
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the GNU General Public License for more details.
|
|
|
|
"""
|
|
|
|
import sys, os.path, getopt, re
|
|
|
|
version = "0.13"
|
|
program = os.path.basename(sys.argv[0])
|
|
progdir = os.path.dirname(sys.argv[0])
|
|
|
|
# ----------------------------------------------------------------------
|
|
# Parse options
|
|
|
|
options = ""
|
|
for line in re.findall("\n +(if|elif) +opt in \[(.+)\]:\s+#(.+)\n", open(sys.argv[0]).read()):
|
|
if not options:
|
|
options += "OPTIONS\n"
|
|
options += " %-16s %s\n" % (line[1].replace('"', ''), line[2])
|
|
options = options.strip()
|
|
|
|
# with ' < 1:' on the next line, this is a no-op:
|
|
if len(sys.argv) <= 1:
|
|
help()
|
|
|
|
try:
|
|
opts, files = getopt.gnu_getopt(sys.argv[1:], "dfDhv", ["dirchange", "filechange", "dirpath", "help", "version",])
|
|
except Exception, e:
|
|
print "%s: %s" % (program, e)
|
|
sys.exit(1)
|
|
|
|
# ----------------------------------------------------------------------
|
|
# Handle options
|
|
|
|
# set default values, if any
|
|
opt_dirpath = False
|
|
opt_dirchange = False
|
|
opt_filechange = False
|
|
opt_verbose = False
|
|
|
|
# ----------------------------------------------------------------------
|
|
def help(msg=None, err=0):
|
|
if msg:
|
|
print(msg+'\n')
|
|
print(__doc__ % globals())
|
|
sys.exit(err)
|
|
|
|
# handle individual options
|
|
for opt, value in opts:
|
|
if opt in ["-h", "--help"]: # Output this help, then exit
|
|
help()
|
|
elif opt in ["-v", "--version"]: # Output version information, then exit
|
|
print program, version
|
|
sys.exit(0)
|
|
elif opt in ["-d", "--dirchange"]: # Look only for directory changes
|
|
opt_dirchange = True
|
|
elif opt in ["-f", "--filechange"]: #Look only for file changes
|
|
opt_filechange = True
|
|
elif opt in ["-D", "--dirpath"]: # Output the directory path, not the file path
|
|
opt_dirpath = True
|
|
|
|
# if neither filechange nor dirchange have been specified, look for both
|
|
if not opt_filechange and not opt_dirchange:
|
|
opt_filechange = True
|
|
opt_dirchange = True
|
|
|
|
# ----------------------------------------------------------------------
|
|
def help(msg=None, err=0):
|
|
if msg:
|
|
print(msg+'\n')
|
|
print(__doc__ % globals())
|
|
sys.exit(err)
|
|
|
|
# ----------------------------------------------------------------------
|
|
def say(s):
|
|
sys.stderr.write("%s\n" % (s))
|
|
|
|
# ----------------------------------------------------------------------
|
|
def note(s):
|
|
if opt_verbose:
|
|
sys.stderr.write("%s\n" % (s))
|
|
|
|
# ----------------------------------------------------------------------
|
|
def die(s, error=1):
|
|
sys.stderr.write("\n%s: Error: %s\n\n" % (program, s))
|
|
sys.exit(error)
|
|
|
|
# ----------------------------------------------------------------------
|
|
# Bad args
|
|
|
|
if len(files) < 3:
|
|
help("Not enogh arguments\n\nExpected %s REPO REV NAME" %program, 1)
|
|
|
|
# ----------------------------------------------------------------------
|
|
# The program itself
|
|
|
|
import pysvn
|
|
#import debug
|
|
|
|
repo, rev, name = files
|
|
|
|
changeset = pysvn.Transaction(repo, rev, True)
|
|
changed = changeset.changed()
|
|
|
|
# Each dictionary entry is a tuple, with elements as follows:
|
|
CHG_ACTION, CHG_KIND, CHG_TEXTMOD, CHG_PROPMOD = range(4)
|
|
|
|
node = None
|
|
for key in changed:
|
|
if opt_dirchange and changed[key][CHG_KIND] == pysvn.node_kind.dir:
|
|
node = key
|
|
break
|
|
if opt_filechange and changed[key][CHG_KIND] == pysvn.node_kind.file:
|
|
node = '/'.join(key.split('/')[:-1])
|
|
break
|
|
|
|
while node:
|
|
#debug.show('node')
|
|
list = changeset.list(node)
|
|
if name in list:
|
|
if opt_dirpath:
|
|
print node
|
|
else:
|
|
sys.stdout.write(node)
|
|
sys.stdout.write('/')
|
|
sys.stdout.write(name)
|
|
sys.stdout.write('\n')
|
|
break
|
|
node = '/'.join(node.split('/')[:-1])
|