1
0
mirror of https://github.com/openSUSE/osc.git synced 2024-09-20 09:16:16 +02:00

Merge pull request #1438 from dmach/conf-allow-undefined-fields

Allow undefined fields in Options and HostOptions
This commit is contained in:
Daniel Mach 2023-10-19 14:47:08 +02:00 committed by GitHub
commit 62349a39f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 2 deletions

View File

@ -124,6 +124,10 @@ HttpHeader = NewType("HttpHeader", Tuple[str, str])
class OscOptions(BaseModel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.extra_fields = {}
# compat function with the config dict
def _get_field_name(self, name):
if name in self.__fields__:
@ -139,8 +143,10 @@ class OscOptions(BaseModel):
# compat function with the config dict
def __getitem__(self, name):
field_name = self._get_field_name(name)
if field_name is None:
field_name = name
return self.extra_fields[name]
try:
return getattr(self, field_name)
except AttributeError:
@ -149,8 +155,11 @@ class OscOptions(BaseModel):
# compat function with the config dict
def __setitem__(self, name, value):
field_name = self._get_field_name(name)
if field_name is None:
field_name = name
self.extra_fields[name] = value
return
setattr(self, field_name, value)
# compat function with the config dict
@ -1836,6 +1845,17 @@ def get_config(override_conffile=None,
config = Options()
config.conffile = conffile
# read 'debug' value before it gets properly stored into Options for early debug messages
if override_debug:
debug_str = str(override_debug)
elif "OSC_DEBUG" in os.environ:
debug_str = os.environ["OSC_DEBUG"]
elif "debug" in cp["general"]:
debug_str = cp["general"]["debug"]
else:
debug_str = "0"
debug = True if debug_str.strip().lower() in ("1", "yes", "true", "on") else False
# read host options first in order to populate apiurl aliases
urls = [i for i in cp.sections() if i != "general"]
for url in urls:
@ -1845,8 +1865,10 @@ def get_config(override_conffile=None,
raise oscerr.ConfigMissingCredentialsError(f"No user found in section {url}", conffile, url)
host_options = HostOptions(apiurl=apiurl, username=username, _parent=config)
known_ini_keys = set()
for name, field in host_options.__fields__.items():
ini_key = field.extra.get("ini_key", name)
known_ini_keys.add(ini_key)
if name == "password":
# we need to handle the password first because it may be stored in a keyring instead of a config file
@ -1862,6 +1884,15 @@ def get_config(override_conffile=None,
host_options.set_value_from_string(name, value)
for key, value in cp[url].items():
if key.startswith("_"):
continue
if key in known_ini_keys:
continue
if debug:
print(f"DEBUG: Config option '[{url}]/{key}' doesn't map to any HostOptions field", file=sys.stderr)
host_options[key] = value
scheme = urlsplit(apiurl)[0]
if scheme == "http" and not host_options.allow_http:
msg = "The apiurl '{apiurl}' uses HTTP protocol without any encryption.\n"
@ -1872,8 +1903,10 @@ def get_config(override_conffile=None,
config.api_host_options[apiurl] = host_options
# read the main options
known_ini_keys = set()
for name, field in config.__fields__.items():
ini_key = field.extra.get("ini_key", name)
known_ini_keys.add(ini_key)
env_key = f"OSC_{name.upper()}"
# priority: env, overrides, config
@ -1900,6 +1933,15 @@ def get_config(override_conffile=None,
config.set_value_from_string(name, value)
for key, value in cp["general"].items():
if key.startswith("_"):
continue
if key in known_ini_keys:
continue
if debug:
print(f"DEBUG: Config option '[general]/{key}' doesn't map to any Options field", file=sys.stderr)
config[key] = value
if overrides:
unused_overrides_str = ", ".join((f"'{i}'" for i in overrides))
raise oscerr.ConfigError(f"Unknown config options: {unused_overrides_str}", "<command-line>")

View File

@ -78,6 +78,7 @@ maintained_update_project_attribute = OBS:UpdateProject
show_download_progress = 0
vc-cmd = /usr/lib/build/vc
status_mtime_heuristic = 0
plugin-option = plugin-general-option
[https://api.opensuse.org]
credentials_mgr_class=osc.credentials.PlaintextConfigFileCredentialsManager
@ -97,6 +98,7 @@ trusted_prj = openSUSE:* SUSE:*
downloadurl = http://example.com/
sshkey = ~/.ssh/id_rsa.pub
disable_hdrmd5_check = 0
plugin-option = plugin-host-option
"""
@ -401,6 +403,22 @@ class TestExampleConfig(unittest.TestCase):
host_options = self.config["api_host_options"][self.config["apiurl"]]
self.assertEqual(host_options["disable_hdrmd5_check"], False)
def test_extra_fields(self):
self.assertEqual(self.config["plugin-option"], "plugin-general-option")
self.assertEqual(self.config.extra_fields, {"plugin-option": "plugin-general-option"})
self.config["new-option"] = "value"
self.assertEqual(self.config["new-option"], "value")
self.assertEqual(self.config.extra_fields, {"plugin-option": "plugin-general-option", "new-option": "value"})
host_options = self.config["api_host_options"][self.config["apiurl"]]
self.assertEqual(host_options["plugin-option"], "plugin-host-option")
self.assertEqual(host_options.extra_fields, {"plugin-option": "plugin-host-option"})
host_options["new-option"] = "value"
self.assertEqual(host_options["new-option"], "value")
self.assertEqual(host_options.extra_fields, {"plugin-option": "plugin-host-option", "new-option": "value"})
class TestFromParent(unittest.TestCase):
def setUp(self):