create core framework
This commit is contained in:
54
cli/pyproject.toml
Normal file
54
cli/pyproject.toml
Normal 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
171
cli/requirements-dev.txt
Normal 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
59
cli/requirements.txt
Normal 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
|
118
cli/src/bugis/cli/__init__.py
Normal file
118
cli/src/bugis/cli/__init__.py
Normal 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()
|
4
cli/src/bugis/cli/__main__.py
Normal file
4
cli/src/bugis/cli/__main__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from . import main
|
||||
import sys
|
||||
|
||||
main(sys.argv[1:])
|
30
cli/src/bugis/cli/default-conf/logging.yaml
Normal file
30
cli/src/bugis/cli/default-conf/logging.yaml
Normal 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
|
Reference in New Issue
Block a user