from mercurial import util, commands, mdiff, node
import os

def slimecommit(ui, repo, cvsdir, start, *revs):
    "Commit revisions to a cvs repo."
    print("cvsdir: %s" % cvsdir)
    if dirtyp(ui, repo, cvsdir):
	raise util.Abort("CVS directory is dirty.")
    node1 = repo.lookup(start)
    for r in revs:
	node2 = repo.lookup(r)
	msg = ("Committing %s (%s..%s)" % 
	       (r, node.short(node1), node.short(node2)))
	ui.note(msg + " -- \n")
	transmit(ui, repo, cvsdir, node1, node2)
	ui.note(msg + " -- done.\n")
	node1 = node2

def transmit(ui, repo, cvsdir, start, end):
    (modified, add, rem, delete, unknown, ign, clean) = repo.status(start, end)
    assert(not (add or rem or delete))
    if not insyncp(ui, repo, cvsdir, start, modified):
	raise util.Abort("CVS directory and start rev not in sync.")
    id = repo.changelog.read(end)[0]
    manifest = repo.manifest.read(id)
    for f in modified:
	cvs = os.path.join(cvsdir, f)
	data = repo.file(f).read(manifest[f])
	file(cvs, 'w').write(data)
    commit(ui, repo, cvsdir, end, modified)

def commit(ui, repo, cvsdir, node, files):
    (id, user, date, _files, desc, extra) = repo.changelog.read(node)
    args = ["-", "/bin/bash", "-c", 
	    ("cd %s " % cvsdir) + '&& cvs commit -m "$@"', "cvs", desc]
    status = os.spawnv(os.P_WAIT, "/usr/bin/env", args + files)
    assert(status == 0)

def dirtyp(ui, repo, cvsdir):
    ui.note("Running cvs update.\n")
    status = os.system(("cd %s " % cvsdir ) + 
		       "&& cvs update >/dev/null 2>&1 " +
		       "&& cvs -n update 2>&1 " +
		       "| awk '/(cvs update:|\? )/{next}; " +
		       "{ print; bad += 1 }; " + 
		       "END { exit bad }'" )
    return status != 0

def insyncp(ui, repo, cvsdir, node, files):
    (id, user, date, _files, desc, extra) = repo.changelog.read(node)
    manifest = repo.manifest.read(id)
    for f in files:
	ui.note("Checking file %s\n" % f)
	cvs = os.path.join(cvsdir, f)
	if not os.path.isfile(cvs):
	    raise util.Abort('CVS out of sync. File "%s" is missing' % f)
	data = repo.file(f).read(manifest[f])
	if data != file(cvs).read():
	    diff = mdiff.unidiff(data, util.datestr(date),
	    			 file(cvs).read(), util.datestr(), f)
	    ui.note('Offending difference of %s\n%s\n' % (f, diff))
	    raise util.Abort('CVS out of sync.  File %s differs.' % f)
    return True

cmdtable = {
    "slimecommit":
	(slimecommit,
	 [],
	 "hg slimecommit CVSDIR START REV..."),
    }
