source: trunk/GSASIIpath.py @ 5135

Last change on this file since 5135 was 5135, checked in by toby, 9 months ago

show that max(shtf/esd) is from all cycles; fix bug for install path w/underscore

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 49.0 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIpath - file location & update routines
3########### SVN repository information ###################
4# $Date: 2022-01-10 16:15:57 +0000 (Mon, 10 Jan 2022) $
5# $Author: toby $
6# $Revision: 5135 $
7# $URL: trunk/GSASIIpath.py $
8# $Id: GSASIIpath.py 5135 2022-01-10 16:15:57Z 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: 5135 $"
98      that is set by subversion when the file is retrieved from subversion.
99
100    Place ``GSASIIpath.SetVersionNumber("$Revision: 5135 $")`` 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 'arm' in platform.machine() and sys.platform == "darwin":
801        bits = 'arm'
802    elif 'aarch' in platform.machine() and '64' in platform.architecture()[0]:
803        bits = 'arm64'
804    elif 'arm' in platform.machine():
805        bits = 'arm32'
806    elif '64' in platform.architecture()[0]:
807        bits = '64'
808    else:
809        bits = '32'
810
811    # format current python version
812    if pyver:
813        pyver = 'p'+pyver
814    else:
815        pyver = 'p{}.{}'.format(*sys.version_info[0:2])
816
817    return '_'.join([prefix,bits,pyver])
818
819def svnList(URL,verbose=True):
820    '''Get a list of subdirectories from and svn repository
821    '''   
822    svn = whichsvn()
823    if not svn:
824        print('**** unable to load files: svn not found ****')
825        return ''
826    # get binaries matching the required type -- other than for the numpy version
827    cmd = [svn, 'list', URL,'--non-interactive', '--trust-server-cert']
828    if proxycmds: cmd += proxycmds
829    if verbose:
830        s = 'Running svn command:\n  '
831        for i in cmd: s += i + ' '
832        print(s)
833    p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
834    res,err = MakeByte2str(p.communicate())
835    return res
836
837def DownloadG2Binaries(g2home,verbose=True):
838    '''Download GSAS-II binaries from appropriate section of the
839    GSAS-II svn repository based on the platform, numpy and Python
840    version
841    '''   
842    bindir = GetBinaryPrefix()
843    #npver = 'n{}.{}'.format(*np.__version__.split('.')[0:2])
844    inpver = intver(np.__version__)
845    svn = whichsvn()
846    if not svn:
847        print('**** unable to load files: svn not found ****')
848        return ''
849    # get binaries matching the required type -- other than for the numpy version
850    cmd = [svn, 'list', g2home + '/Binaries/','--non-interactive', '--trust-server-cert']
851    if proxycmds: cmd += proxycmds
852    if verbose:
853        s = 'Running svn command:\n  '
854        for i in cmd: s += i + ' '
855        print(s)
856    p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
857    res,err = MakeByte2str(p.communicate())
858    versions = {}
859    for d in res.split():
860        if d.startswith(bindir):
861            v = intver(d.rstrip('/').split('_')[3].lstrip('n'))
862            versions[v] = d
863    intVersionsList = sorted(versions.keys())
864    if not intVersionsList:
865        print('No binaries located matching',bindir)
866        return
867    elif inpver < min(intVersionsList):
868        vsel = min(intVersionsList)
869        print('Warning: The current numpy version, {}, is older than\n\tthe oldest dist version, {}'
870              .format(np.__version__,fmtver(vsel)))
871    elif inpver >= max(intVersionsList):
872        vsel = max(intVersionsList)
873        if verbose: print(
874                'FYI: The current numpy version, {}, is newer than the newest dist version {}'
875                .format(np.__version__,fmtver(vsel)))
876    else:
877        vsel = min(intVersionsList)
878        for v in intVersionsList:
879            if v <= inpver:
880                vsel = v
881            else:
882                if verbose: print(
883                        'FYI: Selecting dist version {} as the current numpy version, {},\n\tis older than the next dist version {}'
884                        .format(fmtver(vsel),np.__version__,fmtver(v)))
885                break
886    distdir = g2home + '/Binaries/' + versions[vsel]
887    # switch reset command: distdir = g2home + '/trunk/bindist'
888    svnSwitchDir('bindist','',distdir,verbose=verbose)
889    return os.path.join(path2GSAS2,'bindist')
890
891# def svnTestBranch(loc=None):
892#     '''Returns the name of the branch directory if the installation has been switched.
893#     Returns none, if not a branch
894#     the test 2frame branch. False otherwise
895#     '''
896#     if loc is None: loc = path2GSAS2
897#     svn = whichsvn()
898#     if not svn:
899#         print('**** unable to load files: svn not found ****')
900#         return ''
901#     cmd = [svn, 'info', loc]
902#     if proxycmds: cmd += proxycmds
903#     p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
904#     res,err = MakeByte2str(p.communicate())
905#     for l in res.split('\n'):
906#         if "Relative URL:" in l: break
907#     if "/branch/" in l:
908#         return l[l.find("/branch/")+8:].strip()
909#     else:
910#         return None
911   
912def svnSwitch2branch(branch=None,loc=None,svnHome=None):
913    '''Switch to a subversion branch if specified. Switches to trunk otherwise.
914    '''
915    if svnHome is None: svnHome = g2home
916    svnURL = svnHome + '/trunk'
917    if branch:
918        if svnHome.endswith('/'):
919            svnURL = svnHome[:-1]
920        else:
921            svnURL = svnHome
922        if branch.startswith('/'):
923            svnURL += branch
924        else:
925            svnURL += '/' + branch
926    svnSwitchDir('','',svnURL,loadpath=loc)
927   
928
929def IPyBreak_base(userMsg=None):
930    '''A routine that invokes an IPython session at the calling location
931    This routine is only used when debug=True is set in config.py
932    '''
933    savehook = sys.excepthook # save the exception hook
934    try: 
935        from IPython.terminal.embed import InteractiveShellEmbed
936    except ImportError:
937        try:
938            # try the IPython 0.12 approach
939            from IPython.frontend.terminal.embed import InteractiveShellEmbed
940        except ImportError:
941            print ('IPython InteractiveShellEmbed not found')
942            return
943    import inspect
944    ipshell = InteractiveShellEmbed()
945
946    frame = inspect.currentframe().f_back
947    msg   = 'Entering IPython console inside {0.f_code.co_filename} at line {0.f_lineno}\n'.format(frame)
948    if userMsg: msg += userMsg
949    # globals().update(locals()) # This might help with vars inside list comprehensions, etc.
950    ipshell(msg,stack_depth=2) # Go up one level, to see the calling routine
951    sys.excepthook = savehook # reset IPython's change to the exception hook
952
953try:
954    from IPython.core import ultratb
955except:
956    pass
957
958def exceptHook(*args):
959    '''A routine to be called when an exception occurs. It prints the traceback
960    with fancy formatting and then calls an IPython shell with the environment
961    of the exception location.
962   
963    This routine is only used when debug=True is set in config.py   
964    '''
965    import IPython.core
966    if sys.platform.startswith('win'):
967        IPython.core.ultratb.FormattedTB(call_pdb=False,color_scheme='NoColor')(*args)
968    else:
969        IPython.core.ultratb.FormattedTB(call_pdb=False,color_scheme='LightBG')(*args)
970
971    try: 
972        from IPython.terminal.embed import InteractiveShellEmbed
973    except ImportError:
974        try:
975            # try the IPython 0.12 approach
976            from IPython.frontend.terminal.embed import InteractiveShellEmbed
977        except ImportError:
978            print ('IPython InteractiveShellEmbed not found')
979            return
980    import inspect
981    frame = inspect.getinnerframes(args[2])[-1][0]
982    msg   = 'Entering IPython console at {0.f_code.co_filename} at line {0.f_lineno}\n'.format(frame)
983    savehook = sys.excepthook # save the exception hook
984    try: # try IPython 5 call 1st
985        class c(object): pass
986        pseudomod = c() # create something that acts like a module
987        pseudomod.__dict__ = frame.f_locals
988        InteractiveShellEmbed(banner1=msg)(module=pseudomod,global_ns=frame.f_globals)
989    except:
990        InteractiveShellEmbed(banner1=msg)(local_ns=frame.f_locals,global_ns=frame.f_globals)
991    sys.excepthook = savehook # reset IPython's change to the exception hook
992
993def DoNothing():
994    '''A routine that does nothing. This is called in place of IPyBreak and pdbBreak
995    except when the debug option is set True in config.py
996    '''
997    pass 
998
999IPyBreak = DoNothing
1000pdbBreak = DoNothing
1001def InvokeDebugOpts():
1002    'Called in GSASII.py to set up debug options'
1003    if any('SPYDER' in name for name in os.environ):
1004        print('Running from Spyder, keeping breakpoint() active & skipping exception trapping')
1005    elif GetConfigValue('debug'):
1006        try:
1007            import pdb
1008            global pdbBreak
1009            pdbBreak = pdb.set_trace
1010            import IPython
1011            global IPyBreak
1012            IPyBreak = IPyBreak_base
1013            sys.excepthook = exceptHook
1014            os.environ['PYTHONBREAKPOINT'] = 'GSASIIpath.IPyBreak_base'
1015            print ('Debug on: IPython: Exceptions and G2path.IPyBreak(); pdb: G2path.pdbBreak()')
1016        except:
1017            print ('Debug on failed. IPython not installed?')
1018    else: # not in spyder or debug enabled, hide breakpoints
1019        os.environ['PYTHONBREAKPOINT'] = '0'
1020
1021def TestSPG(fpth):
1022    '''Test if pyspg.[so,.pyd] can be run from a location in the path
1023    '''
1024    if not os.path.exists(fpth): return False
1025    if not glob.glob(os.path.join(fpth,'pyspg.*')): return False
1026    savpath = sys.path[:]
1027    sys.path = [fpth]
1028    # test to see if a shared library can be used
1029    try:
1030        import pyspg
1031        pyspg.sgforpy('P -1')
1032    except Exception as err:
1033        print(70*'=')
1034        print('Failed to run pyspg in {}\nerror: {}'.format(fpth,err))
1035        print(70*'=')
1036        sys.path = savpath
1037        return False
1038    sys.path = savpath
1039    return True
1040   
1041# see if a directory for local modifications is defined. If so, stick that in the path
1042if os.path.exists(os.path.expanduser('~/.G2local/')):
1043    sys.path.insert(0,os.path.expanduser('~/.G2local/'))
1044    fl = glob.glob(os.path.expanduser('~/.G2local/GSASII*.py*'))
1045    files = ""
1046    prev = None
1047    for f in sorted(fl): # make a list of files, dropping .pyc files where a .py exists
1048        f = os.path.split(f)[1]
1049        if os.path.splitext(f)[0] == prev: continue
1050        prev = os.path.splitext(f)[0]
1051        if files: files += ", "
1052        files += f
1053    if files:
1054        print("*"*75)
1055        print("Warning: the following source files are locally overridden in "+os.path.expanduser('~/.G2local/'))
1056        print("  "+files)
1057        print("*"*75)
1058
1059BinaryPathLoaded = False
1060binaryPath = ''
1061def SetBinaryPath(printInfo=False, loadBinary=True):
1062    '''
1063    Add location of GSAS-II shared libraries (binaries: .so or .pyd files) to path
1064   
1065    This routine must be executed after GSASIIpath is imported and before any other
1066    GSAS-II imports are done.
1067    '''
1068    # do this only once no matter how many times it is called
1069    global BinaryPathLoaded,binaryPath
1070    if BinaryPathLoaded: return
1071    try:
1072        inpver = intver(np.__version__)
1073    except (AttributeError,TypeError): # happens on building docs
1074        return
1075    binpath = None
1076    binprfx = GetBinaryPrefix()
1077    for loc in os.path.abspath(sys.path[0]),os.path.abspath(os.path.split(__file__)[0]):
1078        # Look at bin directory (created by a local compile) before looking for standard dist files
1079        searchpathlist = [os.path.join(loc,'bin')]
1080        # also look for matching binary dist in loc/AllBinaries
1081        versions = {}
1082        for d in glob.glob(os.path.join(loc,'AllBinaries',binprfx+'*')):
1083            v = intver(d.rstrip('/').split('_')[-1].lstrip('n'))
1084            versions[v] = d
1085        searchpathlist = [os.path.join(loc,'bin')]
1086        vmin = None
1087        vmax = None
1088        for v in sorted(versions.keys()):
1089            if v <= inpver:
1090                vmin = v
1091            elif v > inpver:
1092                vmax = v
1093                break
1094        if vmin in versions:
1095            searchpathlist.append(versions[vmin])
1096        if vmax in versions:
1097            searchpathlist.append(versions[vmax])
1098        searchpathlist.append(os.path.join(loc,'bindist'))
1099        for fpth in searchpathlist:
1100            if TestSPG(fpth):
1101                binpath = fpth
1102                break       
1103        if binpath: break
1104    if binpath:                                            # were GSAS-II binaries found
1105        sys.path.insert(0,binpath)
1106        binaryPath = binpath
1107        if printInfo:
1108            print('GSAS-II binary directory: {}'.format(binpath))
1109        BinaryPathLoaded = True
1110    elif not loadBinary:
1111        raise Exception
1112    else:                                                  # try loading them
1113        if printInfo:
1114            print('Attempting to download GSAS-II binary files...')
1115        try:
1116            binpath = DownloadG2Binaries(g2home)
1117        except AttributeError:   # this happens when building in Read The Docs
1118            if printInfo:
1119                print('Problem with download')
1120        if binpath and TestSPG(binpath):
1121            if printInfo:
1122                print('GSAS-II binary directory: {}'.format(binpath))
1123            sys.path.insert(0,binpath)
1124            binaryPath = binpath
1125            BinaryPathLoaded = True
1126        # this must be imported before anything that imports any .pyd/.so file for GSASII
1127        else:
1128            #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1129            #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1130            # patch: use old location based on the host OS and the python version, 
1131            # path is relative to location of the script that is called as well as this file
1132            BinaryPathLoaded = True
1133            bindir = None
1134            if sys.platform == "win32":
1135                if platform.architecture()[0] == '64bit':
1136                    bindir = 'binwin64-%d.%d' % sys.version_info[0:2]
1137                else:
1138                    bindir = 'binwin%d.%d' % sys.version_info[0:2]
1139            elif sys.platform == "darwin":
1140                if platform.architecture()[0] == '64bit':
1141                    bindir = 'binmac64-%d.%d' % sys.version_info[0:2]
1142                else:
1143                    bindir = 'binmac%d.%d' % sys.version_info[0:2]
1144                #if platform.mac_ver()[0].startswith('10.5.'):
1145                #    bindir += '_10.5'
1146            elif sys.platform.startswith("linux"):
1147                if platform.architecture()[0] == '64bit':
1148                    bindir = 'binlinux64-%d.%d' % sys.version_info[0:2]
1149                else:
1150                    bindir = 'binlinux%d.%d' % sys.version_info[0:2]
1151            for loc in os.path.abspath(sys.path[0]),os.path.abspath(os.path.split(__file__)[0]):
1152            # Look at bin directory (created by a local compile) before standard dist
1153            # that at the top of the path
1154                fpth = os.path.join(loc,bindir)
1155                binpath = fpth
1156                if TestSPG(fpth):
1157                    sys.path.insert(0,binpath)
1158                    binaryPath = binpath
1159                    if printInfo:
1160                        print('\n'+75*'*')
1161                        print('  Warning. Using an old-style GSAS-II binary library. This is unexpected')
1162                        print('  and will break in future GSAS-II versions. Please contact toby@anl.gov')
1163                        print('  so we can learn what is not working on your installation.')
1164                        print('GSAS-II binary directory: {}'.format(binpath))
1165                        print(75*'*')
1166                    break
1167            else:
1168            # end patch
1169            #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1170            #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1171                if printInfo:
1172                    print(75*'*')
1173                    print('Use of GSAS-II binary directory {} failed!'.format(binpath))
1174                    print(75*'*')
1175                raise Exception("**** ERROR GSAS-II binary libraries not found, GSAS-II cannot run ****")
1176
1177    # add the data import and export directory to the search path
1178    newpath = os.path.join(path2GSAS2,'imports')
1179    if newpath not in sys.path: sys.path.append(newpath)
1180    newpath = os.path.join(path2GSAS2,'exports')
1181    if newpath not in sys.path: sys.path.append(newpath)
1182    LoadConfig(printInfo)
1183
1184def LoadConfig(printInfo=True):
1185    # setup read of config.py, if present
1186    global configDict
1187    try:
1188        import config
1189        configDict = config.__dict__
1190        import inspect
1191        vals = [True for i in inspect.getmembers(config) if '__' not in i[0]]
1192        if printInfo:
1193            print (str(len(vals))+' values read from config file '+os.path.abspath(config.__file__))
1194    except ImportError:
1195        configDict = {'Clip_on':True}
1196    except Exception as err:
1197        print(60*'*',"\nError reading config.py file")
1198        if printInfo:
1199            import traceback
1200            print(traceback.format_exc())
1201        print(60*'*')
1202        configDict = {'Clip_on':True}
1203
1204def MacStartGSASII(g2script,project=''):
1205    '''Start a new instance of GSAS-II by opening a new terminal window and starting
1206    a new GSAS-II process. Used on Mac OS X only.
1207
1208    :param str g2script: file name for the GSASII.py script
1209    :param str project: GSAS-II project (.gpx) file to be opened, default is blank
1210      which opens a new project
1211    '''
1212    if project and os.path.splitext(project)[1] != '.gpx':
1213        print('file {} cannot be used. Not GSAS-II project (.gpx) file'.format(project))
1214        return
1215    if project and not os.path.exists(project):
1216        print('file {} cannot be found.'.format(project))
1217        return 
1218    elif project:
1219        project = os.path.abspath(project)
1220    g2script = os.path.abspath(g2script)
1221    pythonapp = sys.executable
1222    if os.path.exists(pythonapp+'w'): pythonapp += 'w'
1223    script = '''
1224set python to "{}"
1225set appwithpath to "{}"
1226set filename to "{}"
1227
1228tell application "Terminal"
1229     activate
1230     do script python & " " & appwithpath & " " & filename & "; exit"
1231end tell
1232'''.format(pythonapp,g2script,project)
1233    subprocess.Popen(["osascript","-e",script])
1234
1235def MacRunScript(script):
1236    '''Start a bash script in a new terminal window.
1237    Used on Mac OS X only.
1238
1239    :param str script: file name for a bash script
1240    '''
1241    script = os.path.abspath(script)
1242    osascript = '''
1243set bash to "/bin/bash"
1244set filename to "{}"
1245
1246tell application "Terminal"
1247     activate
1248     do script bash & " " & filename & "; exit"
1249end tell
1250'''.format(script)
1251    subprocess.Popen(["osascript","-e",osascript])
1252   
1253def findConda():
1254    '''Determines if GSAS-II has been installed as g2conda or gsas2full
1255    with conda located relative to this file.
1256    We could also look for conda relative to the python (sys.executable)
1257    image, but I don't want to muck around with python that someone else
1258    installed.
1259    '''
1260    parent = os.path.split(path2GSAS2)[0]
1261    if sys.platform != "win32":
1262        activate = os.path.join(parent,'bin','activate')
1263        conda = os.path.join(parent,'bin','conda')
1264    else:
1265        activate = os.path.join(parent,'Scripts','activate.bat')
1266        conda = os.path.join(parent,'condabin','conda.bat')
1267    if os.path.exists(activate) and os.path.exists(conda):
1268        return conda,activate
1269    else:
1270        return None
1271
1272def runScript(cmds=[], wait=False, G2frame=None):
1273    '''run a shell script of commands in an external process
1274   
1275    :param list cmds: a list of str's, each ietm containing a shell (cmd.exe
1276      or bash) command
1277    :param bool wait: if True indicates the commands should be run and then
1278      the script should return. If False, then the currently running Python
1279      will exit. Default is False
1280    :param wx.Frame G2frame: provides the location of the current .gpx file
1281      to be used to restart GSAS-II after running the commands, if wait
1282      is False. Default is None which prevents restarting GSAS-II regardless of
1283      the value of wait.
1284    '''
1285    import tempfile
1286    if not cmds:  #debug
1287        print('nothing to do in runScript')
1288        return
1289    if sys.platform != "win32":
1290        suffix = '.sh'
1291    else:
1292        suffix = '.bat'
1293       
1294    fp = tempfile.NamedTemporaryFile(mode='w', suffix=suffix, delete=False)
1295    shellname = fp.name
1296    for line in cmds:
1297        fp.write(line)
1298        fp.write('\n')
1299
1300    if not wait:
1301        if G2frame:
1302            projectfile = ''
1303            if G2frame.GSASprojectfile:
1304                projectfile = os.path.realpath(G2frame.GSASprojectfile)
1305            main = os.path.join(path2GSAS2,'GSASII.py')
1306            ex = sys.executable
1307            if sys.platform == "darwin": # mac requires pythonw which is not always reported as sys.executable
1308                if os.path.exists(ex+'w'): ex += 'w'
1309            print ('restart using ',' '.join([ex,main,projectfile]))
1310            fp.write(' '.join([ex,main,projectfile]))
1311            fp.write('\n')
1312    fp.close()
1313
1314    # start the upgrade in a separate interpreter (avoids loading .pyd files)
1315    if sys.platform != "win32":
1316        proc = subprocess.Popen(['bash',shellname])
1317    else:
1318        proc = subprocess.Popen([shellname],shell=True)
1319    if wait:
1320        proc.wait()
1321    else:
1322        if sys.platform != "win32": proc.wait()
1323        sys.exit()
1324   
1325if __name__ == '__main__':
1326    '''What follows is called to update (or downdate) GSAS-II in a separate process.
1327    '''
1328    LoadConfig()
1329    import time
1330    time.sleep(1) # delay to give the main process a chance to exit
1331    # perform an update and restart GSAS-II
1332    try:
1333        project,version = sys.argv[1:3]
1334    except ValueError:
1335        project = None
1336        version = 'trunk'
1337    loc = os.path.dirname(__file__)
1338    if version == 'trunk':
1339        svnSwitch2branch('')
1340    elif '/' in version:
1341        svnSwitch2branch(version)
1342    elif version:
1343        print("Regress to version "+str(version))
1344        svnUpdateDir(loc,version=version)
1345    else:
1346        print("Update to current version")
1347        svnUpdateDir(loc)
1348    ex = sys.executable
1349    if sys.platform == "darwin": # mac requires pythonw which is not always reported as sys.executable
1350        if os.path.exists(ex+'w'): ex += 'w'
1351    if project:
1352        print("Restart GSAS-II with project file "+str(project))
1353        subprocess.Popen([ex,os.path.join(loc,'GSASII.py'),project])
1354    else:
1355        print("Restart GSAS-II without a project file ")
1356        subprocess.Popen([ex,os.path.join(loc,'GSASII.py')])
1357    print ('exiting update process')
1358    sys.exit()
Note: See TracBrowser for help on using the repository browser.