source: trunk/GSASIIpath.py @ 5046

Last change on this file since 5046 was 5046, checked in by toby, 18 months ago

suppress breakpoint() unless inside spyder or debug mode is set; divert breakpoint to IPyBreak

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