Changeset 3997
- Timestamp:
- May 24, 2019 5:34:19 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/makeMacApp.py
r3166 r3997 4 4 =============================== 5 5 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 ''' 6 This script creates an AppleScript app bundle to launch GSAS-II. The app is 7 created in the directory where the GSAS-II script (GSASII.py) is located. 8 A softlink to Python is created, but is named GSAS-II, and placed inside 9 the bundle so that GSAS-II shows up as the name of the app rather than 10 Python in the menu bar, etc. A soft link named GSAS-II.py, referencing 11 GSASII.py, is created so that appropriate menu items also are labeled with 12 GSAS-II (but not the right capitalization, alas). 13 14 This has been tested with several versions of Python interpreters 15 from Anaconda and does not require pythonw (Python.app). It tests to 16 make sure that a wx python script will run inside Python and if not, 17 it searches for a pythonw image and tries that. 18 19 Run this script with no arguments or with one optional argument, 20 a reference to the GSASII.py, with a relative or absolute path. Either way 21 the path will be converted via an absolute path. If no arguments are 22 supplied, the GSASII.py script must be located in the same directory as 23 this file. 24 25 ''' 26 from __future__ import division, print_function 21 27 import sys, os, os.path, stat, shutil, subprocess, plistlib 22 28 def Usage(): … … 36 42 return '','Exception = '+err 37 43 38 project="GSAS-II"39 44 AppleScript = '' 40 '''Contains an AppleScript to start GSAS-II launching python and the45 '''Contains an AppleScript to start GSAS-II, launching Python and the 41 46 GSAS-II python script 42 47 ''' 43 48 44 if __name__ == '__main__': AppleScript += '''(* GSAS-II AppleScript by B. Toby (brian.toby@anl.gov) 49 if __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) 45 77 It can launch GSAS-II by double clicking or by dropping a data file 46 78 or folder over the app. … … 106 138 end open 107 139 ''' 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() 118 205 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')) 189 207 d['CFBundleDocumentTypes'] = [{ 190 208 'CFBundleTypeExtensions': ['gpx'], … … 192 210 'CFBundleTypeRole': 'Editor'}] 193 211 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)+ 197 220 ").\nViewing app in Finder so you can drag it to the dock if, you wish.") 198 subprocess.call(["open","-R",app path])221 subprocess.call(["open","-R",appPath])
Note: See TracChangeset
for help on using the changeset viewer.