Cloned SEACAS for EXODUS library with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

556 lines
19 KiB

2 years ago
#!/usr/bin/env python
# @HEADER
# ************************************************************************
#
# TriBITS: Tribal Build, Integrate, and Test System
# Copyright 2013 Sandia Corporation
#
# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
# the U.S. Government retains certain rights in this software.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the Corporation nor the names of the
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# ************************************************************************
# @HEADER
from CheckinTestConstants import *
from FindGeneralScriptSupport import *
from GeneralScriptSupport import *
from gitdist import addOptionParserChoiceOption
import gitdist
#
# Constants
#
g_extraReposTypes = g_knownTribitsTestRepoTypes
g_extraReposTypeDefault = "Nightly"
g_extraReposTypesDefaulIdx = findInSequence(g_extraReposTypes, g_extraReposTypeDefault)
g_extraRerposFileDefault = "cmake/ExtraRepositoriesList.cmake"
g_verbosityLevels = [ "none", "minimal", "more", "most" ]
g_verbosityLevelDefault = "more"
g_verbosityLevelDefaultIdx = findInSequence(g_verbosityLevels, g_verbosityLevelDefault)
#
# Help message
#
# This part can be reused in other scripts that are project-specific
genericUsageHelp = \
r"""
By default, this will clone all the 'Nightly' extra repos that are listed in
the file:
<projectDir>/"""+g_extraRerposFileDefault+r"""
(other repo types can be selected using --extra-repos-type).
The list of which repos to clone can be "white-list" selected with the option
--extra-repos (see options below for details). Extra repos can in addition be
"back-listed" using the option --not-extra-repos.
To see the full list of repos that can be cloned, pass in just:
--skip-clone --verbosity=more
That will print out a table like:
------------------------------------------------------------------------------
| ID | Repo Name | Repo Dir | VC | Repo URL | Category |
|----|------------|------------|-----|--------------------------|------------|
| 1 | ExtraRepo1 | ExtraRepo1 | GIT | someurl.com.ExtraRepo1 | Continuous |
| 2 | ExtraRepo3 | ExtraRepo3 | GIT | someurl3.com:/ExtraRepo3 | Continuous |
------------------------------------------------------------------------------
If the git repo server is using gitolite, one can set
--gitolite-root=<gitolite-root> and that will result in git repos being
selected only if the selected repos are listed in 'ssh <gitolite-root> info'.
This allows one to automatically exclude repos from being cloned that the user
has no permissions to clone. NOTE: See warning about the --gitolite-root option below!
TIP: After cloning the set of repos, a nice way to interact with the repos is
to use the tool 'gitdist'. If your project does not have a version controlled
.gitdist.default file, you can generate one using the
--create-gitdist-file=<gitdist-file> argument, for example with:
--create-gitdist-file=.gitdist
This will restrict the list of repos processed by gitdist to just the repos cloned.
"""
usageHelp = r"""clone_extra_repos.py [options]
This script clones one more extra repos listed in a TriBITS
ExtraRepositoriesList.cmake file. The standard usage is:
$ cd base <projectDir>
$ ./cmake/tribits/ci_support/clone-extra-repos.py
where <projectDir> is the base TriBITS project dir and base git repo.
""" + \
genericUsageHelp
#
# Helper functions
#
def injectCmndLineOptionsInParser(clp, gitoliteRootDefault=""):
clp.add_option(
"--extra-repos", dest="extraRepos", type="string", default="",
help="List of names of extra repos to be cloned <extra-repos>" \
" (i.e. \"repo0,repo1,,...\"). When set to empty '' (the default value)" \
" then all repos that match <extra-repos-type> listed in <extra-repos-file>" \
" will be selected. But the repos listed in <extra-repos> must always" \
" be a subset of the repos of type <extra-repos-type> selected from" \
" <extra-repos-file>. (Default '')" )
clp.add_option(
"--not-extra-repos", dest="notExtraRepos", type="string", default="",
help="List of names of extra repos *NOT* to clone (i.e. \"repo0,repo1,...\")." \
" (Default '')" )
clp.add_option(
"--extra-repos-file", dest="extraReposFile", type="string",
default=g_extraRerposFileDefault,
help="The file path <extra-repos-file> for the ExtraRepositoriesList.cmake file." \
" This can be an absolute or relative path." \
" (Default = '"+g_extraRerposFileDefault+"')")
addOptionParserChoiceOption(
"--extra-repos-type", "extraReposType",
g_extraReposTypes , g_extraReposTypesDefaulIdx,
"Type of extra repositories <extra-repos-type> to select from " \
"<extra-repos-file>. When --extra-repos is set, then this argument" \
" is ignored.",
clp )
clp.add_option(
"--gitolite-root", dest="gitoliteRoot", type="string", default=gitoliteRootDefault,
help="Gives the root for a gitolite repos <gitolite-root> (e.g. git@<some-url>)." \
" If specified, then any git repos with the <gitolite-root> listed as their" \
" root will only be selected if they are listed with 'R' permissions returned" \
" from 'ssh <gitolite-root> info'. WARNING: Make sure that you have your" \
" gitoliote SSH registered correctly before using this option by typing" \
" the command 'ssh <gitlite-root> info' and make sure that it does *not*"
" ask for a password! (Default = '"+gitoliteRootDefault+"')" )
clp.add_option(
"--with-cmake", dest="withCmake", type="string", default="cmake",
help="CMake executable to use with cmake -P scripts internally (only set" \
+" by unit testing code). (Default = 'cmake')")
addOptionParserChoiceOption(
"--verbosity", "verbLevel", g_verbosityLevels, g_verbosityLevelDefaultIdx,
"Verbosity of the script (levels are cumulative):" \
" none = no output at all (except for commands with --no-op). " \
" minimal = print script args echo and clone commands." \
" more = print basic repo include/exclude logic and print repo table." \
" most = print output from cmake script called, the output from gitolite," \
" and other detailed info." \
,
clp )
clp.add_option(
"--do-clone", dest="doClone", action="store_true",
help="Do the clone of the selected repos. [default]")
clp.add_option(
"--skip-clone", dest="doClone", action="store_false",
help="Skip the clone of the repos and just show what would be done.",
default=True )
clp.add_option(
"--do-op", dest="doOp", action="store_true",
help="Do the clone of the selected repos. [default]" )
clp.add_option(
"--no-op", dest="doOp", action="store_false",
help="Skip cloning the repos and just show the clone commands.",
default=True )
clp.add_option(
"--create-gitdist-file", dest="createGitdistFile", type="string", default="",
help="If specified, the file <gitdist-file> will get generated with the list" \
" of git repos (the same list that is cloned with --do-clone)." \
" (Default = '')")
clp.add_option(
"--show-defaults", dest="showDefaults", action="store_true",
help="Show the default option values and do nothing at all.",
default=False )
def getCmndLineOptions():
from optparse import OptionParser
clp = OptionParser(usage=usageHelp)
injectCmndLineOptionsInParser(clp)
(options, args) = clp.parse_args()
return options
def isVerbosityLevel(inOptions, testVerbLevel):
requestedVerbLevelInt = findInSequence(g_verbosityLevels, inOptions.verbLevel)
testVerbLevelInt = findInSequence(g_verbosityLevels, testVerbLevel)
if testVerbLevelInt <= requestedVerbLevelInt:
return True
return False
def fwdCmndLineOptions(inOptions, terminator=""):
cmndLineOpts = \
" --extra-repos='"+inOptions.extraRepos+"'"+terminator + \
" --not-extra-repos='"+inOptions.notExtraRepos+"'"+terminator + \
" --extra-repos-file='"+inOptions.extraReposFile+"'"+terminator + \
" --extra-repos-type='"+inOptions.extraReposType+"'"+terminator + \
" --gitolite-root='"+inOptions.gitoliteRoot+"'"+terminator + \
" --with-cmake='"+inOptions.withCmake+"'"+terminator + \
" --verbosity='"+inOptions.verbLevel+"'"+terminator
if inOptions.doClone:
cmndLineOpts += " --do-clone" + terminator
else:
cmndLineOpts +=" --skip-clone" + terminator
if inOptions.doOp:
cmndLineOpts += " --do-op" + terminator
else:
cmndLineOpts += " --no-op" + terminator
cmndLineOpts += \
" --create-gitdist-file='"+inOptions.createGitdistFile+"'"+terminator
return cmndLineOpts
def echoCmndLineOptions(inOptions):
print(fwdCmndLineOptions(inOptions, " \\\n"))
def echoCmndLine(inOptions):
print("")
print("**************************************************************************")
print("Script: clone_extra_repos.py \\")
echoCmndLineOptions(inOptions)
def getHeaderOutputAndExtraReposDictList(rawOutputFromCmakefile):
rawOutputFromCmakefile = s(rawOutputFromCmakefile)
headerOuput = ""
pythonDictListStr = ""
processingPythonDict = False
for line in rawOutputFromCmakefile.splitlines():
if line == "*** Extra Repositories Python Dictionary":
processingPythonDict=True
continue
if processingPythonDict:
pythonDictListStr += (line + "\n")
else:
headerOuput += (line + "\n")
#print("\nheaderOuput:\n\n", headerOuput)
#print("\npythonDictListStr = '"+pythonDictListStr+"'")
pythonDictList = eval(pythonDictListStr)
return (headerOuput, pythonDictList)
def getExtraReposDictListFromCmakefile(projectDir, extraReposFile, withCmake,
extraReposType=g_extraReposTypeDefault, extraRepos="",
tribitsDir=tribitsDir, verbose=True,
):
cmnd = "\""+withCmake+"\""+ \
" -DPROJECT_SOURCE_DIR="+projectDir+ \
" -DTRIBITS_BASE_DIR="+tribitsDir+ \
" -DEXTRA_REPOS_FILE="+extraReposFile+ \
" -DENABLE_KNOWN_EXTERNAL_REPOS_TYPE="+extraReposType+ \
" -DEXTRA_REPOS="+extraRepos+\
" -DCHECK_EXTRAREPOS_EXIST=FALSE"
# " -DTRIBITS_PROCESS_EXTRAREPOS_LISTS_DEBUG=TRUE"
cmnd += \
" -P "+ciSupportDir+"/TribitsGetExtraReposForCheckinTest.cmake"
rawOutput = getCmndOutput(cmnd, throwOnError=True, getStdErr=True)
(headerOutput, extraReposPytonDictList) = getHeaderOutputAndExtraReposDictList(rawOutput)
if verbose:
print("\n" + headerOutput)
return extraReposPytonDictList
# Parse raw 'ssh <gitolite-root> info' output and return list of gitolite
# repos.
def parseRawSshGitoliteRootInfoOutput(rawSshGitoliteRootInfoOutput, verbose=False):
rawSshGitoliteRootInfoOutputList = rawSshGitoliteRootInfoOutput.splitlines()
gitoliteSshHeader = rawSshGitoliteRootInfoOutputList[0]
if verbose:
print(gitoliteSshHeader)
gitolioteReposList = []
parsingRepos = False
for line in rawSshGitoliteRootInfoOutputList:
#print("line = '"+line+"'")
# Look for the first blank line and then the next line will be the first
# listed repo.
if line == "":
parsingRepos = True
continue
# Parse the repos
if parsingRepos:
# The permissions and the repo name are split by a tab such as:
# R W ExtraRepo1
repoSplit = line.split("\t")
#print("repoSplit =", repoSplit)
if len(repoSplit) == 2:
gitolioteReposList.append(repoSplit[1])
return gitolioteReposList
# Get the list of gitolite repos from 'ssh <gitolite-root> info'.
def getGitoliteReposList(inOptions, trace=False, dumpGitoliteOutput=False):
cmnd = "ssh "+inOptions.gitoliteRoot+" info"
if trace:
"Running: "+cmnd
rawSshGitoliteRootInfoOutput = getCmndOutput(cmnd)
if dumpGitoliteOutput:
print(rawSshGitoliteRootInfoOutput)
if (trace and not dumpGitoliteOutput): verbose=True
else: verbose=False
return parseRawSshGitoliteRootInfoOutput(rawSshGitoliteRootInfoOutput, verbose=verbose)
def filterOutNotExtraRepos(extraRepoDictList_in, notExtraRepos, verbose=False):
notExtraReposSet = set(notExtraRepos)
extraRepoDictList = []
for extraReposDict in extraRepoDictList_in:
extraRepoName = extraReposDict["NAME"]
if extraRepoName in notExtraReposSet:
if verbose:
print("Excluding extra repo '"+extraRepoName+"'!")
else:
extraRepoDictList.append(extraReposDict)
return extraRepoDictList
def filterOutMissingGitoliteRepos(extraRepoDictList_in,
gitoliteRepos, verbose=False):
gitoliteReposSet = set(gitoliteRepos)
extraRepoDictList = []
for extraReposDict in extraRepoDictList_in:
extraRepoName = extraReposDict["NAME"]
if not extraRepoName in gitoliteReposSet:
if verbose:
print("Excluding extra repo '" + extraRepoName +
"' not listed by gitolite!")
else:
extraRepoDictList.append(extraReposDict)
return extraRepoDictList
def getExtraReposTable(extraRepoDictList):
# Get the lists for each column in the table
repoIdList = []
repoNameList = []
repoDirList = []
repoVcTypeList = []
repoUrlList = []
repoCategoryList = []
repoId = 1 # Use one-base indexing to match gitdist IDs!
for extraRepoDict in extraRepoDictList:
repoIdList.append(str(repoId))
repoNameList.append(extraRepoDict["NAME"])
repoDirList.append(extraRepoDict["DIR"])
repoVcTypeList.append(extraRepoDict["REPOTYPE"])
repoUrlList.append(extraRepoDict["REPOURL"])
repoCategoryList.append(extraRepoDict["CATEGORY"])
repoId += 1
# Create the table
extraReposTableDictList = [
{ "label":"ID", "align":"R", "fields":repoIdList },
{ "label":"Repo Name", "align":"L", "fields":repoNameList },
{ "label":"Repo Dir", "align":"L", "fields":repoDirList },
{ "label":"VC", "align":"L", "fields":repoVcTypeList },
{ "label":"Repo URL", "align":"L", "fields":repoUrlList },
{ "label":"Category", "align":"L", "fields":repoCategoryList },
]
#print("extraReposTableDictList =", extraReposTableDictList)
extraReposTable = gitdist.createTable(extraReposTableDictList)
# Return the table
return extraReposTable
def createGitDistFile(extraRepoDictList, gitdistFile, verbose=False):
gitdistFileStr = ""
for extraRepoDict in extraRepoDictList:
gitdistFileStr += extraRepoDict["DIR"]+"\n"
if verbose:
print("Writing the file '" + gitdistFile + "' ...")
open(gitdistFile, 'w').write(gitdistFileStr)
def cloneExtraRepo(inOptions, extraRepoDict):
repoName = extraRepoDict["NAME"]
repoDir = extraRepoDict["DIR"]
repoUrl = extraRepoDict["REPOURL"]
repoVcType = extraRepoDict["REPOTYPE"]
verbLevelIsMinimum = isVerbosityLevel(inOptions, "minimal")
if verbLevelIsMinimum:
print("\nCloning repo " + repoName + " ...")
if os.path.exists(repoDir):
if verbLevelIsMinimum:
print("\n ==> Repo dir = '" + repoDir +
"' already exists. Skipping clone!")
return
if repoVcType != "GIT":
print("\n ==> ERROR: Repo type '"+repoVcType+"' not supported!")
sys.exit(1)
cmnd = "git clone "+repoUrl+" "+repoDir
if inOptions.doOp:
echoRunSysCmnd(cmnd, timeCmnd=True, verbose=verbLevelIsMinimum)
elif verbLevelIsMinimum:
print("\nRunning: " + cmnd)
def cloneExtraRepos(inOptions):
verbLevelIsMinimal = isVerbosityLevel(inOptions, "minimal")
#
# A) Get the list of extra repos
#
extraRepoDictList = getExtraReposDictListFromCmakefile(
projectDir=os.getcwd(),
extraReposFile=inOptions.extraReposFile,
extraReposType=inOptions.extraReposType,
extraRepos=inOptions.extraRepos,
withCmake=inOptions.withCmake,
verbose=isVerbosityLevel(inOptions, "most")
)
#print("extraRepoDictList =" + str(extraRepoDictList))
#
# B) Get the list of gitolite repos
#
if inOptions.gitoliteRoot:
if verbLevelIsMinimal:
print("\n***")
print("*** Get the list of repos that can be cloned from gitolite server:")
print("***\n")
gitoliteRepos = getGitoliteReposList(inOptions,
trace=verbLevelIsMinimal,
dumpGitoliteOutput=isVerbosityLevel(inOptions, "most"))
else:
gitoliteRepos = []
#print("gitoliteRepos =", gitoliteRepos)
#
# C) Filter the list of extra repos
#
if gitoliteRepos:
if verbLevelIsMinimal:
print("\n***")
print("*** Filtering the set of extra repos based on gitolite repos:")
print("***\n")
extraRepoDictList = filterOutMissingGitoliteRepos(
extraRepoDictList, gitoliteRepos, verbose=verbLevelIsMinimal)
if inOptions.notExtraRepos:
if verbLevelIsMinimal:
print("\n***")
print("*** Filtering the set of extra repos based on --not-extra-repos:")
print("***\n")
extraRepoDictList = filterOutNotExtraRepos(
extraRepoDictList,
inOptions.notExtraRepos.split(","),
verbose=verbLevelIsMinimal)
#
# D) print out table of repos
#
if isVerbosityLevel(inOptions, "more"):
print("\n***")
print("*** List of selected extra repos to clone:")
print("***\n")
extraReposTable = getExtraReposTable(extraRepoDictList)
print(extraReposTable)
#
# E) Clone the repos
#
if inOptions.doClone:
if verbLevelIsMinimal:
print("\n***")
print("*** Clone the selected extra repos:")
print("***\n")
for extraRepoDict in extraRepoDictList:
cloneExtraRepo(inOptions, extraRepoDict)
#
# F) Create the gitdist file
#
if inOptions.createGitdistFile:
if verbLevelIsMinimal:
print("\n***")
print("*** Create the gitdist file:")
print("***\n")
createGitDistFile(extraRepoDictList, inOptions.createGitdistFile,
verbose=verbLevelIsMinimal)
#
# Run the script
#
if __name__ == '__main__':
inOptions = getCmndLineOptions()
if isVerbosityLevel(inOptions, "minimal"):
echoCmndLine(inOptions)
if inOptions.showDefaults:
sys.exit(0)
cloneExtraRepos(inOptions)