create core framework

This commit is contained in:
2024-11-02 23:04:36 +08:00
parent 6acf6d1d6e
commit 544229b7a6
30 changed files with 1612 additions and 16 deletions

54
cli/pyproject.toml Normal file
View File

@@ -0,0 +1,54 @@
[build-system]
requires = ["setuptools>=61.0", "setuptools-scm>=8"]
build-backend = "setuptools.build_meta"
[project]
name = "bugis_cli"
dynamic = ["version"]
authors = [
{ name="Walter Oggioni", email="oggioni.walter@gmail.com" },
]
description = "Markdown to HTML renderer"
readme = "README.md"
requires-python = ">=3.10"
classifiers = [
'Development Status :: 3 - Alpha',
'Topic :: Utilities',
'License :: OSI Approved :: MIT License',
'Intended Audience :: System Administrators',
'Intended Audience :: Developers',
'Environment :: Console',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3',
]
dependencies = [
"granian",
"bugis"
]
[project.optional-dependencies]
dev = [
"build", "mypy", "ipdb", "twine"
]
[project.urls]
"Homepage" = "https://github.com/woggioni/bugis"
"Bug Tracker" = "https://github.com/woggioni/bugis/issues"
[tool.mypy]
python_version = "3.12"
disallow_untyped_defs = true
show_error_codes = true
no_implicit_optional = true
warn_return_any = true
warn_unused_ignores = true
exclude = ["scripts", "docs", "test"]
strict = true
[tool.setuptools_scm]
root='..'
version_file = "src/bugis/cli/_version.py"
[project.scripts]
bugis = "bugis.cli:main"

171
cli/requirements-dev.txt Normal file
View File

@@ -0,0 +1,171 @@
#
# This file is autogenerated by pip-compile with Python 3.12
# by the following command:
#
# pip-compile --extra=dev --output-file=requirements-dev.txt
#
--index-url https://gitea.woggioni.net/api/packages/woggioni/pypi/simple
--extra-index-url https://pypi.org/simple
aiofiles==24.1.0
# via bugis
anyio==4.6.2.post1
# via httpx
asttokens==2.4.1
# via stack-data
bugis==0.2.2
# via bugis_cli (pyproject.toml)
build==1.2.2.post1
# via bugis_cli (pyproject.toml)
certifi==2024.8.30
# via
# httpcore
# httpx
# requests
cffi==1.17.1
# via cryptography
charset-normalizer==3.4.0
# via requests
click==8.1.7
# via granian
cryptography==43.0.3
# via secretstorage
decorator==5.1.1
# via
# ipdb
# ipython
docutils==0.21.2
# via readme-renderer
executing==2.1.0
# via stack-data
granian==1.6.3
# via bugis_cli (pyproject.toml)
h11==0.14.0
# via httpcore
h2==4.1.0
# via httpx
hpack==4.0.0
# via h2
httpcore==1.0.6
# via httpx
httpx[http2]==0.27.2
# via bugis
hyperframe==6.0.1
# via h2
idna==3.10
# via
# anyio
# httpx
# requests
importlib-metadata==8.5.0
# via twine
ipdb==0.13.13
# via bugis_cli (pyproject.toml)
ipython==8.29.0
# via ipdb
jaraco-classes==3.4.0
# via keyring
jaraco-context==6.0.1
# via keyring
jaraco-functools==4.1.0
# via keyring
jedi==0.19.1
# via ipython
jeepney==0.8.0
# via
# keyring
# secretstorage
keyring==25.5.0
# via twine
markdown==3.7
# via bugis
markdown-it-py==3.0.0
# via rich
matplotlib-inline==0.1.7
# via ipython
mdurl==0.1.2
# via markdown-it-py
more-itertools==10.5.0
# via
# jaraco-classes
# jaraco-functools
mypy==1.13.0
# via bugis_cli (pyproject.toml)
mypy-extensions==1.0.0
# via mypy
nh3==0.2.18
# via readme-renderer
packaging==24.1
# via build
parso==0.8.4
# via jedi
pexpect==4.9.0
# via ipython
pkginfo==1.10.0
# via twine
prompt-toolkit==3.0.48
# via ipython
ptyprocess==0.7.0
# via pexpect
pure-eval==0.2.3
# via stack-data
pwo==0.0.4
# via bugis
pycparser==2.22
# via cffi
pygments==2.18.0
# via
# bugis
# ipython
# readme-renderer
# rich
pygraphviz==1.14
# via bugis
pyproject-hooks==1.2.0
# via build
pyyaml==6.0.2
# via bugis
readme-renderer==44.0
# via twine
requests==2.32.3
# via
# requests-toolbelt
# twine
requests-toolbelt==1.0.0
# via twine
rfc3986==2.0.0
# via twine
rich==13.9.3
# via twine
secretstorage==3.3.3
# via keyring
six==1.16.0
# via asttokens
sniffio==1.3.1
# via
# anyio
# httpx
stack-data==0.6.3
# via ipython
traitlets==5.14.3
# via
# ipython
# matplotlib-inline
twine==5.1.1
# via bugis_cli (pyproject.toml)
typing-extensions==4.12.2
# via
# mypy
# pwo
urllib3==2.2.3
# via
# requests
# twine
uvloop==0.21.0
# via granian
watchdog==5.0.3
# via bugis
wcwidth==0.2.13
# via prompt-toolkit
zipp==3.20.2
# via importlib-metadata

59
cli/requirements.txt Normal file
View File

@@ -0,0 +1,59 @@
#
# This file is autogenerated by pip-compile with Python 3.12
# by the following command:
#
# pip-compile --output-file=requirements.txt
#
--index-url https://gitea.woggioni.net/api/packages/woggioni/pypi/simple
--extra-index-url https://pypi.org/simple
aiofiles==24.1.0
# via bugis
anyio==4.6.2.post1
# via httpx
bugis==0.2.2
# via bugis_cli (pyproject.toml)
certifi==2024.8.30
# via
# httpcore
# httpx
click==8.1.7
# via granian
granian==1.6.3
# via bugis_cli (pyproject.toml)
h11==0.14.0
# via httpcore
h2==4.1.0
# via httpx
hpack==4.0.0
# via h2
httpcore==1.0.6
# via httpx
httpx[http2]==0.27.2
# via bugis
hyperframe==6.0.1
# via h2
idna==3.10
# via
# anyio
# httpx
markdown==3.7
# via bugis
pwo==0.0.4
# via bugis
pygments==2.18.0
# via bugis
pygraphviz==1.14
# via bugis
pyyaml==6.0.2
# via bugis
sniffio==1.3.1
# via
# anyio
# httpx
typing-extensions==4.12.2
# via pwo
uvloop==0.21.0
# via granian
watchdog==5.0.3
# via bugis

View File

@@ -0,0 +1,118 @@
from os import environ
from pathlib import Path
from typing import Optional, Sequence
import argparse
import yaml
from granian import Granian
from pwo import Maybe
from bugis.configuration import instance, Configuration
from granian.constants import HTTPModes, ThreadModes, Loops
from dataclasses import asdict
from typing import Any, Mapping
def main(args: Optional[Sequence[str]] = None) -> None:
parser = argparse.ArgumentParser(description="A simple CLI program to render Markdown files")
default_configuration_file = (Maybe.of_nullable(environ.get('XDG_CONFIG_HOME'))
.map(lambda it: Path(it))
.map(lambda it: it / 'bugis' / 'bugis.yaml')
.or_else_get(
lambda: Maybe.of_nullable(environ.get('HOME'))
.map(lambda it: Path(it) / '.config' / 'bugis' / 'bugis.yaml').or_none())
.filter(Path.exists)
.or_none()
)
parser.add_argument(
'-c',
'--configuration',
help='Path to the configuration file',
default=default_configuration_file,
type=Path,
)
parser.add_argument(
'-a',
'--address',
help='Server bind address',
default='127.0.0.1',
)
parser.add_argument(
'-p',
'--port',
help='Server port',
default='8000',
type=int
)
parser.add_argument(
'--access-log',
help='Enable access log',
action='store_true',
dest='log_access'
)
parser.add_argument(
'--logging-configuration',
help='Logging configuration file',
dest='log_config_file'
)
parser.add_argument(
'-w', '--workers',
help='Number of worker processes',
default='1',
dest='workers',
type=int
)
parser.add_argument(
'-t', '--threads',
help='Number of threads per worker',
default='1',
dest='threads',
type=int
)
parser.add_argument(
'--http',
help='HTTP protocol version',
dest='http',
type=lambda it: HTTPModes(it),
choices=[str(mode) for mode in HTTPModes],
default='auto',
)
parser.add_argument(
'--threading-mode',
help='Threading mode',
dest='threading_mode',
type=lambda it: ThreadModes(it),
choices=[str(mode) for mode in ThreadModes],
default=ThreadModes.workers
)
parser.add_argument(
'--loop',
help='Loop',
dest='loop',
type=lambda it: Loops(it),
choices=[str(mode) for mode in Loops]
)
arguments = parser.parse_args(args)
def parse(configuration: Path) -> Any:
with open(configuration, 'r') as f:
return yaml.safe_load(f)
def assign(it: Configuration) -> None:
global instance
instance = it
Maybe.of_nullable(arguments.configuration).map(parse).if_present(assign)
conf = instance
granian_conf = asdict(conf).setdefault('granian', dict())
for k, v in vars(arguments).items():
if v is not None:
granian_conf[k] = v
if arguments.log_config_file:
with open(arguments.log_config_file, 'r') as f:
granian_conf['log_dictconfig'] = yaml.safe_load(f)
granian_conf = Configuration.GranianConfiguration.from_dict(granian_conf)
Granian(
"bugis.asgi:application",
**asdict(granian_conf)
).serve()

View File

@@ -0,0 +1,4 @@
from . import main
import sys
main(sys.argv[1:])

View File

@@ -0,0 +1,30 @@
version: 1
disable_existing_loggers: False
handlers:
console:
class : logging.StreamHandler
formatter: default
level : INFO
stream : ext://sys.stderr
access:
class : logging.StreamHandler
formatter: access
level : INFO
stream : ext://sys.stdout
formatters:
default:
format: '{asctime}.{msecs:0<3.0f} [{levelname}] ({processName:s}/{threadName:s}) - {name} - {message}'
style: '{'
datefmt: '%Y-%m-%d %H:%M:%S'
access:
format: '%(message)s'
loggers:
root:
handlers: [console]
_granian:
level: INFO
propagate: False
granian.access:
handlers: [ access ]
level: INFO
propagate: False