Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Francesco Faraone committed Feb 28, 2024
1 parent 1b64602 commit 65f2506
Show file tree
Hide file tree
Showing 19 changed files with 1,745 additions and 738 deletions.
8 changes: 0 additions & 8 deletions .flake8

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
poetry install
- name: Linting
run: |
flake8
ruff check .
- name: Testing
run: |
pytest
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
poetry install
- name: Linting
run: |
flake8
ruff check .
- name: Unit tests
run: |
pytest
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,11 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# Ruff
.ruff_cache/
# VSCode
.devcontainer/
.vscode/

# Project specifics
sud-config.yml
1,239 changes: 965 additions & 274 deletions poetry.lock

Large diffs are not rendered by default.

62 changes: 34 additions & 28 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ packages = [
{ include = "sud" },
]


documentation = "https://github.com/ffaraone/sud"
homepage = "https://github.com/ffaraone/sud"
repository = "https://github.com/ffaraone/sud"
Expand All @@ -29,47 +28,37 @@ classifiers = [

keywords = ["sud", "scaleway", "dns", "dynamic", "dynamicdns"]


[tool.poetry.scripts]
sud = "sud.cli:app"

[tool.poetry.dependencies]
python = ">=3.10,<4"
humanize = "^4.9.0"
python-telegram-bot = "^20.8"
pyyaml = "^6.0.1"
requests = "^2.31.0"
click = "^8.1.7"
rich = "^13.7.0"
pyyaml = "^6.0.1"
python-telegram-bot = "^20.8"
humanize = "^4.9.0"
rich-click = "^1.7.3"

[tool.poetry.scripts]
sud = "sud.cli:main"
typer = {extras = ["all"], version = "^0.9.0"}

[tool.poetry.group.dev.dependencies]
ruff = "^0.2.2"
ipython = "^8.21.0"
mypy = "^1.8.0"
poetry-plugin-sort = "^0.2.1"
pytest = "^8.0.1"
black = "^24.2.0"
isort = "^5.13.2"
flake8 = "^7.0.0"
flake8-pytest-style = "^1.7.2"
flake8-bugbear = "^24.2.6"
flake8-debugger = "^4.1.2"
pytest-randomly = "^3.15.0"
pytest-asyncio = "^0.23.5"
pytest-cov = "^4.1.0"
flake8-black = "^0.3.6"
flake8-isort = "^6.1.1"
pytest-deadfixtures = "^2.2.1"
pytest-mock = "^3.12.0"
pytest-randomly = "^3.15.0"
responses = "^0.25.0"
pytest-deadfixtures = "^2.2.1"
mypy = "^1.8.0"
types-requests = "^2.31.0.20240218"
types-pyyaml = "^6.0.12.12"

types-requests = "^2.31.0.20240218"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"


[tool.pytest.ini_options]
testpaths = "tests"
pythonpath = "."
Expand All @@ -93,11 +82,28 @@ exclude_lines = [
"if __name__ == .__main__.:",
]

[tool.isort]
profile = "black"
[tool.ruff]
extend-exclude = [".vscode", ".devcontainer"]
output-format = "full"

[tool.ruff.lint]

select = [
"E", # w errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade,
"PT", # flake8-pytest-style
"T10", # flake8-pytest-style
]
ignore = [
"PT004", # fixture '{name}' does not return anything, add leading underscore
"B008", # do not perform function calls in argument defaults
]

[tool.black]
line-length = 79

[tool.mypy]
warn_no_return = false
4 changes: 1 addition & 3 deletions sud/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ def _get_git_revision(path):

def get_revision():
package_dir = os.path.dirname(__file__)
checkout_dir = os.path.normpath(
os.path.join(package_dir, os.pardir, os.pardir)
)
checkout_dir = os.path.normpath(os.path.join(package_dir, os.pardir, os.pardir))
path = os.path.join(checkout_dir)
if os.path.exists(path):
return _get_git_revision(path)
Expand Down
4 changes: 2 additions & 2 deletions sud/__main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from sud.cli import main
from sud.cli import app

if __name__ == "__main__":
main()
app()
173 changes: 112 additions & 61 deletions sud/cli.py
Original file line number Diff line number Diff line change
@@ -1,82 +1,133 @@
import logging
from datetime import timedelta
from pathlib import Path
from typing import Annotated, Optional, Tuple

from rich.console import Console
import typer
from rich import print
from rich.logging import RichHandler

from sud import click as click
from sud import config, get_version
from sud import get_version
from sud.config import Config
from sud.prompt import APISecretPrompt, HostnamePrompt
from sud.updater import Updater

console = Console()
app = typer.Typer(
add_completion=False,
rich_markup_mode="rich",
)


@click.group()
@click.option(
"-c",
"--config-file",
type=click.Path(
dir_okay=False,
readable=True,
writable=True,
),
default="/etc/sud/sud-config.yml",
help="Load the configuration file from a specific location.",
)
@click.version_option(get_version())
@config.pass_config
def cli(ctx, config_file):
"""
SUD the Python Scaleway DNS Updater utility.
"""
def version_callback(value: bool):
if value:
print(f"[bold dark_orange]SUD[/] version: {get_version()}")
raise typer.Exit()


@cli.command(load_config=False)
# @click.option(
# "-H",
# "--hostname",
# required=True,
# prompt="[cyan]Hostname[/cyan]",
# )
# @click.option(
# "-s",
# "--api-secret",
# required=True,
# prompt="[cyan]Scaleway API secret[/cyan]",
# hide_input=True,
# confirmation_prompt=True,
# )
@click.option(
"-s",
"--frequency",
required=True,
prompt="Check frequency",
default=300,
show_default=True,
)
@config.pass_config
def init(config, frequency):
pass
def validate_frequency_callback(value: int):
if value < 60:
raise typer.BadParameter("Minimum frequency is once per minutes (60 seconds).")
return value


@app.command()
def init(
ctx: typer.Context,
hostname: Annotated[
Optional[str],
typer.Option(
"--hostname",
"-H",
show_default=False,
help="Hostname that must be created/updated.",
),
] = None,
api_secret: Annotated[
Optional[str],
typer.Option(
"--api-secret",
"-s",
show_default=False,
help="Scaleway API secret.",
),
] = None,
frequency: Annotated[
Optional[int],
typer.Option(
"--frequency",
"-f",
callback=validate_frequency_callback,
help="Number of seconds between checks.",
),
] = 300,
telegram: Annotated[
Optional[Tuple[int, str]],
typer.Option(
"--telegram-notifications",
"-t",
metavar="CHAT_ID TOKEN",
help="Add telegram configuration for notifications.",
),
] = (None, None),
):
"""Generate a SUD configuration file."""
if not hostname:
hostname = HostnamePrompt.ask(
"Enter the hostname that must be created or update",
)

@cli.command()
@config.pass_config
def run(config):
if not api_secret:
api_secret = APISecretPrompt.ask(
"Enter the Scaleway API secret",
password=True,
)

config: Config = ctx.obj
config.hostname = hostname
config.api_secret = api_secret
config.frequency = timedelta(seconds=frequency)
config.store()


@app.command()
def run(ctx: typer.Context):
"""Run the [magenta][link=https://scaleway.com]Scaleway[/link][/magenta] \
DNS Updater."""
logging.basicConfig(
level=logging.INFO,
format="%(message)s",
datefmt="[%X]",
handlers=[RichHandler()],
)
updater = Updater(config)
updater = Updater(ctx.obj)
updater.run()


def main():
try:
cli(standalone_mode=False)
except click.ClickException as e:
console.print(f"[bold red]Error:[/bold red] {str(e)}")
except click.Abort:
pass
except Exception:
console.print_exception()
@app.callback()
def main(
ctx: typer.Context,
config_file: Annotated[
Optional[Path],
typer.Option(
"--config-file",
"-c",
help="Load the configuration file from a specific location.",
),
] = "/etc/sud/sud-config.yml",
version: Annotated[
Optional[bool],
typer.Option("--version", callback=version_callback, is_eager=True),
] = None,
):
"""
[bold dark_orange]SUD[/] is a small DDNS updater utility for the
Scaleway DNS service.
It periodically (default: 300 seconds) check for the IP public IP
address from through the utility goes to internet
and create or update a [cyan]Host (A)[/] record in the DNS zone of the
specified domain name.
"""
config = Config(config_file)
ctx.obj = config
if ctx.invoked_subcommand != "init":
config.load()
Loading

0 comments on commit 65f2506

Please sign in to comment.