mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-07-15 06:55:48 +00:00
allow to use multiple upload and report targets with the same name
In this feature target option must allways point to section name instead of type. Type will be read from type option. In case if type option is not presented it will try to check if section with architecture exists (e.g. target = email, section = email:x86_64); if it does, the correct section name and type will be used. Otherwise it will check if the specified section exists; if it does, seection name and type will be returned.
This commit is contained in:
@ -24,7 +24,7 @@ import logging
|
||||
|
||||
from logging.config import fileConfig
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional, Type
|
||||
from typing import Any, Dict, List, Optional, Tuple, Type
|
||||
|
||||
from ahriman.core.exceptions import InitializeException
|
||||
|
||||
@ -42,7 +42,7 @@ class Configuration(configparser.RawConfigParser):
|
||||
DEFAULT_LOG_FORMAT = "[%(levelname)s %(asctime)s] [%(filename)s:%(lineno)d] [%(funcName)s]: %(message)s"
|
||||
DEFAULT_LOG_LEVEL = logging.DEBUG
|
||||
|
||||
ARCHITECTURE_SPECIFIC_SECTIONS = ["build", "html", "rsync", "s3", "sign", "web"]
|
||||
ARCHITECTURE_SPECIFIC_SECTIONS = ["build", "sign", "web"]
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""
|
||||
@ -121,6 +121,26 @@ class Configuration(configparser.RawConfigParser):
|
||||
|
||||
def getpath(self, *args: Any, **kwargs: Any) -> Path: ...
|
||||
|
||||
def gettype(self, section: str, architecture: str) -> Tuple[str, str]:
|
||||
"""
|
||||
get type variable with fallback to old logic
|
||||
Despite the fact that it has same semantics as other get* methods, but it has different argument list
|
||||
:param section: section name
|
||||
:param architecture: repository architecture
|
||||
:return: section name and found type name
|
||||
"""
|
||||
group_type = self.get(section, "type", fallback=None) # new-style logic
|
||||
if group_type is not None:
|
||||
return section, group_type
|
||||
# okay lets check for the section with architecture name
|
||||
full_section = self.section_name(section, architecture)
|
||||
if self.has_section(full_section):
|
||||
return full_section, section
|
||||
# okay lets just use section as type
|
||||
if not self.has_section(section):
|
||||
raise configparser.NoSectionError(section)
|
||||
return section, section
|
||||
|
||||
def load(self, path: Path) -> None:
|
||||
"""
|
||||
fully load configuration
|
||||
|
@ -45,27 +45,28 @@ class Email(Report, JinjaTemplate):
|
||||
:ivar user: username to authenticate via SMTP
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
def __init__(self, architecture: str, configuration: Configuration, section: str) -> None:
|
||||
"""
|
||||
default constructor
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param section: settings section name
|
||||
"""
|
||||
Report.__init__(self, architecture, configuration)
|
||||
JinjaTemplate.__init__(self, "email", configuration)
|
||||
JinjaTemplate.__init__(self, section, configuration)
|
||||
|
||||
self.full_template_path = configuration.getpath("email", "full_template_path", fallback=None)
|
||||
self.template_path = configuration.getpath("email", "template_path")
|
||||
self.full_template_path = configuration.getpath(section, "full_template_path", fallback=None)
|
||||
self.template_path = configuration.getpath(section, "template_path")
|
||||
|
||||
# base smtp settings
|
||||
self.host = configuration.get("email", "host")
|
||||
self.no_empty_report = configuration.getboolean("email", "no_empty_report", fallback=True)
|
||||
self.password = configuration.get("email", "password", fallback=None)
|
||||
self.port = configuration.getint("email", "port")
|
||||
self.receivers = configuration.getlist("email", "receivers")
|
||||
self.sender = configuration.get("email", "sender")
|
||||
self.ssl = SmtpSSLSettings.from_option(configuration.get("email", "ssl", fallback="disabled"))
|
||||
self.user = configuration.get("email", "user", fallback=None)
|
||||
self.host = configuration.get(section, "host")
|
||||
self.no_empty_report = configuration.getboolean(section, "no_empty_report", fallback=True)
|
||||
self.password = configuration.get(section, "password", fallback=None)
|
||||
self.port = configuration.getint(section, "port")
|
||||
self.receivers = configuration.getlist(section, "receivers")
|
||||
self.sender = configuration.get(section, "sender")
|
||||
self.ssl = SmtpSSLSettings.from_option(configuration.get(section, "ssl", fallback="disabled"))
|
||||
self.user = configuration.get(section, "user", fallback=None)
|
||||
|
||||
def _send(self, text: str, attachment: Dict[str, str]) -> None:
|
||||
"""
|
||||
|
@ -31,17 +31,18 @@ class HTML(Report, JinjaTemplate):
|
||||
:ivar report_path: output path to html report
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
def __init__(self, architecture: str, configuration: Configuration, section: str) -> None:
|
||||
"""
|
||||
default constructor
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param section: settings section name
|
||||
"""
|
||||
Report.__init__(self, architecture, configuration)
|
||||
JinjaTemplate.__init__(self, "html", configuration)
|
||||
JinjaTemplate.__init__(self, section, configuration)
|
||||
|
||||
self.report_path = configuration.getpath("html", "path")
|
||||
self.template_path = configuration.getpath("html", "template_path")
|
||||
self.report_path = configuration.getpath(section, "path")
|
||||
self.template_path = configuration.getpath(section, "template_path")
|
||||
|
||||
def generate(self, packages: Iterable[Package], built_packages: Iterable[Package]) -> None:
|
||||
"""
|
||||
|
@ -53,16 +53,17 @@ class Report:
|
||||
load client from settings
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param target: target to generate report (e.g. html)
|
||||
:param target: target to generate report aka section name (e.g. html)
|
||||
:return: client according to current settings
|
||||
"""
|
||||
provider = ReportSettings.from_option(target)
|
||||
section, provider_name = configuration.gettype(target, architecture)
|
||||
provider = ReportSettings.from_option(provider_name)
|
||||
if provider == ReportSettings.HTML:
|
||||
from ahriman.core.report.html import HTML
|
||||
return HTML(architecture, configuration)
|
||||
return HTML(architecture, configuration, section)
|
||||
if provider == ReportSettings.Email:
|
||||
from ahriman.core.report.email import Email
|
||||
return Email(architecture, configuration)
|
||||
return Email(architecture, configuration, section)
|
||||
return cls(architecture, configuration) # should never happen
|
||||
|
||||
def generate(self, packages: Iterable[Package], built_packages: Iterable[Package]) -> None:
|
||||
|
@ -36,15 +36,16 @@ class Github(HttpUpload):
|
||||
:ivar gh_repository: github repository name
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
def __init__(self, architecture: str, configuration: Configuration, section: str) -> None:
|
||||
"""
|
||||
default constructor
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param section: settings section name
|
||||
"""
|
||||
HttpUpload.__init__(self, architecture, configuration, "github")
|
||||
self.gh_owner = configuration.get("github", "owner")
|
||||
self.gh_repository = configuration.get("github", "repository")
|
||||
HttpUpload.__init__(self, architecture, configuration, section)
|
||||
self.gh_owner = configuration.get(section, "owner")
|
||||
self.gh_repository = configuration.get(section, "repository")
|
||||
|
||||
def asset_remove(self, release: Dict[str, Any], name: str) -> None:
|
||||
"""
|
||||
|
@ -35,15 +35,16 @@ class Rsync(Upload):
|
||||
|
||||
_check_output = check_output
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
def __init__(self, architecture: str, configuration: Configuration, section: str) -> None:
|
||||
"""
|
||||
default constructor
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param section: settings section name
|
||||
"""
|
||||
Upload.__init__(self, architecture, configuration)
|
||||
self.command = configuration.getlist("rsync", "command")
|
||||
self.remote = configuration.get("rsync", "remote")
|
||||
self.command = configuration.getlist(section, "command")
|
||||
self.remote = configuration.get(section, "remote")
|
||||
|
||||
def sync(self, path: Path, built_packages: Iterable[Package]) -> None:
|
||||
"""
|
||||
|
@ -37,15 +37,15 @@ class S3(Upload):
|
||||
:ivar chunk_size: chunk size for calculating checksums
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
def __init__(self, architecture: str, configuration: Configuration, section: str) -> None:
|
||||
"""
|
||||
default constructor
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
"""
|
||||
Upload.__init__(self, architecture, configuration)
|
||||
self.bucket = self.get_bucket(configuration)
|
||||
self.chunk_size = configuration.getint("s3", "chunk_size", fallback=8 * 1024 * 1024)
|
||||
self.bucket = self.get_bucket(configuration, section)
|
||||
self.chunk_size = configuration.getint(section, "chunk_size", fallback=8 * 1024 * 1024)
|
||||
|
||||
@staticmethod
|
||||
def calculate_etag(path: Path, chunk_size: int) -> str:
|
||||
@ -70,17 +70,18 @@ class S3(Upload):
|
||||
return f"{checksum.hexdigest()}{suffix}"
|
||||
|
||||
@staticmethod
|
||||
def get_bucket(configuration: Configuration) -> Any:
|
||||
def get_bucket(configuration: Configuration, section: str) -> Any:
|
||||
"""
|
||||
create resource client from configuration
|
||||
:param configuration: configuration instance
|
||||
:param section: settings section name
|
||||
:return: amazon client
|
||||
"""
|
||||
client = boto3.resource(service_name="s3",
|
||||
region_name=configuration.get("s3", "region"),
|
||||
aws_access_key_id=configuration.get("s3", "access_key"),
|
||||
aws_secret_access_key=configuration.get("s3", "secret_key"))
|
||||
return client.Bucket(configuration.get("s3", "bucket"))
|
||||
region_name=configuration.get(section, "region"),
|
||||
aws_access_key_id=configuration.get(section, "access_key"),
|
||||
aws_secret_access_key=configuration.get(section, "secret_key"))
|
||||
return client.Bucket(configuration.get(section, "bucket"))
|
||||
|
||||
@staticmethod
|
||||
def files_remove(local_files: Dict[Path, str], remote_objects: Dict[Path, Any]) -> None:
|
||||
|
@ -57,16 +57,17 @@ class Upload:
|
||||
:param target: target to run sync (e.g. s3)
|
||||
:return: client according to current settings
|
||||
"""
|
||||
provider = UploadSettings.from_option(target)
|
||||
section, provider_name = configuration.gettype(target, architecture)
|
||||
provider = UploadSettings.from_option(provider_name)
|
||||
if provider == UploadSettings.Rsync:
|
||||
from ahriman.core.upload.rsync import Rsync
|
||||
return Rsync(architecture, configuration)
|
||||
return Rsync(architecture, configuration, section)
|
||||
if provider == UploadSettings.S3:
|
||||
from ahriman.core.upload.s3 import S3
|
||||
return S3(architecture, configuration)
|
||||
return S3(architecture, configuration, section)
|
||||
if provider == UploadSettings.Github:
|
||||
from ahriman.core.upload.github import Github
|
||||
return Github(architecture, configuration)
|
||||
return Github(architecture, configuration, section)
|
||||
return cls(architecture, configuration) # should never happen
|
||||
|
||||
def run(self, path: Path, built_packages: Iterable[Package]) -> None:
|
||||
|
Reference in New Issue
Block a user