properly (that is, rcs-fast-export | rcs-fast-import won't be an exact
copy) with differences near deleted, renamed, and copied files.
+Warning: All tag metadata other than the name will be lost.
"""
import sys, os, getopt, re, cStringIO, subprocess, shutil
def announce(msg):
print "rcs-fast-import:", msg
-def master(filename):
- "Return the master file corresponding to a specified filename."
- return "RCS/%s,v" % filename
-
def do_or_die(cmd, legend=""):
"Either execute a command or raise a fatal exception."
if legend:
raise FatalException("execution of %s%s failed: %s" % (cmd, legend, e))
#
-# All RCS-specific code is beyond this point.
-# It wouldn't be difficult to adapt this for SCCS, if there were any need.
+# All VCS-specific code is beyond this point. At the moment there's
+# just one VCS class, for RCS, but it would be easy to write another
+# for, say, SCCS.
#
-def modify_file(path, mode, copy):
- "Perform RCS file modifications,"
- rcsdir = os.path.join(os.path.dirname(path), "RCS")
- if not os.path.exists(rcsdir):
- try:
- os.mkdir(rcsdir)
- except OSError:
- raise FatalException("can't create %s." % rcsdir)
- # FIXME
+class RCS:
+ "Class encapsulating RCS version-control operations."
+ def __init__(self):
+ # Rev-to-branch map will go here
+ pass
+ @staticmethod
+ def master(filename):
+ "Return the master file corresponding to a specified filename."
+ return "RCS/%s,v" % filename
+ def modify(self, path, mode, copy):
+ "Perform RCS file checkins and modifications,"
+ rcsdir = os.path.join(os.path.dirname(path), "RCS")
+ if not os.path.exists(rcsdir):
+ try:
+ os.mkdir(rcsdir)
+ except OSError:
+ raise FatalException("can't create %s." % rcsdir)
+ def rename(self, source, target):
+ "Preform RCS renames."
+ # Dodgy, but since user is more likely to be
+ # interested in later versions this is better
+ # than doing nothing.
+ os.rename(RCS.master(op.source), RCS.master(op.target))
+ def copy(self, source, target):
+ "Preform RCS copies."
+ # The copy will get the original's history.
+ # There's a case that what we ought to do instead
+ # is check out the tip rev and use it to initialize
+ # a new master.
+ shutil.copy(RCS.master(source), RCS.master(target))
+ def tag(self, event):
+ "Process a tag event."
+ pass
+ def checkout(self, switch):
+ "Post-conversion actions."
+ pass
if __name__ == '__main__':
(options, arguments) = getopt.getopt(sys.argv[1:], "dlnuvV?")
- do_deletes = do_locked_checkouts = do_unlocked_checkouts = False
+ do_unlocked_checkouts = False
+ checkout_mode = None
dryrun = False
for (switch, val) in options:
if (switch == '-?'):
print __doc__
raise SystemExit, 0
- elif (switch == '-d'):
+ elif switch == '-d':
do_deletes = True
- elif (switch == '-l'):
- do_locked_checkouts = True
+ elif switch in ('-l', '-u'):
+ checkout_mode = switch
elif (switch == '-n'):
dryrun = True
- elif (switch == 'u'):
- do_unlocked_checkouts = True
elif (switch == '-v'):
verbose += 1
elif (switch == '-V'):
repo = Repository()
repo.fast_import(sys.stdin)
+ vcs = RCS()
try:
for (i, event) in enumerate(repo.events):
if isinstance(event, Blob) or isinstance(event, Reset) or isinstance(event, Passthrough):
continue
elif isinstance(event, Tag):
- # Tagger and comment info is lost.
if verbose:
announce("Tagging %s with %s" % (event.committish, event.name))
+ vcs.tag(event)
elif isinstance(event, Commit):
for op in event.fileops:
if op.op == "M":
if verbose:
announce("%5d M %s" % (i+1, op.path))
if not dryrun:
- modify_file(op.path, op.mode, op.copyname)
+ vcs.modify_file(op.path, op.mode, op.copyname)
elif op.op in ("D", "deleteall"):
- masterfile = master(op.path)
# If we delete masters, we lose ability to
# retrieve old versions.
if do_deletes:
if verbose:
announce("%5d D %s" % (i+1, op.path))
if not dryrun:
- os.remove(masterfile)
+ vcs.remove(op.path)
elif verbose:
- announce("%5d D %s ignored" % (i+1, masterfile))
+ announce("%5d D %s ignored" % (i+1, op.path))
elif op.op == "R":
- # Dodgy, but since user is more likely to be
- # interested in later versions this is better
- # than doing nothing.
if verbose:
announce("%5d R '%s' '%s'" % (i+1, op.source, op.target))
if not dryrun:
- os.rename(master(op.source), master(op.target))
+ vcs.rename(op.source, op.target)
elif op.op == "C":
- # The copy will get the original's history.
- # There's a case that what we ought to do instead
- # is check out the tip rev and use it to initialize
- # a new master.
if verbose:
announce("%d C '%s' '%s'" % (i+1, op.source, op.target))
if not dryrun:
- shutil.copy(master(op.source), master(op.target))
+ vcs.copy(ops.source, op.target)
else:
raise FatalException("unknown op type %s" % op.op)
- if do_locked_checkouts or do_unlocked_checkouts:
- # FIXME
- pass
+ vcs.checkout(checkout_mode)
raise SystemExit, 0
except FatalException, e:
complain(e.msg)