#
#    make_pkg.py
#
import os

print( 'Info: make_pkg' )
import sys
import time
import glob
import subprocess

sys.path.insert( 0, os.path.abspath( '../../Source' ) )
import pysvn

archs = subprocess.run(['lipo', '-archs', sys.executable], capture_output=True, check=True)
archs = archs.stdout.decode('utf-8').strip().split()

is_x86_64 = 'x86_64' in archs
is_arm64 = 'arm64' in archs

if is_x86_64 and is_arm64:
    processor = 'universal2'

elif is_x86_64:
    processor = 'x86_64'

elif is_arm64:
    processor = 'arm64'

else:
    assert False, 'Unknown processor type'

python_vendor = os.environ.get( 'BUILDER_VENDOR', 'unknown' )

print( 'Info: Processor is %s' % (processor,) )

pymaj, pymin, pypat, _, _ = sys.version_info
python_version_string = '%d.%d.%d' % (pymaj, pymin, pypat)
pysvnmaj, pysvnmin, pysvnpat, _ = pysvn.version
pysvn_version_string = '%d.%d.%d-%d' % (pysvn.version[0], pysvn.version[1], pysvn.version[2], pysvn.version[3])
pysvn_short_version_string = '%d.%d.%d' % (pysvn.version[0], pysvn.version[1], pysvn.version[2])
svn_version_package_string = '%d%d%d' % (pysvn.svn_version[0], pysvn.svn_version[1], pysvn.svn_version[2])
svn_version_string = '%d.%d.%d' % (pysvn.svn_version[0], pysvn.svn_version[1], pysvn.svn_version[2])
pysvn_so_string = '_pysvn_%d_%d.so' % (pymaj, pymin)
pkg_filename = 'py%s%s-%s-pysvn-svn%s-%s-%s' % (pymaj, pymin, python_vendor, svn_version_package_string, pysvn_version_string, processor)

print( 'Info: Packaging %s' % (pkg_filename,) )
build_time  = time.time()
build_time_str = time.strftime( '%d-%b-%Y %H:%M', time.localtime( build_time ) )
year = time.strftime( '%Y', time.localtime( build_time ) )
tmpdir = os.path.join( os.getcwd(), 'tmp' )

install_dir = '/Library/Frameworks/Python.framework/Versions/3.%d/lib/python3.%d/site-packages' % (pymin, pymin)

if os.path.exists( tmpdir ):
    print( 'Info: Clean up tmp directory' )
    subprocess.run( ['rm', '-rf', 'tmp'], check=True )

print( 'Info: Create directories' )

for kit_dir in [
    tmpdir,
    os.path.join( tmpdir, 'Resources' ),
    os.path.join( tmpdir, 'Contents' ),
    os.path.join( tmpdir, 'Contents/pysvn' ),
    os.path.join( tmpdir, pkg_filename),
    os.path.join( tmpdir, '%s/Examples' % (pkg_filename,) ),
    os.path.join( tmpdir, '%s/Examples/Client' % (pkg_filename,) ),
    os.path.join( tmpdir, '%s/Documentation' % (pkg_filename,) ),
    ]:
    if not os.path.exists( kit_dir ):
        os.makedirs( kit_dir )

print( 'Info: Finding dylibs used by pysvn' )

def findDylibs( image, dylib_list, depth=0 ):
    cmd = ['otool', '-L', image]
    #print( 'Debug: cmd %r' % (cmd,) )
    rc = subprocess.run( cmd, check=True, capture_output=True )
    # always skip the first line that lists the image being dumped
    for line in rc.stdout.decode('utf-8').split('\n'):
        line = line.strip()
        if line == '':
            continue
        libpath = line.split()[0]
        #print( 'Debug: line %r' % (line,) )
        if( libpath.startswith( '/' )               # lines with libs on them
        and not libpath.startswith( '/usr/lib' )    # ignore libs shipped by Apple
        and not libpath.startswith( '/System' )     # ignore libs shipped by Apple
        and not libpath.endswith( '/Python' ) ):    # do not need ignore python
            if libpath not in dylib_list:
                #print( 'Info: ',depth,' Need lib',libpath,'for',image )
                dylib_list.append( libpath )
                findDylibs( libpath, dylib_list, depth+1 )

dylib_list = []
findDylibs( '../../Source/pysvn/%s' % (pysvn_so_string,), dylib_list )

print( 'Info: Copy files' )

cp_list = [
    ('../../Source/pysvn/__init__.py',
        'Contents/pysvn'),
    ('../../Source/pysvn/%s' % (pysvn_so_string,),
        'Contents/pysvn'),
    ('../../LICENSE.txt',
        'Resources/License.txt'),
    ('../../LICENSE.txt',
        '%s/License.txt' % (pkg_filename,) ),
    ('../../Docs/pysvn.html',
        '%s/Documentation' % (pkg_filename,) ),
    ('../../Docs/pysvn_prog_ref.html',
        '%s/Documentation' % (pkg_filename,) ),
    ('../../Docs/pysvn_prog_ref.js',
        '%s/Documentation' % (pkg_filename,) ),
    ('../../Docs/pysvn_prog_guide.html',
        '%s/Documentation' % (pkg_filename,) ),
    ('../../Examples/Client/svn_cmd.py',
        '%s/Examples/Client' % (pkg_filename,) ),
    ('../../Examples/Client/parse_datetime.py',
        '%s/Examples/Client' % (pkg_filename,) ),
    ]

for libpath in dylib_list:
    cp_list.append( (libpath, 'Contents/pysvn') )

for cp_src, cp_dst_dir_fmt in cp_list:
    cmd = ['cp', '-f', cp_src, 'tmp/%s' % (cp_dst_dir_fmt % locals(),)]
    print( 'Info: CMD %r' % (cmd,) )
    subprocess.run( cmd, check=True )

for dylib in glob.glob( 'tmp/Contents/pysvn/*.dylib' ):
    # all the dylib need to be writable
    cmd = ['chmod', '+w', dylib]
    print( 'Info: CMD %r' % (cmd,) )
    subprocess.run( cmd, check=True )

print( 'Info: Fix the install paths for the dylib files' )

fixup_path_list = ['tmp/Contents/pysvn/%s' % pysvn_so_string]
for libpath in dylib_list:
    fixup_path_list.append( 'tmp/Contents/pysvn/' + os.path.basename( libpath ) )

for fixup_path in fixup_path_list:
    for libpath in dylib_list:
        if libpath != fixup_path:
            cmd = ['install_name_tool',
                '-change',
                libpath,
                '%s/pysvn/%s' % (install_dir, os.path.basename( libpath )),
                fixup_path]
            print( 'Info: CMD %s' % (cmd,) )
            subprocess.run( cmd, check=True )

for dylib in glob.glob( 'tmp/Contents/pysvn/*.dylib' ):
    # can now remove the +w
    cmd = ['chmod', '-w', dylib]
    print( 'Info: CMD %r' % (cmd,) )
    subprocess.run( cmd, check=True )

if python_vendor == 'apple_com':
    readme_vendor_name = "Apple's"

elif python_vendor == 'python_org':
    readme_vendor_name = "Python.org's"

else:
    readme_vendor_name = python_vendor

print( 'Info: Create tmp/Resources/ReadMe.txt' )
with open( 'tmp/%s/ReadMe.txt' % (pkg_filename,), 'w' ) as f:
    f.write('''<html>
<body>
<h1>PySVN %(pysvn_version_string)s for Mac OS X, %(readme_vendor_name)s Python %(pymaj)s.%(pymin)s and Subversion %(svn_version_string)s</h1>

<h2>Copyright Barry A. Scott (c) 2003-%(year)s</h2>

<h2>Mail <a href="mailto:barry@barrys-emacs.org">barry@barrys-emacs.org</a></h2>

<h2>Pysvn home <a href="https://pysvn.sourceforge.io">https://pysvn.sourceforge.io</a></h2>

<h2>&#160;&#160;&#160;&#160;&#160;Barry Scott</h2>
</body>
</html>
''' % locals() )

print( 'Info: Create installation script' )
with open( 'tmp/%s/Install PySVN' % (pkg_filename,), 'w' ) as f:
    f.write( '''#!/bin/bash
if [ "$( id -u )" != "0" ]
then
    clear
    echo "To install PYSVN required root (administrator) privileges."
    echo "Enter your password to proceed."
    exec sudo "$0"
fi

kit_dir=$( dirname "$0" )

echo "Installing pysvn Extension %(pysvn_version_string)s for Python %(pymaj)s.%(pymin)s"

tar xzf "${kit_dir}/%(pkg_filename)s.tar.gz" -C "%(install_dir)s"

echo "Installation complete. Press RETURN to exit."
read A

''' % locals() )

subprocess.run( ['chmod', '+x', 'tmp/%s/Install PYSVN' % (pkg_filename,)], check=True )

cmd = ['tar',
       'czf',
       'tmp/%s/%s.tar.gz' % (pkg_filename, pkg_filename),
       '-C' 'tmp/Contents',
       'pysvn']

subprocess.run( cmd, check=True )

print( 'Info: Make Disk Image' )

# hdiutil will randomly fail with resource unavailable error
# consensus is to keep retrying till it works
created = False
cmd = ['hdiutil', 'create', '-srcfolder', 'tmp/%s' % (pkg_filename,), 'tmp/tmp.dmg']
print( 'Info: CMD %r' % (cmd,) )
for _ in range(6):
    rc = subprocess.run( cmd )
    if rc.returncode == 0:
        created = True
        break

    time.sleep( 10 )

if not created:
    print( 'Error: failed to create DMG' )
    sys.exit( 1 )

cmd = ['hdiutil', 'convert', 'tmp/tmp.dmg', '-format', 'UDZO', '-imagekey', 'zlib-level=9',
        '-o', 'tmp/%s.dmg' % (pkg_filename,)]
print( 'Info: CMD %r' % (cmd,) )
subprocess.run( cmd )
