generated from jCloud/repository-template
175 lines
5.3 KiB
Python
175 lines
5.3 KiB
Python
# Copyright 2026 jCloud
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
from dataclasses import dataclass
|
|
from .exceptions import Fail
|
|
import os
|
|
import jcloud_config_parser
|
|
import ipaddress
|
|
import pathlib
|
|
import logging
|
|
import argparse
|
|
from typing import Optional
|
|
|
|
__all__ = [
|
|
'load_config',
|
|
'process_host_and_port',
|
|
'GiteaConfig',
|
|
'process_gitea_config',
|
|
]
|
|
|
|
def load_config(config_directory: pathlib.Path) -> tuple[
|
|
jcloud_config_parser.ini.INIConfiguration,
|
|
jcloud_config_parser.ini.INIConfiguration
|
|
]:
|
|
'''
|
|
Loads the configuration and the default configuration.
|
|
|
|
:param config_directory: The configuration directory.
|
|
:type config_directory: pathlib.Path
|
|
|
|
:return: The configuration.
|
|
:rtype: tuple[jcloud_config_parser.ini.INIConfiguration, jcloud_config_parser.ini.INIConfiguration]
|
|
'''
|
|
|
|
# load default configuration
|
|
with open(os.path.dirname(__file__) + '/../../../default_configuration.conf') as f:
|
|
default_configuration = jcloud_config_parser.ini.INIConfiguration.from_string(f.read())
|
|
f.close()
|
|
|
|
# load configuration
|
|
configuration = jcloud_config_parser.ini.INIConfiguration.from_string(
|
|
(config_directory / 'server.conf').read_text(),
|
|
default=default_configuration,
|
|
ignore_errors=True
|
|
)
|
|
|
|
return configuration, default_configuration
|
|
|
|
def _validate_host(host: str) -> bool:
|
|
'''
|
|
Checks whether the address is a valid address (``ip:port``), e. g. ``0.0.0.0:3000``.
|
|
|
|
:param addr: The address
|
|
:type addr: str
|
|
|
|
:return: ``True`` if the address is valid, otherwise ``False``.
|
|
:rtype: bool
|
|
'''
|
|
|
|
try:
|
|
ipaddress.ip_address(host)
|
|
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
def process_host_and_port(
|
|
configuration: jcloud_config_parser.ini.INIConfiguration,
|
|
default_configuration: jcloud_config_parser.ini.INIConfiguration,
|
|
args: argparse.Namespace,
|
|
logger: logging.Logger
|
|
) -> tuple[str, int]:
|
|
'''
|
|
Processes the host and port in the configuration.
|
|
|
|
Uses default values and the configuration data passed via
|
|
command-line arguments as a fallback.
|
|
|
|
:param configuration: The configuration.
|
|
:type configuration: jcloud_config_parser.ini.INIConfiguration
|
|
:param default_configuration: The default configuration.
|
|
:type default_configuration: jcloud_config_parser.ini.INIConfiguration
|
|
:param args: The arguments.
|
|
:type args: argparse.Namespace
|
|
|
|
:return: The host and the port
|
|
:rtype: tuple[str, int]
|
|
'''
|
|
|
|
# host
|
|
host = args.host or configuration.server.host
|
|
if not _validate_host(host):
|
|
logger.error(f'Error in configuration: [server]host: \'{host}\' is not a valid host, using default value.')
|
|
host = default_configuration.server.host
|
|
|
|
# port
|
|
port = args.port or configuration.server.port
|
|
if not port.isdigit():
|
|
logger.error(f'Error in configuration: [server]port: \'{port}\' is not an integer, using default value.')
|
|
port = default_configuration.server.port
|
|
else:
|
|
if not (0 <= int(port) <= 65535):
|
|
logger.error(f'Error in configuration: [server]port: {port} is not between 0 and 65535, using default value.')
|
|
port = default_configuration.server.port
|
|
|
|
return host, int(port)
|
|
|
|
@dataclass
|
|
class GiteaConfig:
|
|
enabled: bool
|
|
webhook_secret_file_path: Optional[pathlib.Path]
|
|
|
|
def _is_readable_file(path: pathlib.Path) -> bool:
|
|
'''
|
|
Returns whether the file is readable and exists.
|
|
|
|
:param path: The file path.
|
|
:type path: pathlib.Path
|
|
|
|
:return: Whether the file is readable and exists.
|
|
:rtype: bool
|
|
'''
|
|
|
|
if not path.exists():
|
|
return False
|
|
|
|
try:
|
|
with open(str(path), 'rb'):
|
|
pass
|
|
except (OSError, PermissionError):
|
|
return False
|
|
|
|
return True
|
|
|
|
def process_gitea_config(
|
|
configuration: jcloud_config_parser.ini.INIConfiguration,
|
|
logger: logging.Logger
|
|
) -> GiteaConfig:
|
|
'''
|
|
Processes the Gitea configuration.
|
|
|
|
:param configuration: The configuration.
|
|
:type configuration: jcloud_config_parser.ini.INIConfiguration
|
|
:param logger: The logger.
|
|
:type logger: logging.Logger
|
|
|
|
:return: The Gitea configuration.
|
|
:rtype: GiteaConfig
|
|
'''
|
|
|
|
if configuration['gitea'].enabled not in ('true', 'yes', 't', 'y'):
|
|
return GiteaConfig(False, None)
|
|
|
|
secret_file_path = configuration['gitea'].webhook_secret_file
|
|
|
|
if not secret_file_path: # disable secret
|
|
secret_file_path = None
|
|
else:
|
|
secret_file_path = pathlib.Path(secret_file_path)
|
|
if not _is_readable_file(secret_file_path):
|
|
logger.critical(f'{secret_file_path}: Cannot read Gitea webhook secret file')
|
|
raise Fail(f'{secret_file_path}: Cannot read Gitea webhook secret file', exit_code = 2)
|
|
|
|
return GiteaConfig(True, secret_file_path) |