#!/usr/bin/env python
# Multiple URL Command Client
#
# Combine a list of mv, cp, rm, and put commands on URLs into a single commit
#
# To read the help for this program, type python mucc.py --help
import os
from csvn.core import *
from csvn.repos import RemoteRepository, RepositoryURI
from csvn.auth import User
from optparse import OptionParser
usage = """python mucc.py [OPTION]... [ACTION]...
Actions:
cp REV URL1 URL2 copy URL1@REV to URL2
mkdir URL create new directory URL
mv URL1 URL2 move URL1 to URL2
rm URL delete URL
put SRC-FILE URL add or modify file URL with contents copied
from SRC-FILE
propset NAME VAL URL Set property NAME on URL to value VAL
propdel NAME URL Delete property NAME from URL
"""
# Read and parse options
parser = OptionParser(usage=usage)
parser.add_option("-m", "--message", dest="message",
help="use MESSAGE as a log message")
parser.add_option("-F", "--file", dest="file",
help="read log message from FILE")
parser.add_option("-u", "--username", dest="username",
help="commit the changes as USERNAME")
parser.add_option("-p", "--password", dest="password",
help="use password PASSWORD")
parser.add_option("-U", "--root-url", dest="root_url",
help="Interpret all action URLs as relative to ROOT_URL")
parser.add_option("-r", "--revision", dest="rev",
help="Use REV as baseline for changes")
parser.add_option("-X", "--extra-args ARG", dest="extra_args",
help='append arguments from file EXTRA_ARGS (one per line; '
'use "-" to read from standard input)')
(options, args) = parser.parse_args()
# Read any extra arguments
if options.extra_args:
f = file(options.extra_args)
for line in f:
args.append(line.strip())
if not args:
parser.print_help()
sys.exit(1)
# Initialize variables
root_url = options.root_url
actions = []
svn_cmdline_init("", stderr)
pool = Pool()
action = None
if root_url:
anchor = RepositoryURI(root_url)
else:
anchor = None
states = None
ancestor = None
# A list of the arguments accepted by each command
cmds = {
"cp": [ "rev", "url", "url" ],
"mkdir": [ "url" ],
"mv": [ "url", "url" ],
"rm": [ "url" ],
"put": [ "file", "url" ],
"propset": [ "name", "val", "url" ],
"propdel": [ "name", "url" ],
}
# Build up a list of the actions we want to perform
for arg in args:
if not states:
action = [arg]
actions.append((arg, action))
states = list(cmds[arg])
states.reverse()
else:
state = states.pop()
if state == "rev":
action.append(arg.upper() != "HEAD" and int(arg) or None)
elif state == "url":
arg = RepositoryURI(arg)
if anchor:
arg = anchor.join(arg)
action.append(arg)
# It's legal to make a copy of the repository root,
# so, we should treat copyfrom paths as possible
# repository roots
may_be_root = (len(action) == 2 and action[0] == "cp")
if not may_be_root:
arg = arg.dirname()
if ancestor:
ancestor = ancestor.longest_ancestor(arg)
else:
ancestor = arg
else:
action.append(arg)
session = RemoteRepository(ancestor, user=User(username=options.username))
txn = session.txn()
# Carry out the transaction
for action, args in actions:
if action == "cp":
txn.copy(src_rev=args[1], src_path=args[2], dest_path=args[3])
elif action == "mv":
txn.delete(str(args[1]))
txn.copy(src_path=args[1], dest_path=args[2])
elif action == "rm":
txn.delete(args[1])
elif action == "mkdir":
txn.mkdir(args[1])
elif action == "put":
txn.upload(local_path=args[1], remote_path=args[2])
elif action == "propset":
txn.propset(key=args[1], value=args[2], path=args[3])
elif action == "propdel":
txn.propdel(key=args[1], path=args[2])
# Get the log message
message = options.message
if options.file:
message = file(options.file).read()
# Finally commit
txn.commit(message)
print("r%ld committed by %s at %s" % (txn.committed_rev, options.username,
txn.committed_date))