]> thyrsus.com Git - src.git/commitdiff
src cat is working. So is revspec parsing.
authorEric S. Raymond <esr@thyrsus.com>
Thu, 6 Nov 2014 22:38:51 +0000 (17:38 -0500)
committerEric S. Raymond <esr@thyrsus.com>
Thu, 6 Nov 2014 22:38:51 +0000 (17:38 -0500)
src

diff --git a/src b/src
index c046738b41aad7c0599b94d9094dfc679e2449c9..8350814ad1ee8609eb5c6c534a9a15fe883652d6 100755 (executable)
--- a/src
+++ b/src
@@ -28,11 +28,11 @@ def croak(msg):
 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 = ""
@@ -77,6 +77,14 @@ class popen_or_die:
             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:
@@ -126,6 +134,9 @@ src commit ['revison-spec'] ['file'...]
 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.
 
@@ -159,18 +170,34 @@ def init_method(*args):
 
 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)
@@ -182,7 +209,9 @@ def add_method(*args):
 
 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)
@@ -198,41 +227,56 @@ def commit_method(*args):
            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,
@@ -241,13 +285,19 @@ dispatch = {
     "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: