#!/usr/bin/python
"""
cvssync - discover and fetch a CVS repository using rsync

This tool is a front end for rsync that attempts to deduce how to get
a copy of a CVS repository by analyzing the arguments you are told
to pass CVS to check out a copy.

The magic (when there is any) is in knowing how to construct the
actual path to the repository from the host, path and module arguments.
"""

# Hosting-site rules live inside the following function.

def computesource(host, path, module):
    "Compute an rsync source given a CVS host, path, and module"
    if "sourceforge" in host:
        # On SourceForge you need to double the colon and strip the
        # leading / to invoke the rsync module facility.
        return "%s::%s/%s/" % (host, path[1:], module)
    elif "berlios" in host:
        # The pattern is rsync -av cvs.berlios.de::<projectname>_cvs cvs
        return "cvs.berlios.de::%s_cvs" % module
    # Savannah retrievals work by pasting the pieces together
    # in the default way.
    else:
        return "%s:%s/%s/" % (host, path, module)

# You should not need to modify anything below this line

import sys, getopt, subprocess

verbose = False
execute = True

def do_or_die(dcmd):
    "Either execute a command or raise a fatal exception."
    if verbose:
        sys.stdout.write("cvssync: executing '%s'\n" % (dcmd,))
    if execute:
        try:
            retcode = subprocess.call(dcmd, shell=True)
            if retcode < 0:
                sys.stderr.write("cvssync: child was terminated by signal %d.\n" % -retcode)
                sys.exit(1)
            elif retcode != 0:
                sys.stderr.write("cvssync: child returned %d.\n" % retcode)
                sys.exit(1)
        except (OSError, IOError) as e:
            sys.stderr.write("cvssync: execution of %s%s failed: %s\n" % (dcmd, legend, e))
            sys.exit(1)

if __name__ == '__main__':

    (opts, arguments) = getopt.getopt(sys.argv[1:], "no:v")
    oopt = None
    for (opt, arg) in opts:
        if opt == '-n':
            execute = False
        if opt == '-o':
            oopt = arg
        if opt == '-v':
            verbose += 1

    if len(arguments) == 1 and arguments[0].startswith("cvs://"):
        try:
            (host, module) = arguments[0][6:].split("#")
            i = host.find('/')
            (host, path) = (host[:i], host[i:])
            if "@" in host:
                host = host.split("@")[1]
        except ValueError:
            sys.stderr.write("cvssync: ill-formed CVS URL\n")
            sys.exit(1)
    elif len(arguments) == 2:
        host = arguments[0]
        module = arguments[1]
        if "@" in host:
            host = host.split("@")[1]
        if ":" not in host:
            sys.stderr.write("cvssync: repository path is missing.\n")
            sys.exit(1)
        (host, path) = host.split(":")
    else:
        sys.stderr.write("cvssync: requires a host/path and module argument\n")
        sys.exit(1)

    if verbose:
        print("host = %s, path = %s, module = %s" % (host, path, module))

    directory = oopt or module 
    vopt = "v" if verbose else ""

    source = computesource(host, path, module)

    do_or_die("rsync -a%sz %s %s" % (vopt, source, directory))

# end
