DEBUG_DELETE = 2 # Debug canonicalization after deletes
DEBUG_COMMANDS = 2 # Show commands as they are executed
+dryrun = False
+
class Baton:
"Ship progress indications to stdout."
def __init__(self, prompt, endmsg='done', enable=False):
def announce(msg):
print "rcs-fast-import:", msg
+class popen_or_die:
+ "Read or write from a subordinate process."
+ def __init__(self, cmd, legend="", mode="r"):
+ assert mode in ("r", "w")
+ self.cmd = cmd
+ self.legend = legend
+ self.mode = mode
+ if self.legend:
+ self.legend = " " + self.legend
+ def __enter__(self):
+ if verbose >= DEBUG_COMMANDS:
+ if self.mode == "r":
+ announce("reading from '%s'%s" % (self.cmd, self.legend))
+ else:
+ announce("writing to '%s'%s" % (self.cmd, self.legend))
+ if dryrun:
+ self.fp = file("/dev/null", self.mode)
+ return self.fp
+ try:
+ self.fp = os.popen(self.cmd, self.mode)
+ return self.fp
+ except OSError, e:
+ raise FatalException("execution of %s%s failed: %s" \
+ % (self.cmd, self.legend, e))
+ def __exit__(self, type, value, traceback):
+ if self.fp.close() is not None:
+ raise FatalException("%s%s returned error." \
+ % (self.cmd, self.legend))
+ return False
def do_or_die(cmd, legend=""):
"Either execute a command or raise a fatal exception."
if legend:
legend = " " + legend
if verbose >= DEBUG_COMMANDS:
announce("executing '%s'%s" % (cmd, legend))
+ if dryrun:
+ return
try:
retcode = subprocess.call(cmd, shell=True)
if retcode < 0:
@staticmethod
def master(filename):
"Return the master file corresponding to a specified filename."
- parts = os.path.split(filename)
+ parts = list(os.path.split(filename))
parts.insert(-1, "RCS")
- return os.path.join(parts)
- def modify(self, event, path, mode, copyfile):
+ return os.path.join(*parts)
+ def commit(self, event, committables):
"Perform RCS file checkins and modifications,"
- rcsdir = os.path.join(os.path.dirname(path), "RCS")
- if not os.path.exists(rcsdir):
- try:
- os.makdirs(rcsdir)
- except OSError:
- raise FatalException("can't create %s." % rcsdir)
- workdir = os.path.dirname(filename)
- masterfile = RCS.master(filename)
- exists = os.path.exists(path)
- shutil.copy(copyfile, workdir)
- exists = os.path.exists(path)
- if exists:
- fp = do_or_die("ci -m '%s'" % (event.comment))
+ inargs = []
+ for (path, mode, copyfile) in committables:
+ if mode == "160000":
+ announce("ignoring a submodule link %s", path)
+ continue
+ else:
+ inargs.append(RCS.master(path))
+ rcsdir = os.path.join(os.path.dirname(path), "RCS")
+ if not os.path.exists(rcsdir):
+ try:
+ os.makedirs(rcsdir)
+ except OSError:
+ raise FatalException("can't create %s." % rcsdir)
+ if verbose >= DEBUG_SHUFFLE:
+ announce("copying %s to %s" \
+ % (copyfile, os.path.dirname(path) or '.'))
+ if not dryrun:
+ shutil.copy(copyfile, os.path.dirname(path))
+ with popen_or_die("ci " + " ".join(inargs), "checkin", "w") as fp:
+ fp.write(event.comment)
def rename(self, source, target):
"Perform RCS renames."
# Dodgy, but since user is more likely to be
(options, arguments) = getopt.getopt(sys.argv[1:], "dlnuvV?")
do_unlocked_checkouts = False
checkout_mode = None
- dryrun = False
for (switch, val) in options:
if (switch == '-?'):
print __doc__
announce("Tagging %s with %s" % (event.committish, event.name))
vcs.tag(event)
elif isinstance(event, Commit):
+ committables = []
for op in event.fileops:
if op.op == "M":
if verbose:
announce("%5d M %s" % (i+1, op.path))
- if not dryrun:
- vcs.modify_file(event,
- op.path, op.mode, op.copyname)
+ committables.append((op.path, op.mode, op.copyname))
elif op.op in ("D", "deleteall"):
# If we delete masters, we lose ability to
# retrieve old versions.
vcs.copy(ops.source, op.target)
else:
raise FatalException("unknown op type %s" % op.op)
+ vcs.commit(event, committables)
vcs.checkout(checkout_mode)
raise SystemExit, 0
except FatalException, e: