| #!/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) |