source: trunk/GSASIIpath.py @ 4976

Last change on this file since 4976 was 4976, checked in by toby, 2 years ago

Mac M1 changes

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