source: trunk/GSASIIpath.py @ 4752

Last change on this file since 4752 was 4741, checked in by toby, 4 years ago

deal with install python not matching target system

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