source: install/g2complete/src/bootstrap.py @ 4257

Last change on this file since 4257 was 4256, checked in by toby, 4 years ago

more testing for offline mac install

  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 18.2 KB
Line 
1#!/usr/bin/env python
2# Installs GSAS-II from network using subversion and creates platform-specific shortcuts.
3# works for Mac & Linux & Windows
4from __future__ import division, print_function
5import os, stat, sys, platform, subprocess, datetime
6
7version = "$Id: bootstrap.py 3515 2018-07-30 02:14:14Z toby $"
8g2home = 'https://subversion.xray.aps.anl.gov/pyGSAS/'
9path2GSAS2 = os.path.dirname(os.path.abspath(os.path.expanduser(__file__)))
10
11skipInstallSteps = False
12skipDownloadSteps = False
13skipProxy = False
14showWXerror = False
15help = False
16allBinaries = False
17for a in sys.argv[1:]:
18    if 'noinstall' in a.lower():
19        skipInstallSteps = True
20        if sys.platform.startswith('win'): showWXerror = True
21    elif 'nonet' in a.lower():
22        skipDownloadSteps = True
23        skipProxy = True
24    elif 'noproxy' in a.lower():
25        skipProxy = True
26    elif 'help' in a.lower():
27        help = True
28    elif 'allbin' in a.lower() or 'server' in a.lower():
29        allBinaries = True
30    else:
31        help = True
32
33if help:
34    print('''
35  bootstrap.py options:
36
37    --noinstall skip post-install, such as creating run shortcuts
38    --noproxy   do not ask for proxy information
39    --server    load all binary versions
40    --allbin    load all binary versions (same as --server)
41    --help      this message
42    --nonet     skip steps requiring internet
43
44''')
45    sys.exit()
46
47now = str(datetime.datetime.now())
48print('Running bootstrap from {} at {}\n\tId: {}'.format(path2GSAS2,now,version))
49fp = open(os.path.join(path2GSAS2,'bootstrap.log'),'a')
50fp.write('Running bootstrap from {} at {}\n\tId: {}\n'.format(path2GSAS2,now,version))
51fp.close()
52       
53################################################################################
54################################################################################
55def BailOut(msg):
56    '''Exit with an error message. Use a GUI to show the error when
57    showWXerror == True (on windows when --noinstall is specified)
58    '''
59    print(msg)
60    if showWXerror:
61        import wx
62        app = wx.App()
63        app.MainLoop()
64        dlg = wx.MessageDialog(None,msg,'GSAS-II installation error', 
65                wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP)
66        dlg.Raise()
67        dlg.ShowModal()
68        dlg.Destroy()
69#    else:
70#        print(msg,file=sys.stderr)
71    sys.exit()
72       
73def GetConfigValue(*args): return True
74# routines copied from GSASIIpath.py
75proxycmds = []
76'Used to hold proxy information for subversion, set if needed in whichsvn'
77svnLocCache = None
78'Cached location of svn to avoid multiple searches for it'
79
80def MakeByte2str(arg):
81    '''Convert output from subprocess pipes (bytes) to str (unicode) in Python 3.
82    In Python 2: Leaves output alone (already str).
83    Leaves stuff of other types alone (including unicode in Py2)
84    Works recursively for string-like stuff in nested loops and tuples.
85
86    typical use::
87
88        out = MakeByte2str(out)
89
90    or::
91
92        out,err = MakeByte2str(s.communicate())
93   
94    '''
95    if isinstance(arg,str): return arg
96    if isinstance(arg,bytes): return arg.decode()
97    if isinstance(arg,list):
98        return [MakeByte2str(i) for i in arg]
99    if isinstance(arg,tuple):
100        return tuple([MakeByte2str(i) for i in arg])
101    return arg
102
103def getsvnProxy():
104    '''Loads a proxy for subversion from the file created by bootstrap.py
105    '''
106    proxyinfo = os.path.join(path2GSAS2,"proxyinfo.txt")
107    if os.path.exists(proxyinfo):
108        global proxycmds
109        global host,port  # only in bootstrap.py
110        proxycmds = []
111        fp = open(proxyinfo,'r')
112        host = fp.readline().strip()
113        port = fp.readline().strip()
114        fp.close()
115        setsvnProxy(host,port)
116        if not host.strip(): return '',''
117        return host,port
118    return '',''
119
120def setsvnProxy(host,port):
121    '''Sets the svn commands needed to use a proxy
122    '''
123    global proxycmds
124    proxycmds = []
125    host = host.strip()
126    port = port.strip()
127    if not host.strip(): return
128    proxycmds.append('--config-option')
129    proxycmds.append('servers:global:http-proxy-host='+host)
130    if port.strip():
131        proxycmds.append('--config-option')
132        proxycmds.append('servers:global:http-proxy-port='+port)
133       
134def whichsvn():
135    '''Returns a path to the subversion exe file, if any is found.
136    Searches the current path after adding likely places where GSAS-II
137    might install svn.
138
139    :returns: None if svn is not found or an absolute path to the subversion
140      executable file.
141    '''
142    # use a previosuly cached svn location
143    global svnLocCache
144    if svnLocCache: return svnLocCache
145    # prepare to find svn
146    is_exe = lambda fpath: os.path.isfile(fpath) and os.access(fpath, os.X_OK)
147    svnprog = 'svn'
148    if sys.platform.startswith('win'): svnprog += '.exe'
149    host,port = getsvnProxy()
150    if GetConfigValue('debug') and host:
151        print('DBG_Using proxy host {} port {}'.format(host,port))
152    # add likely places to find subversion when installed with GSAS-II
153    pathlist = os.environ["PATH"].split(os.pathsep)
154    pathlist.insert(0,os.path.split(sys.executable)[0])
155    pathlist.insert(1,path2GSAS2)
156    for rpt in ('..','bin'),('..','Library','bin'),('svn','bin'),('svn',),('.'):
157        pt = os.path.normpath(os.path.join(path2GSAS2,*rpt))
158        if os.path.exists(pt):
159            pathlist.insert(0,pt)   
160    # search path for svn or svn.exe
161    for path in pathlist:
162        exe_file = os.path.join(path, svnprog)
163        if is_exe(exe_file):
164            try:
165                p = subprocess.Popen([exe_file,'help'],stdout=subprocess.PIPE)
166                res = p.stdout.read()
167                p.communicate()
168                svnLocCache = os.path.abspath(exe_file)
169                return svnLocCache
170            except:
171                pass       
172    svnLocCache = None
173
174def svnVersion(svn=None):
175    '''Get the version number of the current subversion executable
176
177    :returns: a string with a version number such as "1.6.6" or None if
178      subversion is not found.
179
180    '''
181    if not svn: svn = whichsvn()
182    if not svn: return
183
184    cmd = [svn,'--version','--quiet']
185    s = subprocess.Popen(cmd,
186                         stdout=subprocess.PIPE,stderr=subprocess.PIPE)
187    out,err = MakeByte2str(s.communicate())
188    if err:
189        print ('subversion error!\nout=%s'%out)
190        print ('err=%s'%err)
191        s = '\nsvn command:  '
192        for i in cmd: s += i + ' '
193        print(s)
194        return None
195    return out.strip()
196
197def svnVersionNumber(svn=None):
198    '''Get the version number of the current subversion executable
199
200    :returns: a fractional version number such as 1.6 or None if
201      subversion is not found.
202
203    '''
204    ver = svnVersion(svn)
205    if not ver: return 
206    M,m = ver.split('.')[:2]
207    return int(M)+int(m)/10.
208
209################################################################################
210################################################################################
211print(70*'*')
212#testing for incorrect locale code'
213try:
214    import locale
215    locale.getdefaultlocale()
216except ValueError:
217    print('Your location is not set properly. This causes problems for matplotlib')
218    print('  (see https://github.com/matplotlib/matplotlib/issues/5420.)')
219    print('Will try to bypass problem by setting LC_ALL to en_US.UTF-8 (US English)')
220    os.environ['LC_ALL'] = 'en_US.UTF-8'
221    locale.getdefaultlocale()
222print('Preloading matplotlib to build fonts...')
223try:
224    import matplotlib
225except:
226    pass
227print('Checking python packages...')
228missing = []
229for pkg in ['numpy','scipy','matplotlib','wx','OpenGL',]:
230    try:
231        exec('import '+pkg)
232    except:
233        missing.append(pkg)
234
235if missing and not skipInstallSteps:
236    msg = """Sorry, this version of Python cannot be used
237for GSAS-II. It is missing the following package(s):
238\t"""
239    for pkg in missing: msg += " "+pkg
240    msg += "\nPlease install these package(s) and try running bootstrap.py again."
241    #print("Showing first error: ")
242    #for pkg in ['numpy','scipy','matplotlib','wx','OpenGL',]:
243    #    exec('import '+pkg)
244    BailOut(msg)
245
246if not skipDownloadSteps:
247    host = None
248    port = '80'
249    print('\nChecking for subversion...')
250    svn = whichsvn() # resets host & port if proxyinfo.txt is found
251    if not svn:
252        msg ="Sorry, subversion (svn) could not be found on your system."
253        msg += "\nPlease install this or place in path and rerun this."
254        BailOut(msg)
255    else:
256        print(' found svn image: '+svn)
257
258#if install_with_easyinstall:           
259#    print('\nInstalling PyOpenGL. Lots of warnings will follow... ')
260#    install_with_easyinstall('PyOpenGl')               
261#    print('done.')
262   
263print('Ready to bootstrap GSAS-II from repository\n\t'+g2home+'\nto '+path2GSAS2)
264proxycmds = []
265proxyinfo = os.path.join(path2GSAS2,"proxyinfo.txt")
266if os.path.exists(proxyinfo):
267    fp = open(proxyinfo,'r')
268    host = fp.readline().strip()
269    port = fp.readline().strip()
270    fp.close()
271    os.remove(proxyinfo)
272print(70*"=")
273if sys.version_info[0] == 2:
274    getinput = raw_input
275else:
276    getinput = input
277
278# get proxy from environment variable
279key = None
280for i in os.environ.keys():
281    if 'https_proxy' == i.lower():
282        key = i
283        break
284else:
285    for i in os.environ.keys():
286        if 'http_proxy' == i.lower():
287            key = i
288            break
289val = ''
290if key:
291    val = os.environ[key].strip()
292if val:
293    if val[-1] == '/':
294        val = val[:-1]
295    if len(val.split(':')) > 2:
296        host = ':'.join(val.split(':')[:-1])
297        port = val.split(':')[-1]
298    else:
299        host = ':'.join(val.split(':')[:-1])
300        port = val.split(':')[-1]
301
302# get proxy from user, if terminal available
303try:
304    if skipProxy:
305        host = ""
306    elif host:
307        ans = getinput("Enter the proxy address (type none to remove) ["+host+"]: ").strip()
308        if ans.lower() == "none": host = ""
309    else:
310        ans = getinput("Enter your proxy address [none needed]: ").strip()
311        if ans: host = ans
312    if host:
313        ans = getinput("Enter the proxy port ["+port+"]: ").strip()
314        if ans == "": ans=port
315        port = ans
316except EOFError:
317    host = ""
318    port = ""
319if host:
320    proxycmds.append('--config-option')
321    proxycmds.append('servers:global:http-proxy-host='+host.strip())
322    if port:
323        proxycmds.append('--config-option')
324        proxycmds.append('servers:global:http-proxy-port='+port.strip())
325    fp = open(proxyinfo,'w')
326    fp.write(host.strip()+'\n')
327    fp.write(port.strip()+'\n')
328    fp.close()
329    fp = open(os.path.join(path2GSAS2,'bootstrap.log'),'a')
330    fp.write('Proxy info written: {} port\n'.format(host,port))
331    print('Proxy info written: {} port'.format(host,port))
332    fp.close()
333
334if not skipDownloadSteps:
335    # patch: switch GSAS-II location if linked to XOR server (relocated May/June 2017)
336    cmd = [svn, 'info']
337    p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
338    res,err = p.communicate()
339    if '.xor.' in str(res):
340        print('Switching previous install with .xor. download location to\n\thttps://subversion.xray.aps.anl.gov/pyGSAS')
341        cmd = [svn, 'switch','--relocate','https://subversion.xor.aps.anl.gov/pyGSAS',
342               'https://subversion.xray.aps.anl.gov/pyGSAS']
343        if proxycmds: cmd += proxycmds
344        p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
345        res,err = p.communicate()
346        if err:
347            print('Please report this error to toby@anl.gov:')
348            print(err)
349            print(res)
350    # patch: switch GSAS-II location if switched to 2frame version (removed August 2017)
351    if '2frame' in str(res):
352        print('Switching previous 2frame install to trunk\n\thttps://subversion.xray.aps.anl.gov/pyGSAS')
353        cmd = [svn, 'switch',g2home + '/trunk',path2GSAS2,
354               '--non-interactive','--trust-server-cert',
355               '--accept','theirs-conflict','--force','--ignore-ancestry']
356        if proxycmds: cmd += proxycmds
357        p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
358        res,err = p.communicate()
359        if err:
360            print('Please report this error to toby@anl.gov:')
361            print(err)
362            print(res)
363
364    print('\n'+75*'*')
365    print('Now preparing to install GSAS-II')
366    tryagain = True
367    err = False
368    firstPass = 0
369    while(tryagain):
370        tryagain = False
371        if err:
372            print('Retrying after a cleanup...')
373            cmd = [svn, 'cleanup', path2GSAS2]
374            s = subprocess.Popen(cmd,stderr=subprocess.PIPE)
375            out,err = MakeByte2str(s.communicate())
376            if err:
377                print('subversion returned an error:')
378                print(out)
379                print(err)
380        cmd = [svn, 'co', g2home+ 'trunk/', path2GSAS2, '--non-interactive', '--trust-server-cert']
381        if proxycmds: cmd += proxycmds
382        msg = 'svn load command: '
383        for item in cmd: msg += " "+item
384        print(msg)
385        s = subprocess.Popen(cmd,stderr=subprocess.PIPE)
386        print('\nsubversion output:')
387        out,err = MakeByte2str(s.communicate())
388        if err:
389            print('subversion returned an error:')
390            print(out)
391            print(err)
392            if firstPass == 0: tryagain = True
393        firstPass += 1
394    if err:
395        print('Retrying with a command for older svn version...')
396        cmd = [svn, 'co', g2home+ 'trunk/', path2GSAS2]
397        if proxycmds: cmd += proxycmds
398        msg = ""
399        for item in cmd: msg += " " + item
400        print(msg)
401        s = subprocess.Popen(cmd,stderr=subprocess.PIPE)
402        out,err = MakeByte2str(s.communicate())
403        if err:
404            msg = 'subversion returned an error:\n'
405            msg += err
406            if os.path.exists(os.path.join(path2GSAS2,"makeBat.py")):
407                msg += '\n\nGSAS-II failed to be updated. A likely reason is a network access'
408                msg += '\nproblem. If your web browser works, but the update did not.'
409                msg += '\nThe most common reason is you need to use a network proxy. Please'
410                msg += '\ncheck with a network administrator or use http://www.whatismyproxy.com/'
411            else:               
412                msg += '\n\n  *** GSAS-II failed to be installed. A likely reason is a network access'
413                msg += '\n  *** problem, most commonly because you need to use a network proxy. Please'
414                msg += '  *** check with a network administrator or use http://www.whatismyproxy.com/\n'
415            BailOut(msg)
416    print('\n'+75*'*')
417
418try:
419    import GSASIIpath
420    print('import of GSASIIpath completed')
421except Exception as err:
422    msg = 'Failed with import of GSASIIpath. This is unexpected.'
423    msg += '\nGSAS-II will not run without correcting this. Contact toby@anl.gov'
424    BailOut(msg)
425
426if allBinaries and not skipDownloadSteps:
427    print('Loading all binaries with command...')
428    if not GSASIIpath.svnSwitchDir('AllBinaries','',g2home+ 'Binaries/',None,True):
429        msg = 'Binary load failed'
430        BailOut(msg)
431else:
432    GSASIIpath.DownloadG2Binaries(g2home)
433       
434#===========================================================================
435# test if the compiled files load correctly
436#===========================================================================
437
438script = """  # commands that test each module can at least be loaded & run something in pyspg
439try:
440    import GSASIIpath
441    GSASIIpath.SetBinaryPath(loadBinary=False)
442    import pyspg
443    import histogram2d
444    import polymask
445    import pypowder
446    import pytexture
447    pyspg.sgforpy('P -1')
448    print('==OK==')
449except Exception as err:
450    print(err)
451"""
452p = subprocess.Popen([sys.executable,'-c',script],stdout=subprocess.PIPE,stderr=subprocess.PIPE,
453                     cwd=path2GSAS2)
454res,err = MakeByte2str(p.communicate())
455if '==OK==' not in str(res) or p.returncode != 0:
456    #print('\n'+75*'=')
457    msg = 'Failed when testing the GSAS-II compiled files. GSAS-II will not run'
458    msg += ' without correcting this.\n\nError message:\n'
459    if res: 
460        msg += res
461        msg += '\n'
462    if err:
463        msg += err
464    #print('\nAttempting to open a web page on compiling GSAS-II...')
465    msg += '\n\nPlease see web page\nhttps://subversion.xray.aps.anl.gov/trac/pyGSAS/wiki/CompileGSASII'
466    BailOut(msg)
467    #import webbrowser
468    #webbrowser.open_new('https://subversion.xray.aps.anl.gov/trac/pyGSAS/wiki/CompileGSASII')
469    #print(75*'=')
470#    if '86' in platform.machine() and (sys.platform.startswith('linux')
471#                                        or sys.platform == "darwin"
472#                                        or sys.platform.startswith('win')):
473#        print('Platform '+sys.platform+' with processor type '+platform.machine()+' is supported')
474#    else:
475#        print('Platform '+sys.platform+' with processor type '+platform.machine()+' not is supported')
476else:
477    print('Successfully tested compiled routines')
478#===========================================================================
479# import all .py files so that .pyc files get created
480if not skipInstallSteps:
481    print('Byte-compiling all .py files...')
482    import compileall
483    compileall.compile_dir(path2GSAS2,quiet=True)
484    print('done')
485#===========================================================================
486# platform-dependent stuff
487#===========================================================================
488if sys.version_info[0] > 2:
489    def execfile(file):
490        with open(file) as source_file:
491            exec(source_file.read())
492
493if skipInstallSteps:
494    pass
495#===========================================================================
496# on Windows, make a batch file with Python and GSAS-II location hard-coded
497elif sys.platform.startswith('win') and os.path.exists(
498    os.path.join(path2GSAS2,"makeBat.py")):
499    execfile(os.path.join(path2GSAS2,"makeBat.py"))
500#===========================================================================
501# on a Mac, make an applescript
502elif sys.platform.startswith('darwin') and os.path.exists(
503    os.path.join(path2GSAS2,"makeMacApp.py")):
504    sys.argv = [os.path.join(path2GSAS2,"makeMacApp.py")]
505    print(u'running '+sys.argv[0])
506    execfile(sys.argv[0])
507#===========================================================================
508# On linux, make desktop icon
509elif sys.platform.startswith('linux') and os.path.exists(
510    os.path.join(path2GSAS2,"makeLinux.py")):
511    sys.argv = [os.path.join(path2GSAS2,"makeLinux.py")]
512    print(u'running '+sys.argv[0])
513    execfile(sys.argv[0])
514
Note: See TracBrowser for help on using the repository browser.