debug = 0
DEBUG_COMMANDS = 1 # Show commands as they are executed
-def do_or_die(dcmd, legend=b""):
+def do_or_die(dcmd, legend=b"", loud=False):
"Either execute a command or raise a fatal exception."
if legend:
legend = " " + legend
- if debug == 0:
+ if debug == 0 and not loud:
mute = " >/dev/null 2>&1"
else:
mute = ""
complain(b"%s%s returned error." % (self.command, self.legend))
return False
+class RCSRevisionItem:
+ "Capture the state of an RCS revision item in the log."
+ def __init__(self, revno):
+ self.revno = revno;
+ self.revision = None
+ self.log = ""
+ self.date = None
+
def log_capture(fn):
"Capture and parse the metadata for a specified file."
with popen_or_die("cd .src >/dev/null; rlog %s; cd ..>/dev/null" % fn) as fp:
src checkout [revspec] ['file'...]
Refresh the working copy of the file(s) from their history files.
+src cat [revspec] ['file'...]
+ Send the specified revisions of the files to standard output.
+
src branch [delete] ['branchname']
Create, switch to, or delete a branch. With no arguments, list branches.
def preamble(cmd, args):
"Common setup code."
- if args:
- return list(args)
- else:
+ args = list(args)
+ revspec = None
+ if args and args[0].isdigit():
+ revspec = args.pop(0)
+ try:
+ if "-" in revspec:
+ (start, end) = revspec.split("-")
+ start = int(start)
+ end = int(end)
+ else:
+ start = int(revspec)
+ end = start
+ except ValueError:
+ croak("malformed revision spec: %s" % revspec)
+ revspec = range(start, end+1)
+ if not args:
masters = os.listdir(".src")
if len(masters) == 1:
- return [masters[0][:-2]]
+ args += [master[:-2] for master in masters]
else:
croak("%s requires at least one file argument" % cmd)
+ return(revspec, args)
def add_method(*args):
"Register a file into src control."
- args = preamble("add", args)
+ (revspec, args) = preamble("add", args)
+ if revspec is not None:
+ croak("add doesn't take a revision spec")
for arg in args:
if not os.path.exists(arg):
complain("I see no '%s' here." % arg)
def commit_method(*args):
"Commit changes to files."
- args = preamble("commit", args)
+ (revspec, args) = preamble("commit", args)
+ if revspec is not None:
+ croak("commit doesn't take a revision spec")
for arg in args:
if not os.path.exists(arg):
complain("I see no '%s' here." % arg)
revlist = log_capture(arg)
announce("%s -> %d" % (arg, len(revlist)))
-class RCSRevisionItem:
- "Capture the state of an RCS revision item in the log."
- def __init__(self, revno):
- self.revno = revno;
- self.revision = None
- self.log = ""
- self.date = None
-
def list_method(*args):
- args = preamble("list", args)
+ "Generate a summary listing of commits, one line per commit."
+ (revspec, args) = preamble("list", args)
width = screenwidth()
for arg in args:
sys.stdout.write("= %s %s\n" % (arg, ((width - len(arg) - 5) * "=")))
for item in log_capture(arg):
- # Must allow enough room for revno and date
- summary = item.log.strip()[:width - 32]
- sys.stdout.write("%-4d %s %s\n" % (item.revno, item.date, summary))
+ if not revspec or item.revno in revspec:
+ # Must allow enough room for revno and date
+ summary = item.log.strip()[:width - 32]
+ sys.stdout.write("%-4d %s %s\n" % (item.revno, item.date, summary))
def log_method(*args):
- args = preamble("log", args)
+ "Report revision logs"
+ (revspec, args) = preamble("log", args)
width = screenwidth()
for arg in args:
sys.stdout.write("= %s %s\n" % (arg, ((width - len(arg) - 5) * "=")))
for item in log_capture(arg):
- sys.stdout.write("%-4d | %s\n%s" % (item.revno, item.date, item.log))
- sys.stdout.write(("-" * (width - 1)) + "\n")
+ if not revspec or item.revno in revspec:
+ sys.stdout.write("%-4d | %s\n%s" % (item.revno, item.date, item.log))
+ sys.stdout.write(("-" * (width - 1)) + "\n")
def checkout_method(*args):
- args = preamble("checkout", args)
- width = screenwidth()
+ (revspec, args) = preamble("checkout", args)
+ if len(revspec) > 1:
+ croak("checkout needs an empty or singleton revision spec")
for arg in args:
revlist = log_capture(arg)
- do_or_die("mv .src/{0},v . && rm {0} && co -l {0} && mv {0},v .src".format(arg))
+ if revspec is None:
+ revision = ""
+ elif len(revspec) == 1:
+ revision = "-r" + revlist[revspec[0]-1].revision
+ else:
+ croak("checkout cannot take a range")
+ do_or_die("mv .src/{0},v . && rm {0} && co -l -r%s {0} && mv {0},v .src".format(arg, revision))
announce("%s <- %d" % (arg, len(revlist)))
+def cat_method(*args):
+ (revspec, args) = preamble("cat", args)
+ for arg in args:
+ revlist = log_capture(arg)
+ if revspec is None:
+ revspec = range(1, len(revlist)+1)
+ do_or_die("mv .src/{0},v .".format(arg))
+ for item in revlist:
+ if item.revno in revspec:
+ do_or_die("co -q -p -r{1} {0}".format(arg, item.revision), loud=True)
+ do_or_die("mv {0},v .src".format(arg))
+
dispatch = {
"help": help_method,
"init": init_method,
"list": list_method,
"log": log_method,
"checkout": checkout_method,
+ "cat": cat_method,
}
if __name__ == "__main__":
+
command = sys.argv[1:]
if not command:
help_method()
else:
+ command = list(command)
+ while command[0] == "-d":
+ debug += 1
+ command.pop(0)
try:
apply(dispatch[command[0]], command[1:])
except KeyError: