aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCristián Maureira-Fredes <[email protected]>2024-12-12 12:53:05 +0100
committerCristián Maureira-Fredes <[email protected]>2024-12-18 10:08:01 +0100
commitb513d1e0ba84f997561f624c73ee54ab91581861 (patch)
tree200a3f6d4e0dbb1795e67a8d2626bb5c11cb0e05
parent45548b18a9e73012521a7b16a234e9689da0d9ab (diff)
build: options as a singleton
Avoid finding the dynamic options each time the OPTION dictionary was imported in the different build_scripts files. Now each setup.py invocation will have the same object. Pick-to: 6.8 Change-Id: Ic556d572e77e54fe27603332b7d2f99697eab86c Reviewed-by: Friedemann Kleint <[email protected]>
-rw-r--r--build_scripts/options.py157
-rw-r--r--build_scripts/utils.py14
-rw-r--r--coin/instructions_utils.py30
3 files changed, 105 insertions, 96 deletions
diff --git a/build_scripts/options.py b/build_scripts/options.py
index 7a03afbfe..f20e79167 100644
--- a/build_scripts/options.py
+++ b/build_scripts/options.py
@@ -10,7 +10,7 @@ from pathlib import Path
from .log import log, LogLevel
from .qtinfo import QtInfo
-from .utils import memoize, which
+from .utils import memoize, which, Singleton
_AVAILABLE_MKSPECS = ["ninja", "msvc", "mingw"] if sys.platform == "win32" else ["ninja", "make"]
@@ -41,7 +41,7 @@ def _warn_deprecated_option(option, replacement=None):
log.warning(w)
-class Options(object):
+class Options(object, metaclass=Singleton):
def __init__(self):
# Dictionary containing values of all the possible options.
@@ -103,86 +103,82 @@ class Options(object):
self.dict[name] = value
return value
+ def find_qtpaths(self):
+ # Skip the first run that will trigger the three different build
+ # stated of the setup process
+ if self.dict["internal-build-type"] is None:
+ return None
+ # for these command --qtpaths should not be required
+ no_qtpaths_commands = ["--help", "--help-commands", "--qt-target-path", "build_base_docs"]
-options = Options()
-
-
-def has_option(*args, **kwargs):
- return options.has_option(*args, **kwargs)
-
-
-def option_value(*args, **kwargs):
- return options.option_value(*args, **kwargs)
-
+ for no_qtpaths_command in no_qtpaths_commands:
+ if any(no_qtpaths_command in argument for argument in sys.argv):
+ return None
-def _jobs_option_value():
- """Option value for parallel builds."""
- value = option_value('parallel', short_option_name='j')
- if value:
- return f"-j{value}" if not value.startswith('-j') else value
- return ''
+ qtpaths = self.option_value("qtpaths")
+ if qtpaths is not None:
+ return qtpaths
+ # if qtpaths is not given as cli option, try to find it in PATH
+ qtpaths = which("qtpaths6")
+ if qtpaths is not None:
+ return str(Path(qtpaths).resolve())
-def find_qtpaths():
- # for these command --qtpaths should not be required
- no_qtpaths_commands = ["--help", "--help-commands", "--qt-target-path", "build_base_docs"]
+ qtpaths = which("qtpaths")
+ if qtpaths is not None:
+ return str(Path(qtpaths).resolve())
- for no_qtpaths_command in no_qtpaths_commands:
- if any(no_qtpaths_command in argument for argument in sys.argv):
- return None
+ if qtpaths is None:
+ sys.exit(-1)
- qtpaths = option_value("qtpaths")
- if qtpaths:
return qtpaths
- # if qtpaths is not given as cli option, try to find it in PATH
- qtpaths = which("qtpaths6")
- if qtpaths:
- return str(qtpaths.resolve())
-
- qtpaths = which("qtpaths")
- if qtpaths:
- return str(qtpaths.resolve())
-
- return qtpaths
-
-
-# Declare options which need to be known when instantiating the setuptools
-# commands or even earlier during SetupRunner.run().
-OPTION = {
- "BUILD_TYPE": option_value("build-type"),
- "INTERNAL_BUILD_TYPE": option_value("internal-build-type"),
- # number of parallel build jobs
- "JOBS": _jobs_option_value(),
- # Legacy, not used any more.
- "JOM": has_option('jom'),
- "MACOS_USE_LIBCPP": has_option("macos-use-libc++"),
- "LOG_LEVEL": option_value("log-level", remove=False),
- "QUIET": has_option('quiet'),
- "VERBOSE_BUILD": has_option('verbose-build'),
- "SNAPSHOT_BUILD": has_option("snapshot-build"),
- "LIMITED_API": option_value("limited-api"),
- "UNOPTIMIZE": option_value("unoptimize"),
- "DISABLE_PYI": has_option("disable-pyi"),
- "SKIP_MYPY_TEST": has_option("skip-mypy-test"),
- "PACKAGE_TIMESTAMP": option_value("package-timestamp"),
- # This is used automatically by setuptools.command.install object, to
- # specify the final installation location.
- "FINAL_INSTALL_PREFIX": option_value("prefix", remove=False),
- "CMAKE_TOOLCHAIN_FILE": option_value("cmake-toolchain-file"),
- "SHIBOKEN_HOST_PATH": option_value("shiboken-host-path"),
- "SHIBOKEN_HOST_PATH_QUERY_FILE": option_value("internal-shiboken-host-path-query-file"),
- "QT_HOST_PATH": option_value("qt-host-path"),
- # This is used to identify the template for doc builds
- "QTPATHS": find_qtpaths()
- # This is an optional command line option. If --qtpaths is not provided via command-line,
- # then qtpaths is checked inside PATH variable
-}
-
-_deprecated_option_jobs = option_value('jobs')
-if _deprecated_option_jobs:
- _warn_deprecated_option('jobs', 'parallel')
- OPTION["JOBS"] = _deprecated_option_jobs
+ def _jobs_option_value(self):
+ """Option value for parallel builds."""
+ value = self.option_value('parallel', short_option_name='j')
+
+ _deprecated_option_jobs = self.option_value('jobs')
+ if _deprecated_option_jobs:
+ _warn_deprecated_option('jobs', 'parallel')
+ value = _deprecated_option_jobs
+
+ if value:
+ return f"-j{value}" if not value.startswith('-j') else value
+ return ''
+
+ def resolve(self):
+ return {
+ "BUILD_TYPE": self.option_value("build-type"),
+ "INTERNAL_BUILD_TYPE": self.option_value("internal-build-type"),
+ # number of parallel build jobs
+ "JOBS": self._jobs_option_value(),
+ # Legacy, not used any more.
+ "JOM": self.has_option('jom'),
+ "MACOS_USE_LIBCPP": self.has_option("macos-use-libc++"),
+ "LOG_LEVEL": self.option_value("log-level", remove=False),
+ "QUIET": self.has_option('quiet'),
+ "VERBOSE_BUILD": self.has_option('verbose-build'),
+ "SNAPSHOT_BUILD": self.has_option("snapshot-build"),
+ "LIMITED_API": self.option_value("limited-api"),
+ "UNOPTIMIZE": self.option_value("unoptimize"),
+ "DISABLE_PYI": self.has_option("disable-pyi"),
+ "SKIP_MYPY_TEST": self.has_option("skip-mypy-test"),
+ "PACKAGE_TIMESTAMP": self.option_value("package-timestamp"),
+ # This is used automatically by setuptools.command.install object, to
+ # specify the final installation location.
+ "FINAL_INSTALL_PREFIX": self.option_value("prefix", remove=False),
+ "CMAKE_TOOLCHAIN_FILE": self.option_value("cmake-toolchain-file"),
+ "SHIBOKEN_HOST_PATH": self.option_value("shiboken-host-path"),
+ "SHIBOKEN_HOST_PATH_QUERY_FILE": self.option_value(
+ "internal-shiboken-host-path-query-file"
+ ),
+ "QT_HOST_PATH": self.option_value("qt-host-path"),
+ # This is used to identify the template for doc builds
+ "QTPATHS": self.find_qtpaths()
+ # This is an optional command line option.
+ # If --qtpaths is not provided via command-line,
+ # then qtpaths is checked inside PATH variable
+ }
class CommandMixin(object):
@@ -499,12 +495,11 @@ class CommandMixin(object):
except Exception as e:
if not self.qt_target_path:
log.error(
- "\nCould not find Qt. You can pass the --qt-target-path=<qt-dir> option "
- "as a hint where to find Qt. Error was:\n\n\n")
+ "Could not find Qt. You can pass the --qt-target-path=<qt-dir> option "
+ "as a hint where to find Qt.\n")
else:
- log.error(
- f"\nCould not find Qt via provided option --qt-target-path={qt_target_path}"
- "Error was:\n\n\n")
+ log.error("Could not find Qt via provided option "
+ f"--qt-target-path={qt_target_path}\n")
raise e
OPTION['CMAKE'] = self.cmake.resolve()
@@ -629,3 +624,7 @@ class CommandMixin(object):
return False
return True
+
+
+# OPTION dictionary that will be imported in other build_scripts
+OPTION = Options().resolve()
diff --git a/build_scripts/utils.py b/build_scripts/utils.py
index 43ff9e003..9d021c81d 100644
--- a/build_scripts/utils.py
+++ b/build_scripts/utils.py
@@ -29,6 +29,15 @@ except NameError:
WindowsError = None
+class Singleton(type):
+ _instances = {}
+
+ def __call__(cls, *args, **kwargs):
+ if cls not in cls._instances:
+ cls._instances[cls] = super().__call__(*args, **kwargs)
+ return cls._instances[cls]
+
+
def which(name):
"""
Like shutil.which, but accepts a string or a PathLike and returns a Path
@@ -38,9 +47,8 @@ def which(name):
if isinstance(name, Path):
name = str(name)
path = shutil.which(name)
- if path is None:
- raise TypeError("None was returned")
- path = Path(path)
+ if path is not None:
+ path = Path(path)
except TypeError as e:
log.error(f"{name} was not found in PATH: {e}")
return path
diff --git a/coin/instructions_utils.py b/coin/instructions_utils.py
index f8ea5a593..176a6d225 100644
--- a/coin/instructions_utils.py
+++ b/coin/instructions_utils.py
@@ -9,33 +9,35 @@ import site
import sys
from pathlib import Path
-from build_scripts.options import has_option, option_value
+from build_scripts.options import Options
from build_scripts.utils import (parse_cmake_conf_assignments_by_key,
remove_tree, run_instruction)
+options = Options()
+
class CI:
def __init__(self):
# Values must match COIN thrift
- self.HOST_OS = option_value("os")
- self.TARGET_OS = option_value("targetOs")
- self.HOST_ARCH = option_value("hostArch")
- self.TARGET_ARCH = option_value("targetArch")
- self.HOST_OS_VER = option_value("osVer")
- self.ENV_INSTALL_DIR = option_value("instdir")
- self.ENV_AGENT_DIR = option_value("agentdir") or "."
- self.COMPILER = option_value("compiler")
- self.USE_SCCACHE = option_value("compiler-launcher")
- self.INTEGRATION_ID = option_value("coinIntegrationId") or str(
+ self.HOST_OS = options.option_value("os")
+ self.TARGET_OS = options.option_value("targetOs")
+ self.HOST_ARCH = options.option_value("hostArch")
+ self.TARGET_ARCH = options.option_value("targetArch")
+ self.HOST_OS_VER = options.option_value("osVer")
+ self.ENV_INSTALL_DIR = options.option_value("instdir")
+ self.ENV_AGENT_DIR = options.option_value("agentdir") or "."
+ self.COMPILER = options.option_value("compiler")
+ self.USE_SCCACHE = options.option_value("compiler-launcher")
+ self.INTEGRATION_ID = options.option_value("coinIntegrationId") or str(
calendar.timegm(datetime.datetime.now().timetuple())
)
self.FEATURES = []
- _ci_features = option_value("features")
+ _ci_features = options.option_value("features")
if _ci_features is not None:
for f in _ci_features.split(", "):
self.FEATURES.append(f)
- self.RELEASE_CONF = has_option("packaging")
- self.TEST_PHASE = option_value("phase")
+ self.RELEASE_CONF = options.has_option("packaging")
+ self.TEST_PHASE = options.option_value("phase")
if self.TEST_PHASE not in ["ALL", "BUILD"]:
self.TEST_PHASE = "ALL"