Source code for saturnin.base.config

# SPDX-FileCopyrightText: 2023-present The Firebird Projects <www.firebirdsql.org>
#
# SPDX-License-Identifier: MIT
#
# PROGRAM/MODULE: saturnin
# FILE:           saturnin/base/config.py
# DESCRIPTION:    Saturnin configuration
# CREATED:        6.2.2023
#
# The contents of this file are subject to the MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Copyright (c) 2023 Firebird Project (www.firebirdsql.org)
# All Rights Reserved.
#
# Contributor(s): Pavel Císař (original code)
#                 ______________________________________

"""Code for configuration of Saturnin installation.

"""

from __future__ import annotations
from typing import Optional, List, Final
import sys
import os
import sysconfig
from pathlib import Path
from configparser import ConfigParser, ExtendedInterpolation
from firebird.base.config import DirectoryScheme, get_directory_scheme, Config, StrOption

#: filename for Saturnin configuration file
SATURNIN_CFG: Final[str] = 'saturnin.conf'
#: filename for Firebird configuration file
FIREBIRD_CFG: Final[str] = 'firebird.conf'
#: filename for logging configuration file
LOGGING_CFG: Final[str] = 'logging.conf'
#: Saturnin configuration file header
CONFIG_HDR: Final[str] = """;
; A configuration file consists of sections, each led by a [section] header, followed by
; key/value entries separated by = or : string. Section names are case sensitive but keys
; are not. Leading and trailing whitespace is removed from keys and values. Values can be
; omitted, in which case the key/value delimiter may also be left out. Values can also
; span multiple lines, as long as they are indented deeper than the first line of the value.
;
; Configuration files may include comments, prefixed by # and ; characters. Comments may
; appear on their own on an otherwise empty line, possibly indented.
;
; Values can contain ${section:option} format strings which refer to other values.
; If the section: part is omitted, interpolation defaults to the current section (and possibly
; the default values from the special DEFAULT section). Interpolation can span multiple levels.

"""

#: True if current platform is Windows
WINDOWS: Final[bool] = sys.platform == "win32"
#: True if current platform is based on MINGW
MINGW: Final[bool] = sysconfig.get_platform().startswith("mingw")

[docs] class SaturninScheme(DirectoryScheme): """Saturnin platform directory scheme. When SATURNIN_HOME environment variable is not set, and Saturnin resides in virtual environment that contains `home` subdirectory, it's set as Saturnin HOME directory. This `home` subdirectory is created by `saturnin create home` command on request. """ def __init__(self): super().__init__('saturnin') if not self.has_home_env() and is_virtual(): home_dir: Path = venv() / 'home' if home_dir.is_dir(): os.environ['SATURNIN_HOME'] = str(home_dir) self.dir_map.update(get_directory_scheme('saturnin').dir_map) self.__pip_path: Path = 'pip' self.__pip_cmd: List[str] = ['pip'] if is_virtual(): root = venv() if WINDOWS: bin_path = root / "Scripts" if not MINGW else root / "bin" python_path = bin_path / "python.exe" else: bin_path = root / "bin" python_path = bin_path / "python" pip_path = bin_path / 'pip' if pip_path.is_file(): self.__pip_path = pip_path self.__pip_cmd = [str(pip_path)] else: # No pip shortcut in venv, we must relly on python -m to run it, typical for pipx self.__pip_path = None self.__pip_cmd = [str(python_path), '-m', 'pip']
[docs] def get_pip_cmd(self, *args) -> List[str]: """Returns list with command to run pip. Arguments: args: Arguments for pip """ result = self.__pip_cmd.copy() result.extend(args) return result
@property def recipes(self) -> Path: """Path to directory with recipe files. """ return self.data / 'recipes' @property def pids(self) -> Path: """Path to directory with PID files for running daemons. """ return self.run_data / 'pids' @property def site_services_toml(self) -> Path: """Saturnin service registry file. """ return self.data / 'services.toml' @property def site_apps_toml(self) -> Path: """Saturnin application registry file. """ return self.data / 'apps.toml' @property def site_oids_toml(self) -> Path: """Saturnin OID registry file. """ return self.data / 'oids.toml' @property def site_conf(self) -> Path: """Saturnin site configuration file. """ return self.config / SATURNIN_CFG @property def user_conf(self) -> Path: """Saturnin user configuration file. """ return self.user_config / SATURNIN_CFG @property def firebird_conf(self) -> Path: """Firebird driver configuration file. """ return self.config / FIREBIRD_CFG @property def logging_conf(self) -> Path: """Python logging configuration file. """ return self.config / LOGGING_CFG @property def log_file(self) -> Path: """Saturnin log file. """ return self.logs / 'saturnin.log' @property def history_file(self) -> Path: """Saturnin console command history file. """ return self.data / 'saturnin.hist' @property def theme_file(self) -> Path: """Saturnin console theme file. """ return self.config / 'theme.conf' @property def pip_path(self) -> Path: """Path to `pip`. """ return self.__pip_path
[docs] class SaturninConfig(Config): """Saturnin (a Firebird Butler platform) configuration. """ def __init__(self): super().__init__('saturnin') #: External editor self.editor: StrOption = StrOption('editor', "External editor", default=os.getenv('EDITOR'))
[docs] def is_virtual() -> bool: """Returns True if Saturnin runs in a virtual environtment. """ # Check supports venv && virtualenv >= 20.0.0 return getattr(sys, 'base_prefix', sys.prefix) != sys.prefix
[docs] def venv() -> Optional[Path]: """Path to Saturnin virtual environment. """ return Path(sys.prefix) if is_virtual() else None
# Set SATURNIN_HOME if defined in virtual environment if is_virtual(): path: Path = venv() / 'home' if path.is_dir(): os.environ['SATURNIN_HOME'] = str(path) #: Active Saturnin directory scheme directory_scheme: SaturninScheme = SaturninScheme() #: Saturnin configuration object saturnin_config: SaturninConfig = SaturninConfig() parser: ConfigParser = ConfigParser(interpolation=ExtendedInterpolation()) parser.read([directory_scheme.site_conf, directory_scheme.user_conf]) if parser.has_section('saturnin'): saturnin_config.load_config(parser) del parser