diff options
author | Yuqian Yang <crupest@crupest.life> | 2025-02-23 16:40:32 +0800 |
---|---|---|
committer | Yuqian Yang <crupest@crupest.life> | 2025-02-23 16:40:32 +0800 |
commit | 90868bf85dc295f70620dbcbd5790999fe239550 (patch) | |
tree | 08c0f73597a751acff14a4d224446e87b2d8775d | |
parent | 1e9b2436eaffa4130f6a69c3a108f6feb9dd4ac8 (diff) | |
download | crupest-90868bf85dc295f70620dbcbd5790999fe239550.tar.gz crupest-90868bf85dc295f70620dbcbd5790999fe239550.tar.bz2 crupest-90868bf85dc295f70620dbcbd5790999fe239550.zip |
feat(python): move python codes.
-rw-r--r-- | python/.gitignore | 3 | ||||
-rw-r--r-- | python/.python-version (renamed from services/.python-version) | 0 | ||||
-rw-r--r-- | python/cru/__init__.py (renamed from services/manager/__init__.py) | 0 | ||||
-rw-r--r-- | python/cru/_base.py (renamed from services/manager/_base.py) | 0 | ||||
-rw-r--r-- | python/cru/_const.py (renamed from services/manager/_const.py) | 0 | ||||
-rw-r--r-- | python/cru/_decorator.py (renamed from services/manager/_decorator.py) | 0 | ||||
-rw-r--r-- | python/cru/_error.py (renamed from services/manager/_error.py) | 0 | ||||
-rw-r--r-- | python/cru/_event.py (renamed from services/manager/_event.py) | 0 | ||||
-rw-r--r-- | python/cru/_func.py (renamed from services/manager/_func.py) | 0 | ||||
-rw-r--r-- | python/cru/_helper.py (renamed from services/manager/_helper.py) | 0 | ||||
-rw-r--r-- | python/cru/_iter.py (renamed from services/manager/_iter.py) | 0 | ||||
-rw-r--r-- | python/cru/_type.py (renamed from services/manager/_type.py) | 0 | ||||
-rw-r--r-- | python/cru/attr.py (renamed from services/manager/attr.py) | 0 | ||||
-rw-r--r-- | python/cru/config.py (renamed from services/manager/config.py) | 0 | ||||
-rw-r--r-- | python/cru/list.py (renamed from services/manager/list.py) | 0 | ||||
-rw-r--r-- | python/cru/parsing.py (renamed from services/manager/parsing.py) | 0 | ||||
-rw-r--r-- | python/cru/service/__init__.py (renamed from services/manager/service/__init__.py) | 0 | ||||
-rw-r--r-- | python/cru/service/__main__.py (renamed from services/manager/service/__main__.py) | 2 | ||||
-rw-r--r-- | python/cru/service/_app.py (renamed from services/manager/service/_app.py) | 4 | ||||
-rw-r--r-- | python/cru/service/_base.py (renamed from services/manager/service/_base.py) | 12 | ||||
-rw-r--r-- | python/cru/service/_gen_cmd.py | 200 | ||||
-rw-r--r-- | python/cru/service/_nginx.py (renamed from services/manager/service/_nginx.py) | 4 | ||||
-rw-r--r-- | python/cru/service/_template.py (renamed from services/manager/service/_template.py) | 8 | ||||
-rw-r--r-- | python/cru/system.py (renamed from services/manager/system.py) | 0 | ||||
-rw-r--r-- | python/cru/template.py (renamed from services/manager/template.py) | 0 | ||||
-rw-r--r-- | python/cru/tool.py (renamed from services/manager/tool.py) | 0 | ||||
-rw-r--r-- | python/cru/value.py (renamed from services/manager/value.py) | 0 | ||||
-rw-r--r-- | python/poetry.lock (renamed from services/poetry.lock) | 0 | ||||
-rw-r--r-- | python/pyproject.toml (renamed from services/pyproject.toml) | 2 | ||||
-rw-r--r-- | services/.gitignore | 4 | ||||
-rwxr-xr-x | services/gen-tplt | 7 | ||||
-rwxr-xr-x | services/git-add-user | 14 | ||||
-rwxr-xr-x | services/manage | 18 | ||||
-rw-r--r-- | services/manager/service/_external.py | 81 | ||||
-rwxr-xr-x | services/update-blog | 5 |
35 files changed, 234 insertions, 130 deletions
diff --git a/python/.gitignore b/python/.gitignore new file mode 100644 index 0000000..f5833b1 --- /dev/null +++ b/python/.gitignore @@ -0,0 +1,3 @@ +__pycache__ +.venv +.mypy_cache diff --git a/services/.python-version b/python/.python-version index 2c07333..2c07333 100644 --- a/services/.python-version +++ b/python/.python-version diff --git a/services/manager/__init__.py b/python/cru/__init__.py index 17799a9..17799a9 100644 --- a/services/manager/__init__.py +++ b/python/cru/__init__.py diff --git a/services/manager/_base.py b/python/cru/_base.py index 2599d8f..2599d8f 100644 --- a/services/manager/_base.py +++ b/python/cru/_base.py diff --git a/services/manager/_const.py b/python/cru/_const.py index 8246b35..8246b35 100644 --- a/services/manager/_const.py +++ b/python/cru/_const.py diff --git a/services/manager/_decorator.py b/python/cru/_decorator.py index 137fc05..137fc05 100644 --- a/services/manager/_decorator.py +++ b/python/cru/_decorator.py diff --git a/services/manager/_error.py b/python/cru/_error.py index e53c787..e53c787 100644 --- a/services/manager/_error.py +++ b/python/cru/_error.py diff --git a/services/manager/_event.py b/python/cru/_event.py index 51a794c..51a794c 100644 --- a/services/manager/_event.py +++ b/python/cru/_event.py diff --git a/services/manager/_func.py b/python/cru/_func.py index fc57802..fc57802 100644 --- a/services/manager/_func.py +++ b/python/cru/_func.py diff --git a/services/manager/_helper.py b/python/cru/_helper.py index 43baf46..43baf46 100644 --- a/services/manager/_helper.py +++ b/python/cru/_helper.py diff --git a/services/manager/_iter.py b/python/cru/_iter.py index f9683ca..f9683ca 100644 --- a/services/manager/_iter.py +++ b/python/cru/_iter.py diff --git a/services/manager/_type.py b/python/cru/_type.py index 1f81da3..1f81da3 100644 --- a/services/manager/_type.py +++ b/python/cru/_type.py diff --git a/services/manager/attr.py b/python/cru/attr.py index d4cc86a..d4cc86a 100644 --- a/services/manager/attr.py +++ b/python/cru/attr.py diff --git a/services/manager/config.py b/python/cru/config.py index 0f6f0d0..0f6f0d0 100644 --- a/services/manager/config.py +++ b/python/cru/config.py diff --git a/services/manager/list.py b/python/cru/list.py index 216a561..216a561 100644 --- a/services/manager/list.py +++ b/python/cru/list.py diff --git a/services/manager/parsing.py b/python/cru/parsing.py index 0e9239d..0e9239d 100644 --- a/services/manager/parsing.py +++ b/python/cru/parsing.py diff --git a/services/manager/service/__init__.py b/python/cru/service/__init__.py index e69de29..e69de29 100644 --- a/services/manager/service/__init__.py +++ b/python/cru/service/__init__.py diff --git a/services/manager/service/__main__.py b/python/cru/service/__main__.py index 6ea0a8a..2a0268b 100644 --- a/services/manager/service/__main__.py +++ b/python/cru/service/__main__.py @@ -1,6 +1,6 @@ import sys -from manager import CruException +from cru import CruException from ._app import create_app diff --git a/services/manager/service/_app.py b/python/cru/service/_app.py index 2304340..b4c6271 100644 --- a/services/manager/service/_app.py +++ b/python/cru/service/_app.py @@ -5,7 +5,7 @@ from ._base import ( ) from ._template import TemplateManager from ._nginx import NginxManager -from ._external import CliToolCommandProvider +from ._gen_cmd import GenCmdProvider APP_ID = "crupest" @@ -16,7 +16,7 @@ class App(AppBase): self.add_feature(PathCommandProvider()) self.add_feature(TemplateManager()) self.add_feature(NginxManager()) - self.add_feature(CliToolCommandProvider()) + self.add_feature(GenCmdProvider()) self.add_feature(CommandDispatcher()) def run_command(self): diff --git a/services/manager/service/_base.py b/python/cru/service/_base.py index 783296c..e1eee70 100644 --- a/services/manager/service/_base.py +++ b/python/cru/service/_base.py @@ -7,7 +7,7 @@ import os from pathlib import Path from typing import TypeVar, overload -from manager import CruException, CruLogicError +from cru import CruException, CruLogicError _Feature = TypeVar("_Feature", bound="AppFeatureProvider") @@ -160,7 +160,7 @@ class AppFeaturePath(AppPath): class AppRootPath(AppPath): def __init__(self, app: AppBase, path: Path): - super().__init__(f"/{id}", True, f"Application {id} path.") + super().__init__(f"/{id}", True, f"Application {id} root path.") self._app = app self._full_path = path.resolve() @@ -218,16 +218,18 @@ class PathCommandProvider(AppCommandFeatureProvider): def setup_arg_parser(self, arg_parser: ArgumentParser) -> None: subparsers = arg_parser.add_subparsers( - dest="path_command", required=True, metavar="PATH_COMMAND" + dest="path_command", metavar="PATH_COMMAND" ) _list_parser = subparsers.add_parser( "list", help="list special paths used by app" ) def run_command(self, args: Namespace) -> None: - if args.path_command == "list": + if args.path_command is None or args.path_command == "list": for path in self.app.paths: - print(f"{path.app_relative_path.as_posix()}: {path.description}") + print( + f"{path.app_relative_path.as_posix()}{'/' if path.is_dir else ''}: {path.description}" + ) class CommandDispatcher(AppFeatureProvider): diff --git a/python/cru/service/_gen_cmd.py b/python/cru/service/_gen_cmd.py new file mode 100644 index 0000000..f51d65f --- /dev/null +++ b/python/cru/service/_gen_cmd.py @@ -0,0 +1,200 @@ +from dataclasses import dataclass, replace +from typing import TypeAlias + +from ._base import AppCommandFeatureProvider +from ._nginx import NginxManager + +_Str_Or_Cmd_List: TypeAlias = str | list["_Cmd"] + + +@dataclass +class _Cmd: + name: str + desc: str + cmd: _Str_Or_Cmd_List + + def clean(self) -> "_Cmd": + if isinstance(self.cmd, list): + return replace( + self, + cmd=[cmd.clean() for cmd in self.cmd], + ) + elif isinstance(self.cmd, str): + return replace(self, cmd=self.cmd.strip()) + else: + raise ValueError("Unexpected type for cmd.") + + def generate_text( + self, + info_only: bool, + *, + parent: str | None = None, + ) -> str: + if parent is None: + tag = "COMMAND" + long_name = self.name + indent = "" + else: + tag = "SUBCOMMAND" + long_name = f"{parent}.{self.name}" + indent = " " + + if info_only: + return f"{indent}[{long_name}]: {self.desc}" + + text = f"--- {tag}[{long_name}]: {self.desc}" + if isinstance(self.cmd, str): + text += "\n" + self.cmd + elif isinstance(self.cmd, list): + for sub in self.cmd: + text += "\n" * 2 + sub.generate_text(info_only, parent=self.name) + else: + raise ValueError("Unexpected type for cmd.") + + lines: list[str] = [] + for line in text.splitlines(): + if len(line) == 0: + lines.append("") + else: + lines.append(indent + line) + text = "\n".join(lines) + + return text + + +_docker_uninstall = _Cmd( + "uninstall", + "uninstall apt docker", + """ +for pkg in docker.io docker-doc docker-compose \ +podman-docker containerd runc; \ +do sudo apt-get remove $pkg; done +""", +) + +_docker_apt_certs = _Cmd( + "apt-certs", + "prepare apt certs", + """ +sudo apt-get update +sudo apt-get install ca-certificates curl +sudo install -m 0755 -d /etc/apt/keyrings +""", +) + +_docker_docker_certs = _Cmd( + "docker-certs", + "add docker certs", + """ +sudo curl -fsSL https://download.docker.com/linux/debian/gpg \ +-o /etc/apt/keyrings/docker.asc +sudo chmod a+r /etc/apt/keyrings/docker.asc +""", +) + +_docker_apt_repo = _Cmd( + "apt-repo", + "add docker apt repo", + """ +echo \\ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \ +https://download.docker.com/linux/debian \\ + $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \\ + sudo tee /etc/apt/sources.list.d/docker.list > /dev/null +""", +) + +_docker_install = _Cmd( + "install", + "update apt and install docker", + """ +sudo apt-get update +sudo apt-get install docker-ce docker-ce-cli containerd.io \ +docker-buildx-plugin docker-compose-plugin +""", +) + +_docker_setup = _Cmd( + "setup", + "setup system for docker", + """ +sudo systemctl enable docker +sudo systemctl start docker +sudo groupadd -f docker +sudo usermod -aG docker $USER +# Remember to log out and log back in for the group changes to take effect +""", +) + +_docker = _Cmd( + "install-docker", + "install docker for a fresh new system", + [ + _docker_uninstall, + _docker_apt_certs, + _docker_docker_certs, + _docker_apt_repo, + _docker_install, + _docker_setup, + ], +) + +_update_blog = _Cmd( + "update-blog", + "re-generate blog pages", + """ +docker exec -it blog /scripts/update.bash +""", +) + +_git_user = _Cmd( + "git-user", + "add/set git server user and password", + """ +docker run -it --rm -v "$ps_file:/user-info" httpd htpasswd "/user-info" [username] +""", +) + + +class GenCmdProvider(AppCommandFeatureProvider): + def __init__(self) -> None: + super().__init__("gen-cmd-provider") + self._cmds: dict[str, _Cmd] = {} + self._register_cmds(_docker, _update_blog, _git_user) + + def _register_cmd(self, cmd: "_Cmd"): + self._cmds[cmd.name] = cmd.clean() + + def _register_cmds(self, *cmds: "_Cmd"): + for c in cmds: + self._register_cmd(c) + + def setup(self): + pass + + def get_command_info(self): + return ("gen-cmd", "Get commands of running external cli tools.") + + def setup_arg_parser(self, arg_parser): + subparsers = arg_parser.add_subparsers( + dest="gen_cmd", metavar="GEN_CMD_COMMAND" + ) + certbot_parser = subparsers.add_parser("certbot", help="print certbot commands") + certbot_parser.add_argument( + "-t", "--test", action="store_true", help="run certbot in test mode" + ) + for cmd in self._cmds.values(): + subparsers.add_parser(cmd.name, help=cmd.desc) + + def _print_cmd(self, name: str): + print(self._cmds[name].generate_text(False)) + + def run_command(self, args): + if args.gen_cmd is None or args.gen_cmd == "list": + print("[certbot]: certbot ssl cert commands") + for cmd in self._cmds.values(): + print(cmd.generate_text(True)) + elif args.gen_cmd == "certbot": + self.app.get_feature(NginxManager).print_all_certbot_commands(args.test) + else: + self._print_cmd(args.gen_cmd) diff --git a/services/manager/service/_nginx.py b/python/cru/service/_nginx.py index 5dfc3ab..87cff6d 100644 --- a/services/manager/service/_nginx.py +++ b/python/cru/service/_nginx.py @@ -4,7 +4,7 @@ import re import subprocess from typing import TypeAlias -from manager import CruInternalError +from cru import CruInternalError from ._base import AppCommandFeatureProvider from ._template import TemplateManager @@ -56,7 +56,7 @@ class NginxManager(AppCommandFeatureProvider): def _join_generated_nginx_conf_text(self) -> str: result = "" for path, text in self._template_manager.generate(): - if path.parents[-1] == "nginx": + if "nginx" in str(path): result += text return result diff --git a/services/manager/service/_template.py b/python/cru/service/_template.py index 90c19ec..22c1d21 100644 --- a/services/manager/service/_template.py +++ b/python/cru/service/_template.py @@ -4,9 +4,9 @@ import shutil from typing import NamedTuple import graphlib -from manager import CruException -from manager.parsing import SimpleLineVarParser -from manager.template import TemplateTree, CruStrWrapperTemplate +from cru import CruException +from cru.parsing import SimpleLineVarParser +from cru.template import TemplateTree, CruStrWrapperTemplate from ._base import AppCommandFeatureProvider, AppFeaturePath @@ -125,7 +125,7 @@ class TemplateManager(AppCommandFeatureProvider): config | {key: template.variables for key, template in entry_templates.items()} ) - + vars: dict[str, str] = config.copy() for _ in sorter.static_order(): del_keys = [] diff --git a/services/manager/system.py b/python/cru/system.py index f321717..f321717 100644 --- a/services/manager/system.py +++ b/python/cru/system.py diff --git a/services/manager/template.py b/python/cru/template.py index 3a70337..3a70337 100644 --- a/services/manager/template.py +++ b/python/cru/template.py diff --git a/services/manager/tool.py b/python/cru/tool.py index 377f5d7..377f5d7 100644 --- a/services/manager/tool.py +++ b/python/cru/tool.py diff --git a/services/manager/value.py b/python/cru/value.py index 9c03219..9c03219 100644 --- a/services/manager/value.py +++ b/python/cru/value.py diff --git a/services/poetry.lock b/python/poetry.lock index 4338200..4338200 100644 --- a/services/poetry.lock +++ b/python/poetry.lock diff --git a/services/pyproject.toml b/python/pyproject.toml index 960e161..28c753e 100644 --- a/services/pyproject.toml +++ b/python/pyproject.toml @@ -1,5 +1,5 @@ [project] -name = "cru-service-manager" +name = "cru" version = "0.1.0" requires-python = ">=3.11" license = "MIT" diff --git a/services/.gitignore b/services/.gitignore index b284dd9..e324eac 100644 --- a/services/.gitignore +++ b/services/.gitignore @@ -1,5 +1 @@ -__pycache__ -.venv -.mypy_cache - /generated diff --git a/services/gen-tplt b/services/gen-tplt deleted file mode 100755 index 38ceb33..0000000 --- a/services/gen-tplt +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -set -e - -script_dir="$(dirname "$0")" - -exec "$script_dir/manage" "template" "generate" "$@" diff --git a/services/git-add-user b/services/git-add-user deleted file mode 100755 index 2e500d2..0000000 --- a/services/git-add-user +++ /dev/null @@ -1,14 +0,0 @@ -#! /usr/bin/bash - -set -e - -script_dir="$(dirname "$0")" -. "$script_dir/common.bash" - -ps_dir="$CRUPEST_PROJECT_DIR/$CRUPEST_DATA_DIR/git/private" -ps_file="$ps_dir/user-info" -echo "Password file at $ps_file" -[[ -d "$ps_dir" ]] || mkdir -p "$ps_dir" -[[ -f "$ps_file" ]] || touch "$ps_file" - -exec docker run -it --rm -v "$ps_file:/user-info" httpd htpasswd "/user-info" "$1" diff --git a/services/manage b/services/manage index 01f3145..4589475 100755 --- a/services/manage +++ b/services/manage @@ -2,13 +2,23 @@ set -e -python3 --version > /dev/null 2>&1 || ( +python3 --version >/dev/null 2>&1 || ( echo Error: failed to run Python with python3 --version. exit 1 ) script_dir="$(dirname "$0")" -. "$script_dir/common.bash" -export PYTHONPATH="$CRUPEST_PROJECT_DIR/$CRUPEST_SERVICES_DIR:$PYTHONPATH" -python3 -m manager.service "$@" +# shellcheck disable=SC2046 +export $(xargs <"${script_dir:?}/base-config") + +CRUPEST_PROJECT_DIR="$(realpath "$script_dir/..")" +export CRUPEST_PROJECT_DIR + +export PYTHONPATH="$CRUPEST_PROJECT_DIR/python:$PYTHONPATH" + +if [[ "$#" != "0" ]] && [[ "$1" == "gen-tmpl" ]]; then + python3 -m cru.service template generate "${@:2}" +else + python3 -m cru.service "$@" +fi diff --git a/services/manager/service/_external.py b/services/manager/service/_external.py deleted file mode 100644 index 2347e95..0000000 --- a/services/manager/service/_external.py +++ /dev/null @@ -1,81 +0,0 @@ -from ._base import AppCommandFeatureProvider -from ._nginx import NginxManager - - -class CliToolCommandProvider(AppCommandFeatureProvider): - def __init__(self) -> None: - super().__init__("cli-tool-command-provider") - - def setup(self): - pass - - def get_command_info(self): - return ("gen-cli", "Get commands of running external cli tools.") - - def setup_arg_parser(self, arg_parser): - subparsers = arg_parser.add_subparsers( - dest="gen_cli_command", required=True, metavar="GEN_CLI_COMMAND" - ) - certbot_parser = subparsers.add_parser("certbot", help="print certbot commands") - certbot_parser.add_argument( - "-t", "--test", action="store_true", help="run certbot in test mode" - ) - _install_docker_parser = subparsers.add_parser( - "install-docker", help="print docker installation commands" - ) - _update_blog_parser = subparsers.add_parser( - "update-blog", help="print blog update command" - ) - - def _print_install_docker_commands(self) -> None: - output = """ -### COMMAND: uninstall apt docker -for pkg in docker.io docker-doc docker-compose \ -podman-docker containerd runc; \ -do sudo apt-get remove $pkg; done - -### COMMAND: prepare apt certs -sudo apt-get update -sudo apt-get install ca-certificates curl -sudo install -m 0755 -d /etc/apt/keyrings - -### COMMAND: install certs -sudo curl -fsSL https://download.docker.com/linux/debian/gpg \ --o /etc/apt/keyrings/docker.asc -sudo chmod a+r /etc/apt/keyrings/docker.asc - -### COMMAND: add docker apt source -echo \\ - "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \ -https://download.docker.com/linux/debian \\ - $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \\ - sudo tee /etc/apt/sources.list.d/docker.list > /dev/null - -### COMMAND: update apt and install docker -sudo apt-get update -sudo apt-get install docker-ce docker-ce-cli containerd.io \ -docker-buildx-plugin docker-compose-plugin - -### COMMAND: setup system for docker -sudo systemctl enable docker -sudo systemctl start docker -sudo groupadd -f docker -sudo usermod -aG docker $USER -# Remember to log out and log back in for the group changes to take effect -""".strip() - print(output) - - def _print_update_blog_command(self): - output = """ -### COMMAND: update blog -docker exec -it blog /scripts/update.bash -""".strip() - print(output) - - def run_command(self, args): - if args.gen_cli_command == "certbot": - self.app.get_feature(NginxManager).print_all_certbot_commands(args.test) - elif args.gen_cli_command == "install-docker": - self._print_install_docker_commands() - elif args.gen_cli_command == "update-blog": - self._print_update_blog_command()
\ No newline at end of file diff --git a/services/update-blog b/services/update-blog deleted file mode 100755 index d85acc1..0000000 --- a/services/update-blog +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -set -e - -exec docker compose exec -it blog /scripts/update.bash |