build-and-test: Allow flags to be read from files
Use the built-in support from the argparse module to allow our
subcommand to read flags from configuration files.
This is achieved by specifying a prefix (in our case '@') that indicates
to argparse that it should read arguments from the file ('@filepath'),
one per line.
They are then processed as if they had been given on the command line in
the position where the filename is. This makes it possible for flags in
the file to override or be overriden by flags given on the command line,
depending on their position relative to the filename. Flags that
accumulate all the values that they receive cannot be overriden, but
will instead accumulate everything regardless of whether it came from
the command line or the file.
Change-Id: I22a9a92a0f5ba49dd085ef5860c37bd4fc1009e1
diff --git a/tests/cli/testbuildandtest.py b/tests/cli/testbuildandtest.py
index 86e2203..fe879a2 100644
--- a/tests/cli/testbuildandtest.py
+++ b/tests/cli/testbuildandtest.py
@@ -5,6 +5,7 @@
"""
import os
+from tempfile import NamedTemporaryFile
from llvmtestcase import LLVMTestCase, require_command_arg, debug
@@ -15,6 +16,13 @@
def llvm_build_and_test(cls, *args, **kwargs):
return cls.command_with_defaults("build-and-test", *args, **kwargs)
+ @classmethod
+ def get_temp_file_with_content(cls, content):
+ """Return a temporary file with the given content."""
+ theFile = NamedTemporaryFile(mode='wt')
+ print(content, file=theFile, flush=True)
+ return theFile
+
def test_default_stage1(self):
"""
Test that we dump the correct commands for a single stage build of LLVM.
@@ -393,3 +401,100 @@
"--sandbox={sandbox} --test-suite={testsuite} "
"--use-lit={build}/bin/llvm-lit --cc={build}/bin/clang".format(
sandbox=sandboxDir, testsuite=testSuiteDir, build=buildDir2))
+
+ def test_read_flags_from_file(self):
+ """Test that we can read our flags from a configuration file."""
+ reposDir = "path-to-repos"
+ sourceDir = "path-to-sources"
+ buildDir = "path-to-stage1"
+
+ flagsInFile = ("--dry-run\n"
+ "--repos-dir\n"
+ "{repos}\n"
+ "--source-dir\n"
+ "{sources}\n"
+ "--stage1-build-dir\n"
+ "{build}").format(
+ repos=reposDir, sources=sourceDir, build=buildDir)
+
+ with self.get_temp_file_with_content(flagsInFile) as configFile:
+ output = self.run_with_output(
+ self.llvm_build_and_test("@{}".format(configFile.name)))
+
+ commands = output.splitlines()
+
+ self.assertRegex(commands[0],
+ "{build}\$ cmake -G Ninja .* {sources}".format(
+ build=buildDir, sources=sourceDir))
+
+ self.assertRegex(commands[1],
+ "{build}\$ ninja".format(build=buildDir))
+
+ def test_override_flags_from_file(self):
+ """
+ Test that we can combine flags from a configuration file and command
+ line flags. The command line flags that come before the name of the
+ configuration file should be overriden by those from the file, whereas
+ command line flags that come after the name of the configuration file
+ should override the values found in the file. For arguments that can be
+ passed multiple times, all the values are collected (both from the
+ command line and from the config file). They should however appear in
+ the order that they were given.
+ """
+ reposDir = "path-to-repos"
+ sourceDir = "path-to-sources"
+ buildDir = "path-to-stage1"
+
+ overridenSourceDir = "overriden-sources"
+ overridenBuildDir = "overriden-build"
+
+ flagsInFile = (
+ "--dry-run\n"
+ "--repos-dir\n"
+ "{repos}\n"
+ "--source-dir\n"
+ "{sources}\n"
+ "--stage1-build-dir\n"
+ "{build}\n"
+ "--stage1-subproject\n"
+ "clang\n"
+ "--stage1-cmake-def\n"
+ "CMAKE_CXX_FLAGS=-mthumb").format(repos=reposDir, sources=sourceDir,
+ build=overridenBuildDir)
+
+ with self.get_temp_file_with_content(flagsInFile) as configFile:
+ output = self.run_with_output(
+ self.llvm_build_and_test(
+ # This should be overriden by the value in the config file.
+ "--source-dir", overridenSourceDir,
+ # This should be appended to the value in the config file.
+ "--stage1-subproject", "lld",
+ # The config file.
+ "@{}".format(configFile.name),
+ # This should override the value in the config file.
+ "--stage1-build-dir", buildDir,
+ # These should be appended to the values in the config file.
+ "--stage1-subproject", "compiler-rt",
+ "--stage1-cmake-def", "CMAKE_CXX_FLAGS=-marm",
+ "--stage1-cmake-def", "LLVM_ENABLE_ASSERTIONS=True"))
+
+ commands = output.splitlines()
+
+ self.assertRegex(commands[0],
+ "{build}\$ cmake -G Ninja .* {sources}".format(
+ build=buildDir, sources=sourceDir))
+
+ self.assertIn("-DLLVM_TOOL_CLANG_BUILD=ON", commands[0])
+ self.assertIn("-DLLVM_TOOL_LLD_BUILD=ON", commands[0])
+ self.assertIn("-DLLVM_TOOL_COMPILER_RT_BUILD=ON", commands[0])
+ self.assertIn("-DLLVM_TOOL_LIBCXX_BUILD=OFF", commands[0])
+ self.assertIn("-DLLVM_TOOL_LLDB_BUILD=OFF", commands[0])
+
+ self.assertIn("-DCMAKE_CXX_FLAGS=-marm", commands[0])
+ self.assertIn("-DCMAKE_CXX_FLAGS=-mthumb", commands[0])
+ self.assertLess(commands[0].find("-DCMAKE_CXX_FLAGS=-mthumb"),
+ commands[0].find("-DCMAKE_CXX_FLAGS=-marm"))
+ self.assertIn("-DLLVM_ENABLE_ASSERTIONS=True", commands[0])
+
+ self.assertRegex(commands[1],
+ "{build}\$ ninja".format(build=buildDir))