#
# src - simple revision control.
#
-import sys, os
+import sys, os, subprocess
version = 0.1
+def announce(msg):
+ sys.stdout.write("src: " + msg + "\n")
+
def complain(msg):
sys.stderr.write("src: " + msg + "\n")
-def help(*args):
+debug = 0
+DEBUG_COMMANDS = 1 # Show commands as they are executed
+
+def do_or_die(dcmd, legend=b""):
+ "Either execute a command or raise a fatal exception."
+ if legend:
+ legend = " " + legend
+ if debug >= DEBUG_COMMANDS:
+ announce(b"executing '%s'%s" % (dcmd, legend))
+ try:
+ retcode = subprocess.call(dcmd, shell=True)
+ if retcode < 0:
+ complain(b"child was terminated by signal %d." % -retcode)
+ elif retcode != 0:
+ complain(b"child returned %d." % retcode)
+ except (OSError, IOError) as e:
+ complain(b"execution of %s%s failed: %s" % (dcmd, legend, e))
+
+class popen_or_die:
+ "Read or write from a subordinate process."
+ def __init__(self, command, legend=b"", mode=b"rb"):
+ assert mode in (b"rb", b"wb")
+ self.command = command
+ self.legend = legend
+ self.mode = mode
+ if self.legend:
+ self.legend = b" " + self.legend
+ self.fp = None
+ def __enter__(self):
+ if debug >= DEBUG_COMMANDS:
+ if self.mode == "r":
+ announce(b"%s: reading from '%s'%s" % (rfc3339(time.time()), self.command, self.legend))
+ else:
+ announce(b"%s: writing to '%s'%s" % (rfc3339(time.time()), self.command, self.legend))
+ try:
+ self.fp = os.popen(self.command, self.mode)
+ return self.fp
+ except (OSError, IOError) as oe:
+ complain(b"execution of %s%s failed: %s" \
+ % (self.command, self.legend, oe))
+ def __exit__(self, extype, value, traceback_unused):
+ if extype:
+ if verbose:
+ complain(b"fatal exception in popen_or_die.")
+ raise extype(value)
+ if self.fp.close() is not None:
+ complain(b"%s%s returned error." % (self.command, self.legend))
+ return False
+
+def help_method(*args):
"Summarize src commands, or (with argument) show help for a single command."
print"""
src help [command]
src commit ['revison-spec'] ['file'...]
Enters a commit for specified files. Separately to each one.
+src checkout [revspec] ['file'...]
+ Refresh the working copy of the file(s) from their history files.
+
src branch [delete] ['branchname']
Create, switch to, or delete a branch. With no arguments, list branches.
Export one or more projects as a git fast-import stream.
"""
-def init(*args):
+def init_method(*args):
"Create a .src directory if none already exists."
if not os.path.exists(".src"):
try:
else:
complain(".src/ exists but is not a directory.")
+def add_method(*args):
+ "Register a file into src control."
+ for arg in args:
+ if not os.path.exists(arg):
+ complain("I see no '%s' here." % arg)
+ elif os.path.exists(".src/%s,v"):
+ complain("%s is already registered.")
+ else:
+ do_or_die("rcs -q -i %s </dev/null" % arg)
+ do_or_die("ci -l %s && mv %s,v .src" % (arg, arg))
+ announce("%s: 1" % arg)
+
+dispatch = {
+ "help": help_method,
+ "init": init_method,
+ "add": add_method,
+}
+
if __name__ == "__main__":
command = sys.argv[1:]
if not command:
- help()
+ help_method()
else:
try:
- eval(command[0])(*command[1:])
- except NameError:
+ apply(dispatch[command[0]], command[1:])
+ except KeyError:
sys.stderr.write("src: no such command as '%s'. Try 'src help'\n" \
% command[0])