#!/usr/bin/python
#
# Copyright (C) 2004 Federico Di Gregorio <fog@debian.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.

import sys
import os
import os.path
import optparse
import shutil
import time
import glob
import urllib2
import md5


CG_LIBRARIES_OLD_1 = ('libCg.so', 'libCgFX.so', 'libCgGL.so', 'libCgFXGL.so')
CG_LIBRARIES = ('libCg.so', 'libCgGL.so')

pipe = os.popen('dpkg --print-architecture', 'r')
arch = pipe.read().strip()
pipe.close()

"""
Variables used for location and checksum of the NVIDIA Cg Toolkit archive
and spec file from the NVIDIA website.
"""
CG_URL = 'http://developer.download.nvidia.com/cg/Cg_2.0/2.0.0010/'
CG_SPEC_FILE = 'Cg-2.0_Dec2007_LanguageSpecification.pdf'
CG_SPEC_MD5 = 'ceb7802283c73536b2e8614ab18870b1'
if arch == 'i386':
    CG_FILE = 'Cg-2.0_Dec2007_x86.tar.gz'
    CG_MD5  = 'f6191a01b22f29f7df0b1e1a013aa971'
    CG_USR_LIB = 'usr/lib'
elif arch == 'amd64':
    CG_FILE = 'Cg-2.0_Dec2007_x86_64.tar.gz'
    CG_MD5  = 'bc3567a806405c3db12fb46daf450166'
    CG_USR_LIB = 'usr/lib64'
else:
    sys.stderr.write("Error: architecture %s is not supported\n" % arch)
    sys.exit(1)

"""Uninstall all components."""
def cg_uninstall():
    print "Uninstalling NVIDIA Cg Toolkit components:"

    print "  Cg compiler,",
    try:
        os.unlink('/usr/bin/cgc')
    except OSError:
        pass

    print "header files,",
    shutil.rmtree('/usr/include/Cg', ignore_errors=True)
    shutil.rmtree('/usr/include/CgFX', ignore_errors=True)    

    print "libraries,",
    for l in CG_LIBRARIES_OLD_1 + CG_LIBRARIES:
        try:
            os.unlink(os.path.join('/', CG_USR_LIB, l))
        except OSError:
            pass

    print "documentation,"
    for l in glob.glob('/usr/share/doc/nvidia-cg-toolkit/*.pdf'):
        os.unlink(l)

    shutil.rmtree('/usr/share/doc/nvidia-cg-toolkit/html', ignore_errors=True)
    shutil.rmtree('/usr/share/doc/nvidia-cg-toolkit/txt', ignore_errors=True)

    print "  examples,",
    shutil.rmtree('/usr/share/doc/nvidia-cg-toolkit/examples',
                  ignore_errors=True)

    print "manual pages,",
    for f in glob.glob('/usr/share/man/man3/*.3nvidiacg*'):
        try:
            os.unlink(f)
        except OSError:
            pass
    for f in glob.glob('/usr/share/man/man3/*.3Cg*'):
        try:
            os.unlink(f)
        except OSError:
            pass

    print "(running ldconfig),",
    os.system('/sbin/ldconfig')

    print "done."

"""Install the toolkit archive and spec file"""
def cg_install(toolkitfile, specfile):
    # Check md5 on toolkit
    print "Checking md5 checksum on " + os.path.basename(toolkitfile)
    md5sum = md5.new(open(toolkitfile).read()).hexdigest()
    if md5sum != CG_MD5:
        e = "Error: md5sum mismatch: %s != %s"
        sys.stderr.write(e % (CG_MD5, md5sum))
        sys.exit(2)
    # Check md5 on spec file
    print "Checking md5 checksum on " + os.path.basename(specfile)
    md5sum = md5.new(open(specfile).read()).hexdigest()
    if md5sum != CG_SPEC_MD5:
        e = "Error: md5sum mismatch: %s != %s"
        sys.stderr.write(e % (CG_SPEC_MD5, md5sum))
        sys.exit(2)

    target = os.path.join('/tmp', 'cg.%f' % time.time())
    try:
        os.mkdir(target)
    except:
        e = "Error: can't create directory: %s."
        sys.stderr.write(e % target)
        sys.exit(2)

    cg_uninstall()
    
    print "Uncompressing NVIDIA Cg toolkit into " + target
    os.system("/bin/tar xzf %s -C %s" % (toolkitfile, target))

    print "Moving files to their final destinations:"

    print "  cg compiler,",
    shutil.move(os.path.join(target, 'usr/bin/cgc'), '/usr/bin/cgc')
    
    print "header files,",
    shutil.move(os.path.join(target, 'usr/include/Cg'), '/usr/include/Cg')
    #shutil.move(os.path.join(target, 'usr/include/CgFX'), '/usr/include/CgFX')

    print "libraries,",
    for l in CG_LIBRARIES:
        shutil.move(os.path.join(target, CG_USR_LIB, l),
                    os.path.join('/', CG_USR_LIB, l))

    print "documentation,"
    for l in glob.glob(os.path.join(target, 'usr/local/Cg/docs/*.pdf')):
        f = os.path.basename(l)
        shutil.move(l, os.path.join('/usr/share/doc/nvidia-cg-toolkit', f))
    shutil.move(os.path.join(target, 'usr/local/Cg/docs/html'),
                '/usr/share/doc/nvidia-cg-toolkit/html')
    shutil.move(os.path.join(target, 'usr/local/Cg/docs/txt'),
                '/usr/share/doc/nvidia-cg-toolkit/txt')
    # Install spec file as well
    shutil.copy(specfile,
                os.path.join('/usr/share/doc/nvidia-cg-toolkit',
                os.path.basename(specfile)))

    print "  examples,",
    shutil.move(os.path.join(target, 'usr/local/Cg/examples'),
                '/usr/share/doc/nvidia-cg-toolkit/examples')

    print "manual pages",
    for f in os.listdir(os.path.join(target, 'usr/share/man/man3')):
        src = os.path.join(target, 'usr/share/man/man3', f)
        dst = os.path.join('/usr/share/man/man3', f+'Cg')
        shutil.move(src, dst)
    for f in os.listdir(os.path.join(target, 'usr/share/man/manCg')):
        src = os.path.join(target, 'usr/share/man/manCg', f)
        dst = os.path.join('/usr/share/man/man3', f[:-2]+"3Cg")
        shutil.move(src, dst)

    print "(compressing),",
    os.system('/bin/gzip -9 /usr/share/man/man3/*.3Cg')

    print "(running ldconfig),",
    os.system('/sbin/ldconfig')

    shutil.rmtree(target)
    print "done."

"""Download a file from the NVIDIA website."""
def cg_wget(target, file):
    try:
        os.mkdir(target)
    except:
        e = "Error: can't create directory: %s."
        sys.stderr.write(e % target)
        sys.exit(2)
    dst = open(os.path.join(target, file), 'w')

    print "Downloading " + os.path.basename(dst.name) + " from"
    print "   " + CG_URL
    src = urllib2.urlopen(CG_URL+file)
    dst.write(src.read())
    return dst.name

"""Return the path to an existing file or None."""
def cg_path(path, filename):
    if filename and os.path.exists(filename):
        return filename
    if path:
        filename = os.path.join(path, CG_FILE)
        if filename and os.path.exists(filename):
            return filename

parser = optparse.OptionParser(usage="%prog [options] <file or URL>")	
parser.add_option('-i', '--install', action='store_true',
                  help="install the NVIDIA Cg Toolkit")
parser.add_option('-u', '--uninstall', action='store_true',
                  help="uninstall the NVIDIA Cg Toolkit")
parser.add_option('-t', '--toolkit-file', action='store',
                  help="install from given toolkit archive file")
parser.add_option('-s', '--spec-file', action='store',
                  help="install from given spec file")
parser.add_option('-p', '--search-path', action='store',
                  help="search for files in given path")
parser.add_option('-d', '--delete-after', action='store_true',
                  help="remove toolkit and spec file after install")
opts, args = parser.parse_args()

""" Run main operation """
if opts.install:
    toolkit_file = cg_path(opts.search_path, opts.toolkit_file)
    spec_file = cg_path(opts.search_path, opts.spec_file)
    if not toolkit_file or not os.path.exists(toolkit_file):
        toolkit_target = os.path.join('/tmp', 'cg.%f' % time.time())
        toolkit_file = cg_wget(toolkit_target, CG_FILE)
    if not spec_file or not os.path.exists(spec_file):
        spec_target = os.path.join('/tmp', 'cg.%f' % time.time())
        spec_file = cg_wget(spec_target, CG_SPEC_FILE)
    cg_install(toolkit_file, spec_file)
    if opts.delete_after:
        os.unlink(toolkit_file)
        os.unlink(spec_file)
        # Also remove temporary directories if used
        if toolkit_target:
            os.removedirs(toolkit_target)
        if spec_target:
            os.removedirs(spec_target)

elif opts.uninstall:      
    cg_uninstall()

else:
    e = "Error: one action (--install or --uninstall) is required.\n"
    sys.stderr.write(e)
    sys.exit(1)
