Compare commits

...

3 Commits

16 changed files with 74 additions and 52 deletions

View File

@ -57,7 +57,7 @@ class ConfigurationMultiDict(dict[str, Any]):
OptionError: if the key already exists in the dictionary, but not a single value list or a string OptionError: if the key already exists in the dictionary, but not a single value list or a string
""" """
match self.get(key): match self.get(key):
case [current_value] | str(current_value): case [current_value] | (str() as current_value):
value = f"{current_value} {value}" value = f"{current_value} {value}"
case None: case None:
pass pass

View File

@ -47,6 +47,7 @@ class LogsRotationTrigger(Trigger):
}, },
}, },
} }
REQUIRES_REPOSITORY = True
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None: def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:
""" """

View File

@ -336,6 +336,7 @@ class ReportTrigger(Trigger):
}, },
}, },
} }
REQUIRES_REPOSITORY = True
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None: def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:
""" """

View File

@ -103,6 +103,7 @@ class KeyringTrigger(Trigger):
}, },
}, },
} }
REQUIRES_REPOSITORY = True
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None: def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:
""" """

View File

@ -90,6 +90,7 @@ class MirrorlistTrigger(Trigger):
}, },
}, },
} }
REQUIRES_REPOSITORY = True
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None: def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:
""" """

View File

@ -36,6 +36,7 @@ class Trigger(LazyLogging):
CONFIGURATION_SCHEMA(ConfigurationSchema): (class attribute) configuration schema template CONFIGURATION_SCHEMA(ConfigurationSchema): (class attribute) configuration schema template
CONFIGURATION_SCHEMA_FALLBACK(str | None): (class attribute) optional fallback option for defining CONFIGURATION_SCHEMA_FALLBACK(str | None): (class attribute) optional fallback option for defining
configuration schema type used configuration schema type used
REQUIRES_REPOSITORY(bool): (class attribute) either trigger requires loaded repository or not
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
repository_id(RepositoryId): repository unique identifier repository_id(RepositoryId): repository unique identifier
@ -59,6 +60,7 @@ class Trigger(LazyLogging):
CONFIGURATION_SCHEMA: ClassVar[ConfigurationSchema] = {} CONFIGURATION_SCHEMA: ClassVar[ConfigurationSchema] = {}
CONFIGURATION_SCHEMA_FALLBACK: ClassVar[str | None] = None CONFIGURATION_SCHEMA_FALLBACK: ClassVar[str | None] = None
REQUIRES_REPOSITORY: ClassVar[bool] = True
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None: def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:
""" """
@ -79,6 +81,16 @@ class Trigger(LazyLogging):
""" """
return self.repository_id.architecture return self.repository_id.architecture
@property
def is_allowed_to_run(self) -> bool:
"""
whether trigger allowed to run or not
Returns:
bool: ``True`` in case if trigger allowed to run and ``False`` otherwise
"""
return not (self.REQUIRES_REPOSITORY and self.repository_id.is_empty)
@classmethod @classmethod
def configuration_schema(cls, configuration: Configuration | None) -> ConfigurationSchema: def configuration_schema(cls, configuration: Configuration | None) -> ConfigurationSchema:
""" """

View File

@ -77,8 +77,9 @@ class TriggerLoader(LazyLogging):
""" """
instance = cls() instance = cls()
instance.triggers = [ instance.triggers = [
instance.load_trigger(trigger, repository_id, configuration) trigger
for trigger in instance.selected_triggers(configuration) for trigger_name in instance.selected_triggers(configuration)
if (trigger := instance.load_trigger(trigger_name, repository_id, configuration)).is_allowed_to_run
] ]
return instance return instance

View File

@ -160,6 +160,7 @@ class UploadTrigger(Trigger):
}, },
}, },
} }
REQUIRES_REPOSITORY = True
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None: def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:
""" """

View File

@ -7,6 +7,13 @@ from ahriman.core.status import Client
from ahriman.models.result import Result from ahriman.models.result import Result
def test_requires_repository() -> None:
"""
must require repository identifier to be set to start
"""
assert LogsRotationTrigger.REQUIRES_REPOSITORY
def test_configuration_sections(configuration: Configuration) -> None: def test_configuration_sections(configuration: Configuration) -> None:
""" """
must correctly parse target list must correctly parse target list

View File

@ -5,6 +5,13 @@ from ahriman.core.report import ReportTrigger
from ahriman.models.result import Result from ahriman.models.result import Result
def test_requires_repository() -> None:
"""
must require repository identifier to be set to start
"""
assert ReportTrigger.REQUIRES_REPOSITORY
def test_configuration_sections(configuration: Configuration) -> None: def test_configuration_sections(configuration: Configuration) -> None:
""" """
must correctly parse target list must correctly parse target list

View File

@ -7,6 +7,13 @@ from ahriman.core.sign.gpg import GPG
from ahriman.core.support import KeyringTrigger from ahriman.core.support import KeyringTrigger
def test_requires_repository() -> None:
"""
must require repository identifier to be set to start
"""
assert KeyringTrigger.REQUIRES_REPOSITORY
def test_configuration_sections(configuration: Configuration) -> None: def test_configuration_sections(configuration: Configuration) -> None:
""" """
must correctly parse target list must correctly parse target list

View File

@ -4,6 +4,13 @@ from ahriman.core.configuration import Configuration
from ahriman.core.support import MirrorlistTrigger from ahriman.core.support import MirrorlistTrigger
def test_requires_repository() -> None:
"""
must require repository identifier to be set to start
"""
assert MirrorlistTrigger.REQUIRES_REPOSITORY
def test_configuration_sections(configuration: Configuration) -> None: def test_configuration_sections(configuration: Configuration) -> None:
""" """
must correctly parse target list must correctly parse target list

View File

@ -3,6 +3,7 @@ from unittest.mock import MagicMock
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.report import ReportTrigger from ahriman.core.report import ReportTrigger
from ahriman.core.triggers import Trigger from ahriman.core.triggers import Trigger
from ahriman.models.repository_id import RepositoryId
from ahriman.models.result import Result from ahriman.models.result import Result
@ -13,6 +14,19 @@ def test_architecture(trigger: Trigger) -> None:
assert trigger.architecture == trigger.repository_id.architecture assert trigger.architecture == trigger.repository_id.architecture
def test_is_allowed_to_run(trigger: Trigger) -> None:
"""
must return flag correctly
"""
assert trigger.is_allowed_to_run
trigger.repository_id = RepositoryId("", "")
assert not trigger.is_allowed_to_run
trigger.REQUIRES_REPOSITORY = False
assert trigger.is_allowed_to_run
def test_configuration_schema(configuration: Configuration) -> None: def test_configuration_schema(configuration: Configuration) -> None:
""" """
must return used configuration schema must return used configuration schema

View File

@ -5,6 +5,13 @@ from ahriman.core.upload import UploadTrigger
from ahriman.models.result import Result from ahriman.models.result import Result
def test_requires_repository() -> None:
"""
must require repository identifier to be set to start
"""
assert UploadTrigger.REQUIRES_REPOSITORY
def test_configuration_sections(configuration: Configuration) -> None: def test_configuration_sections(configuration: Configuration) -> None:
""" """
must correctly parse target list must correctly parse target list

View File

@ -140,8 +140,6 @@ dynamic_version = "{[project]name}.__version__"
extras = [ extras = [
{ replace = "ref", of = ["project", "extras"], extend = true }, { replace = "ref", of = ["project", "extras"], extend = true },
] ]
# TODO: steamline shlex usage after https://github.com/iterative/shtab/pull/192 merge
handle_redirect = true
pip_pre = true pip_pre = true
set_env.PYTHONPATH = "src" set_env.PYTHONPATH = "src"
set_env.SPHINX_APIDOC_OPTIONS = "members,no-undoc-members,show-inheritance" set_env.SPHINX_APIDOC_OPTIONS = "members,no-undoc-members,show-inheritance"
@ -149,18 +147,14 @@ commands = [
[ [
"shtab", "shtab",
{ replace = "ref", of = ["flags", "shtab"], extend = true }, { replace = "ref", of = ["flags", "shtab"], extend = true },
"--shell", "--shell", "bash",
"bash", "--output", "package/share/bash-completion/completions/_ahriman",
">",
"package/share/bash-completion/completions/_ahriman",
], ],
[ [
"shtab", "shtab",
{ replace = "ref", of = ["flags", "shtab"], extend = true }, { replace = "ref", of = ["flags", "shtab"], extend = true },
"--shell", "--shell", "zsh",
"zsh", "--output", "package/share/zsh/site-functions/_ahriman",
">",
"package/share/zsh/site-functions/_ahriman",
], ],
[ [
"argparse-manpage", "argparse-manpage",

View File

@ -18,11 +18,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
import importlib import importlib
import shlex
import sys import sys
from tox.config.sets import EnvConfigSet from tox.config.sets import EnvConfigSet
from tox.config.types import Command
from tox.plugin import impl from tox.plugin import impl
from tox.session.state import State from tox.session.state import State
from tox.tox_env.api import ToxEnv from tox.tox_env.api import ToxEnv
@ -56,35 +54,6 @@ def _extract_version(env_conf: EnvConfigSet, python_path: str | None = None) ->
return {"VERSION": version} return {"VERSION": version}
def _wrap_commands(env_conf: EnvConfigSet, shell: str = "bash") -> None:
"""
wrap commands into shell if there is redirect
Args:
env_conf(EnvConfigSet): the core configuration object
shell(str, optional): shell command to use (Default value = "bash")
"""
if not env_conf["handle_redirect"]:
return
# append shell just in case
env_conf["allowlist_externals"].append(shell)
for command in env_conf["commands"]:
if len(command.args) < 3: # command itself, redirect and output
continue
redirect, output = command.args[-2:]
if redirect not in (">", "2>", "&>"):
continue
command.args = [
shell,
"-c",
f"{Command(command.args[:-2]).shell} {redirect} {shlex.quote(output)}",
]
@impl @impl
def tox_add_env_config(env_conf: EnvConfigSet, state: State) -> None: def tox_add_env_config(env_conf: EnvConfigSet, state: State) -> None:
""" """
@ -103,12 +72,6 @@ def tox_add_env_config(env_conf: EnvConfigSet, state: State) -> None:
default="", default="",
desc="import path for the version variable", desc="import path for the version variable",
) )
env_conf.add_config(
keys=["handle_redirect"],
of_type=bool,
default=False,
desc="wrap commands to handle redirects if any",
)
@impl @impl
@ -124,5 +87,3 @@ def tox_before_run_commands(tox_env: ToxEnv) -> None:
python_path = set_env.load("PYTHONPATH") if "PYTHONPATH" in set_env else None python_path = set_env.load("PYTHONPATH") if "PYTHONPATH" in set_env else None
set_env.update(_extract_version(env_conf, python_path)) set_env.update(_extract_version(env_conf, python_path))
_wrap_commands(env_conf)