aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuqian Yang <crupest@crupest.life>2025-02-23 16:40:32 +0800
committerYuqian Yang <crupest@crupest.life>2025-02-23 16:40:32 +0800
commit90868bf85dc295f70620dbcbd5790999fe239550 (patch)
tree08c0f73597a751acff14a4d224446e87b2d8775d
parent1e9b2436eaffa4130f6a69c3a108f6feb9dd4ac8 (diff)
downloadcrupest-90868bf85dc295f70620dbcbd5790999fe239550.tar.gz
crupest-90868bf85dc295f70620dbcbd5790999fe239550.tar.bz2
crupest-90868bf85dc295f70620dbcbd5790999fe239550.zip
feat(python): move python codes.
-rw-r--r--python/.gitignore3
-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.py200
-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/.gitignore4
-rwxr-xr-xservices/gen-tplt7
-rwxr-xr-xservices/git-add-user14
-rwxr-xr-xservices/manage18
-rw-r--r--services/manager/service/_external.py81
-rwxr-xr-xservices/update-blog5
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