compose-generator 0.2.1__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {compose_generator-0.2.1 → compose_generator-0.3.0}/PKG-INFO +1 -1
- {compose_generator-0.2.1 → compose_generator-0.3.0}/README.md +35 -35
- {compose_generator-0.2.1 → compose_generator-0.3.0}/compose_generator/__init__.py +228 -174
- {compose_generator-0.2.1 → compose_generator-0.3.0}/compose_generator/example.env +16 -16
- {compose_generator-0.2.1 → compose_generator-0.3.0}/compose_generator/example.py +103 -101
- {compose_generator-0.2.1 → compose_generator-0.3.0}/pyproject.toml +16 -16
- compose_generator-0.2.1/compose_generator/.env.example +0 -21
- compose_generator-0.2.1/compose_generator/docker-compose.yml +0 -40
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
Этот проект представляет собой **генератор docker-compose.yml файла** на основе настроек приложения. Вот подробное описание:
|
|
2
|
-
|
|
3
|
-
## Основное назначение
|
|
4
|
-
Автоматическое создание `docker-compose.yml` файла с подстановкой всех переменных окружения из конфигурации приложения.
|
|
5
|
-
|
|
6
|
-
## Ключевые компоненты
|
|
7
|
-
|
|
8
|
-
### 1. `ConfigurationComponent`
|
|
9
|
-
- **Назначение**: Преобразует объекты конфигурации в строки переменных окружения
|
|
10
|
-
- **Функциональность**:
|
|
11
|
-
- Извлекает префикс переменных окружения из конфигурации Pydantic
|
|
12
|
-
- Генерирует строки в формате `VARIABLE_NAME: ${VARIABLE_NAME}`
|
|
13
|
-
- Добавляет комментарии с названиями классов конфигурации
|
|
14
|
-
|
|
15
|
-
### 2. `Generator`
|
|
16
|
-
- **Назначение**: Основной класс для генерации docker-compose файла
|
|
17
|
-
- **Функциональность**:
|
|
18
|
-
- Заменяет плейсхолдеры `[ENV]` и `[VERSION]` в шаблоне
|
|
19
|
-
- Сохраняет форматирование и отступы
|
|
20
|
-
- Записывает результат в файл `docker-compose.yml`
|
|
21
|
-
|
|
22
|
-
## Особенности реализации
|
|
23
|
-
|
|
24
|
-
### Автоматизация конфигурации
|
|
25
|
-
- Извлекает все переменные из объектов `BaseSettings`
|
|
26
|
-
- Сохраняет структуру и префиксы конфигурации
|
|
27
|
-
- Генерирует полный список переменных окружения
|
|
28
|
-
|
|
29
|
-
### Преимущества подхода
|
|
30
|
-
1. **Синхронизация** - версии и настройки всегда актуальны
|
|
31
|
-
2. **Безопасность** - не хранит чувствительные данные в репозитории
|
|
32
|
-
3. **Автоматизация** - исключает ручное редактирование
|
|
33
|
-
4. **Масштабируемость** - легко добавлять новые сервисы и настройки
|
|
34
|
-
|
|
35
|
-
|
|
1
|
+
Этот проект представляет собой **генератор docker-compose.yml файла** на основе настроек приложения. Вот подробное описание:
|
|
2
|
+
|
|
3
|
+
## Основное назначение
|
|
4
|
+
Автоматическое создание `docker-compose.yml` файла с подстановкой всех переменных окружения из конфигурации приложения.
|
|
5
|
+
|
|
6
|
+
## Ключевые компоненты
|
|
7
|
+
|
|
8
|
+
### 1. `ConfigurationComponent`
|
|
9
|
+
- **Назначение**: Преобразует объекты конфигурации в строки переменных окружения
|
|
10
|
+
- **Функциональность**:
|
|
11
|
+
- Извлекает префикс переменных окружения из конфигурации Pydantic
|
|
12
|
+
- Генерирует строки в формате `VARIABLE_NAME: ${VARIABLE_NAME}`
|
|
13
|
+
- Добавляет комментарии с названиями классов конфигурации
|
|
14
|
+
|
|
15
|
+
### 2. `Generator`
|
|
16
|
+
- **Назначение**: Основной класс для генерации docker-compose файла
|
|
17
|
+
- **Функциональность**:
|
|
18
|
+
- Заменяет плейсхолдеры `[ENV]` и `[VERSION]` в шаблоне
|
|
19
|
+
- Сохраняет форматирование и отступы
|
|
20
|
+
- Записывает результат в файл `docker-compose.yml`
|
|
21
|
+
|
|
22
|
+
## Особенности реализации
|
|
23
|
+
|
|
24
|
+
### Автоматизация конфигурации
|
|
25
|
+
- Извлекает все переменные из объектов `BaseSettings`
|
|
26
|
+
- Сохраняет структуру и префиксы конфигурации
|
|
27
|
+
- Генерирует полный список переменных окружения
|
|
28
|
+
|
|
29
|
+
### Преимущества подхода
|
|
30
|
+
1. **Синхронизация** - версии и настройки всегда актуальны
|
|
31
|
+
2. **Безопасность** - не хранит чувствительные данные в репозитории
|
|
32
|
+
3. **Автоматизация** - исключает ручное редактирование
|
|
33
|
+
4. **Масштабируемость** - легко добавлять новые сервисы и настройки
|
|
34
|
+
|
|
35
|
+
|
|
36
36
|
Проект полезен для CI/CD процессов, где требуется автоматическое создание docker-compose файлов с актуальными настройками окружения.
|
|
@@ -1,174 +1,228 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
|
-
from pydantic_settings import BaseSettings
|
|
4
|
-
|
|
5
|
-
ENV_KEY = '[ENV]'
|
|
6
|
-
VERSION_KEY = '[VERSION]'
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
self
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
""
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
def
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
self
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
1
|
+
from typing import Optional, Any
|
|
2
|
+
|
|
3
|
+
from pydantic_settings import BaseSettings
|
|
4
|
+
|
|
5
|
+
ENV_KEY = '[ENV]'
|
|
6
|
+
VERSION_KEY = '[VERSION]'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ConfigurationComponent:
|
|
10
|
+
"""Конфигурационный объект, составляющий настройки приложения."""
|
|
11
|
+
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
item: BaseSettings,
|
|
15
|
+
ignore: Optional[list[str]] = None,
|
|
16
|
+
) -> None:
|
|
17
|
+
self.item = item
|
|
18
|
+
self.ignore = ignore or []
|
|
19
|
+
|
|
20
|
+
self.env_prefix = item.model_config.get("env_prefix", "")
|
|
21
|
+
|
|
22
|
+
self.schema: dict[str, Any] = item.__class__.model_json_schema()
|
|
23
|
+
self.properties: dict[str, Any] = self.schema.get("properties", {})
|
|
24
|
+
self.required: set[str] = set(self.schema.get("required", []))
|
|
25
|
+
|
|
26
|
+
self.attrs = list(self.properties.keys())
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def title(self) -> str:
|
|
30
|
+
return f"# {self.item.__class__.__name__}"
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def max_attr_length(self) -> int:
|
|
34
|
+
return max(
|
|
35
|
+
(
|
|
36
|
+
len(self.env_prefix + attr)
|
|
37
|
+
for attr in self.attrs
|
|
38
|
+
if self.env_prefix + attr not in self.ignore
|
|
39
|
+
),
|
|
40
|
+
default=0,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
def compose_parsed(self, max_length: int = 0) -> str:
|
|
44
|
+
"""
|
|
45
|
+
Генерирует переменные для docker-compose.yml.
|
|
46
|
+
Обязательные поля получают проверку на пустое значение.
|
|
47
|
+
Имена переменных выравниваются по общей максимальной длине.
|
|
48
|
+
"""
|
|
49
|
+
result = [self.title]
|
|
50
|
+
|
|
51
|
+
for attr in self.attrs:
|
|
52
|
+
full_attr = self.env_prefix + attr
|
|
53
|
+
|
|
54
|
+
if full_attr in self.ignore:
|
|
55
|
+
continue
|
|
56
|
+
|
|
57
|
+
name = f"{full_attr}:".ljust(max_length + 1)
|
|
58
|
+
|
|
59
|
+
if attr in self.required:
|
|
60
|
+
value = f"${{{full_attr}:?{full_attr} is required}}"
|
|
61
|
+
else:
|
|
62
|
+
value = f"${{{full_attr}}}"
|
|
63
|
+
|
|
64
|
+
result.append(f"{name} {value}")
|
|
65
|
+
|
|
66
|
+
return "\n".join(result)
|
|
67
|
+
|
|
68
|
+
def get_type_string(self, attr: str) -> str:
|
|
69
|
+
"""Возвращает тип атрибута из JSON Schema."""
|
|
70
|
+
property_schema = self.properties.get(attr, {})
|
|
71
|
+
|
|
72
|
+
if "type" in property_schema:
|
|
73
|
+
return property_schema["type"]
|
|
74
|
+
|
|
75
|
+
any_of = property_schema.get("anyOf")
|
|
76
|
+
|
|
77
|
+
if any_of:
|
|
78
|
+
types = [
|
|
79
|
+
item["type"]
|
|
80
|
+
for item in any_of
|
|
81
|
+
if "type" in item
|
|
82
|
+
]
|
|
83
|
+
return "|".join(types)
|
|
84
|
+
|
|
85
|
+
return "unknown"
|
|
86
|
+
|
|
87
|
+
def env_parsed(self) -> str:
|
|
88
|
+
"""Генерирует переменные для .env.example."""
|
|
89
|
+
result = [self.title]
|
|
90
|
+
|
|
91
|
+
for attr in self.attrs:
|
|
92
|
+
full_attr = self.env_prefix + attr
|
|
93
|
+
|
|
94
|
+
if full_attr in self.ignore:
|
|
95
|
+
continue
|
|
96
|
+
|
|
97
|
+
line = f"{full_attr}={self.get_type_string(attr)}"
|
|
98
|
+
result.append(line)
|
|
99
|
+
|
|
100
|
+
return "\n".join(result)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class DockerCompose:
|
|
104
|
+
def __init__(
|
|
105
|
+
self,
|
|
106
|
+
settings: list[BaseSettings],
|
|
107
|
+
template: str,
|
|
108
|
+
version: Optional[str] = None,
|
|
109
|
+
ignore: Optional[list[str]] = None,
|
|
110
|
+
) -> None:
|
|
111
|
+
self.settings = settings
|
|
112
|
+
self.template = template
|
|
113
|
+
self.version = version
|
|
114
|
+
self.ignore = ignore
|
|
115
|
+
|
|
116
|
+
def insert_to_template(self, content: str, key: str) -> None:
|
|
117
|
+
# TODO: делать Trilling Whitespace
|
|
118
|
+
# Разбиваем вставляемую строку на отдельные строки
|
|
119
|
+
|
|
120
|
+
def define_indentation() -> str:
|
|
121
|
+
lines = self.template.split('\n')
|
|
122
|
+
for line in lines:
|
|
123
|
+
if key in line:
|
|
124
|
+
return line.split(key)[0]
|
|
125
|
+
return ''
|
|
126
|
+
|
|
127
|
+
# Форматируем каждую строку с правильным отступом
|
|
128
|
+
formatted = '\n'.join(
|
|
129
|
+
[define_indentation() + line for line in content.split('\n')]
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Заменяем {ENV} в шаблоне
|
|
133
|
+
self.template = self.template.replace(key, formatted.strip())
|
|
134
|
+
|
|
135
|
+
def replace_version(self, version: Optional[str] = None) -> None:
|
|
136
|
+
if version is not None:
|
|
137
|
+
self.template = self.template.replace(VERSION_KEY, version)
|
|
138
|
+
|
|
139
|
+
@property
|
|
140
|
+
def max_attr_length(self) -> int:
|
|
141
|
+
return max(
|
|
142
|
+
(
|
|
143
|
+
ConfigurationComponent(c, self.ignore).max_attr_length
|
|
144
|
+
for c in self.settings
|
|
145
|
+
),
|
|
146
|
+
default=0,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
def __call__(self, filename: str) -> None:
|
|
150
|
+
max_length = self.max_attr_length
|
|
151
|
+
|
|
152
|
+
parsed_components: list[str] = [
|
|
153
|
+
ConfigurationComponent(c, self.ignore).compose_parsed(max_length)
|
|
154
|
+
for c in self.settings
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
self.insert_to_template(
|
|
158
|
+
content='\n\n'.join(parsed_components),
|
|
159
|
+
key=ENV_KEY,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
self.replace_version(self.version)
|
|
163
|
+
|
|
164
|
+
with open(filename, 'w') as f:
|
|
165
|
+
f.write(self.template)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class ExampleEnv:
|
|
169
|
+
def __init__(
|
|
170
|
+
self,
|
|
171
|
+
settings: list[BaseSettings],
|
|
172
|
+
ignore: Optional[list[str]] = None,
|
|
173
|
+
) -> None:
|
|
174
|
+
self.settings = settings
|
|
175
|
+
self.ignore = ignore
|
|
176
|
+
|
|
177
|
+
def __call__(self, filename: str) -> None:
|
|
178
|
+
parsed_components: list[str] = [
|
|
179
|
+
ConfigurationComponent(c, self.ignore).env_parsed() for c in self.settings
|
|
180
|
+
]
|
|
181
|
+
text = '\n\n'.join(parsed_components)
|
|
182
|
+
with open(filename, 'w') as f:
|
|
183
|
+
f.write(text)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class Generate:
|
|
187
|
+
def __init__(
|
|
188
|
+
self,
|
|
189
|
+
settings: list[BaseSettings],
|
|
190
|
+
) -> None:
|
|
191
|
+
self.settings = settings
|
|
192
|
+
|
|
193
|
+
def docker_compose(
|
|
194
|
+
self,
|
|
195
|
+
template: str,
|
|
196
|
+
version: Optional[str] = None,
|
|
197
|
+
ignore: Optional[list[str]] = None,
|
|
198
|
+
filename: str = 'docker-compose.yml'
|
|
199
|
+
) -> None:
|
|
200
|
+
DockerCompose(
|
|
201
|
+
settings=self.settings,
|
|
202
|
+
template=template,
|
|
203
|
+
version=version,
|
|
204
|
+
ignore=ignore,
|
|
205
|
+
)(filename)
|
|
206
|
+
|
|
207
|
+
def example_env(self,
|
|
208
|
+
ignore: Optional[list[str]] = None,
|
|
209
|
+
filename: str = '.env.example'
|
|
210
|
+
) -> None:
|
|
211
|
+
ExampleEnv(
|
|
212
|
+
settings=self.settings,
|
|
213
|
+
ignore=ignore,
|
|
214
|
+
)(filename)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class Generator:
|
|
218
|
+
"""Генератор docker-compose.yml"""
|
|
219
|
+
|
|
220
|
+
def __init__(
|
|
221
|
+
self,
|
|
222
|
+
settings: list[BaseSettings],
|
|
223
|
+
) -> None:
|
|
224
|
+
self.settings = settings
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def generate(self) -> Generate:
|
|
228
|
+
return Generate(settings=self.settings)
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
APP_SERVER_PORT=5000
|
|
2
|
-
|
|
3
|
-
DEFAULT_DB_USER=test
|
|
4
|
-
DEFAULT_DB_PASS=test
|
|
5
|
-
DEFAULT_DB_HOST=test
|
|
6
|
-
DEFAULT_DB_PORT=123
|
|
7
|
-
DEFAULT_DB_NAME=test
|
|
8
|
-
|
|
9
|
-
JWT_EXPIRES_SECONDS=259200
|
|
10
|
-
JWT_SECRET_KEY=ls6ied8kQ2jd
|
|
11
|
-
|
|
12
|
-
API_KEY=ls6ied8sdaf4wkQ2jd
|
|
13
|
-
|
|
14
|
-
SWAGGER_LOGIN=admin
|
|
15
|
-
SWAGGER_PASSWORD=admin
|
|
16
|
-
|
|
1
|
+
APP_SERVER_PORT=5000
|
|
2
|
+
|
|
3
|
+
DEFAULT_DB_USER=test
|
|
4
|
+
DEFAULT_DB_PASS=test
|
|
5
|
+
DEFAULT_DB_HOST=test
|
|
6
|
+
DEFAULT_DB_PORT=123
|
|
7
|
+
DEFAULT_DB_NAME=test
|
|
8
|
+
|
|
9
|
+
JWT_EXPIRES_SECONDS=259200
|
|
10
|
+
JWT_SECRET_KEY=ls6ied8kQ2jd
|
|
11
|
+
|
|
12
|
+
API_KEY=ls6ied8sdaf4wkQ2jd
|
|
13
|
+
|
|
14
|
+
SWAGGER_LOGIN=admin
|
|
15
|
+
SWAGGER_PASSWORD=admin
|
|
16
|
+
|
|
@@ -1,102 +1,104 @@
|
|
|
1
|
-
# Example
|
|
2
|
-
from compose_generator import Generator
|
|
3
|
-
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
|
|
6
|
-
from pydantic import Field
|
|
7
|
-
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class FromEnvFile(BaseSettings):
|
|
11
|
-
model_config = SettingsConfigDict(
|
|
12
|
-
env_file=Path(Path(__file__).resolve().parent, "example.env"),
|
|
13
|
-
extra="ignore",
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class BaseConnection(FromEnvFile):
|
|
18
|
-
USER: str
|
|
19
|
-
PASS: str
|
|
20
|
-
HOST: str
|
|
21
|
-
PORT: int
|
|
22
|
-
NAME: str
|
|
23
|
-
|
|
24
|
-
def get_connection_config(self) -> dict:
|
|
25
|
-
return {
|
|
26
|
-
"engine": "tortoise.backends.asyncpg",
|
|
27
|
-
"credentials": {
|
|
28
|
-
"host": self.HOST,
|
|
29
|
-
"port": self.PORT,
|
|
30
|
-
"user": self.USER,
|
|
31
|
-
"password": self.PASS,
|
|
32
|
-
"database": self.NAME,
|
|
33
|
-
},
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class DefaultDB(BaseConnection):
|
|
38
|
-
model_config = SettingsConfigDict(env_prefix="DEFAULT_DB_")
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
class App(FromEnvFile):
|
|
42
|
-
model_config = SettingsConfigDict(env_prefix="APP_")
|
|
43
|
-
SERVER_PORT: int
|
|
44
|
-
VERSION: str = '1.0.0'
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
class API(FromEnvFile):
|
|
48
|
-
model_config = SettingsConfigDict(env_prefix="API_")
|
|
49
|
-
KEY: str
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
class Swagger(FromEnvFile):
|
|
53
|
-
model_config = SettingsConfigDict(env_prefix="SWAGGER_")
|
|
54
|
-
LOGIN: str
|
|
55
|
-
PASSWORD: str
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
class JWT(FromEnvFile):
|
|
59
|
-
model_config = SettingsConfigDict(env_prefix="JWT_")
|
|
60
|
-
SECRET_KEY: str
|
|
61
|
-
EXPIRES_SECONDS: int
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class Settings(BaseSettings):
|
|
65
|
-
app: App = Field(default_factory=App)
|
|
66
|
-
db: DefaultDB = Field(default_factory=DefaultDB)
|
|
67
|
-
jwt: JWT = Field(default_factory=JWT)
|
|
68
|
-
api: API = Field(default_factory=API)
|
|
69
|
-
swagger: Swagger = Field(default_factory=Swagger)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
TEMPLATE = """version: "3.9"
|
|
73
|
-
|
|
74
|
-
networks:
|
|
75
|
-
common-net:
|
|
76
|
-
external: true
|
|
77
|
-
|
|
78
|
-
x-serv-common-env: &serv-common-env
|
|
79
|
-
[ENV]
|
|
80
|
-
|
|
81
|
-
services:
|
|
82
|
-
api:
|
|
83
|
-
image: /project/user/super-project/api:[VERSION]
|
|
84
|
-
networks:
|
|
85
|
-
- common-net
|
|
86
|
-
ports:
|
|
87
|
-
- ${APP_SERVER_PORT}:${APP_SERVER_PORT}
|
|
88
|
-
environment:
|
|
89
|
-
<<: *serv-common-env
|
|
90
|
-
restart:
|
|
91
|
-
unless-stopped
|
|
92
|
-
"""
|
|
93
|
-
|
|
94
|
-
if __name__ == "__main__":
|
|
95
|
-
stt = Settings()
|
|
96
|
-
generator = Generator(
|
|
97
|
-
settings=list(stt.__dict__.values()),
|
|
98
|
-
)
|
|
99
|
-
generator.generate.docker_compose(
|
|
100
|
-
template=TEMPLATE,
|
|
101
|
-
|
|
1
|
+
# Example
|
|
2
|
+
from compose_generator import Generator
|
|
3
|
+
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from pydantic import Field
|
|
7
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class FromEnvFile(BaseSettings):
|
|
11
|
+
model_config = SettingsConfigDict(
|
|
12
|
+
env_file=Path(Path(__file__).resolve().parent, "example.env"),
|
|
13
|
+
extra="ignore",
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class BaseConnection(FromEnvFile):
|
|
18
|
+
USER: str
|
|
19
|
+
PASS: str
|
|
20
|
+
HOST: str
|
|
21
|
+
PORT: int
|
|
22
|
+
NAME: str
|
|
23
|
+
|
|
24
|
+
def get_connection_config(self) -> dict:
|
|
25
|
+
return {
|
|
26
|
+
"engine": "tortoise.backends.asyncpg",
|
|
27
|
+
"credentials": {
|
|
28
|
+
"host": self.HOST,
|
|
29
|
+
"port": self.PORT,
|
|
30
|
+
"user": self.USER,
|
|
31
|
+
"password": self.PASS,
|
|
32
|
+
"database": self.NAME,
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class DefaultDB(BaseConnection):
|
|
38
|
+
model_config = SettingsConfigDict(env_prefix="DEFAULT_DB_")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class App(FromEnvFile):
|
|
42
|
+
model_config = SettingsConfigDict(env_prefix="APP_")
|
|
43
|
+
SERVER_PORT: int
|
|
44
|
+
VERSION: str = '1.0.0'
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class API(FromEnvFile):
|
|
48
|
+
model_config = SettingsConfigDict(env_prefix="API_")
|
|
49
|
+
KEY: str
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Swagger(FromEnvFile):
|
|
53
|
+
model_config = SettingsConfigDict(env_prefix="SWAGGER_")
|
|
54
|
+
LOGIN: str
|
|
55
|
+
PASSWORD: str
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class JWT(FromEnvFile):
|
|
59
|
+
model_config = SettingsConfigDict(env_prefix="JWT_")
|
|
60
|
+
SECRET_KEY: str
|
|
61
|
+
EXPIRES_SECONDS: int
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class Settings(BaseSettings):
|
|
65
|
+
app: App = Field(default_factory=App)
|
|
66
|
+
db: DefaultDB = Field(default_factory=DefaultDB)
|
|
67
|
+
jwt: JWT = Field(default_factory=JWT)
|
|
68
|
+
api: API = Field(default_factory=API)
|
|
69
|
+
swagger: Swagger = Field(default_factory=Swagger)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
TEMPLATE = """version: "3.9"
|
|
73
|
+
|
|
74
|
+
networks:
|
|
75
|
+
common-net:
|
|
76
|
+
external: true
|
|
77
|
+
|
|
78
|
+
x-serv-common-env: &serv-common-env
|
|
79
|
+
[ENV]
|
|
80
|
+
|
|
81
|
+
services:
|
|
82
|
+
api:
|
|
83
|
+
image: /project/user/super-project/api:[VERSION]
|
|
84
|
+
networks:
|
|
85
|
+
- common-net
|
|
86
|
+
ports:
|
|
87
|
+
- ${APP_SERVER_PORT}:${APP_SERVER_PORT}
|
|
88
|
+
environment:
|
|
89
|
+
<<: *serv-common-env
|
|
90
|
+
restart:
|
|
91
|
+
unless-stopped
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
stt = Settings()
|
|
96
|
+
generator = Generator(
|
|
97
|
+
settings=list(stt.__dict__.values()),
|
|
98
|
+
)
|
|
99
|
+
generator.generate.docker_compose(
|
|
100
|
+
template=TEMPLATE,
|
|
101
|
+
version=stt.app.VERSION,
|
|
102
|
+
ignore=['APP_VERSION'],
|
|
103
|
+
)
|
|
102
104
|
generator.generate.example_env()
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
[project]
|
|
2
|
-
name = "compose-generator"
|
|
3
|
-
version = "0.
|
|
4
|
-
description = "Проект представляет собой генератор docker-compose.yml файла на основе настроек приложения"
|
|
5
|
-
authors = [
|
|
6
|
-
{name = "pasha_danilevich",email = "danilevitch.pasha@yandex.ru"}
|
|
7
|
-
]
|
|
8
|
-
readme = "README.md"
|
|
9
|
-
requires-python = ">=3.10"
|
|
10
|
-
|
|
11
|
-
[tool.poetry.dependencies]
|
|
12
|
-
pydantic-settings = "^2.11.0"
|
|
13
|
-
|
|
14
|
-
[build-system]
|
|
15
|
-
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
16
|
-
build-backend = "poetry.core.masonry.api"
|
|
1
|
+
[project]
|
|
2
|
+
name = "compose-generator"
|
|
3
|
+
version = "0.3.0"
|
|
4
|
+
description = "Проект представляет собой генератор docker-compose.yml файла на основе настроек приложения"
|
|
5
|
+
authors = [
|
|
6
|
+
{name = "pasha_danilevich",email = "danilevitch.pasha@yandex.ru"}
|
|
7
|
+
]
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
|
+
|
|
11
|
+
[tool.poetry.dependencies]
|
|
12
|
+
pydantic-settings = "^2.11.0"
|
|
13
|
+
|
|
14
|
+
[build-system]
|
|
15
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
16
|
+
build-backend = "poetry.core.masonry.api"
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# App
|
|
2
|
-
APP_SERVER_PORT=value
|
|
3
|
-
APP_VERSION=value
|
|
4
|
-
|
|
5
|
-
# DefaultDB
|
|
6
|
-
DEFAULT_DB_USER=value
|
|
7
|
-
DEFAULT_DB_PASS=value
|
|
8
|
-
DEFAULT_DB_HOST=value
|
|
9
|
-
DEFAULT_DB_PORT=value
|
|
10
|
-
DEFAULT_DB_NAME=value
|
|
11
|
-
|
|
12
|
-
# JWT
|
|
13
|
-
JWT_SECRET_KEY=value
|
|
14
|
-
JWT_EXPIRES_SECONDS=value
|
|
15
|
-
|
|
16
|
-
# API
|
|
17
|
-
API_KEY=value
|
|
18
|
-
|
|
19
|
-
# Swagger
|
|
20
|
-
SWAGGER_LOGIN=value
|
|
21
|
-
SWAGGER_PASSWORD=value
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
version: "3.9"
|
|
2
|
-
|
|
3
|
-
networks:
|
|
4
|
-
common-net:
|
|
5
|
-
external: true
|
|
6
|
-
|
|
7
|
-
x-serv-common-env: &serv-common-env
|
|
8
|
-
# App
|
|
9
|
-
APP_SERVER_PORT: ${APP_SERVER_PORT}
|
|
10
|
-
APP_VERSION: ${APP_VERSION}
|
|
11
|
-
|
|
12
|
-
# DefaultDB
|
|
13
|
-
DEFAULT_DB_USER: ${DEFAULT_DB_USER}
|
|
14
|
-
DEFAULT_DB_PASS: ${DEFAULT_DB_PASS}
|
|
15
|
-
DEFAULT_DB_HOST: ${DEFAULT_DB_HOST}
|
|
16
|
-
DEFAULT_DB_PORT: ${DEFAULT_DB_PORT}
|
|
17
|
-
DEFAULT_DB_NAME: ${DEFAULT_DB_NAME}
|
|
18
|
-
|
|
19
|
-
# JWT
|
|
20
|
-
JWT_SECRET_KEY: ${JWT_SECRET_KEY}
|
|
21
|
-
JWT_EXPIRES_SECONDS: ${JWT_EXPIRES_SECONDS}
|
|
22
|
-
|
|
23
|
-
# API
|
|
24
|
-
API_KEY: ${API_KEY}
|
|
25
|
-
|
|
26
|
-
# Swagger
|
|
27
|
-
SWAGGER_LOGIN: ${SWAGGER_LOGIN}
|
|
28
|
-
SWAGGER_PASSWORD: ${SWAGGER_PASSWORD}
|
|
29
|
-
|
|
30
|
-
services:
|
|
31
|
-
api:
|
|
32
|
-
image: /project/user/super-project/api:[VERSION]
|
|
33
|
-
networks:
|
|
34
|
-
- common-net
|
|
35
|
-
ports:
|
|
36
|
-
- ${APP_SERVER_PORT}:${APP_SERVER_PORT}
|
|
37
|
-
environment:
|
|
38
|
-
<<: *serv-common-env
|
|
39
|
-
restart:
|
|
40
|
-
unless-stopped
|