source: install/bootstrap.py @ 4239

Last change on this file since 4239 was 4239, checked in by toby, 3 years ago

fix multi-image use in scripts; work on 32-bit windows build

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