source: trunk/GSASIIpath.py @ 5129

Last change on this file since 5129 was 5129, checked in by toby, 13 months ago

Raspbian-64 (bullseye) build & fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 48.9 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIpath - file location & update routines
3########### SVN repository information ###################
4# $Date: 2022-01-08 16:41:19 +0000 (Sat, 08 Jan 2022) $
5# $Author: toby $
6# $Revision: 5129 $
7# $URL: trunk/GSASIIpath.py $
8# $Id: GSASIIpath.py 5129 2022-01-08 16:41:19Z toby $
9########### SVN repository information ###################
10'''
11*GSASIIpath: locations & updates*
12---------------------------------
13
14Routines for dealing with file locations, etc.
15
16Determines the location of the compiled (.pyd or .so) libraries.
17
18Interfaces with subversion (svn):
19Determine the subversion release number by determining the highest version number
20where :func:`SetVersionNumber` is called (best done in every GSASII file).
21Other routines will update GSASII from the subversion server if svn can be
22found.
23
24Accesses configuration options, as defined in config.py
25'''
26
27from __future__ import division, print_function
28import os
29import sys
30import platform
31import glob
32import subprocess
33try:
34    import numpy as np
35except ImportError:
36    print("skipping numpy in GSASIIpath")
37g2home = 'https://subversion.xray.aps.anl.gov/pyGSAS'
38'Define the location of the GSAS-II subversion repository'
39   
40path2GSAS2 = os.path.dirname(os.path.abspath(os.path.expanduser(__file__))) # location of this file; save before any changes in pwd
41
42# convert version numbers as '1.2.3' to integers (1002) and back (to 1.2)
43fmtver = lambda v: str(v//1000)+'.'+str(v%1000)
44intver = lambda vs: sum([int(i) for i in vs.split('.')[0:2]]*np.array((1000,1)))
45
46def GetConfigValue(key,default=None):
47    '''Return the configuration file value for key or a default value if not present
48   
49    :param str key: a value to be found in the configuration (config.py) file
50    :param default: a value to be supplied is none is in the config file or
51      the config file is not found. Defaults to None
52    :returns: the value found or the default.
53    '''
54    try:
55        return configDict.get(key,default)
56    except NameError: # this happens when building docs
57        return None
58
59def SetConfigValue(parmdict):
60    '''Set configuration variables from a dictionary where elements are lists
61    First item in list is the default value and second is the value to use.
62    '''
63    global configDict
64    for var in parmdict:
65        if var in configDict:
66            del configDict[var]
67        if isinstance(parmdict[var],tuple):
68            configDict[var] = parmdict[var]
69        else:
70            if parmdict[var][1] is None: continue
71            if parmdict[var][1] == '': continue
72            if parmdict[var][0] == parmdict[var][1]: continue
73            configDict[var] = parmdict[var][1]
74
75def addPrevGPX(fil,configDict):
76    '''Add a GPX file to the list of previous files.
77    Move previous names to start of list. Keep most recent five files
78    '''
79    fil = os.path.abspath(os.path.expanduser(fil))
80    if 'previous_GPX_files' not in configDict: return
81    try:
82        pos = configDict['previous_GPX_files'][1].index(fil) 
83        if pos == 0: return
84        configDict['previous_GPX_files'][1].pop(pos) # if present, remove if not 1st
85    except ValueError:
86        pass
87    except AttributeError:
88        configDict['previous_GPX_files'][1] = []
89    configDict['previous_GPX_files'][1].insert(0,fil)
90    configDict['previous_GPX_files'][1] = configDict['previous_GPX_files'][1][:5]
91
92# routines for looking a version numbers in files
93version = -1
94def SetVersionNumber(RevString):
95    '''Set the subversion version number
96
97    :param str RevString: something like "$Revision: 5129 $"
98      that is set by subversion when the file is retrieved from subversion.
99
100    Place ``GSASIIpath.SetVersionNumber("$Revision: 5129 $")`` in every python
101    file.
102    '''
103    try:
104        RevVersion = int(RevString.split(':')[1].split()[0])
105        global version
106        version = max(version,RevVersion)
107    except:
108        pass
109       
110def GetVersionNumber():
111    '''Return the maximum version number seen in :func:`SetVersionNumber`
112    '''
113    if version > 1000:
114        return version
115    else:
116        return "unknown"
117
118def LoadConfigFile(filename):
119    '''Read a GSAS-II configuration file.
120    Comments (starting with "%") are removed, as are empty lines
121   
122    :param str filename: base file name (such as 'file.dat'). Files with this name
123      are located from the path and the contents of each are concatenated.
124    :returns: a list containing each non-empty (after removal of comments) line
125      found in every matching config file.
126    '''
127    info = []
128    for path in sys.path:
129        fil = os.path.join(path,filename)
130        if not os.path.exists(fil): continue
131        try:
132            i = 0
133            fp = open(fil,'r')
134            for line in fp:
135                expr = line.split('#')[0].strip()
136                if expr:
137                    info.append(expr)
138                    i += 1
139            print(str(i)+' lines read from config file '+fil)
140        finally:
141            fp.close()
142    return info
143
144
145# routines to interface with subversion
146proxycmds = []
147'Used to hold proxy information for subversion, set if needed in whichsvn'
148svnLocCache = None
149'Cached location of svn to avoid multiple searches for it'
150
151def MakeByte2str(arg):
152    '''Convert output from subprocess pipes (bytes) to str (unicode) in Python 3.
153    In Python 2: Leaves output alone (already str).
154    Leaves stuff of other types alone (including unicode in Py2)
155    Works recursively for string-like stuff in nested loops and tuples.
156
157    typical use::
158
159        out = MakeByte2str(out)
160
161    or::
162
163        out,err = MakeByte2str(s.communicate())
164   
165    '''
166    if isinstance(arg,str): return arg
167    if isinstance(arg,bytes):
168        try:
169            return arg.decode()
170        except:
171            if GetConfigValue('debug'): print('Decode error')
172            return arg
173    if isinstance(arg,list):
174        return [MakeByte2str(i) for i in arg]
175    if isinstance(arg,tuple):
176        return tuple([MakeByte2str(i) for i in arg])
177    return arg
178               
179def getsvnProxy():
180    '''Loads a proxy for subversion from the proxyinfo.txt file created
181    by bootstrap.py or File => Edit Proxy...; If not found, then the
182    standard http_proxy and https_proxy environment variables are scanned
183    (see https://docs.python.org/3/library/urllib.request.html#urllib.request.getproxies)
184    with case ignored and that is used.
185    '''
186    global proxycmds
187    proxycmds = []
188    proxyinfo = os.path.join(os.path.expanduser('~/.G2local/'),"proxyinfo.txt")
189    if not os.path.exists(proxyinfo):
190        proxyinfo = os.path.join(path2GSAS2,"proxyinfo.txt")
191    if os.path.exists(proxyinfo):
192        fp = open(proxyinfo,'r')
193        host = fp.readline().strip()
194        # allow file to begin with comments
195        while host.startswith('#'):
196            host = fp.readline().strip()
197        port = fp.readline().strip()
198        etc = []
199        line = fp.readline()
200        while line:
201            etc.append(line.strip())
202            line = fp.readline()
203        fp.close()
204        setsvnProxy(host,port,etc)
205        return host,port,etc
206    import urllib.request
207    proxdict = urllib.request.getproxies()
208    varlist = ("https","http")
209    for var in proxdict:
210        if var.lower() in varlist:
211            proxy = proxdict[var]
212            pl = proxy.split(':')
213            if len(pl) < 2: continue
214            host = pl[1].strip('/')
215            port = ''
216            if len(pl) == 3:
217                port = pl[2].strip('/').strip()
218            return host,port,''
219    return '','',''
220
221def setsvnProxy(host,port,etc=[]):
222    '''Sets the svn commands needed to use a proxy
223    '''
224    global proxycmds
225    proxycmds = []
226    host = host.strip()
227    port = port.strip()
228    if host: 
229        proxycmds.append('--config-option')
230        proxycmds.append('servers:global:http-proxy-host='+host)
231        if port:
232            proxycmds.append('--config-option')
233            proxycmds.append('servers:global:http-proxy-port='+port)
234    for item in etc:
235        proxycmds.append(item)
236       
237def whichsvn():
238    '''Returns a path to the subversion exe file, if any is found.
239    Searches the current path after adding likely places where GSAS-II
240    might install svn.
241
242    :returns: None if svn is not found or an absolute path to the subversion
243      executable file.
244    '''
245    # use a previosuly cached svn location
246    global svnLocCache
247    if svnLocCache: return svnLocCache
248    # prepare to find svn
249    is_exe = lambda fpath: os.path.isfile(fpath) and os.access(fpath, os.X_OK)
250    svnprog = 'svn'
251    if sys.platform.startswith('win'): svnprog += '.exe'
252    host,port,etc = getsvnProxy()
253    if GetConfigValue('debug') and host:
254        print('DBG_Using proxy host {} port {}'.format(host,port))
255    if GetConfigValue('svn_exec'):
256        exe_file = GetConfigValue('svn_exec')
257        print('Using ',exe_file)
258        if is_exe(exe_file):
259            try:
260                p = subprocess.Popen([exe_file,'help'],stdout=subprocess.PIPE)
261                res = p.stdout.read()
262                if not res: return
263                p.communicate()
264                svnLocCache = os.path.abspath(exe_file)
265                return svnLocCache
266            except:
267                pass
268    # add likely places to find subversion when installed with GSAS-II
269    pathlist = os.environ["PATH"].split(os.pathsep)
270    pathlist.insert(0,os.path.split(sys.executable)[0])
271    pathlist.insert(1,path2GSAS2)
272    for rpt in ('..','bin'),('..','Library','bin'),('svn','bin'),('svn',),('.'):
273        pt = os.path.normpath(os.path.join(path2GSAS2,*rpt))
274        if os.path.exists(pt):
275            pathlist.insert(0,pt)   
276    # search path for svn or svn.exe
277    for path in pathlist:
278        exe_file = os.path.join(path, svnprog)
279        if is_exe(exe_file):
280            try:
281                p = subprocess.Popen([exe_file,'help'],stdout=subprocess.PIPE)
282                res = p.stdout.read()
283                if not res: return
284                p.communicate()
285                svnLocCache = os.path.abspath(exe_file)
286                return svnLocCache
287            except:
288                pass       
289    svnLocCache = None
290
291def svnVersion(svn=None):
292    '''Get the version number of the current subversion executable
293
294    :returns: a string with a version number such as "1.6.6" or None if
295      subversion is not found.
296
297    '''
298    if not svn: svn = whichsvn()
299    if not svn: return
300
301    cmd = [svn,'--version','--quiet']
302    s = subprocess.Popen(cmd,
303                         stdout=subprocess.PIPE,stderr=subprocess.PIPE)
304    out,err = MakeByte2str(s.communicate())
305    if err:
306        print ('subversion error!\nout=%s'%out)
307        print ('err=%s'%err)
308        s = '\nsvn command:  '
309        for i in cmd: s += i + ' '
310        print(s)
311        return None
312    return out.strip()
313
314def svnVersionNumber(svn=None):
315    '''Get the version number of the current subversion executable
316
317    :returns: a fractional version number such as 1.6 or None if
318      subversion is not found.
319
320    '''
321    ver = svnVersion(svn)
322    if not ver: return 
323    M,m = ver.split('.')[:2]
324    return int(M)+int(m)/10.
325
326def svnGetLog(fpath=os.path.split(__file__)[0],version=None):
327    '''Get the revision log information for a specific version of the specified package
328
329    :param str fpath: path to repository dictionary, defaults to directory where
330       the current file is located.
331    :param int version: the version number to be looked up or None (default)
332       for the latest version.
333
334    :returns: a dictionary with keys (one hopes) 'author', 'date', 'msg', and 'revision'
335
336    '''
337    import xml.etree.ElementTree as ET
338    svn = whichsvn()
339    if not svn: return
340    if version is not None:
341        vstr = '-r'+str(version)
342    else:
343        vstr = '-rHEAD'
344
345    cmd = [svn,'log',fpath,'--xml',vstr]
346    if proxycmds: cmd += proxycmds
347    s = subprocess.Popen(cmd,
348                         stdout=subprocess.PIPE,stderr=subprocess.PIPE)
349    out,err = MakeByte2str(s.communicate())
350    if err:
351        print ('out=%s'%out)
352        print ('err=%s'%err)
353        s = '\nsvn command:  '
354        for i in cmd: s += i + ' '
355        print(s)
356        return None
357    x = ET.fromstring(out)
358    d = {}
359    for i in x.iter('logentry'):
360        d = {'revision':i.attrib.get('revision','?')}
361        for j in i:
362            d[j.tag] = j.text
363        break # only need the first
364    return d
365
366svnLastError = ''
367def svnGetRev(fpath=os.path.split(__file__)[0],local=True):
368    '''Obtain the version number for the either the last update of the local version
369    or contacts the subversion server to get the latest update version (# of Head).
370
371    :param str fpath: path to repository dictionary, defaults to directory where
372       the current file is located
373    :param bool local: determines the type of version number, where
374       True (default): returns the latest installed update
375       False: returns the version number of Head on the server
376
377    :Returns: the version number as an str or
378       None if there is a subversion error (likely because the path is
379       not a repository or svn is not found). The error message is placed in
380       global variable svnLastError
381    '''
382
383    import xml.etree.ElementTree as ET
384    svn = whichsvn()
385    if not svn: return
386    if local:
387        cmd = [svn,'info',fpath,'--xml']
388    else:
389        cmd = [svn,'info',fpath,'--xml','-rHEAD']
390    if svnVersionNumber() >= 1.6:
391        cmd += ['--non-interactive', '--trust-server-cert']
392    if proxycmds: cmd += proxycmds
393    # if GetConfigValue('debug'):
394    #     s = 'subversion command:\n  '
395    #     for i in cmd: s += i + ' '
396    #     print(s)
397    s = subprocess.Popen(cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
398    out,err = MakeByte2str(s.communicate())
399    if err:
400        print ('svn failed\n%s'%out)
401        print ('err=%s'%err)
402        s = '\nsvn command:  '
403        for i in cmd: s += i + ' '
404        print(s)
405        global svnLastError
406        svnLastError = err
407        return None
408    x = ET.fromstring(out)
409    for i in x.iter('entry'):
410        rev = i.attrib.get('revision')
411        if rev: return rev
412
413def svnFindLocalChanges(fpath=os.path.split(__file__)[0]):
414    '''Returns a list of files that were changed locally. If no files are changed,
415       the list has length 0
416
417    :param fpath: path to repository dictionary, defaults to directory where
418       the current file is located
419
420    :returns: None if there is a subversion error (likely because the path is
421       not a repository or svn is not found)
422
423    '''
424    import xml.etree.ElementTree as ET
425    svn = whichsvn()
426    if not svn: return
427    cmd = [svn,'status',fpath,'--xml']
428    if proxycmds: cmd += proxycmds
429    s = subprocess.Popen(cmd,
430                         stdout=subprocess.PIPE,stderr=subprocess.PIPE)
431    out,err = MakeByte2str(s.communicate())
432    if err: return None
433    x = ET.fromstring(out)
434    changed = []
435    for i in x.iter('entry'):
436        if i.find('wc-status').attrib.get('item') == 'modified': 
437            changed.append(i.attrib.get('path'))
438    return changed
439
440def svnCleanup(fpath=os.path.split(__file__)[0],verbose=True):
441    '''This runs svn cleanup on a selected local directory.
442
443    :param str fpath: path to repository dictionary, defaults to directory where
444       the current file is located
445    '''
446    svn = whichsvn()
447    if not svn: return
448    if verbose: print(u"Performing svn cleanup at "+fpath)
449    cmd = [svn,'cleanup',fpath]
450    if verbose: showsvncmd(cmd)       
451    s = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
452    out,err = MakeByte2str(s.communicate())
453    if err:
454        print(60*"=")
455        print("****** An error was noted, see below *********")
456        print(60*"=")
457        print(err)
458        s = '\nsvn command:  '
459        for i in cmd: s += i + ' '
460        print(s)
461        #raise Exception('svn cleanup failed')
462        return False
463    elif verbose:
464        print(out)
465    return True
466       
467def svnUpdateDir(fpath=os.path.split(__file__)[0],version=None,verbose=True):
468    '''This performs an update of the files in a local directory from a server.
469
470    :param str fpath: path to repository dictionary, defaults to directory where
471       the current file is located
472    :param version: the number of the version to be loaded. Used only
473       cast as a string, but should be an integer or something that corresponds to a
474       string representation of an integer value when cast. A value of None (default)
475       causes the latest version on the server to be used.
476    '''
477    svn = whichsvn()
478    if not svn: return
479    if version:
480        verstr = '-r' + str(version)
481    else:
482        verstr = '-rHEAD'
483    if verbose: print(u"Updating files at "+fpath)
484    cmd = [svn,'update',fpath,verstr,
485           '--non-interactive',
486           '--accept','theirs-conflict','--force']
487    if svnVersionNumber() >= 1.6:
488        cmd += ['--trust-server-cert']
489    if proxycmds: cmd += proxycmds
490    #if verbose or GetConfigValue('debug'):
491    if verbose:
492        s = 'subversion command:\n  '
493        for i in cmd: s += i + ' '
494        print(s)
495    s = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
496    out,err = MakeByte2str(s.communicate())
497    if err:
498        print(60*"=")
499        print("****** An error was noted, see below *********")
500        print(60*"=")
501        print(err)
502        s = '\nsvn command:  '
503        for i in cmd: s += i + ' '
504        print(s)
505        if svnCleanup(fpath):
506            s = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
507            out,err = MakeByte2str(s.communicate())
508            if err:
509                print(60*"=")
510                print("****** Drat, failed again: *********")
511                print(60*"=")
512                print(err)
513            else:
514                return
515        if 'Checksum' in err:  # deal with Checksum problem
516            err = svnChecksumPatch(svn,fpath,verstr)
517            if err:
518                print('error from svnChecksumPatch\n\t',err)
519            else:
520                return
521        raise Exception('svn update failed')
522    elif verbose:
523        print(out)
524
525def showsvncmd(cmd):
526    s = '\nsvn command:  '
527    for i in cmd: s += i + ' '
528    print(s)
529
530def svnChecksumPatch(svn,fpath,verstr):
531    '''This performs a fix when svn cannot finish an update because of
532    a Checksum mismatch error. This seems to be happening on OS X for
533    unclear reasons.
534    '''
535    print('\nAttempting patch for svn Checksum mismatch error\n')
536    svnCleanup(fpath)
537    cmd = ['svn','update','--set-depth','empty',
538               os.path.join(fpath,'bindist')]
539    showsvncmd(cmd)       
540    s = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
541    out,err = MakeByte2str(s.communicate())
542    #if err: print('error=',err)
543    cmd = ['svn','switch',g2home+'/trunk/bindist',
544               os.path.join(fpath,'bindist'),
545               '--non-interactive', '--trust-server-cert', '--accept',
546               'theirs-conflict', '--force', '-rHEAD', '--ignore-ancestry']
547    showsvncmd(cmd)       
548    s = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
549    out,err = MakeByte2str(s.communicate())
550    DownloadG2Binaries(g2home,verbose=True)
551    cmd = ['svn','update','--set-depth','infinity',
552               os.path.join(fpath,'bindist')]
553    showsvncmd(cmd)       
554    s = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
555    out,err = MakeByte2str(s.communicate())
556    #if err: print('error=',err)
557    cmd = [svn,'update',fpath,verstr,
558                       '--non-interactive',
559                       '--accept','theirs-conflict','--force']
560    if svnVersionNumber() >= 1.6:
561        cmd += ['--trust-server-cert']
562    if proxycmds: cmd += proxycmds
563    showsvncmd(cmd)       
564    s = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
565    out,err = MakeByte2str(s.communicate())
566    #if err: print('error=',err)
567    return err
568       
569def svnUpgrade(fpath=os.path.split(__file__)[0]):
570    '''This reformats subversion files, which may be needed if an upgrade of subversion is
571    done.
572
573    :param str fpath: path to repository dictionary, defaults to directory where
574       the current file is located
575    '''
576    svn = whichsvn()
577    if not svn: return
578    cmd = [svn,'upgrade',fpath,'--non-interactive']
579    if proxycmds: cmd += proxycmds
580    s = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
581    out,err = MakeByte2str(s.communicate())
582    if err:
583        print("svn upgrade did not happen (this is probably OK). Messages:")
584        print (err)
585        s = '\nsvn command:  '
586        for i in cmd: s += i + ' '
587        print(s)
588
589def svnUpdateProcess(version=None,projectfile=None,branch=None):
590    '''perform an update of GSAS-II in a separate python process'''
591    if not projectfile:
592        projectfile = ''
593    else:
594        projectfile = os.path.realpath(projectfile)
595        print ('restart using %s'%projectfile)
596    if branch:
597        version = branch
598    elif not version:
599        version = ''
600    else:
601        version = str(version)
602    # start the upgrade in a separate interpreter (avoids loading .pyd files)
603    ex = sys.executable
604    if sys.platform == "darwin": # mac requires pythonw which is not always reported as sys.executable
605        if os.path.exists(ex+'w'): ex += 'w'
606    proc = subprocess.Popen([ex,__file__,projectfile,version])
607    if sys.platform != "win32":
608        proc.wait()
609    sys.exit()
610
611def svnSwitchDir(rpath,filename,baseURL,loadpath=None,verbose=True):
612    '''This performs a switch command to move files between subversion trees.
613    Note that if the files were previously downloaded,
614    the switch command will update the files to the newest version.
615   
616    :param str rpath: path to locate files, relative to the GSAS-II
617      installation path (defaults to path2GSAS2)
618    :param str URL: the repository URL
619    :param str loadpath: the prefix for the path, if specified. Defaults to path2GSAS2
620    :param bool verbose: if True (default) diagnostics are printed
621    '''
622    svn = whichsvn()
623    if not svn: return
624    URL = baseURL[:]
625    if baseURL[-1] != '/':
626        URL = baseURL + '/' + filename
627    else:
628        URL = baseURL + filename
629    if loadpath:
630        fpath = os.path.join(loadpath,rpath,filename)
631        svntmp = os.path.join(loadpath,'.svn','tmp')
632    else:
633        fpath = os.path.join(path2GSAS2,rpath,filename)
634        svntmp = os.path.join(path2GSAS2,'.svn','tmp')
635    # fix up problems with missing empty directories
636    if not os.path.exists(fpath):
637        print('Repairing missing directory',fpath)
638        cmd = [svn,'revert',fpath]
639        s = subprocess.Popen(cmd,stderr=subprocess.PIPE)
640        out,err = MakeByte2str(s.communicate())
641        if out: print(out)
642        if err: print(err)
643    if not os.path.exists(svntmp):
644        print('Repairing missing directory',svntmp)
645        cmd = ['mkdir',svntmp]
646        s = subprocess.Popen(cmd,stderr=subprocess.PIPE)
647        out,err = MakeByte2str(s.communicate())
648        if out: print(out)
649        if err: print(err)
650       
651    cmd = [svn,'switch',URL,fpath,
652           '--non-interactive','--trust-server-cert',
653           '--accept','theirs-conflict','--force','-rHEAD']
654    if svnVersionNumber(svn) > 1.6: cmd += ['--ignore-ancestry']
655    if proxycmds: cmd += proxycmds
656    if verbose:
657        print(u"Loading files to "+fpath+u"\n  from "+URL)
658    s = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
659    out,err = MakeByte2str(s.communicate())
660    if err:
661        print(60*"=")
662        print ("****** An error was noted, see below *********")
663        print(60*"=")
664        print ('out=%s'%out)
665        print ('err=%s'%err)
666        s = '\nsvn command:  '
667        for i in cmd: s += i + ' '
668        print(s)
669        if svnCleanup(fpath):
670            s = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
671            out,err = MakeByte2str(s.communicate())
672            if err:
673                print(60*"=")
674                print("****** Drat, failed again: *********")
675                print(60*"=")
676                print(err)
677            else:
678                return True
679        return False
680    if verbose:
681        s = '\nsvn command:  '
682        for i in cmd: s += i + ' '
683        print(s)
684        print('\n=== Output from svn switch'+(43*'='))
685        print(out.strip())
686        print((70*'=')+'\n')
687    return True
688
689def svnInstallDir(URL,loadpath):
690    '''Load a subversion tree into a specified directory
691
692    :param str URL: the repository URL
693    :param str loadpath: path to locate files
694
695    '''
696    svn = whichsvn()
697    if not svn: return
698    cmd = [svn,'co',URL,loadpath,'--non-interactive']
699    if svnVersionNumber() >= 1.6: cmd += ['--trust-server-cert']
700    print("Loading files from "+URL)
701    if proxycmds: cmd += proxycmds
702    s = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
703    out,err = MakeByte2str(s.communicate())   #this fails too easily
704    if err:
705        print(60*"=")
706        print ("****** An error was noted, see below *********")
707        print(60*"=")
708        print (err)
709        s = '\nsvn command:  '
710        for i in cmd: s += i + ' '
711        print(s)
712        if svnCleanup(loadpath):
713            s = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
714            out,err = MakeByte2str(s.communicate())
715            if err:
716                print(60*"=")
717                print("****** Drat, failed again: *********")
718                print(60*"=")
719                print(err)
720                return False
721        else:
722            return False
723    print ("Files installed at: "+loadpath)
724    return True
725
726def svnGetFileStatus(fpath=os.path.split(__file__)[0],version=None):
727    '''Compare file status to repository (svn status -u)
728
729    :returns: updatecount,modcount,locked where
730       updatecount is the number of files waiting to be updated from
731       repository
732       modcount is the number of files that have been modified locally
733       locked  is the number of files tagged as locked
734    '''
735    import xml.etree.ElementTree as ET
736    svn = whichsvn()
737    if version is not None:
738        vstr = '-r'+str(version)
739    else:
740        vstr = '-rHEAD'
741    cmd = [svn,'st',fpath,'--xml','-u',vstr]
742    if proxycmds: cmd += proxycmds
743    s = subprocess.Popen(cmd,
744                         stdout=subprocess.PIPE,stderr=subprocess.PIPE)
745    out,err = MakeByte2str(s.communicate())
746    if err:
747        print ('out=%s'%out)
748        print ('err=%s'%err)
749        s = '\nsvn command:  '
750        for i in cmd: s += i + ' '
751        print(s)
752        return None
753
754    locked = 0
755    updatecount = 0
756    modcount = 0
757    x = ET.fromstring(out)
758    for i0 in x.iter('entry'):
759        filename = i0.attrib.get('path','?')
760        wc_rev = ''
761        status = ''
762        switched = ''
763        for i1 in i0.iter('wc-status'):
764            wc_rev = i1.attrib.get('revision','')
765            status = i1.attrib.get('item','')
766            switched = i1.attrib.get('switched','')
767            if i1.attrib.get('wc-locked',''): locked += 1
768        if status == "unversioned": continue
769        if switched == "true": continue
770        if status == "modified":
771            modcount += 1
772        elif status == "normal":
773            updatecount += 1
774        file_rev = ''
775        for i2 in i1.iter('commit'):
776            file_rev = i2.attrib.get('revision','')
777        local_status = ''
778        for i1 in i0.iter('repos-status'):
779            local_status = i1.attrib.get('item','')
780        #print(filename,wc_rev,file_rev,status,local_status,switched)
781    return updatecount,modcount,locked
782
783def GetBinaryPrefix(pyver=None):
784    '''Creates the first part of the binary directory name
785    such as linux_64_p3.9 (where the full name will be
786    linux_64_p3.9_n1.21).
787
788    Note that any change made here is also needed in GetBinaryDir in
789    fsource/SConstruct
790    '''
791    if sys.platform == "win32":
792        prefix = 'win'
793    elif sys.platform == "darwin":
794        prefix = 'mac'
795    elif sys.platform.startswith("linux"):
796        prefix = 'linux'
797    else:
798        print(u'Unknown platform: '+sys.platform)
799        raise Exception('Unknown platform')
800    if 'aarch' in platform.machine() and platform.architecture()[0] == '64bit':
801        bits = 'arm64'
802    elif 'arm' in platform.machine():
803        bits = 'arm32'
804    elif platform.architecture()[0] == '64bit':
805        bits = '64'
806    else:
807        bits = '32'
808
809    # format current python version
810    if pyver:
811        pyver = 'p'+pyver
812    else:
813        pyver = 'p{}.{}'.format(*sys.version_info[0:2])
814
815    return '_'.join([prefix,bits,pyver])
816
817def svnList(URL,verbose=True):
818    '''Get a list of subdirectories from and svn repository
819    '''   
820    svn = whichsvn()
821    if not svn:
822        print('**** unable to load files: svn not found ****')
823        return ''
824    # get binaries matching the required type -- other than for the numpy version
825    cmd = [svn, 'list', URL,'--non-interactive', '--trust-server-cert']
826    if proxycmds: cmd += proxycmds
827    if verbose:
828        s = 'Running svn command:\n  '
829        for i in cmd: s += i + ' '
830        print(s)
831    p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
832    res,err = MakeByte2str(p.communicate())
833    return res
834
835def DownloadG2Binaries(g2home,verbose=True):
836    '''Download GSAS-II binaries from appropriate section of the
837    GSAS-II svn repository based on the platform, numpy and Python
838    version
839    '''   
840    bindir = GetBinaryPrefix()
841    #npver = 'n{}.{}'.format(*np.__version__.split('.')[0:2])
842    inpver = intver(np.__version__)
843    svn = whichsvn()
844    if not svn:
845        print('**** unable to load files: svn not found ****')
846        return ''
847    # get binaries matching the required type -- other than for the numpy version
848    cmd = [svn, 'list', g2home + '/Binaries/','--non-interactive', '--trust-server-cert']
849    if proxycmds: cmd += proxycmds
850    if verbose:
851        s = 'Running svn command:\n  '
852        for i in cmd: s += i + ' '
853        print(s)
854    p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
855    res,err = MakeByte2str(p.communicate())
856    versions = {}
857    for d in res.split():
858        if d.startswith(bindir):
859            v = intver(d.rstrip('/').split('_')[3].lstrip('n'))
860            versions[v] = d
861    intVersionsList = sorted(versions.keys())
862    if not intVersionsList:
863        print('No binaries located matching',bindir)
864        return
865    elif inpver < min(intVersionsList):
866        vsel = min(intVersionsList)
867        print('Warning: The current numpy version, {}, is older than\n\tthe oldest dist version, {}'
868              .format(np.__version__,fmtver(vsel)))
869    elif inpver >= max(intVersionsList):
870        vsel = max(intVersionsList)
871        if verbose: print(
872                'FYI: The current numpy version, {}, is newer than the newest dist version {}'
873                .format(np.__version__,fmtver(vsel)))
874    else:
875        vsel = min(intVersionsList)
876        for v in intVersionsList:
877            if v <= inpver:
878                vsel = v
879            else:
880                if verbose: print(
881                        'FYI: Selecting dist version {} as the current numpy version, {},\n\tis older than the next dist version {}'
882                        .format(fmtver(vsel),np.__version__,fmtver(v)))
883                break
884    distdir = g2home + '/Binaries/' + versions[vsel]
885    # switch reset command: distdir = g2home + '/trunk/bindist'
886    svnSwitchDir('bindist','',distdir,verbose=verbose)
887    return os.path.join(path2GSAS2,'bindist')
888
889# def svnTestBranch(loc=None):
890#     '''Returns the name of the branch directory if the installation has been switched.
891#     Returns none, if not a branch
892#     the test 2frame branch. False otherwise
893#     '''
894#     if loc is None: loc = path2GSAS2
895#     svn = whichsvn()
896#     if not svn:
897#         print('**** unable to load files: svn not found ****')
898#         return ''
899#     cmd = [svn, 'info', loc]
900#     if proxycmds: cmd += proxycmds
901#     p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
902#     res,err = MakeByte2str(p.communicate())
903#     for l in res.split('\n'):
904#         if "Relative URL:" in l: break
905#     if "/branch/" in l:
906#         return l[l.find("/branch/")+8:].strip()
907#     else:
908#         return None
909   
910def svnSwitch2branch(branch=None,loc=None,svnHome=None):
911    '''Switch to a subversion branch if specified. Switches to trunk otherwise.
912    '''
913    if svnHome is None: svnHome = g2home
914    svnURL = svnHome + '/trunk'
915    if branch:
916        if svnHome.endswith('/'):
917            svnURL = svnHome[:-1]
918        else:
919            svnURL = svnHome
920        if branch.startswith('/'):
921            svnURL += branch
922        else:
923            svnURL += '/' + branch
924    svnSwitchDir('','',svnURL,loadpath=loc)
925   
926
927def IPyBreak_base(userMsg=None):
928    '''A routine that invokes an IPython session at the calling location
929    This routine is only used when debug=True is set in config.py
930    '''
931    savehook = sys.excepthook # save the exception hook
932    try: 
933        from IPython.terminal.embed import InteractiveShellEmbed
934    except ImportError:
935        try:
936            # try the IPython 0.12 approach
937            from IPython.frontend.terminal.embed import InteractiveShellEmbed
938        except ImportError:
939            print ('IPython InteractiveShellEmbed not found')
940            return
941    import inspect
942    ipshell = InteractiveShellEmbed()
943
944    frame = inspect.currentframe().f_back
945    msg   = 'Entering IPython console inside {0.f_code.co_filename} at line {0.f_lineno}\n'.format(frame)
946    if userMsg: msg += userMsg
947    # globals().update(locals()) # This might help with vars inside list comprehensions, etc.
948    ipshell(msg,stack_depth=2) # Go up one level, to see the calling routine
949    sys.excepthook = savehook # reset IPython's change to the exception hook
950
951try:
952    from IPython.core import ultratb
953except:
954    pass
955
956def exceptHook(*args):
957    '''A routine to be called when an exception occurs. It prints the traceback
958    with fancy formatting and then calls an IPython shell with the environment
959    of the exception location.
960   
961    This routine is only used when debug=True is set in config.py   
962    '''
963    import IPython.core
964    if sys.platform.startswith('win'):
965        IPython.core.ultratb.FormattedTB(call_pdb=False,color_scheme='NoColor')(*args)
966    else:
967        IPython.core.ultratb.FormattedTB(call_pdb=False,color_scheme='LightBG')(*args)
968
969    try: 
970        from IPython.terminal.embed import InteractiveShellEmbed
971    except ImportError:
972        try:
973            # try the IPython 0.12 approach
974            from IPython.frontend.terminal.embed import InteractiveShellEmbed
975        except ImportError:
976            print ('IPython InteractiveShellEmbed not found')
977            return
978    import inspect
979    frame = inspect.getinnerframes(args[2])[-1][0]
980    msg   = 'Entering IPython console at {0.f_code.co_filename} at line {0.f_lineno}\n'.format(frame)
981    savehook = sys.excepthook # save the exception hook
982    try: # try IPython 5 call 1st
983        class c(object): pass
984        pseudomod = c() # create something that acts like a module
985        pseudomod.__dict__ = frame.f_locals
986        InteractiveShellEmbed(banner1=msg)(module=pseudomod,global_ns=frame.f_globals)
987    except:
988        InteractiveShellEmbed(banner1=msg)(local_ns=frame.f_locals,global_ns=frame.f_globals)
989    sys.excepthook = savehook # reset IPython's change to the exception hook
990
991def DoNothing():
992    '''A routine that does nothing. This is called in place of IPyBreak and pdbBreak
993    except when the debug option is set True in config.py
994    '''
995    pass 
996
997IPyBreak = DoNothing
998pdbBreak = DoNothing
999def InvokeDebugOpts():
1000    'Called in GSASII.py to set up debug options'
1001    if any('SPYDER' in name for name in os.environ):
1002        print('Running from Spyder, keeping breakpoint() active & skipping exception trapping')
1003    elif GetConfigValue('debug'):
1004        try:
1005            import pdb
1006            global pdbBreak
1007            pdbBreak = pdb.set_trace
1008            import IPython
1009            global IPyBreak
1010            IPyBreak = IPyBreak_base
1011            sys.excepthook = exceptHook
1012            os.environ['PYTHONBREAKPOINT'] = 'GSASIIpath.IPyBreak_base'
1013            print ('Debug on: IPython: Exceptions and G2path.IPyBreak(); pdb: G2path.pdbBreak()')
1014        except:
1015            print ('Debug on failed. IPython not installed?')
1016    else: # not in spyder or debug enabled, hide breakpoints
1017        os.environ['PYTHONBREAKPOINT'] = '0'
1018
1019def TestSPG(fpth):
1020    '''Test if pyspg.[so,.pyd] can be run from a location in the path
1021    '''
1022    if not os.path.exists(fpth): return False
1023    if not glob.glob(os.path.join(fpth,'pyspg.*')): return False
1024    savpath = sys.path[:]
1025    sys.path = [fpth]
1026    # test to see if a shared library can be used
1027    try:
1028        import pyspg
1029        pyspg.sgforpy('P -1')
1030    except Exception as err:
1031        print(70*'=')
1032        print('Failed to run pyspg in {}\nerror: {}'.format(fpth,err))
1033        print(70*'=')
1034        sys.path = savpath
1035        return False
1036    sys.path = savpath
1037    return True
1038   
1039# see if a directory for local modifications is defined. If so, stick that in the path
1040if os.path.exists(os.path.expanduser('~/.G2local/')):
1041    sys.path.insert(0,os.path.expanduser('~/.G2local/'))
1042    fl = glob.glob(os.path.expanduser('~/.G2local/GSASII*.py*'))
1043    files = ""
1044    prev = None
1045    for f in sorted(fl): # make a list of files, dropping .pyc files where a .py exists
1046        f = os.path.split(f)[1]
1047        if os.path.splitext(f)[0] == prev: continue
1048        prev = os.path.splitext(f)[0]
1049        if files: files += ", "
1050        files += f
1051    if files:
1052        print("*"*75)
1053        print("Warning: the following source files are locally overridden in "+os.path.expanduser('~/.G2local/'))
1054        print("  "+files)
1055        print("*"*75)
1056
1057BinaryPathLoaded = False
1058binaryPath = ''
1059def SetBinaryPath(printInfo=False, loadBinary=True):
1060    '''
1061    Add location of GSAS-II shared libraries (binaries: .so or .pyd files) to path
1062   
1063    This routine must be executed after GSASIIpath is imported and before any other
1064    GSAS-II imports are done.
1065    '''
1066    # do this only once no matter how many times it is called
1067    global BinaryPathLoaded,binaryPath
1068    if BinaryPathLoaded: return
1069    try:
1070        inpver = intver(np.__version__)
1071    except (AttributeError,TypeError): # happens on building docs
1072        return
1073    binpath = None
1074    binprfx = GetBinaryPrefix()
1075    for loc in os.path.abspath(sys.path[0]),os.path.abspath(os.path.split(__file__)[0]):
1076        # Look at bin directory (created by a local compile) before looking for standard dist files
1077        searchpathlist = [os.path.join(loc,'bin')]
1078        # also look for matching binary dist in loc/AllBinaries
1079        versions = {}
1080        for d in glob.glob(os.path.join(loc,'AllBinaries',binprfx+'*')):
1081            v = intver(d.rstrip('/').split('_')[3].lstrip('n'))
1082            versions[v] = d
1083        searchpathlist = [os.path.join(loc,'bin')]
1084        vmin = None
1085        vmax = None
1086        for v in sorted(versions.keys()):
1087            if v <= inpver:
1088                vmin = v
1089            elif v > inpver:
1090                vmax = v
1091                break
1092        if vmin in versions:
1093            searchpathlist.append(versions[vmin])
1094        if vmax in versions:
1095            searchpathlist.append(versions[vmax])
1096        searchpathlist.append(os.path.join(loc,'bindist'))
1097        for fpth in searchpathlist:
1098            if TestSPG(fpth):
1099                binpath = fpth
1100                break       
1101        if binpath: break
1102    if binpath:                                            # were GSAS-II binaries found
1103        sys.path.insert(0,binpath)
1104        binaryPath = binpath
1105        if printInfo:
1106            print('GSAS-II binary directory: {}'.format(binpath))
1107        BinaryPathLoaded = True
1108    elif not loadBinary:
1109        raise Exception
1110    else:                                                  # try loading them
1111        if printInfo:
1112            print('Attempting to download GSAS-II binary files...')
1113        try:
1114            binpath = DownloadG2Binaries(g2home)
1115        except AttributeError:   # this happens when building in Read The Docs
1116            if printInfo:
1117                print('Problem with download')
1118        if binpath and TestSPG(binpath):
1119            if printInfo:
1120                print('GSAS-II binary directory: {}'.format(binpath))
1121            sys.path.insert(0,binpath)
1122            binaryPath = binpath
1123            BinaryPathLoaded = True
1124        # this must be imported before anything that imports any .pyd/.so file for GSASII
1125        else:
1126            #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1127            #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1128            # patch: use old location based on the host OS and the python version, 
1129            # path is relative to location of the script that is called as well as this file
1130            BinaryPathLoaded = True
1131            bindir = None
1132            if sys.platform == "win32":
1133                if platform.architecture()[0] == '64bit':
1134                    bindir = 'binwin64-%d.%d' % sys.version_info[0:2]
1135                else:
1136                    bindir = 'binwin%d.%d' % sys.version_info[0:2]
1137            elif sys.platform == "darwin":
1138                if platform.architecture()[0] == '64bit':
1139                    bindir = 'binmac64-%d.%d' % sys.version_info[0:2]
1140                else:
1141                    bindir = 'binmac%d.%d' % sys.version_info[0:2]
1142                #if platform.mac_ver()[0].startswith('10.5.'):
1143                #    bindir += '_10.5'
1144            elif sys.platform.startswith("linux"):
1145                if platform.architecture()[0] == '64bit':
1146                    bindir = 'binlinux64-%d.%d' % sys.version_info[0:2]
1147                else:
1148                    bindir = 'binlinux%d.%d' % sys.version_info[0:2]
1149            for loc in os.path.abspath(sys.path[0]),os.path.abspath(os.path.split(__file__)[0]):
1150            # Look at bin directory (created by a local compile) before standard dist
1151            # that at the top of the path
1152                fpth = os.path.join(loc,bindir)
1153                binpath = fpth
1154                if TestSPG(fpth):
1155                    sys.path.insert(0,binpath)
1156                    binaryPath = binpath
1157                    if printInfo:
1158                        print('\n'+75*'*')
1159                        print('  Warning. Using an old-style GSAS-II binary library. This is unexpected')
1160                        print('  and will break in future GSAS-II versions. Please contact toby@anl.gov')
1161                        print('  so we can learn what is not working on your installation.')
1162                        print('GSAS-II binary directory: {}'.format(binpath))
1163                        print(75*'*')
1164                    break
1165            else:
1166            # end patch
1167            #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1168            #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1169                if printInfo:
1170                    print(75*'*')
1171                    print('Use of GSAS-II binary directory {} failed!'.format(binpath))
1172                    print(75*'*')
1173                raise Exception("**** ERROR GSAS-II binary libraries not found, GSAS-II cannot run ****")
1174
1175    # add the data import and export directory to the search path
1176    newpath = os.path.join(path2GSAS2,'imports')
1177    if newpath not in sys.path: sys.path.append(newpath)
1178    newpath = os.path.join(path2GSAS2,'exports')
1179    if newpath not in sys.path: sys.path.append(newpath)
1180    LoadConfig(printInfo)
1181
1182def LoadConfig(printInfo=True):
1183    # setup read of config.py, if present
1184    global configDict
1185    try:
1186        import config
1187        configDict = config.__dict__
1188        import inspect
1189        vals = [True for i in inspect.getmembers(config) if '__' not in i[0]]
1190        if printInfo:
1191            print (str(len(vals))+' values read from config file '+os.path.abspath(config.__file__))
1192    except ImportError:
1193        configDict = {'Clip_on':True}
1194    except Exception as err:
1195        print(60*'*',"\nError reading config.py file")
1196        if printInfo:
1197            import traceback
1198            print(traceback.format_exc())
1199        print(60*'*')
1200        configDict = {'Clip_on':True}
1201
1202def MacStartGSASII(g2script,project=''):
1203    '''Start a new instance of GSAS-II by opening a new terminal window and starting
1204    a new GSAS-II process. Used on Mac OS X only.
1205
1206    :param str g2script: file name for the GSASII.py script
1207    :param str project: GSAS-II project (.gpx) file to be opened, default is blank
1208      which opens a new project
1209    '''
1210    if project and os.path.splitext(project)[1] != '.gpx':
1211        print('file {} cannot be used. Not GSAS-II project (.gpx) file'.format(project))
1212        return
1213    if project and not os.path.exists(project):
1214        print('file {} cannot be found.'.format(project))
1215        return 
1216    elif project:
1217        project = os.path.abspath(project)
1218    g2script = os.path.abspath(g2script)
1219    pythonapp = sys.executable
1220    if os.path.exists(pythonapp+'w'): pythonapp += 'w'
1221    script = '''
1222set python to "{}"
1223set appwithpath to "{}"
1224set filename to "{}"
1225
1226tell application "Terminal"
1227     activate
1228     do script python & " " & appwithpath & " " & filename & "; exit"
1229end tell
1230'''.format(pythonapp,g2script,project)
1231    subprocess.Popen(["osascript","-e",script])
1232
1233def MacRunScript(script):
1234    '''Start a bash script in a new terminal window.
1235    Used on Mac OS X only.
1236
1237    :param str script: file name for a bash script
1238    '''
1239    script = os.path.abspath(script)
1240    osascript = '''
1241set bash to "/bin/bash"
1242set filename to "{}"
1243
1244tell application "Terminal"
1245     activate
1246     do script bash & " " & filename & "; exit"
1247end tell
1248'''.format(script)
1249    subprocess.Popen(["osascript","-e",osascript])
1250   
1251def findConda():
1252    '''Determines if GSAS-II has been installed as g2conda or gsas2full
1253    with conda located relative to this file.
1254    We could also look for conda relative to the python (sys.executable)
1255    image, but I don't want to muck around with python that someone else
1256    installed.
1257    '''
1258    parent = os.path.split(path2GSAS2)[0]
1259    if sys.platform != "win32":
1260        activate = os.path.join(parent,'bin','activate')
1261        conda = os.path.join(parent,'bin','conda')
1262    else:
1263        activate = os.path.join(parent,'Scripts','activate.bat')
1264        conda = os.path.join(parent,'condabin','conda.bat')
1265    if os.path.exists(activate) and os.path.exists(conda):
1266        return conda,activate
1267    else:
1268        return None
1269
1270def runScript(cmds=[], wait=False, G2frame=None):
1271    '''run a shell script of commands in an external process
1272   
1273    :param list cmds: a list of str's, each ietm containing a shell (cmd.exe
1274      or bash) command
1275    :param bool wait: if True indicates the commands should be run and then
1276      the script should return. If False, then the currently running Python
1277      will exit. Default is False
1278    :param wx.Frame G2frame: provides the location of the current .gpx file
1279      to be used to restart GSAS-II after running the commands, if wait
1280      is False. Default is None which prevents restarting GSAS-II regardless of
1281      the value of wait.
1282    '''
1283    import tempfile
1284    if not cmds:  #debug
1285        print('nothing to do in runScript')
1286        return
1287    if sys.platform != "win32":
1288        suffix = '.sh'
1289    else:
1290        suffix = '.bat'
1291       
1292    fp = tempfile.NamedTemporaryFile(mode='w', suffix=suffix, delete=False)
1293    shellname = fp.name
1294    for line in cmds:
1295        fp.write(line)
1296        fp.write('\n')
1297
1298    if not wait:
1299        if G2frame:
1300            projectfile = ''
1301            if G2frame.GSASprojectfile:
1302                projectfile = os.path.realpath(G2frame.GSASprojectfile)
1303            main = os.path.join(path2GSAS2,'GSASII.py')
1304            ex = sys.executable
1305            if sys.platform == "darwin": # mac requires pythonw which is not always reported as sys.executable
1306                if os.path.exists(ex+'w'): ex += 'w'
1307            print ('restart using ',' '.join([ex,main,projectfile]))
1308            fp.write(' '.join([ex,main,projectfile]))
1309            fp.write('\n')
1310    fp.close()
1311
1312    # start the upgrade in a separate interpreter (avoids loading .pyd files)
1313    if sys.platform != "win32":
1314        proc = subprocess.Popen(['bash',shellname])
1315    else:
1316        proc = subprocess.Popen([shellname],shell=True)
1317    if wait:
1318        proc.wait()
1319    else:
1320        if sys.platform != "win32": proc.wait()
1321        sys.exit()
1322   
1323if __name__ == '__main__':
1324    '''What follows is called to update (or downdate) GSAS-II in a separate process.
1325    '''
1326    LoadConfig()
1327    import time
1328    time.sleep(1) # delay to give the main process a chance to exit
1329    # perform an update and restart GSAS-II
1330    try:
1331        project,version = sys.argv[1:3]
1332    except ValueError:
1333        project = None
1334        version = 'trunk'
1335    loc = os.path.dirname(__file__)
1336    if version == 'trunk':
1337        svnSwitch2branch('')
1338    elif '/' in version:
1339        svnSwitch2branch(version)
1340    elif version:
1341        print("Regress to version "+str(version))
1342        svnUpdateDir(loc,version=version)
1343    else:
1344        print("Update to current version")
1345        svnUpdateDir(loc)
1346    ex = sys.executable
1347    if sys.platform == "darwin": # mac requires pythonw which is not always reported as sys.executable
1348        if os.path.exists(ex+'w'): ex += 'w'
1349    if project:
1350        print("Restart GSAS-II with project file "+str(project))
1351        subprocess.Popen([ex,os.path.join(loc,'GSASII.py'),project])
1352    else:
1353        print("Restart GSAS-II without a project file ")
1354        subprocess.Popen([ex,os.path.join(loc,'GSASII.py')])
1355    print ('exiting update process')
1356    sys.exit()
Note: See TracBrowser for help on using the repository browser.