Skip to content

Commit 38084dc

Browse files
committed
revise mac self-install
1 parent a332a96 commit 38084dc

File tree

2 files changed

+306
-194
lines changed

2 files changed

+306
-194
lines changed

GSASII/install/macStartScript.py

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
# create a MacOS applet to run GSAS-II. The purpose of the Applet is
2+
# so that the Apple menus are named GSAS-II rather than Python. It also
3+
# allows .gpx files to be dropped on the applet.
4+
5+
# this runs but has not been fully tested
6+
7+
import sys
8+
import os
9+
import subprocess
10+
import shutil
11+
import plistlib
12+
import platform
13+
14+
makePath = os.path.dirname(__file__) # location of this script
15+
path2GSAS = os.path.dirname(makePath)
16+
appPath = '/tmp/GSAS-II.app'
17+
projectname = 'GSAS-II'
18+
#G2script = os.path.abspath(os.path.join(path2GSAS,"G2.py"))
19+
20+
if __name__ == '__main__' and sys.platform == "darwin":
21+
iconfile = os.path.join(path2GSAS,'icons','gsas2.icns') # optional icon file
22+
if not os.path.exists(iconfile): # patch 3/2024 for svn dir organization
23+
iconfile = os.path.join(path2GSAS,'gsas2.icns') # optional icon file
24+
25+
# AppleScript = '''(* GSAS-II AppleScript by B. Toby ([email protected])
26+
# It can launch GSAS-II by double clicking or by dropping a data file
27+
# or folder over the app.
28+
# It runs GSAS-II in a terminal window.
29+
# *)
30+
31+
# (* test if a file is present and exit with an error message if it is not *)
32+
# on TestFilePresent(appwithpath)
33+
# tell application "System Events"
34+
# if (file appwithpath exists) then
35+
# else
36+
# display dialog "Error: file " & appwithpath & " not found. If you have moved this file recreate the AppleScript with bootstrap.py." with icon caution buttons {{"Quit"}}
37+
# return
38+
# end if
39+
# end tell
40+
# end TestFilePresent
41+
42+
# (*
43+
# ------------------------------------------------------------------------
44+
# this section responds to a double-click. No file is supplied to GSAS-II
45+
# ------------------------------------------------------------------------
46+
# *)
47+
# on run
48+
# set python to "{:s}"
49+
# set appwithpath to "{:s}"
50+
# set env to "{:s}"
51+
# TestFilePresent(appwithpath)
52+
# TestFilePresent(python)
53+
# tell application "Terminal"
54+
# do script env & python & " " & appwithpath & "; exit"
55+
# end tell
56+
# end run
57+
58+
# (*
59+
# -----------------------------------------------------------------------------------------------
60+
# this section handles starting with files dragged into the AppleScript
61+
# o it goes through the list of file(s) dragged in
62+
# o then it converts the colon-delimited macintosh file location to a POSIX filename
63+
# o for every non-directory file dragged into the icon, it starts GSAS-II, passing the file name
64+
# ------------------------------------------------------------------------------------------------
65+
# *)
66+
67+
# on open names
68+
# set python to "{:s}"
69+
# set appwithpath to "{:s}"
70+
# set env to "{:s}"
71+
72+
# TestFilePresent(appwithpath)
73+
# repeat with filename in names
74+
# set filestr to (filename as string)
75+
# if filestr ends with ":" then
76+
# (* should not happen, skip directories *)
77+
# else
78+
# (* if this is an input file, open it *)
79+
# set filename to the quoted form of the POSIX path of filename
80+
# tell application "Terminal"
81+
# activate
82+
# do script env & python & " " & appwithpath & " " & filename & "; exit"
83+
# end tell
84+
# end if
85+
# end repeat
86+
# end open
87+
# '''
88+
AppleScript = '''(* GSAS-II AppleScript by B. Toby ([email protected])
89+
It can launch GSAS-II by double clicking or by dropping a data file
90+
or folder over the app.
91+
It runs GSAS-II in a terminal window.
92+
93+
This is intended for use with a conda-based GSAS-II distribution where
94+
Python is linked from a file (./Contents/MacOS/GSAS-II) inside the current app,
95+
and where the GSAS-II .py files are located in the same directory as this
96+
script. This can be renamed but cannot be moved.
97+
*)
98+
99+
on GetPythonLocation()
100+
(* find python in this script's bundle *)
101+
tell application "Finder"
102+
set scriptpath to the POSIX path of (path to me)
103+
end tell
104+
set python to (scriptpath & "Contents/MacOS/GSAS-II")
105+
TestFilePresent(python)
106+
return python
107+
end GetPythonLocation
108+
109+
on GetG2Location()
110+
(* find the GSASII.py script in the same directory as this script *)
111+
tell application "Finder"
112+
set scriptdir to the POSIX path of (container of (path to me) as alias)
113+
end tell
114+
set g2script to (scriptdir & "GSAS-II.py")
115+
TestFilePresent(g2script)
116+
return g2script
117+
end GetG2Location
118+
119+
on TestFilePresent(filepath)
120+
(* test if a file is present and exit with an error message if it is not *)
121+
tell application "System Events"
122+
if (file filepath exists) then
123+
else
124+
display dialog "Error: file " & filepath & " not found. Was this app moved from the GSASII directory?" with icon caution buttons {"Quit"}
125+
error number -128
126+
end if
127+
end tell
128+
end TestFilePresent
129+
130+
(*
131+
----------------------------------------------------------------------------
132+
this section responds to a double-click. No file is supplied to GSAS-II
133+
----------------------------------------------------------------------------
134+
*)
135+
on run
136+
set python to GetPythonLocation()
137+
set appwithpath to GetG2Location()
138+
139+
tell application "Terminal"
140+
activate
141+
do script (quoted form of python) & " " & (quoted form of appwithpath) & "; exit"
142+
end tell
143+
end run
144+
145+
(*
146+
-----------------------------------------------------------------------------------------------
147+
this section handles starting with files dragged into the AppleScript
148+
o it goes through the list of file(s) dragged in
149+
o then it converts the colon-delimited macintosh file location to a POSIX filename
150+
o for every non-directory file dragged into the icon, it starts GSAS-II, passing the file name
151+
------------------------------------------------------------------------------------------------
152+
*)
153+
on open names
154+
set python to GetPythonLocation()
155+
set appwithpath to GetG2Location()
156+
157+
repeat with filename in names
158+
set filestr to (filename as string)
159+
if filestr ends with ":" then
160+
(* should not happen, skip directories *)
161+
else
162+
(* if this is an input file, open it *)
163+
set filename to the quoted form of the POSIX path of filename
164+
tell application "Terminal"
165+
activate
166+
do script python & " " & appwithpath & " " & filename & "; exit"
167+
end tell
168+
end if
169+
end repeat
170+
end open
171+
'''
172+
# # create a link named GSAS-II.py to the script
173+
# newScript = os.path.join(path2GSAS,'GSAS-II.py')
174+
# if os.path.exists(newScript): # cleanup
175+
# print("\nRemoving sym link",newScript)
176+
# os.remove(newScript)
177+
# os.symlink(os.path.split(G2script)[1],newScript)
178+
# G2script=newScript
179+
180+
# find Python used to run GSAS-II and set a new to use to call it
181+
# inside the app that will be created
182+
pythonExe = os.path.realpath(sys.executable)
183+
newpython = os.path.join(appPath,"Contents","MacOS",projectname)
184+
185+
# create an app using this python and if that fails to run wx, look for a
186+
# pythonw and try that with wx
187+
for i in 1,2,3:
188+
if os.path.exists(appPath): # cleanup
189+
print("\nRemoving old "+projectname+" app ("+str(appPath)+")")
190+
shutil.rmtree(appPath)
191+
192+
shell = os.path.join("/tmp/","appscrpt.script")
193+
f = open(shell, "w")
194+
#f.write(AppleScript.format(newpython,G2script,'',newpython,G2script,''))
195+
f.write(AppleScript)
196+
f.close()
197+
198+
try:
199+
subprocess.check_output(["osacompile","-o",appPath,shell],stderr=subprocess.STDOUT)
200+
except subprocess.CalledProcessError as msg:
201+
print('''Error compiling AppleScript.
202+
Report the next message along with details about your Mac to [email protected]''')
203+
print(msg.output)
204+
sys.exit()
205+
# create a link to conda python relative to this app, named to match the project
206+
os.symlink('../../../../bin/python',newpython)
207+
208+
# # test if newpython can run wx
209+
# def RunPython(image,cmd):
210+
# 'Run a command in a python image'
211+
# try:
212+
# err=None
213+
# p = subprocess.Popen([image,'-c',cmd],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
214+
# out = p.stdout.read()
215+
# err = p.stderr.read()
216+
# p.communicate()
217+
# return out,err
218+
# except Exception(err):
219+
# return '','Exception = '+err
220+
221+
# testout,errout = RunPython(newpython,'import numpy; import wx; wx.App(); print("-"+"OK-")')
222+
# if isinstance(testout,bytes): testout = testout.decode()
223+
# if "-OK-" in testout:
224+
# print('wxpython app ran',testout)
225+
# break
226+
# elif i == 1:
227+
# print('Run of wx in',pythonExe,'failed, looking for pythonw')
228+
# pythonExe = os.path.join(os.path.split(sys.executable)[0],'pythonw')
229+
# if not os.path.exists(pythonExe):
230+
# print('Warning no pythonw found with ',sys.executable,
231+
# '\ncontinuing, hoping for the best')
232+
# elif i == 2:
233+
# print('Warning could not run wx with',pythonExe,
234+
# 'will try with that external to app')
235+
# newpython = pythonExe
236+
# else:
237+
# print('Warning still could not run wx with',pythonExe,
238+
# '\ncontinuing, hoping for the best')
239+
240+
# change the icon
241+
oldicon = os.path.join(appPath,"Contents","Resources","droplet.icns")
242+
#if os.path.exists(iconfile) and os.path.exists(oldicon):
243+
if os.path.exists(iconfile):
244+
shutil.copyfile(iconfile,oldicon)
245+
246+
# Edit the app plist file to restrict the type of files that can be dropped
247+
if hasattr(plistlib,'load'):
248+
fp = open(os.path.join(appPath,"Contents",'Info.plist'),'rb')
249+
d = plistlib.load(fp)
250+
fp.close()
251+
else:
252+
d = plistlib.readPlist(os.path.join(appPath,"Contents",'Info.plist'))
253+
d['CFBundleDocumentTypes'] = [{
254+
'CFBundleTypeExtensions': ['gpx'],
255+
'CFBundleTypeName': 'GSAS-II project',
256+
'CFBundleTypeRole': 'Editor'}]
257+
258+
if hasattr(plistlib,'dump'):
259+
fp = open(os.path.join(appPath,"Contents",'Info.plist'),'wb')
260+
plistlib.dump(d,fp)
261+
fp.close()
262+
else:
263+
plistlib.writePlist(d,os.path.join(appPath,"Contents",'Info.plist'))
264+
265+
# Big Sur: open & save the file in the editor to set authorization levels
266+
osascript = '''
267+
tell application "Script Editor"
268+
set MyName to open "{}"
269+
save MyName
270+
(* close MyName *)
271+
(* quit *)
272+
end tell
273+
'''.format(appPath)
274+
# detect MacOS 11 (11.0 == 10.16!)
275+
if platform.mac_ver()[0].split('.')[0] == '11' or platform.mac_ver()[0][:5] == '10.16':
276+
print("\nFor Big Sur and later, save the app in Script Editor before using it\n")
277+
subprocess.Popen(["osascript","-e",osascript])
278+
print("\nCreated "+projectname+" app ("+str(appPath)+
279+
").\nViewing app in Finder so you can drag it to the dock if, you wish.")
280+
subprocess.call(["open","-R",appPath])

0 commit comments

Comments
 (0)