feat[config]: Use toml for configs
This commit is contained in:
@@ -31,15 +31,7 @@ It is slightly ancient solution for modern Docker/Kubernetes backends,
|
|||||||
but provides configuration in one place and _secure enough_ place to save token.
|
but provides configuration in one place and _secure enough_ place to save token.
|
||||||
|
|
||||||
|
|
||||||
Example config:
|
Example config is available in [config.example.toml](config.example.toml).
|
||||||
```ini
|
|
||||||
[main]
|
|
||||||
endpoint=https://example.com
|
|
||||||
token=XXXXX
|
|
||||||
format={owner}/{name}
|
|
||||||
out_dir=/home/user/repositories
|
|
||||||
ssh_key=/home/user/id_rsa
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Native
|
### Native
|
||||||
@@ -50,9 +42,9 @@ removing the ability to specify a user
|
|||||||
2. Install dependencies (`pip3 install -r requirements.txt`).
|
2. Install dependencies (`pip3 install -r requirements.txt`).
|
||||||
Venv-level is recommended.
|
Venv-level is recommended.
|
||||||
3. Install git (`sudo apt install git`)
|
3. Install git (`sudo apt install git`)
|
||||||
4. And run it with path to ini config.
|
4. And run it with path to TOML config.
|
||||||
```bash
|
```bash
|
||||||
python gitea-mirror.py config.ini
|
python gitea-mirror.py config.toml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[main]
|
||||||
|
endpoint = "https://example.com"
|
||||||
|
token = "XXXXX"
|
||||||
|
format = "{owner}/{name}"
|
||||||
|
out_dir = "/home/user/repositories"
|
||||||
|
ssh_key = "/home/user/id_rsa"
|
||||||
+2
-2
@@ -2,7 +2,7 @@ import os.path
|
|||||||
import sys
|
import sys
|
||||||
from os import makedirs
|
from os import makedirs
|
||||||
|
|
||||||
from src.config import Config, read_ini_config
|
from src.config import Config, read_toml_config
|
||||||
from src.git import git_clone, git_pull
|
from src.git import git_clone, git_pull
|
||||||
from src.gitea_api import GiteaApi
|
from src.gitea_api import GiteaApi
|
||||||
from src.models import GiteaRepository
|
from src.models import GiteaRepository
|
||||||
@@ -28,7 +28,7 @@ def main():
|
|||||||
print("Usage: python gitea-mirror.py CONFIG_PATH")
|
print("Usage: python gitea-mirror.py CONFIG_PATH")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
try:
|
try:
|
||||||
config = read_ini_config(sys.argv[1])
|
config = read_toml_config(sys.argv[1])
|
||||||
except RuntimeError as err:
|
except RuntimeError as err:
|
||||||
print(f"Invalid config: {err}")
|
print(f"Invalid config: {err}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|||||||
+19
-18
@@ -2,38 +2,39 @@
|
|||||||
Token should be treated as password,
|
Token should be treated as password,
|
||||||
files are more secure in general than command-line arguments
|
files are more secure in general than command-line arguments
|
||||||
|
|
||||||
.ini config example
|
TOML config example
|
||||||
[main]
|
[main]
|
||||||
endpoint=https://example.com/gitea
|
endpoint = "https://example.com/gitea"
|
||||||
token=something
|
token = "something"
|
||||||
format={owner}/{name}
|
format = "{owner}/{name}"
|
||||||
out_dir=/home/user/repositories
|
out_dir = "/home/user/repositories"
|
||||||
ssh_key=/home/user/.ssh/id_rsa.pub
|
ssh_key = "/home/user/.ssh/id_rsa.pub"
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import configparser
|
|
||||||
import os
|
import os
|
||||||
|
import tomllib
|
||||||
|
|
||||||
from .models import Config
|
from .models import Config
|
||||||
|
|
||||||
MAIN_SECTION = "main"
|
MAIN_SECTION = "main"
|
||||||
|
|
||||||
|
|
||||||
def read_ini_config(path: str) -> Config:
|
def read_toml_config(path: str) -> Config:
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
raise RuntimeError("INI config path is not exists")
|
raise RuntimeError("TOML config path does not exist")
|
||||||
|
|
||||||
parser = configparser.ConfigParser()
|
|
||||||
parser.read(path)
|
|
||||||
try:
|
try:
|
||||||
endpoint = parser[MAIN_SECTION]["endpoint"]
|
with open(path, "rb") as config_file:
|
||||||
token = parser[MAIN_SECTION]["token"]
|
data = tomllib.load(config_file)
|
||||||
repository_format = parser[MAIN_SECTION]["format"]
|
main = data[MAIN_SECTION]
|
||||||
out_dir = parser[MAIN_SECTION]["out_dir"]
|
endpoint = main["endpoint"]
|
||||||
ssh_key_path = parser[MAIN_SECTION]["ssh_key"]
|
token = main["token"]
|
||||||
except KeyError as err:
|
repository_format = main["format"]
|
||||||
raise RuntimeError(f"No value for section: {err}")
|
out_dir = main["out_dir"]
|
||||||
|
ssh_key_path = main["ssh_key"]
|
||||||
|
except (KeyError, tomllib.TOMLDecodeError) as err:
|
||||||
|
raise RuntimeError(f"Invalid TOML config: {err}") from err
|
||||||
|
|
||||||
return Config(
|
return Config(
|
||||||
repository_format=repository_format,
|
repository_format=repository_format,
|
||||||
|
|||||||
+12
-11
@@ -2,18 +2,18 @@ from tempfile import NamedTemporaryFile
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from src.config import Config, read_ini_config
|
from src.config import Config, read_toml_config
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"config_data, expected",
|
"config_data, expected",
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"[main]\ntoken=something\n"
|
'[main]\ntoken = "something"\n'
|
||||||
"format={owner}/{name}\n"
|
'format = "{owner}/{name}"\n'
|
||||||
"ssh_key=/tmp/no_key\n"
|
'ssh_key = "/tmp/no_key"\n'
|
||||||
"endpoint=https://example.com\n"
|
'endpoint = "https://example.com"\n'
|
||||||
"out_dir=/home/user/repositories",
|
'out_dir = "/home/user/repositories"',
|
||||||
Config(
|
Config(
|
||||||
token="something",
|
token="something",
|
||||||
repository_format="{owner}/{name}",
|
repository_format="{owner}/{name}",
|
||||||
@@ -23,20 +23,21 @@ from src.config import Config, read_ini_config
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
("[main]", None),
|
("[main]", None),
|
||||||
|
("not valid toml", None),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_ini_config(config_data, expected):
|
def test_toml_config(config_data, expected):
|
||||||
with NamedTemporaryFile() as tf:
|
with NamedTemporaryFile() as tf:
|
||||||
if config_data:
|
if config_data:
|
||||||
tf.write(config_data.encode("utf-8"))
|
tf.write(config_data.encode("utf-8"))
|
||||||
tf.flush()
|
tf.flush()
|
||||||
if expected:
|
if expected:
|
||||||
assert read_ini_config(tf.name) == expected
|
assert read_toml_config(tf.name) == expected
|
||||||
else:
|
else:
|
||||||
with pytest.raises(RuntimeError):
|
with pytest.raises(RuntimeError):
|
||||||
read_ini_config(tf.name)
|
read_toml_config(tf.name)
|
||||||
|
|
||||||
|
|
||||||
def test_ini_config_not_exists():
|
def test_toml_config_not_exists():
|
||||||
with pytest.raises(RuntimeError):
|
with pytest.raises(RuntimeError):
|
||||||
read_ini_config("not_existing_file")
|
read_toml_config("not_existing_file")
|
||||||
|
|||||||
Reference in New Issue
Block a user