def create_ahriman_configuration(args: argparse.Namespace, architecture: str, repository: str, include_path: Path) -> None: """ create service specific configuration :param args: command line args :param architecture: repository architecture :param repository: repository name :param include_path: path to directory with configuration includes """ configuration = configparser.ConfigParser() section = Configuration.section_name("build", architecture) configuration.add_section(section) configuration.set(section, "build_command", str(Setup.build_command(args.build_command, architecture))) configuration.add_section("repository") configuration.set("repository", "name", repository) if args.sign_key is not None: section = Configuration.section_name("sign", architecture) configuration.add_section(section) configuration.set(section, "target", " ".join([target.name.lower() for target in args.sign_target])) configuration.set(section, "key", args.sign_key) if args.web_port is not None: section = Configuration.section_name("web", architecture) configuration.add_section(section) configuration.set(section, "port", str(args.web_port)) target = include_path / "setup-overrides.ini" with target.open("w") as ahriman_configuration: configuration.write(ahriman_configuration)
def test_getlist_empty(configuration: Configuration) -> None: """ must return list of string correctly for non-existing option """ assert configuration.getlist("build", "test_list") == [] configuration.set("build", "test_list", "") assert configuration.getlist("build", "test_list") == []
def test_load_full_client(configuration: Configuration) -> None: """ must load full client if no settings set """ configuration.set("web", "host", "localhost") configuration.set("web", "port", "8080") assert isinstance(Client.load(configuration), WebClient)
def test_absolute_path_for_absolute(configuration: Configuration) -> None: """ must not change path for absolute path in settings """ path = Path("/a/b/c") configuration.set("build", "path", str(path)) assert configuration.getpath("build", "path") == path
def test_load_logging_fallback(configuration: Configuration, mocker: MockerFixture) -> None: """ must fallback to stderr without errors """ mocker.patch("logging.config.fileConfig", side_effect=PermissionError()) configuration.load_logging(True)
def test_load_logging_stderr(configuration: Configuration, mocker: MockerFixture) -> None: """ must use stderr if flag set """ logging_mock = mocker.patch("logging.config.fileConfig") configuration.load_logging(False) logging_mock.assert_not_called()
def __init__(self, configuration: Configuration) -> None: """ default constructor :param configuration: configuration instance """ root = configuration.get("alpm", "root") pacman_root = configuration.getpath("alpm", "database") self.handle = Handle(root, str(pacman_root)) for repository in configuration.getlist("alpm", "repositories"): self.handle.register_syncdb(repository, 0) # 0 is pgp_level
def __init__(self, architecture: str, configuration: Configuration) -> None: """ default constructor :param architecture: repository architecture :param configuration: configuration instance """ Upload.__init__(self, architecture, configuration) self.command = configuration.getlist("rsync", "command") self.remote = configuration.get("rsync", "remote")
def test_absolute_path_for_relative(configuration: Configuration) -> None: """ must prepend root path to relative path """ path = Path("a") configuration.set("build", "path", str(path)) result = configuration.getpath("build", "path") assert result.is_absolute() assert result.parent == configuration.path.parent assert result.name == path.name
def test_send_starttls(configuration: Configuration, mocker: MockerFixture) -> None: """ must send an email with attachment with starttls """ configuration.set("email", "ssl", "starttls") smtp_mock = mocker.patch("smtplib.SMTP") report = Email("x86_64", configuration) report._send("a text", {"attachment.html": "an attachment"}) smtp_mock.return_value.starttls.assert_called_once()
def test_merge_sections_missing(configuration: Configuration) -> None: """ must merge create section if not exists """ section = configuration.section_name("build", "x86_64") configuration.remove_section("build") configuration.add_section(section) configuration.set(section, "key", "value") configuration.merge_sections("x86_64") assert configuration.get("build", "key") == "value"
def test_send_auth_no_user(configuration: Configuration, mocker: MockerFixture) -> None: """ must send an email with attachment without auth if no user supplied """ configuration.set("email", "password", "password") smtp_mock = mocker.patch("smtplib.SMTP") report = Email("x86_64", configuration) report._send("a text", {"attachment.html": "an attachment"}) smtp_mock.return_value.login.assert_not_called()
def load(cls: Type[Client], configuration: Configuration) -> Client: """ load client from settings :param configuration: configuration instance :return: client according to current settings """ host = configuration.get("web", "host", fallback=None) port = configuration.getint("web", "port", fallback=None) if host is not None and port is not None: from ahriman.core.status.web_client import WebClient return WebClient(host, port) return cls()
def test_generate_no_empty_with_built(configuration: Configuration, package_ahriman: Package, mocker: MockerFixture) -> None: """ must generate report with built packages if no_empty_report is set """ configuration.set("email", "no_empty_report", "yes") send_mock = mocker.patch("ahriman.core.report.email.Email._send") report = Email("x86_64", configuration) report.generate([package_ahriman], [package_ahriman]) send_mock.assert_called_once()
def sign_options( configuration: Configuration ) -> Tuple[Set[SignSettings], Optional[str]]: """ extract default sign options from configuration :param configuration: configuration instance :return: tuple of sign targets and default PGP key """ targets = { SignSettings.from_option(option) for option in configuration.getlist("sign", "target") } default_key = configuration.get("sign", "key") if targets else None return targets, default_key
def __init__(self, section: str, configuration: Configuration) -> None: """ default constructor :param section: settings section name :param configuration: configuration instance """ self.link_path = configuration.get(section, "link_path") self.template_path = configuration.getpath(section, "template_path") # base template vars self.homepage = configuration.get(section, "homepage", fallback=None) self.name = configuration.get("repository", "name") self.sign_targets, self.default_pgp_key = GPG.sign_options( configuration)
def __init__(self, package: Package, configuration: Configuration, paths: RepositoryPaths) -> None: """ default constructor :param package: package definitions :param configuration: configuration instance :param paths: repository paths instance """ self.logger = logging.getLogger("builder") self.build_logger = logging.getLogger("build_details") self.package = package self.paths = paths self.archbuild_flags = configuration.getlist("build", "archbuild_flags") self.build_command = configuration.get("build", "build_command") self.makepkg_flags = configuration.getlist("build", "makepkg_flags") self.makechrootpkg_flags = configuration.getlist("build", "makechrootpkg_flags")
def setup_service(architecture: str, configuration: Configuration) -> web.Application: """ create web application :param architecture: repository architecture :param configuration: configuration instance :return: web application instance """ application = web.Application(logger=logging.getLogger("http")) application.on_shutdown.append(on_shutdown) application.on_startup.append(on_startup) application.middlewares.append( web.normalize_path_middleware(append_slash=False, remove_slash=True)) application.middlewares.append(exception_handler(application.logger)) application.logger.info("setup routes") setup_routes(application) application.logger.info("setup templates") aiohttp_jinja2.setup(application, loader=jinja2.FileSystemLoader( configuration.getpath("web", "templates"))) application.logger.info("setup configuration") application["configuration"] = configuration application.logger.info("setup watcher") application["watcher"] = Watcher(architecture, configuration) return application
def test_create_ahriman_configuration(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None: """ must create configuration for the service """ args = _default_args(args) mocker.patch("pathlib.Path.open") add_section_mock = mocker.patch("configparser.RawConfigParser.add_section") set_mock = mocker.patch("configparser.RawConfigParser.set") write_mock = mocker.patch("configparser.RawConfigParser.write") command = Setup.build_command(args.build_command, "x86_64") Setup.create_ahriman_configuration(args, "x86_64", args.repository, configuration.include) add_section_mock.assert_has_calls([ mock.call(Configuration.section_name("build", "x86_64")), mock.call("repository"), mock.call(Configuration.section_name("sign", "x86_64")), mock.call(Configuration.section_name("web", "x86_64")), ]) set_mock.assert_has_calls([ mock.call(Configuration.section_name("build", "x86_64"), "build_command", str(command)), mock.call("repository", "name", args.repository), mock.call( Configuration.section_name("sign", "x86_64"), "target", " ".join([target.name.lower() for target in args.sign_target])), mock.call(Configuration.section_name("sign", "x86_64"), "key", args.sign_key), mock.call(Configuration.section_name("web", "x86_64"), "port", str(args.web_port)), ]) write_mock.assert_called_once()
def __init__(self, architecture: str, configuration: Configuration) -> None: self.logger = logging.getLogger("builder") self.architecture = architecture self.configuration = configuration self.aur_url = configuration.get("alpm", "aur_url") self.name = configuration.get("repository", "name") self.paths = RepositoryPaths( configuration.getpath("repository", "root"), architecture) self.paths.create_tree() self.ignore_list = configuration.getlist("build", "ignore_packages") self.pacman = Pacman(configuration) self.sign = GPG(architecture, configuration) self.repo = Repo(self.name, self.paths, self.sign.repository_sign_args) self.reporter = Client.load(configuration)
def extract_architectures(cls: Type[Handler], args: argparse.Namespace) -> Set[str]: """ get known architectures :param args: command line args :return: list of architectures for which tree is created """ if args.architecture is None: raise MissingArchitecture(args.command) if args.architecture: return set(args.architecture) config = Configuration() config.load(args.configuration) root = config.getpath("repository", "root") architectures = RepositoryPaths.known_architectures(root) if not architectures: raise MissingArchitecture(args.command) return architectures
def __init__(self, architecture: str, configuration: Configuration) -> None: """ default constructor :param architecture: repository architecture :param configuration: configuration instance """ Report.__init__(self, architecture, configuration) JinjaTemplate.__init__(self, "html", configuration) self.report_path = configuration.getpath("html", "path")
def test_dump_architecture_specific(configuration: Configuration) -> None: """ dump must contain architecture specific settings """ section = configuration.section_name("build", "x86_64") configuration.add_section(section) configuration.set(section, "archbuild_flags", "hello flag") configuration.merge_sections("x86_64") dump = configuration.dump() assert dump assert "build" in dump assert section not in dump assert dump["build"]["archbuild_flags"] == "hello flag"
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None: """ callback for command line :param args: command line args :param architecture: repository architecture :param configuration: configuration instance """ dump = configuration.dump() for section, values in sorted(dump.items()): Dump._print(f"[{section}]") for key, value in sorted(values.items()): Dump._print(f"{key} = {value}") Dump._print()
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None: """ must run command """ mocker.patch("pathlib.Path.mkdir") print_mock = mocker.patch("ahriman.application.handlers.dump.Dump._print") application_mock = mocker.patch( "ahriman.core.configuration.Configuration.dump", return_value=configuration.dump()) Dump.run(args, "x86_64", configuration) application_mock.assert_called_once() print_mock.assert_called()
def _call(cls: Type[Handler], args: argparse.Namespace, architecture: str) -> bool: """ additional function to wrap all calls for multiprocessing library :param args: command line args :param architecture: repository architecture :return: True on success, False otherwise """ try: configuration = Configuration.from_path(args.configuration, architecture, not args.no_log) with Lock(args, architecture, configuration): cls.run(args, architecture, configuration) return True except Exception: logging.getLogger("root").exception("process exception") return False
def __init__(self, args: argparse.Namespace, architecture: str, configuration: Configuration) -> None: """ default constructor :param args: command line args :param architecture: repository architecture :param configuration: configuration instance """ self.path = Path( f"{args.lock}_{architecture}") if args.lock is not None else None self.force = args.force self.unsafe = args.unsafe self.root = Path(configuration.get("repository", "root")) self.reporter = Client() if args.no_report else Client.load( configuration)
def test_from_path(mocker: MockerFixture) -> None: """ must load configuration """ read_mock = mocker.patch("configparser.RawConfigParser.read") load_includes_mock = mocker.patch( "ahriman.core.configuration.Configuration.load_includes") load_logging_mock = mocker.patch( "ahriman.core.configuration.Configuration.load_logging") path = Path("path") configuration = Configuration.from_path(path, "x86_64", True) assert configuration.path == path read_mock.assert_called_with(path) load_includes_mock.assert_called_once() load_logging_mock.assert_called_once()
def __init__(self, architecture: str, configuration: Configuration) -> None: """ default constructor :param architecture: repository architecture :param configuration: configuration instance """ Report.__init__(self, architecture, configuration) JinjaTemplate.__init__(self, "email", configuration) # 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)
def configuration(resource_path_root: Path) -> Configuration: path = resource_path_root / "core" / "ahriman.ini" return Configuration.from_path(path=path, architecture="x86_64", logfile=False)