#!/usr/bin/env python2
#
# module2pkg - Build an OS package from an environment module.

import re
import sys
import subprocess
from optparse import OptionParser

def main():
    (options, args) = getopts()
    mods = set()
    for arg in args:
        mods.add(arg)
        deps = get_dependencies(arg)
        mods = mods.union(deps)
    for mod in mods:
        build_package(mod, options.pkgtype, options.prefix, options.dryrun)

# Get command line arguments
def getopts():
    parser = OptionParser()
    parser.add_option("-t", "--type", dest="pkgtype", default="rpm",
                      help="Type of package to build")
    parser.add_option("-p", "--prefix", dest="prefix", default="",
                      help="Package name prefix")
    parser.add_option("-d", "--dry-run", dest="dryrun", action="store_true",
                      default=False, help="Print FPM commands but do not execute them")
    (options, args) = parser.parse_args()
    return (options, args)

# Print a failure message and exit
def failmsg(msg):
    sys.stderr.write("%s\n" % msg)
    sys.exit(1)

# Get the full path to the modulefile for a given module
def module2path(modname):
    modshow = subprocess.Popen(['modulecmd', 'python', 'show', modname],
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE).communicate()[1]
    modlines = modshow.split('\n')
    return modlines[1][:-1]

# Get the root directory of a module
def get_root(modname):
    modulefile = module2path(modname)
    check_root = re.compile("^\s*set\s+root\s+(.+)$")
    with open(modulefile, 'r') as f:
        lines = f.readlines()
    for line in lines:
        m = check_root.match(line)
        if m:
            root = m.group(1).strip()
            break
    return root

# Get the list of "module load" or "prereq" dependencies for a module
def get_dependencies(modname):
    modulefile = module2path(modname)
    check_load = re.compile("^\s*module\s+load(.+)$")
    check_prereq = re.compile("^\s*prereq\s+(.+)$")
    deps = set()
    with open(modulefile, 'r') as f:
        lines = f.readlines()
    for line in lines:
        m = check_load.match(line)
        if m:
            deps.add(m.group(1).strip())
            continue
        m = check_prereq.match(line)
        if m:
            deps.add(m.group(1).strip())
            continue
    for dep in deps:
        deps = deps.union(get_dependencies(dep))
    return deps

# Get the version in a module name
def module_version(modname):
    return modname.split('/')[-1]

# Get the name from a module name
def module_name(modname):
    name_parts = modname.split('/')
    return "%s-%s" % (name_parts[0], name_parts[1])

# Fix up a prefix string for an RPM name
def fix_prefix(prefix):
    if prefix != "":
       if prefix[-1] != '-':
           prefix = "%s-" % prefix
    return prefix

# Build a list of package dependencies for the FPM command
def get_rpm_deps(modname, prefix):
    deps = get_dependencies(modname)
    rpm_deps = set()
    for dep in deps:
        rpm_deps.add("%s%s = %s-1" % (prefix, module_name(dep), # -1 = release 
            module_version(dep).replace('-','_') ))             # fpm replaces - with _ in versions 
    return rpm_deps

# Build a list of package dependencies for the FPM command
def get_deb_deps(modname, prefix):
    deps = get_dependencies(modname)
    deb_deps = set()
    for dep in deps:
        deb_deps.add("%s%s" % (prefix, module_name(dep)))
    return deb_deps

# Build an OS package using FPM
def build_package(modname, pkgtype, prefix, dryrun):
    root = get_root(modname)
    mname = module_name(modname).strip()
    version = "0.1m2p"
    #version = module_version(modname).strip()
    prefix = fix_prefix(prefix)

    pkg_deps = set()
    if pkgtype == 'rpm':
        pkg_deps = get_rpm_deps(modname, prefix)
    elif pkgtype == 'deb':
        pkg_deps = get_deb_deps(modname, prefix)

    if mname == version: version = 'NOVERSION'
    mname = "%s%s" % (prefix, mname)
    mpath = module2path(modname)

    cmd = "fpm -s dir -t %s -n %s -v %s --provides %s -p %s-VERSION_ARCH.%s" % (pkgtype, mname, version, mname, mname, pkgtype)
    for pkg_dep in pkg_deps:
        cmd = "%s -d \"%s\"" % (cmd, pkg_dep)
    cmd = "%s -C / %s %s" % (cmd, root, mpath)
    print cmd
    if not dryrun:
        p = subprocess.Popen(cmd, shell=True)
        p.wait()

if __name__ == '__main__':
    main()
