""" This python script is intended to get a new developer machine up and running for CIPRES software development. flags: -n = Run in non-interactive mode -a = Do not check ant version -d = Build and install dependencies only (not CIPRES itself) -b = Build only (no configuration before builds) -c = configure and build CIPRES (even if the -b flag has turned off configuration of the dependencies). all flags must be passed in as separate arguments (use "-c -b" not "-cb" syntax) This script is intended to be run once to "bootstrap" a machine for building CIPRES. After successfully running you should be able to stay up to date by running "make" inside the CIPRES_TOP directory. """ import sys, os, re, shutil import distutils.sysconfig try: import subprocess except: sys.exit('Sorry you have to have Python 2.4 or the subprocess module installed to run this script (if you are on windows)') ################################################################################ # Bundled software info ################################################################################ jacOrbBundle = 'JacORB-2.2.4' omniOrbBundle = 'omniORB-4.0.7' omniOrbPyBundle = 'omniORBpy-2.7' boostBundle = 'boost_1_33_1' installedOmniORB = False maintainerBuild = True addedEnv = {} ################################################################################ # The top portion of the svn repository for the branch (hopefully we'll change # this to trunk soon ################################################################################ svnBranch='trunk' ################################################################################ # Sanity checks to make sure users invoke the script from within the bundle # directory. ################################################################################ sanityCheckFileName = "this-is-CIPRES-dev-bootstrap.txt" cipresAndDepsDir = 'CIPRES-and-deps' ################################################################################ # Help messages (put here for improve code readability ################################################################################ antUpgradeInfo = """You'll have to: 1. download ant from http://ant.apache.org/ 2. install it, which can be as simple as putting ANT_HOME/bin on your PATH (ahead of any old ant versions),and 3. try this script again. """ _prog = os.path.split(sys.argv[0])[1] ################################################################################ # Some globals that control script behavior ################################################################################ interactiveMode = True buildCIPRESCode = True doConfigure = True configureCIPRESinBuildOnly = False # nPromptTries = 10 defaultVerbosity = False usingSubprocess = False isWindows = sys.platform.upper().startswith('WIN') def getFSRoot(): '''Returns root of current filesystem "/" on nonWindows''' if not isWindows: return os.path.sep return os.path.splitdrive(os.path.abspath(os.path.curdir))[0] if isWindows: defaultSysPath = os.path.join(getFSRoot(), 'usr', 'local') else: defaultSysPath = os.environ.get('PROGRAMFILES') if defaultSysPath is None: defaultSysPath = getFSRoot() fastMode = False ################################################################################ # Minimal logging functions # NOTE: calling error reports an error and exits the script! ################################################################################ def infoMessage(s): "Prints message with prefix for clarifying the source of the message." print _prog + ': ' + s def error(s): "Displays the message (with program name and ERROR tag) then exits with error code" sys.exit(_prog + ': ERROR\n' + s + '\n' + _prog + ': Exiting due to ERROR.') def warn(s): "Displays the message (with program name and WARNING tag)" sys.stdout.write(_prog + ': WARNING\n' + s + '\n') def printEnv(environ): "Prints keys and values in environ in an easy-to-read format" for k, v in environ.iteritems(): infoMessage('%-20s = %s' % (k,v)) def chdir(dir): "Changes working directory and notifies the user of the change" infoMessage('Changing current directory to %s' % os.path.abspath(dir)) os.chdir(dir) def findPath(top, pathToFind): '''Returns None or the first path matching "pathToFind" from a top-down walk (starting at "top").''' a = findParent(top, pathToFind) if a is None: return None return os.path.join(a, pathToFind) def findParent(top, pathToFind): '''Returns None or the parent of the first path matching "pathToFind" from a top-down walk (starting at "top").''' if not os.path.exists(top): error('The directory %s was not found' % top) dir, basen = os.path.split(pathToFind) for root, dirs, filen in os.walk(top): if dir: if root.endswith(dir): for f in filen: if f == basen: p = os.path.join(root, basen) return os.path.normpath(root[:-len(dir)]) else: for f in filen: if f == basen: return os.path.normpath(root) return None def processEnvVal(val, env): '''replaces $VAR with value of VAR in env. This is more flexible thatn ''' varName = isWindows and re.compile(r'%([_a-zA-Z0-9]+)%') or re.compile(r'[^\\]\$([_a-zA-Z0-9]+)') s = 0 while True: m = varName.search(val, s) if m: k = m.group(1) val = val[:m.start()] + m.expand(env.get(k, '')) + val[m.end():] s = m.end() else: break return val def appendToEnvDirectoryListVal(key, valsToAdd, prevVal = None): '''Composes a new value for an environmental variable setting that refers to a list of paths The new setting is NOT added to the env.''' newVal = prevVal or '' if isinstance(valsToAdd, str): valsToAdd = [valsToAdd] for el in valsToAdd: if newVal: if newVal == el: pass elif newVal.endswith(os.pathsep + el): pass elif (os.pathsep + el + os.pathsep) in newVal: pass elif newVal.startswith(el + os.pathsep): pass else: newVal = newVal + os.pathsep + el else: newVal = el return newVal def defaultAppendToEnvDirectoryListVal(key, valsToAdd): """Composes a new value for an environmental variable setting that refers to a list of paths. The starting value comes from the scripts "addedEnv" global (or os.environ). The new value is NOT added to "addedEnv" or os.environ.""" global addedEnv oldVal = addedEnv.get(key, os.environ.get(key)) return appendToEnvDirectoryListVal(key, valsToAdd, oldVal) def findAllVersionedDir(prefix): '''Looks for prefix-#.#.# pattern in current directory using the regex ^prefix-?[0-9.]*$ Returns list tuples: [(dir-name, tuple of version numbers), ] of all version-numbered directories found.''' p = re.compile('^%s' % prefix + r'-([0-9.]+)$') children = os.listdir(os.path.curdir) matches = [] for c in children: m = p.match(c) if m: matches.append((c, m.group(1).split('.'))) return matches def versionTupleCmp(f, s): """__cmp__ function for version tuples. cannot use lexigraphic cmp because: 1.1 < 1.04 can't convert the whole thing to a decimal because 1.10 > 1.1.11""" if len(f) == 0: return len(s) != 0 and -1 or 0 for ind, v in enumerate(f): if ind+1 > len(s): return 1 r = cmp(v, s[ind]) if r != 0: return r if len(s) > len(f): return -1 return 0 def findHighestVersionedDir(prefix): '''Looks for prefix-#.#.# pattern in current directory using the regex ^prefix-?[0-9.]*$ Returns the directory with the highest version numer (or None if there are no matches)''' dirTuples = findAllVersionedDir(prefix) if not dirTuples: return None currHighest = dirTuples[0] for d in dirTuples[1:]: if versionTupleCmp(currHighest[1], d[1]) < 0: currHighest = d return currHighest[0] ################################################################################ # Utility functions ################################################################################ if usingSubprocess: try: import subprocess except ImportError: sys.exit("""To run CIPRES (and this script), you need a version of python with the subprocess module.\nEither: - Update to python 2.4 or - download and install the subprocess.py module """) def checkVersionTuple(toCheck, required): '''Returns True if toCheck >= required at all relevant positions. >>> checkVersionTuple((2,), [1,2,5]) True >>> checkVersionTuple((1,2,4), [1,2,5]) False >>> checkVersionTuple((1,3,4), [1,2,5]) True >>> checkVersionTuple((1,2,16), [1,21,5]) False >>> checkVersionTuple([1,21,6], (1,21,5)) True >>> checkVersionTuple((1,21), [1,21,5]) False >>> checkVersionTuple((10,3,9), [10, 4]) False ''' for i in range(len(required)): n = i < len(toCheck) and toCheck[i] or 0 if n < required[i]: return False if n > required[i]: return True return True def expandPath(s): '''returns an absolute path, expanding home dir and env vars''' if len(s) > 0: firstChar = s[0] if firstChar == os.curdir: return os.path.abspath(s) if isWindows: if firstChar == '%' or firstChar == '~': return os.path.abspath(os.path.expanduser(os.path.expandvars(s))) else: if firstChar == '$' or firstChar == '~': return os.path.abspath(os.path.expanduser(os.path.expandvars(s))) return s def verifyWritableDirectory(dir, mustSucceed, promptBeforeCreating=False): '''Checks for or creates dir. Demands write permissions. mustSucceed is treated as a boolean -- if True, then failure causes the program to exit.''' errReportFunc = mustSucceed and error or infoMessage if os.path.exists(dir): if os.access(dir, os.W_OK): return True errReportFunc('You are not able to write to "%s"' % dir) return False if promptBeforeCreating: create = booleanQuery('The directory "%s" does not exist. Do you want me to create it?' % dir, True) if not create: errReportFunc("The directory \"%s\" does not exist, but is required." % dir) return False try: os.makedirs(dir) except: errReportFunc('The directory "%s" could not be created.' % dir) return False if os.access(dir, os.W_OK): return True errReportFunc('The directory "%s" was created, but you are not allowed to write to it!' % dir) return False def verifyDirectory(dir, mustSucceed, promptBeforeCreating=False): '''Checks for or creates dir. mustSucceed is treated as a boolean -- if True, then failure causes the program to exit.''' errReportFunc = mustSucceed and error or infoMessage if os.path.exists(dir): return True if promptBeforeCreating: create = booleanQuery('The directory "%s" does not exist. Do you want me to create it?' % dir, True) if not create: errReportFunc("The directory \"%s\" does not exist, but is required." % dir) return False try: os.makedirs(dir) except: errReportFunc('The directory "%s" could not be created.' % dir) return False return True def verifyExistingDirectory(dir, mustSucceed, promptBeforeCreating=False): '''Checks for existing directory "dir" mustSucceed is treated as a boolean -- if True, then failure causes the program to exit.''' errReportFunc = mustSucceed and error or infoMessage if os.path.exists(dir): return True errReportFunc("The directory \"%s\" does not exist, but is required." % dir) return False def booleanQuery(prompt, default): '''Asks the user a question and parses y/n response to return True or False. Exits with an error after nPromptTries (a global) failed attempts.''' global interactiveMode, nPromptTries fullPrompt = _prog + ': ' + prompt + '\n(y/n) [default = ' + (default and 'Y' or 'N') + ']\n ?> ' if not interactiveMode: print fullPrompt, default and 'y' or 'n', '(non-interactive mode)' return default for i in range(nPromptTries): try: c = raw_input(fullPrompt).upper() except EOFError: c = '' if c == 'Y' or c == 'YES': return True if c == 'N' or c == 'NO': return False if not c: infoMessage('Accepting default "%s"' % (default and 'Yes' or 'No')) return default print 'Please enter "y" or "n".' sys.exit(_prog + ': You seem to be having some problems typing. Try again later.') def directoryQuery(prompt, default, writeable=True, existing=False): '''Asks the user to specify directory. If it does not exist, "existing" controls whether or not it will be created. If "writeable" is True, writeable permissions are verified. Exits with an error after nPromptTries (a global) failed attempts.''' global interactiveMode, nPromptTries verifyFunc = writeable and verifyWritableDirectory or (existing and verifyExistingDirectory or verifyDirectory) fullPrompt = '%s: %s ?\n[default = "%s"]\n ?> ' % (_prog, prompt, default) if not interactiveMode: print '%s "%s" (non-interactive mode)' %(fullPrompt, default) verifyFunc(expandPath(default), mustSucceed=True) return default for i in range(nPromptTries): try: r = raw_input(fullPrompt) except EOFError: r = '' if not r: infoMessage('Accepting default "%s"' % default) r = default c = expandPath(r) if verifyFunc(c, mustSucceed=False, promptBeforeCreating=True): return c sys.exit(_prog + ': %d failures specifying a path. Exiting' % nPromptTries) def commandOS(cmd, args, mustSucceed, environ=os.environ, verbose=defaultVerbosity): '''Spawns "cmd" with "args" environ. Returns True if the command succeeds (calls error if mustSucceed=True and the command fails).''' if verbose: infoMessage('Evironment for command:') printEnv(environ) infoMessage('from %s' % os.path.abspath(os.path.curdir)) infoMessage('%s %s' % (cmd, ' '.join(args))) if sys.platform == 'win32': rc = subprocess.call([cmd] + args, env=environ, shell=True) else: rc = os.spawnvpe(os.P_WAIT, cmd, [cmd] + args, environ) if mustSucceed and rc != 0: error('%s failed with code %d' % (cmd, rc)) return rc == 0 def getCmdOutput(cmd, args, mustSucceed, environ=os.environ, verbose=defaultVerbosity): '''Spawns "cmd" with "args" environ. Returns True if the command succeeds (calls error if mustSucceed=True and the command fails).''' if verbose: infoMessage('Evironment for command:') printEnv(environ) infoMessage('from %s' % os.path.abspath(os.path.curdir)) infoMessage('%s %s' % (cmd, ' '.join(args))) p = subprocess.Popen([cmd] + args, stdout=subprocess.PIPE) output = p.communicate()[0] rc = p.returncode if mustSucceed and rc != 0: error('%s failed with code %d' % (cmd, rc)) return output ################################################################################ # checks and actions ################################################################################ def getAntVersion(): "Calls ant -version and parses output to get the version number." stout = os.popen('ant -version', 'r') linesOut = stout.readlines() nLines = len(linesOut) if nLines == 0: error('"ant -version" failed. Make sure that ant is on your PATH!"\n%s' % antUpgradeInfo) if nLines > 1: error('''The command "ant -version" command returned more than one line of output. This was not expected. Try the command yourself. If it is working correctly, please: * update the getAntVersion() function in %s, OR * use the -a command line argument to suppress the checking of ant (you will need version 1.6.5 or greater to build CIPERS)''' % _prog) output = linesOut[0] versionStringRE = re.compile(r'^(Apache\s*)?[Aa]nt\s+version\s*([0-9.]+)\s+.*') matchObj = versionStringRE.match(output) if not matchObj: error('The output from running "ant -version" command did not match the expected pattern: "Apache Ant version #.#.#"\nTry the command yourself, If it is working correctly, please update the getAntVersion() function in ' + _prog) versionNum = matchObj.group(2) # the numbers should be the second match group vNumSplit = versionNum.split('.') while len(vNumSplit) < 3: vNumSplit.append(0) return tuple(map(int, vNumSplit[:3])) def findCipresSource(branchToCheckout='trunk'): '''Determines the "cipres" directory to use and sets the maintainerBuild global. (presence of a .svn directory implies not a maintainer build) Precedene: - cipres subdirectory - cipres-#.#.# subdir - checkout from SVN ''' global maintainerBuild cipresTop = None hadCIPRES = os.path.exists('cipres') if hadCIPRES: cipresTop = 'cipres' else: cipresTop = findHighestVersionedDir('cipres') externalCIPRES = cipresTop is None if externalCIPRES: if booleanQuery('No cipres source code directory was found in this directory. Do you have a copy of the CIPRES code?', False): cipresTop = directoryQuery('Enter the path to cipres source code directory (named "cipres" or cipres-#.#.# where the # signs indicate the version number)', 'cipres', writeable=False, existing=True) else: if not booleanQuery('Do you have SVN checkout permissions from the CIPRES source code repository?', True): error('\nPlease download a copy of the cipres code, or obtain SVN access before running this script.') maintainerBuild = True if cipresTop is not None: maintainerBuild = os.path.exists(os.path.join(cipresTop, '.svn')) if maintainerBuild: infoMessage('An SVN-controlled %s directory was found.' % cipresTop) else: infoMessage('A %s directory that does NOT appear under SVN control was found.' % cipresTop) if externalCIPRES or booleanQuery('Would you like to use %s as CIPRES_TOP?' % cipresTop, True): return os.path.abspath(cipresTop) if cipresTop == 'cipres': # we'll move the old copy of the source newName = 'oldCipres' i = 1 while os.path.exists(newName): newName = newName + str(i) i += 1 try: infoMessage('Moving "cipres" to "%s"' % newName) os.rename('cipres', newName) except: error('Could not rename the "cipres" to "%s". Please remove the directory and try again' % newName) fullURL = 'http://nladr-cvs.sdsc.edu/svn/CIPRES/cipresdev/' + branchToCheckout + '/cipres' infoMessage('Checking out source code from %s.\n You may be prompted for your CIPRES SVN repository password.' % fullURL) if not commandOS('svn', ['checkout', fullURL], mustSucceed=True): infoMessage('svn checkout failed! Trying "svn --version" to make sure svn is alive.') if not commandOS('svn', ['--version'], mustSucceed=True): error('svn commands failed. Make sure that svn (the subversion client) is installed and on your PATH.\n(The svn homepage is http://subversion.tigris.org/)') error('svn checkout failed (and I cannot diagnose the problem).') return os.path.abspath('cipres') def escapePath(p): "Escapes spaces in a string with backslash-space for passing to a shell." return '\\ '.join(p.split()) def checkOmniInstallation(omniOrbRoot): """Hook for verifying omniORB installation (currently just checks for omniidl). Returns (boolean, string) tuple indicating whether the installation looks good and the path that is missing (if the installation seems to be lacking).""" p = os.path.join(omniOrbRoot, 'bin', 'omniidl') return (os.path.exists(p), p) def omniOrbInstalled(omniOrbRoot): "Hook called after omniORB is installed. (adds appropriate PYTHONPATH elements to env" global addedEnv newPYTHONPATH = defaultAppendToEnvDirectoryListVal('PYTHONPATH', [distutils.sysconfig.get_python_lib(0, 0, prefix=omniOrbRoot), distutils.sysconfig.get_python_lib(1, 0, prefix=omniOrbRoot)]) if newPYTHONPATH != os.environ.get('PYTHONPATH', ''): addedEnv['PYTHONPATH'] = newPYTHONPATH return omniOrbRoot def buildOmniORB(cipresBuild): "Builds and installs omniORB. Returns path to the prefix used to install omniORB or None (if omniORB support is not requested)." global installedOmniORB, addedEnv, doConfigure #################### # Determine omniORB prefix #################### buildRequested =False if not booleanQuery('Do you want to use omniORB (answering "no" will disable C/C++ CIPRES services)?', True): return None omniSrc = omniOrbBundle if booleanQuery('Do you have a previously installation of omniORB that you would like to use?', False): omniOrbRoot = directoryQuery('Please enter the prefix used to install omniORB', defaultSysPath) else: omniOrbRoot = None while omniOrbRoot is None: omniOrbRoot = directoryQuery('Please enter a prefix directory for installing omniORB.', os.path.join(cipresBuild)) if len(omniOrbRoot.split()) > 1: infoMessage('OOPS: Sorry, omniORB does not like to be installed in a directory with a space in the path') omniOrbRoot = None buildRequested = True omniSrc = directoryQuery('Enter the path to omniORB source (or simply return to accept the bundled version)', omniOrbBundle, writeable=False, existing=True) r = checkOmniInstallation(omniOrbRoot) if r[0]: if not buildRequested: return omniOrbInstalled(omniOrbRoot) if not booleanQuery('omniORB appears to be installed in at %s already. Do you want to reinstall omniORB?' % omniOrbRoot, False): return omniOrbInstalled(omniOrbRoot) elif not buildRequested: error("Expected (and required) component %s was not found." % r[1]) #################### # Build omniORB #################### prevDir = os.path.abspath(os.path.curdir) chdir(omniSrc) if not os.path.exists('build'): if not doConfigure: error('%s not found.\nConfiguration step (running script without the -b flag) is needed, before "build only" runs can be attempted' % os.path.abspath('build')) os.mkdir('build') chdir('build') parent = os.path.dirname(os.path.abspath(os.path.curdir)) if doConfigure: commandOS('sh', [os.path.join(parent, 'configure'), '--disable-static', '--prefix=%s' % escapePath(omniOrbRoot)], mustSucceed=True) commandOS('make', [], mustSucceed=True) commandOS('make', ['install'], mustSucceed=True) chdir(prevDir) installedOmniORB = True #################### # Check omniORB #################### r = checkOmniInstallation(omniOrbRoot) if not r[0]: error('omniORB installation does not appear to be complete!\n%s was not found.' % r[1]) return omniOrbInstalled(omniOrbRoot) def checkOmniPyInstallation(omniOrbRoot): """Hook for verifying omniORB installation (currently just checks for omniORB/CORBA.py). Returns (boolean, string) tuple indicating whether the installation looks good and the path that is missing (if the installation seems to be lacking).""" pymods = distutils.sysconfig.get_python_lib(0, 0, prefix=omniOrbRoot); corbapy = os.path.join(pymods, 'omniORB', 'CORBA.py') return (os.path.exists(corbapy), corbapy) def buildOmniORBpy(omniOrbRoot): """Builds and installs omniORBpy into the directory passed in as "omniOrbRoot". R Returns False if omniORBpy has been rejected by the user (True otherwise).""" #################### # Determine omniORBpy prefix #################### global addedEnv, doConfigure assert(os.path.exists(omniOrbRoot)) if installedOmniORB: if not booleanQuery('Do you want to install the python ORB, omniORBpy?', True): return False else: if checkOmniPyInstallation(omniOrbRoot)[0]: if not booleanQuery('Previous installation of omniORB appears to have omniORBpy. Do you want to reinstall omniORBpy?', False): return True else: if not booleanQuery('The python ORB, omniORBpy does not appear to be installed. (Note that if your previous installation of omniORB was not %s, then it may conflict with an installation of %s). Do you want to install omniORBpy?' % (omniOrbBundle, omniOrbPyBundle), True): return False infoMessage('Installing %s to %s' %(omniOrbPyBundle, omniOrbRoot)) #################### # Build omniORBpy #################### prevDir = os.path.abspath(os.path.curdir) chdir(omniOrbPyBundle) if not os.path.exists('build'): if not doConfigure: error('%s not found.\nConfiguration step (running script without the -b flag) is needed, before "build only" runs can be attempted' % os.path.abspath('build')) os.mkdir('build') chdir('build') parent = os.path.dirname(os.path.abspath(os.path.curdir)) if 'PYTHONPATH' in addedEnv: d = dict(os.environ) d['PYTHONPATH'] = addedEnv['PYTHONPATH'] else: d = os.environ if doConfigure: commandOS(os.path.join(parent, 'configure'), ['--prefix=%s' % escapePath(omniOrbRoot), '--with-omniorb=%s' % escapePath(omniOrbRoot)], environ=d, mustSucceed=True) commandOS('make', [], environ=d, mustSucceed=True) commandOS('make', ['install'], environ=d, mustSucceed=True) chdir(prevDir) #################### # Check omniORBpy #################### x = checkOmniPyInstallation(omniOrbRoot) if not x[0]: error('omniORBpy installation does not appear to be complete!\n%s was not found.' % x[1]) return True def buildJacORB(): """Builds and JacORB and returns the path to the built JACORB_TOP directory (env is not changed).""" global doConfigure if not booleanQuery('Do you want to install the Java ORB, %s?' % jacOrbBundle, True): return None prevDir = os.path.abspath(os.path.curdir) chdir(jacOrbBundle) if not os.path.exists('bin'): if not doConfigure: error('%s not found.\nConfiguration step (running script without the -b flag) is needed, before "build only" runs can be attempted' % os.path.abspath('bin')) commandOS('unzip', ['-aqo', 'foo.zip'], mustSucceed=True) commandOS('ant', ['clean'], mustSucceed=True) if not os.path.exists(os.path.join('bin', 'jaco')): commandOS('ant', ['jaco'], mustSucceed=True) if not os.path.exists(os.path.join('bin', 'idl')): commandOS('ant', ['idlcmd'], mustSucceed=True) chdir(prevDir) return os.path.abspath(jacOrbBundle) def buildBoost(prefix): '''Determines boost installation status By default we just use the bundled copy of boost as BOOST_ROOT (we don't do a full install). Boost does not have to be installed to be used by CIPRES (we just use headers with inlined functions), but the directory structure differs for users that have a copy (in which BOOST_ROOT is assumed to be the parent of a boost directory), versus people that have done a full install (in which case the install prefix is passed in to CIPRES' configure using the --with-boost arg). So a pair of strings are returned: (BOOST_ROOT, boost-preix) only 1 of the two has to be valid.''' if booleanQuery('Do you have previous copy or installation of the Boost libraries that you would like to use for building CIPRES?', False): if booleanQuery('Were the boost libraries built and installed?', False): while boostInstall is None: boostInstall = directoryQuery('Please enter a prefix directory for the boost installation.', defaultSysPath, writeable=False, existing=True) if not os.path.exists(os.path.join(boostInstall, 'include')): boostInstall = None if not booleanQuery('Expecting an "include" subdirectory in the boost installation directory. Do you want to try to specify the boost prefix again?', False): break if boostInstall is not None: return (None, boostInstall) p = directoryQuery('Please enter the path to a copy of the boost libraries (or return to accept the bundled boost distribution)', boostBundle) p = os.path.abspath(p) if not os.path.exists(p): error('The specifed boost directory does not exist.') return (p, None) def buildCipres(cipresTop, cipresPrefix, omniOrbRoot=None, omniOrbPyRoot=None, jacOrbRoot=None, boostInfo=None, perlInfo=None): """Uses the results of the other build actions to compose a configure command. The command is written as a simple shell script: $CIPRES_TOP/cfgcommand.sh The script is then executed (preceded by bootstrap.sh to create configure, if needed) make and make install are then invoked to build CIPRES.""" global maintainerBuild, addedEnv, buildCIPRESCode, doConfigure, configureCIPRESinBuildOnly #################### # determine configure args #################### buildJava = bool(bool(jacOrbRoot) and booleanQuery('Do you want to configure the Java portion of the CIPRES libraries? ', True)) buildCxx = (omniOrbRoot is not None) and (boostInfo is not None) and booleanQuery('Do you want to configure the C/C++ portion of the CIPRES libraries?', True) buildPython = omniOrbPyRoot is not None and booleanQuery('Do you want to configure the Python portion of the CIPRES libraries?', True) preciousSettings = [] cfgArgs = ['--prefix="%s"' % expandPath(cipresPrefix)] if not buildJava: cfgArgs.append('--disable-java-lib') else: newPath ='%s%s%s%s/bin' %(os.environ['PATH'], os.path.sep, os.pathsep, jacOrbRoot) preciousSettings.append('PATH="%s"' % newPath) if not buildCxx: cfgArgs.append('--disable-cxx-lib') else: cfgArgs.append('--with-omniorb-prefix="%s"' % omniOrbRoot) if boostInfo[0]: preciousSettings.append('BOOST_ROOT="%s"' % boostInfo[0]) else: assert(boostInfo[1]) cfgArgs.append('--with-boost="%s"' % boostInfo[1]) if not buildPython: cfgArgs.append('--disable-python-lib') if perlInfo is None: cfgArgs.append('--disable-perl-lib') for k, v in addedEnv.iteritems(): preciousSettings.append('%s="%s"' % (k, v)) cfgcommand = ' '.join(['./configure', ' '.join(preciousSettings + cfgArgs)]) #################### # write a script that calls configure with these args #################### scriptContents = """#!/bin/sh set -x %s """ % cfgcommand cfgCmdFileName = os.path.join(os.path.abspath(cipresTop), 'cfgcommand.sh') if doConfigure or configureCIPRESinBuildOnly: try: cfgCmdFile = open(cfgCmdFileName, 'w') cfgCmdFile.write(scriptContents) cfgCmdFile.close() except: error('Could not write CIPRES configuration command file "%s"' % cfgCmdFileName) infoMessage("""A simple script: %s has been created. This script runs the CIPRES configure script with arguments consistent with the build settings that have been accumulated by running %s. """ % (cfgCmdFileName, _prog)) else: if not os.path.exists(cfgCmdFileName): error('%s not found.\nConfiguration step (running script without the -b flag) is needed, before "build only" runs can be attempted' % os.path.abspath(cfgCmdFileName)) oldCfgCommand = open(cfgCmdFileName).read() if oldCfgCommand != scriptContents: error('''Current CIPRES configuration is not the same as the previous version of %s\nCIPRES must be reconfigured before building. ================================================================================ Previous version ================================================================================ %s ================================================================================ Current version: ================================================================================ %s ================================================================================ End ================================================================================ ''' % (os.path.abspath(cfgCmdFileName), oldCfgCommand, cfgcommand)) #################### # build CIPRES #################### prevDir = os.path.abspath(os.path.curdir) chdir(cipresTop) if buildCIPRESCode: if doConfigure or configureCIPRESinBuildOnly: if maintainerBuild: commandOS('sh', ['bootstrap.sh'], mustSucceed=True) commandOS('sh', [cfgCmdFileName], mustSucceed=True) commandOS('make', [], mustSucceed=True) commandOS('make', ['install'], mustSucceed=True) chdir(prevDir) return cfgcommand def checkAnt(): infoMessage('Checking ant') antVersionTuple = getAntVersion() requiredAntVersion = (1, 6, 5) if not checkVersionTuple(antVersionTuple, requiredAntVersion): error("You must have ant version %s (or higher).\n%s" % ('.'.join(map(str,requiredAntVersion)), antUpgradeInfo)) infoMessage("Your version of ant looks good") def installAllPerlModules(cipresTop, prefix): """Hook for installing the perl prerequisites. This used to do the installation and return a dict that held paths keyed by strings that can be used as precious variables passed to configure. Now we are using Makefile.PL to deal with prereqs, so we return None to indicate "do NOT build Perl lib" and anything else (an empty dict) to mean write the cfgcommand.sh script to build the perl parts of the library.""" if booleanQuery('Do you want to install the perl portions of CIPRES?', True): return {} # used to use this return None ################################################################################ # MAIN ################################################################################ if __name__ == '__main__': performAntCheck = True for arg in sys.argv[1:]: if arg == '-n': interactiveMode = False elif arg == '-a': performAntCheck = False elif arg == '-b': doConfigure = False elif arg == '-c': configureCIPRESinBuildOnly = True elif arg == '-d': buildCIPRES = False else: sys.exit(__doc__) if not os.path.exists(sanityCheckFileName): warn('''The excepted file "%s" was not found! You will need to enter paths for all dependencies (or quit and run this script from the %s directory that can be downloaded from the CIPRES web site)''' %(sanityCheckFileName, cipresAndDepsDir)) if performAntCheck: checkAnt() cipresTop = findCipresSource(svnBranch) buildingToSisterDir = False if buildingToSisterDir: #building outside the source tree seems preferable, but I (MTH) am # having a hard time putting an arbitrary external directory (the # build/share/cipres/resources directory) on my classpath in eclipse # so I'm reverting to building in the CIPRES_TOP/build defBuildParent, cipresTopDirName = os.path.split(os.path.abspath(cipresTop)) defBuildDirName = 'build-' + cipresTopDirName defBuildPath = os.path.join(defBuildParent, defBuildDirName) else: defBuildPath = os.path.join(cipresTop, 'build') cipresPrefix = directoryQuery('Please enter a prefix directory for building CIPRES libraries.', defBuildPath) omniOrbRoot = buildOmniORB(cipresPrefix) # If we don't install omniORB, then we won't be using CIPRES python or C++ libraries omniOrbPyRoot = None if omniOrbRoot: if buildOmniORBpy(omniOrbRoot): omniOrbPyRoot = omniOrbRoot boostInfo = buildBoost(omniOrbRoot) jacOrbRoot = buildJacORB() perlInfo = installAllPerlModules(cipresTop, cipresPrefix) cfgCmd = buildCipres(cipresTop=cipresTop, cipresPrefix=cipresPrefix, omniOrbRoot=omniOrbRoot, omniOrbPyRoot=omniOrbPyRoot , jacOrbRoot=jacOrbRoot, boostInfo=boostInfo, perlInfo=perlInfo) print """ SUCCESS! You should be able to stay up to date by using the standard commands: svn update sh bootstrap.sh %s make install from within the CIPRES_TOP (the cipres subdirectory of this directory). The CIPRES executable are found in: %s """ % (cfgCmd, os.path.join(os.path.abspath(cipresPrefix), 'bin'))