Skip to content

Commit 2f41080

Browse files
committed
Load global config if the local one does not exist
1 parent 1ab48bc commit 2f41080

File tree

4 files changed

+46
-21
lines changed

4 files changed

+46
-21
lines changed

tmt/cli/_root.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1896,7 +1896,7 @@ def setup_completion(shell: str, install: bool, context: Context, logger: tmt.lo
18961896
script = Path('~/.config/fish/completions/tmt.fish').expanduser()
18971897
# Bash and zsh get installed to tmt's config directory.
18981898
else:
1899-
script = Path(config.path) / f'{COMPLETE_SCRIPT}.{shell}'
1899+
script = Path(config.user_path) / f'{COMPLETE_SCRIPT}.{shell}'
19001900

19011901
env_var = {COMPLETE_VARIABLE: f'{shell}_source'}
19021902

tmt/config/__init__.py

+40-18
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@
1717

1818
MetadataContainerT = TypeVar('MetadataContainerT', bound='MetadataContainer')
1919

20-
# Config directory
21-
DEFAULT_CONFIG_DIR = Path('~/.config/tmt')
20+
# Config directories
21+
DEFAULT_USER_CONFIG_DIR = Path('~/.config/tmt')
22+
DEFAULT_GLOBAL_CONFIG_DIR = Path('/etc/tmt/config')
2223

2324

24-
def effective_config_dir() -> Path:
25+
def _effective_user_config_dir() -> Path:
2526
"""
2627
Find out what the actual config directory is.
2728
@@ -32,7 +33,7 @@ def effective_config_dir() -> Path:
3233
if 'TMT_CONFIG_DIR' in os.environ:
3334
return Path(os.environ['TMT_CONFIG_DIR']).expanduser()
3435

35-
return DEFAULT_CONFIG_DIR.expanduser()
36+
return DEFAULT_USER_CONFIG_DIR.expanduser()
3637

3738

3839
class Config:
@@ -45,17 +46,21 @@ def __init__(self, logger: tmt.log.Logger) -> None:
4546
Initialize config directory path
4647
"""
4748

48-
self.path = effective_config_dir()
4949
self.logger = logger
5050

51+
self.user_path = _effective_user_config_dir()
52+
self.global_path = DEFAULT_GLOBAL_CONFIG_DIR
53+
5154
try:
52-
self.path.mkdir(parents=True, exist_ok=True)
55+
self.user_path.mkdir(parents=True, exist_ok=True)
5356
except OSError as error:
54-
raise tmt.utils.GeneralError(f"Failed to create config '{self.path}'.") from error
57+
raise tmt.utils.GeneralError(
58+
f"Failed to create user config path '{self.user_path}'."
59+
) from error
5560

5661
@property
5762
def _last_run_symlink(self) -> Path:
58-
return self.path / 'last-run'
63+
return self.user_path / 'last-run'
5964

6065
@property
6166
def last_run(self) -> Optional[Path]:
@@ -83,31 +88,48 @@ def last_run(self, workdir: Path) -> None:
8388
"'tmt run --last' might not pick the right run directory."
8489
)
8590
except OSError as error:
86-
raise tmt.utils.GeneralError(f"Unable to save last run '{self.path}'.\n{error}")
91+
raise tmt.utils.GeneralError(f"Unable to save last run '{self.user_path}'.") from error
8792

8893
@functools.cached_property
89-
def fmf_tree(self) -> Optional[fmf.Tree]:
94+
def _fmf_tree(self) -> tuple[Optional[Path], Optional[fmf.Tree]]:
95+
try:
96+
return (self.user_path, fmf.Tree(self.user_path))
97+
98+
except (fmf.utils.FileError, fmf.utils.RootError):
99+
self.logger.debug(f"Config tree not found in user path '{self.user_path}'.")
100+
101+
try:
102+
return (self.global_path, fmf.Tree(self.global_path))
103+
104+
except (fmf.utils.FileError, fmf.utils.RootError):
105+
self.logger.debug(f"Config tree not found in global path '{self.global_path}'.")
106+
107+
return None, None
108+
109+
@functools.cached_property
110+
def tree(self) -> Optional[fmf.Tree]:
90111
"""
91112
Return the configuration tree
92113
"""
93114

94-
try:
95-
return fmf.Tree(self.path)
96-
except fmf.utils.RootError:
97-
self.logger.debug(f"Config tree not found in '{self.path}'.")
115+
return self._fmf_tree[1]
98116

99-
return None
117+
@functools.cached_property
118+
def tree_location(self) -> Path:
119+
path, _ = self._fmf_tree
120+
121+
return path if path is not None else self.global_path
100122

101123
def _parse_config_subtree(
102124
self, path: str, model: type[MetadataContainerT]
103125
) -> Optional[MetadataContainerT]:
104-
if self.fmf_tree is None:
126+
if self.tree is None:
105127
return None
106128

107-
subtree = cast(Optional[fmf.Tree], self.fmf_tree.find(path))
129+
subtree = cast(Optional[fmf.Tree], self.tree.find(path))
108130

109131
if not subtree:
110-
self.logger.debug(f"Config path '{path}' not found in '{self.path}'.")
132+
self.logger.debug(f"Config path '{path}' not found in '{self.tree_location}'.")
111133

112134
return None
113135

tmt/templates/__init__.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33

44
import tmt
55
import tmt.config
6+
import tmt.log
67
import tmt.utils
78
import tmt.utils.templates
89
from tmt.utils import Path
910

10-
DEFAULT_CUSTOM_TEMPLATES_PATH = tmt.config.effective_config_dir() / 'templates'
11+
DEFAULT_CUSTOM_TEMPLATES_PATH = (
12+
tmt.config.Config(tmt.log.Logger.get_bootstrap_logger()).user_path / 'templates'
13+
)
1114
DEFAULT_PLAN_NAME = "/default/plan"
1215
INIT_TEMPLATES = ['mini', 'base', 'full']
1316
TEMPLATE_FILE_SUFFIX = '.j2'

tmt/trying.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ def get_default_plans(self, run: tmt.base.Run) -> list[Plan]:
208208
# Check user config for custom default plans. Search for all
209209
# plans starting with the default user plan name (there might be
210210
# more than just one).
211-
config_tree = tmt.config.Config(self._logger).fmf_tree
211+
config_tree = tmt.config.Config(self._logger).tree
212212
if config_tree is not None:
213213
plan_name = re.escape(USER_PLAN_NAME)
214214
# cast: once fmf is properly annotated, cast() would not be needed.

0 commit comments

Comments
 (0)