Changeset 3997


Ignore:
Timestamp:
May 24, 2019 5:34:19 PM (4 years ago)
Author:
toby
Message:

Update the mac install to use python rather than pythonw, should now use GSAS-II as app name

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/makeMacApp.py

    r3166 r3997  
    44===============================
    55
    6 This script creates an AppleScript app to launch GSAS-II. The app is
    7 created in the directory where the GSAS-II script is located.
    8 A softlink to Python is created, but is named GSAS-II, so that
    9 GSAS-II shows up as the name of the app rather than Python in the
    10 menu bar, etc. Note that this requires finding an app version of Python
    11 (expected name .../Resources/Python.app/Contents/MacOS/Python in
    12 directory tree of the calling python interpreter).
    13 
    14 Run this script with one optional argument, the path to the GSASII.py
    15 The script path may be specified relative to the current path or given
    16 an absolute path, but will be accessed via an absolute path.
    17 If no arguments are supplied, the GSASII.py script is assumed to be in the
    18 same directory as this file.
    19 
    20 '''
     6This script creates an AppleScript app bundle to launch GSAS-II. The app is
     7created in the directory where the GSAS-II script (GSASII.py) is located.
     8A softlink to Python is created, but is named GSAS-II, and placed inside
     9the bundle so that GSAS-II shows up as the name of the app rather than
     10Python in the menu bar, etc. A soft link named GSAS-II.py, referencing
     11GSASII.py, is created so that appropriate menu items also are labeled with
     12GSAS-II (but not the right capitalization, alas).
     13
     14This has been tested with several versions of Python interpreters
     15from Anaconda and does not require pythonw (Python.app). It tests to
     16make sure that a wx python script will run inside Python and if not,
     17it searches for a pythonw image and tries that.
     18
     19Run this script with no arguments or with one optional argument,
     20a reference to the GSASII.py, with a relative or absolute path. Either way
     21the path will be converted via an absolute path. If no arguments are
     22supplied, the GSASII.py script must be located in the same directory as
     23this file.
     24
     25'''
     26from __future__ import division, print_function
    2127import sys, os, os.path, stat, shutil, subprocess, plistlib
    2228def Usage():
     
    3642        return '','Exception = '+err
    3743
    38 project="GSAS-II"
    3944AppleScript = ''
    40 '''Contains an AppleScript to start GSAS-II launching python and the
     45'''Contains an AppleScript to start GSAS-II, launching Python and the
    4146GSAS-II python script
    4247'''
    4348
    44 if __name__ == '__main__': AppleScript += '''(*   GSAS-II AppleScript by B. Toby (brian.toby@anl.gov)
     49if __name__ == '__main__':
     50    project="GSAS-II"
     51
     52    # set scriptdir: find the main GSAS-II script if not on command line
     53    if len(sys.argv) == 1:
     54        script = os.path.abspath(os.path.join(
     55                os.path.split(__file__)[0],
     56                "GSASII.py"
     57                ))
     58    elif len(sys.argv) == 2:
     59            script = os.path.abspath(sys.argv[1])
     60    else:
     61        Usage()
     62        raise Exception
     63    # make sure we found it
     64    if not os.path.exists(script):
     65        print("\nFile "+script+" not found")
     66        Usage()
     67    if os.path.splitext(script)[1].lower() != '.py':
     68        print("\nScript "+script+" does not have extension .py")
     69        Usage()
     70    # where the app will be created
     71    scriptdir = os.path.split(script)[0]
     72   
     73    appPath = os.path.abspath(os.path.join(scriptdir,project+".app"))
     74    iconfile = os.path.join(scriptdir,'gsas2.icns') # optional icon file
     75   
     76    AppleScript = '''(*   GSAS-II AppleScript by B. Toby (brian.toby@anl.gov)
    4577     It can launch GSAS-II by double clicking or by dropping a data file
    4678     or folder over the app.
     
    106138end open
    107139'''
    108 
    109 if __name__ == '__main__':
    110     # find the main GSAS-II script if not on command line
    111     if len(sys.argv) == 1:
    112         script = os.path.abspath(os.path.join(
    113             os.path.split(__file__)[0],
    114             "GSASII.py"
    115             ))
    116     elif len(sys.argv) == 2:
    117         script = os.path.abspath(sys.argv[1])
     140    # create a link named GSAS-II.py to the script
     141    newScript = os.path.join(scriptdir,project+'.py')
     142    if os.path.exists(newScript): # cleanup
     143        print("\nRemoving sym link",newScript)
     144        os.remove(newScript)
     145    os.symlink(os.path.split(script)[1],newScript)
     146    script=newScript
     147
     148    # find Python used to run GSAS-II and set a new to use to call it
     149    # inside the app that will be created
     150    pythonExe = os.path.realpath(sys.executable)
     151    newpython =  os.path.join(appPath,"Contents","MacOS",project)
     152
     153    # create an app using this python and if that fails to run wx, look for a
     154    # pythonw and try that with wx
     155    for i in 1,2,3:
     156        if os.path.exists(appPath): # cleanup
     157            print("\nRemoving old "+project+" app ("+str(appPath)+")")
     158            shutil.rmtree(appPath)
     159       
     160        shell = os.path.join("/tmp/","appscrpt.script")
     161        f = open(shell, "w")
     162        f.write(AppleScript.format(newpython,script,'',newpython,script,''))
     163        f.close()
     164
     165        try:
     166            subprocess.check_output(["osacompile","-o",appPath,shell],stderr=subprocess.STDOUT)
     167        except subprocess.CalledProcessError as msg:
     168            print('''Error compiling AppleScript.
     169            Report the next message along with details about your Mac to toby@anl.gov''')
     170            print(msg.output)
     171            sys.exit()
     172        # create a link to the python inside the app, if named to match the project
     173        if pythonExe != newpython: os.symlink(pythonExe,newpython)
     174
     175        # test if newpython can run wx
     176        testout,errout = RunPython(newpython,'import numpy; import wx; wx.App(); print("-OK-")')
     177        if isinstance(testout,bytes): testout = testout.decode()
     178        if "-OK-" in testout:
     179            break
     180        elif i == 1:
     181            print('Run of wx in',pythonExe,'failed, looking for pythonw')
     182            pythonExe = os.path.join(os.path.split(sys.executable)[0],'pythonw')
     183            if not os.path.exists(pythonExe):
     184                print('Warning no pythonw found with ',sys.executable,
     185                      '\ncontinuing, hoping for the best')
     186        elif i == 2:
     187            print('Warning could not run wx with',pythonExe,
     188                      'will try with that external to app')
     189            newpython = pythonExe
     190        else:
     191            print('Warning still could not run wx with',pythonExe,
     192                      '\ncontinuing, hoping for the best')
     193
     194    # change the icon
     195    oldicon = os.path.join(appPath,"Contents","Resources","droplet.icns")
     196    #if os.path.exists(iconfile) and os.path.exists(oldicon):
     197    if os.path.exists(iconfile):
     198        shutil.copyfile(iconfile,oldicon)
     199
     200    # Edit the app plist file to restrict the type of files that can be dropped
     201    if hasattr(plistlib,'load'):
     202        fp = open(os.path.join(appPath,"Contents",'Info.plist'),'rb')
     203        d = plistlib.load(fp)
     204        fp.close()
    118205    else:
    119         Usage()
    120 
    121     # make sure we found it
    122     if not os.path.exists(script):
    123         print("\nFile "+script+" not found")
    124         Usage()
    125     if os.path.splitext(script)[1].lower() != '.py':
    126         print("\nScript "+script+" does not have extension .py")
    127         Usage()
    128     # where the app will be created
    129     scriptdir = os.path.split(script)[0]
    130     # name of app
    131     apppath = os.path.abspath(os.path.join(scriptdir,project+".app"))
    132     iconfile = os.path.join(scriptdir,'gsas2.icns') # optional icon file
    133 
    134     # find the python application; must be an OS X app
    135     pythonpath = os.path.realpath(sys.executable)
    136     top = True
    137     while top:
    138         pythonapp = os.path.join(pythonpath,'Resources','Python.app','Contents','MacOS','Python')
    139         if os.path.exists(pythonapp): break
    140         pythonpath,top = os.path.split(pythonpath)
    141     else:
    142         #print("\nSorry, failed to find a Resources directory associated with "+str(sys.executable))
    143         pythonapp = sys.executable
    144    
    145     # create a link to the python app, but named to match the project
    146     if os.path.exists('/tmp/testpython'): os.remove('/tmp/testpython')
    147     os.symlink(pythonapp,'/tmp/testpython')
    148     # test if it runs
    149     testout,errout = RunPython('/tmp/testpython','import numpy; import wx; print("OK")')
    150     os.remove('/tmp/testpython')
    151     #print testout,errout
    152     if testout.strip() != "OK":
    153         print('Run of wx in python failed, looking for pythonw')
    154         pythonapp = os.path.join(os.path.split(sys.executable)[0],'pythonw')
    155         if not os.path.exists(pythonapp):
    156             raise Exception('no pythonw found with '+sys.executable)
    157         newpython = pythonapp
    158     else:
    159         # new name to call python
    160         newpython =  os.path.join(apppath,"Contents","MacOS",project)
    161 
    162     if os.path.exists(apppath): # cleanup
    163         print("\nRemoving old "+project+" app ("+str(apppath)+")")
    164         shutil.rmtree(apppath)
    165 
    166     shell = os.path.join("/tmp/","appscrpt.script")
    167     f = open(shell, "w")
    168     f.write(AppleScript.format(newpython,script,'',newpython,script,''))
    169     f.close()
    170 
    171     try:
    172         subprocess.check_output(["osacompile","-o",apppath,shell],stderr=subprocess.STDOUT)
    173     except subprocess.CalledProcessError as msg:
    174         print('''Error compiling AppleScript.
    175         Report the next message along with details about your Mac to toby@anl.gov''')
    176         print(msg.output)
    177         sys.exit()
    178 
    179     # create a link to the python app, but named to match the project
    180     if pythonapp != newpython: os.symlink(pythonapp,newpython)
    181 
    182     # change the icon
    183     oldicon = os.path.join(apppath,"Contents","Resources","droplet.icns")
    184     if os.path.exists(iconfile) and os.path.exists(oldicon):
    185         shutil.copyfile(iconfile,oldicon)
    186 
    187     # Edit the app plist file to restrict the type of files that can be dropped
    188     d = plistlib.readPlist(os.path.join(apppath,"Contents",'Info.plist'))
     206        d = plistlib.readPlist(os.path.join(appPath,"Contents",'Info.plist'))
    189207    d['CFBundleDocumentTypes'] = [{
    190208        'CFBundleTypeExtensions': ['gpx'],
     
    192210        'CFBundleTypeRole': 'Editor'}]
    193211   
    194     plistlib.writePlist(d,os.path.join(apppath,"Contents",'Info.plist'))
    195 
    196     print("\nCreated "+project+" app ("+str(apppath)+
     212    if hasattr(plistlib,'dump'):
     213        fp = open(os.path.join(appPath,"Contents",'Info.plist'),'wb')
     214        plistlib.dump(d,fp)
     215        fp.close()
     216    else:
     217        plistlib.writePlist(d,os.path.join(appPath,"Contents",'Info.plist'))
     218
     219    print("\nCreated "+project+" app ("+str(appPath)+
    197220          ").\nViewing app in Finder so you can drag it to the dock if, you wish.")
    198     subprocess.call(["open","-R",apppath])
     221    subprocess.call(["open","-R",appPath])
Note: See TracChangeset for help on using the changeset viewer.