Files
OpenSpace/support/jenkins/buildAllModuleCombination.py

141 lines
4.4 KiB
Python

import os
from subprocess import call
from itertools import product, repeat
import shutil
import sys
import re
import random
DefaultEnabledModules = [
"base"
]
# The class that represents a build command
# 'command': The CMake command that will get executed
# 'dependencies': A list of module dependencies for this command
# 'enabledModules': A list of modules that are enabled
class Command:
def __init__(self):
self.command = ""
self.dependencies = []
self.enabledModules = ["base"]
# Extracts the dependencies from a modules 'include.cmake' file
# This method uses a regex to look for OPENSPACE_DEPENDENCIES
# and adds all names to the list. Then, it will remove the modules
# that have been commented out.
# TODO: Right now, only the next module is removed when a comment
# symbol is found. This does not take into account that there might
# be multiple modules defined in a single commented out line, so we
# potentially have extra dependencies
def getDependencies(module):
includeFile = "modules/{}/include.cmake".format(module)
if os.path.isfile(includeFile):
# The file exists
dependencyList = []
with open(includeFile) as f:
# The file can be opened
contents = f.read()
p = re.compile("(\OPENSPACE_DEPENDENCIES(.*)\))", re.DOTALL)
match = p.search(contents)
if match is not None:
string = match.group(match.lastindex)
# Remove the OPENSPACE_DEPENDENCIES string that is part
# of the matched string
string = string.replace("OPENSPACE_DEPENDENCIES", "")
# Remove the ) that is part of the matched string
string = string.replace(")", "")
dependencyList = string.split()
for index, w in enumerate(dependencyList):
# If we find a comment symbol, remove the comment
# and the next command
if dependencyList[index] == "#":
del dependencyList[index]
del dependencyList[index]
return dependencyList
else:
return []
percentage = 1.0
if len(sys.argv) > 1:
percentage = float(sys.argv[1])
print("Percentage of testing:", percentage)
# To be called from the main OpenSpace
modules = os.listdir("modules")
# modules.remove(".DS_Store")
for m in DefaultEnabledModules:
modules.remove(m)
# Get 2**len(modules) combinatorical combinations of ON/OFF
settings = []
for args in product(*repeat(("ON", "OFF"), len(modules))):
settings.append(args)
# Remove the first (all modules enabled) and the last (no modules enabled)
# as we have those version separately
settings = settings[1:-1]
# Create all commands
cmds = []
for s in settings:
cmd = Command()
cmd.command = ["cmake", "-DGHOUL_USE_DEVIL=NO"]
for m in DefaultEnabledModules:
cmd.command.append("-DOPENSPACE_MODULE_" + m.upper() + "=ON")
for m,s in zip(modules, s):
cmd.command.append("-DOPENSPACE_MODULE_" + m.upper() + "=" + s)
if s == "ON":
# If a module is enabled, we get its dependencies and add them
# to the list
deps = getDependencies(m)
cmd.dependencies.append(deps)
cmd.enabledModules.append(m)
# First, we flatten the list of lists that we received before and then
# remove the duplicates by going through a set
cmd.dependencies = list(set([x for sl in cmd.dependencies for x in sl]))
cmd.command.append("..")
cmds.append(cmd)
for cmd in cmds:
# If 'enabledModules' is not a strict superset of 'dependencies'
# We have dependencies that are not enabled, so we shouldn't build
# this version
# if not set(cmd.enabledModules).issuperset(set(cmd.dependencies)):
d = set(cmd.dependencies)
m = set(cmd.enabledModules)
if d < m:
cmds.remove(cmd)
print("Number of builds:", len(cmds))
iter = 1
for cmd in cmds:
if random.random() > percentage:
print("Skipping build #", iter, "/", len(cmds))
iter = iter + 1
continue
print("Build #", iter, "/", len(cmds))
print("Cmd", cmd.command)
print("Deps", cmd.dependencies)
print("Mods", cmd.enabledModules)
print("")
iter = iter + 1
shutil.rmtree("build", ignore_errors=True)
shutil.rmtree("bin", ignore_errors=True)
os.makedirs("build")
os.chdir("build")
call(cmd)
call(["make"])
os.chdir("..")