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

Last change on this file since 4261 was 4261, checked in by toby, 23 months ago

Last(?) updates to mac/linux install

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