#!/usr/bin/python

##
# build-test.py [--verbose]
#
# reads the output of exiv2 -v -V and inspects it for sanity
# inspect run-library libraries platform/compiler/{debug|release}{shared|static}
# TODO: 1 report loaded libraries that we didn't expect
#       2 mingw support
##

import os
import sys
import subprocess

##
#   print error msg and terminate
def error(msg):
    print '***',msg,'***'
    sys.exit(1)

##
#   run a command and return output string
def runCommand(command):
    ##
    # don't use check_output 
    #           this is 2.7 feature.
    #           not available on cygwin's default python 2.6.8 interpreter
    #           result=subprocess.check_output( command.split(' '))
    ##

    result  =subprocess.Popen(command.split(' '), stdout=subprocess.PIPE).communicate()[0]

    # ensure lines are \n terminated (remove \r bytes)
    return result.replace('\r\n', '\n').replace('\r', '\n')

##
#   process the version information dictionary
def platform(dict):
    verbose=dict.has_key('verbose')
    for k in sorted(dict.keys()):
        v=dict[k]
        if type(v)==type([]):
            v='['+str(len(v))+']'
        if verbose:
            print "%-20s -> %s" % (k,v)

##
#   search dict for an array of libraries
def expect(dict,expects):
    verbose=dict.has_key('verbose')
    libs=dict['library']
    E={};
    for e in expects:
        e=e.lower().replace('-','.')      # cygwin uses '-' in versioning
        e=e.split('.')[0]
        if verbose:
            print 'expect library',e
        E[e]=0
        
    for lib in libs:
        lib=lib.lower().replace('\\','/') # cygwin uses '\' in pathnames
        lib=lib.replace('-','.')
        lib=os.path.basename(lib).split('.')[0]
        if E.has_key(lib):
            E[lib]=E[lib]+1
            if verbose:
                print 'found  library',lib
    for e in E.keys():
        if E[e]==0:
            error( "expected library '%s' not found" % e )

## 
def apple(dict):
    expects= [ 'libSystem.B.dylib'
             , 'libexpat.1.dylib'
             , 'libz.1.dylib'
             , 'libiconv.2.dylib'
             , 'libdyld.dylib'
             , 'libc++.1.dylib'
             # , 'libstdc++.6.dylib' # I suspect this is only with GCC (Xcode4 and earlier)
             ] ;

    # which version of MacOS-X ?
    os_major=int(os.uname()[2].split('.')[0])
    os_minor=int(os.uname()[2].split('.')[1])
    NC=13;ML=12;LION=11;SL=10;LEO=9;

    if dict['dll']:
        expects.append('libexiv2.12.dylib')
    
        ## Mountain Lion
        if os_major==ML and dict['dll']:
            expects.append('libexiv2.12.dylib')
            expects.append('libSystem.B.dylib')
            expects.append('libexpat.1.dylib')
            expects.append('libz.1.dylib')
            expects.append('libiconv.2.dylib')
            expects.append('libstdc++.6.dylib')
            expects.append('libdyld.dylib')
            expects.append('libc++.1.dylib')

    expect(dict,expects)

    expect_bits = 32 if os_major==LEO else 64
    if expect_bits != dict['bits']:
        error('*** expected %d bit build ***' % expect_bits)

##
def linux(dict):
    expects = [ 'libdl.so.2'
              , 'libexiv2.so.12'
              , 'libstdc++.so.6'
              , 'libm.so.6'
              , 'libgcc_s.so.1'
              , 'libc.so.6'
              , 'libz.so.1'
              , 'libexpat.so.1'
              ]
    expect(dict,expects)
    
## 
def windows(dict):
    expects = [ 'ntdll.dll'
              , 'kernel32.dll'
              , 'kernelbase.dll'
              , 'psapi.dll'
              ];
    if dict['dll']:
        dll='d.dll' if dict['debug'] else '.dll' 
        expects.append( 'exiv2' + dll )
        expects.append( 'zlib1' + dll ) 
        expects.append('libexpat.dll' )

        # c run time libraries
        # 2003=71, 2005=80, 2008=90, 2010=100
        v=int( float(dict['version'])*10 )
        expects.append('msvcr%d%s' % (v,dll) )
        expects.append('msvcp%d%s' % (v,dll) )

    expect(dict,expects)

## 
def cygwin(dict):
    expects = [ 'ntdll.dll'
              , 'kernel32.dll'
              , 'kernelbase.dll'
              , 'cygexiv2-12.dll'
              , 'cygwin1.dll'
              , 'cyggcc_s-1.dll'
              , 'cygstdc++-6.dll'
              , 'psapi.dll'
              , 'cygexpat-1.dll'
              , 'cygiconv-2.dll'
              , 'cygintl-8.dll'
              ];
    expect(dict,expects)

## 
def mingw(dict):
    error("can't test platform mingw")

## 
def unknown(dict):
    error("can't test platform unknown")

##
def main(args):
    this=os.path.abspath(args[0])

    ##
    # find the exiv2 executable
    exiv2='exiv2'
    if os.environ.has_key('EXIV2_BINDIR'):
        exiv2=os.path.abspath(os.path.join(os.environ['EXIV2_BINDIR'],exiv2))
    else:
        exiv2=os.path.join(os.path.dirname(this),'../bin',exiv2)
        
    ##
    # collect the version dictionary from exiv2
    dict={}
    verbose=False
    for arg in args:
        if arg == '--verbose':
            verbose=True
            dict['verbose']=True
    
    if os.path.exists(exiv2):
        output = runCommand(exiv2 + ' -v -V')
        if verbose: 
            print output
        lines = output.split('\n')
        for l in lines:
            kv=l.split('=')
            if len(kv)==2:
                k=kv[0]
                v=kv[1]
                if not dict.has_key(k):
                    dict[k]=[]
                dict[k].append(v)

        # flatten value arrays of length 1
        for k in dict.keys():
            if type(dict[k])==type([]): 
                if len(dict[k])==1:
                    dict[k]=dict[k][0]
                    
        # convert numeric strings to ints
        debug='debug'
        dll='dll'
        bits='bits'
        dict[dll  ] = int(dict[dll])
        dict[debug] = int(dict[debug])
        dict[bits ] = int(dict[bits])

        ##
        # analyse the version dictionary
        platform(dict)
        eval(dict['platform']+'(dict)')

        ##
        # report
        v='Release' if dict[debug]==0 else 'Debug'
        d='DLL'     if dict[dll  ]==0 else ''
        print "build %dbit %-8s  %-12s looks good" % (dict[bits],dict['platform'],v+d)
    else:
        error("exiv2 not found!")

if __name__ == '__main__':
    main(sys.argv)

# That's all Folks!
##