wrd 0.1.41__py3-none-any.whl → 1.0.2__py3-none-any.whl
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.
- wrd/__init__.py +0 -0
- wrd/__main__.py +518 -0
- wrd-1.0.2.dist-info/METADATA +420 -0
- wrd-1.0.2.dist-info/RECORD +8 -0
- {wrd-0.1.41.dist-info → wrd-1.0.2.dist-info}/WHEEL +2 -1
- wrd-1.0.2.dist-info/entry_points.txt +2 -0
- wrd-1.0.2.dist-info/top_level.txt +1 -0
- dune/__init__.py +0 -31
- dune/__main__.py +0 -6
- dune/config_generator.py +0 -414
- dune/genconfig.py +0 -146
- dune/interactive_dune.py +0 -272
- dune/interactive_mapper.py +0 -599
- dune/llm_analyzer.py +0 -197
- dune/processor_engine.py +0 -114
- dune/smart_env_manager.py +0 -573
- dune/task_validator.py +0 -324
- wrd-0.1.41.dist-info/METADATA +0 -501
- wrd-0.1.41.dist-info/RECORD +0 -15
- wrd-0.1.41.dist-info/entry_points.txt +0 -3
- {wrd-0.1.41.dist-info → wrd-1.0.2.dist-info/licenses}/LICENSE +0 -0
dune/smart_env_manager.py
DELETED
@@ -1,573 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Inteligentny menedżer zmiennych środowiskowych z automatycznym wykrywaniem i validacją.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import os
|
6
|
-
import re
|
7
|
-
import json
|
8
|
-
import subprocess
|
9
|
-
import platform
|
10
|
-
from typing import Dict, List, Any, Optional, Tuple
|
11
|
-
from pathlib import Path
|
12
|
-
from loguru import logger
|
13
|
-
from dataclasses import dataclass
|
14
|
-
|
15
|
-
|
16
|
-
@dataclass
|
17
|
-
class EnvVariable:
|
18
|
-
"""Definicja zmiennej środowiskowej."""
|
19
|
-
name: str
|
20
|
-
description: str
|
21
|
-
type: str # str, int, bool, path, url, email
|
22
|
-
required: bool
|
23
|
-
default_value: Optional[str] = None
|
24
|
-
validation_pattern: Optional[str] = None
|
25
|
-
auto_detect_methods: List[str] = None
|
26
|
-
examples: List[str] = None
|
27
|
-
|
28
|
-
|
29
|
-
class SmartEnvManager:
|
30
|
-
"""Inteligentny menedżer zmiennych środowiskowych."""
|
31
|
-
|
32
|
-
def __init__(self):
|
33
|
-
self.env_definitions = self._load_env_definitions()
|
34
|
-
self.auto_detected = {}
|
35
|
-
self.user_provided = {}
|
36
|
-
|
37
|
-
def _load_env_definitions(self) -> Dict[str, EnvVariable]:
|
38
|
-
"""Ładuje definicje zmiennych środowiskowych."""
|
39
|
-
|
40
|
-
return {
|
41
|
-
# IMAP Configuration
|
42
|
-
"IMAP_SERVER": EnvVariable(
|
43
|
-
name="IMAP_SERVER",
|
44
|
-
description="Adres serwera IMAP (np. imap.gmail.com)",
|
45
|
-
type="str",
|
46
|
-
required=True,
|
47
|
-
validation_pattern=r"^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
|
48
|
-
auto_detect_methods=["common_providers", "dns_lookup"],
|
49
|
-
examples=["imap.gmail.com", "imap.outlook.com", "mail.company.com"]
|
50
|
-
),
|
51
|
-
|
52
|
-
"IMAP_PORT": EnvVariable(
|
53
|
-
name="IMAP_PORT",
|
54
|
-
description="Port serwera IMAP",
|
55
|
-
type="int",
|
56
|
-
required=False,
|
57
|
-
default_value="993",
|
58
|
-
validation_pattern=r"^(143|993|[1-9]\d{1,4})$",
|
59
|
-
examples=["143", "993"]
|
60
|
-
),
|
61
|
-
|
62
|
-
"IMAP_USERNAME": EnvVariable(
|
63
|
-
name="IMAP_USERNAME",
|
64
|
-
description="Nazwa użytkownika IMAP (zazwyczaj email)",
|
65
|
-
type="email",
|
66
|
-
required=True,
|
67
|
-
validation_pattern=r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
|
68
|
-
auto_detect_methods=["git_config", "system_user"],
|
69
|
-
examples=["user@gmail.com", "john.doe@company.com"]
|
70
|
-
),
|
71
|
-
|
72
|
-
"IMAP_PASSWORD": EnvVariable(
|
73
|
-
name="IMAP_PASSWORD",
|
74
|
-
description="Hasło IMAP (lub hasło aplikacji)",
|
75
|
-
type="str",
|
76
|
-
required=True,
|
77
|
-
auto_detect_methods=["keyring", "env_file"]
|
78
|
-
),
|
79
|
-
|
80
|
-
# Database Configuration
|
81
|
-
"DATABASE_URL": EnvVariable(
|
82
|
-
name="DATABASE_URL",
|
83
|
-
description="URL połączenia z bazą danych",
|
84
|
-
type="url",
|
85
|
-
required=False,
|
86
|
-
validation_pattern=r"^(postgresql|mysql|sqlite)://.*",
|
87
|
-
auto_detect_methods=["docker_compose", "local_services"],
|
88
|
-
examples=[
|
89
|
-
"postgresql://user:pass@localhost:5432/dbname",
|
90
|
-
"sqlite:///data.db",
|
91
|
-
"mysql://user:pass@localhost:3306/dbname"
|
92
|
-
]
|
93
|
-
),
|
94
|
-
|
95
|
-
# API Configuration
|
96
|
-
"API_KEY": EnvVariable(
|
97
|
-
name="API_KEY",
|
98
|
-
description="Klucz API do autoryzacji",
|
99
|
-
type="str",
|
100
|
-
required=False,
|
101
|
-
auto_detect_methods=["env_file", "keyring"]
|
102
|
-
),
|
103
|
-
|
104
|
-
"API_BASE_URL": EnvVariable(
|
105
|
-
name="API_BASE_URL",
|
106
|
-
description="Bazowy URL API",
|
107
|
-
type="url",
|
108
|
-
required=False,
|
109
|
-
validation_pattern=r"^https?://.*",
|
110
|
-
examples=["https://api.example.com", "http://localhost:8000"]
|
111
|
-
),
|
112
|
-
|
113
|
-
# File Paths
|
114
|
-
"INPUT_DIR": EnvVariable(
|
115
|
-
name="INPUT_DIR",
|
116
|
-
description="Katalog z plikami wejściowymi",
|
117
|
-
type="path",
|
118
|
-
required=False,
|
119
|
-
default_value="./input",
|
120
|
-
auto_detect_methods=["current_directory", "common_paths"],
|
121
|
-
examples=["./data", "/home/user/documents", "C:\\Data"]
|
122
|
-
),
|
123
|
-
|
124
|
-
"OUTPUT_DIR": EnvVariable(
|
125
|
-
name="OUTPUT_DIR",
|
126
|
-
description="Katalog dla plików wyjściowych",
|
127
|
-
type="path",
|
128
|
-
required=False,
|
129
|
-
default_value="./output",
|
130
|
-
auto_detect_methods=["current_directory"],
|
131
|
-
examples=["./output", "/tmp/results", "C:\\Results"]
|
132
|
-
),
|
133
|
-
|
134
|
-
# System Configuration
|
135
|
-
"LOG_LEVEL": EnvVariable(
|
136
|
-
name="LOG_LEVEL",
|
137
|
-
description="Poziom logowania",
|
138
|
-
type="str",
|
139
|
-
required=False,
|
140
|
-
default_value="INFO",
|
141
|
-
validation_pattern=r"^(DEBUG|INFO|WARNING|ERROR|CRITICAL)$",
|
142
|
-
examples=["DEBUG", "INFO", "WARNING", "ERROR"]
|
143
|
-
)
|
144
|
-
}
|
145
|
-
|
146
|
-
def auto_detect_environment_variables(self, required_vars: List[str]) -> Dict[str, str]:
|
147
|
-
"""Automatycznie wykrywa zmienne środowiskowe."""
|
148
|
-
|
149
|
-
logger.info("🔍 Automatyczne wykrywanie zmiennych środowiskowych...")
|
150
|
-
|
151
|
-
detected = {}
|
152
|
-
|
153
|
-
for var_name in required_vars:
|
154
|
-
if var_name in self.env_definitions:
|
155
|
-
value = self._auto_detect_single_var(self.env_definitions[var_name])
|
156
|
-
if value:
|
157
|
-
detected[var_name] = value
|
158
|
-
self.auto_detected[var_name] = value
|
159
|
-
logger.success(f"✅ Auto-wykryto {var_name}: {value}")
|
160
|
-
|
161
|
-
return detected
|
162
|
-
|
163
|
-
def _auto_detect_single_var(self, env_var: EnvVariable) -> Optional[str]:
|
164
|
-
"""Automatycznie wykrywa pojedynczą zmienną."""
|
165
|
-
|
166
|
-
if not env_var.auto_detect_methods:
|
167
|
-
return None
|
168
|
-
|
169
|
-
for method in env_var.auto_detect_methods:
|
170
|
-
try:
|
171
|
-
value = self._run_detection_method(method, env_var)
|
172
|
-
if value and self._validate_env_value(value, env_var):
|
173
|
-
return value
|
174
|
-
except Exception as e:
|
175
|
-
logger.debug(f"Błąd detekcji {method} dla {env_var.name}: {e}")
|
176
|
-
|
177
|
-
return None
|
178
|
-
|
179
|
-
def _run_detection_method(self, method: str, env_var: EnvVariable) -> Optional[str]:
|
180
|
-
"""Uruchamia konkretną metodę detekcji."""
|
181
|
-
|
182
|
-
if method == "git_config":
|
183
|
-
return self._detect_from_git_config(env_var)
|
184
|
-
elif method == "system_user":
|
185
|
-
return self._detect_from_system_user(env_var)
|
186
|
-
elif method == "common_providers":
|
187
|
-
return self._detect_common_providers(env_var)
|
188
|
-
elif method == "dns_lookup":
|
189
|
-
return self._detect_via_dns(env_var)
|
190
|
-
elif method == "docker_compose":
|
191
|
-
return self._detect_from_docker_compose(env_var)
|
192
|
-
elif method == "local_services":
|
193
|
-
return self._detect_local_services(env_var)
|
194
|
-
elif method == "current_directory":
|
195
|
-
return self._detect_from_current_dir(env_var)
|
196
|
-
elif method == "common_paths":
|
197
|
-
return self._detect_common_paths(env_var)
|
198
|
-
elif method == "env_file":
|
199
|
-
return self._detect_from_env_files(env_var)
|
200
|
-
elif method == "keyring":
|
201
|
-
return self._detect_from_keyring(env_var)
|
202
|
-
|
203
|
-
return None
|
204
|
-
|
205
|
-
def _detect_from_git_config(self, env_var: EnvVariable) -> Optional[str]:
|
206
|
-
"""Wykrywa z konfiguracji Git."""
|
207
|
-
|
208
|
-
if env_var.type != "email":
|
209
|
-
return None
|
210
|
-
|
211
|
-
try:
|
212
|
-
result = subprocess.run(
|
213
|
-
["git", "config", "user.email"],
|
214
|
-
capture_output=True, text=True, timeout=5
|
215
|
-
)
|
216
|
-
if result.returncode == 0:
|
217
|
-
return result.stdout.strip()
|
218
|
-
except:
|
219
|
-
pass
|
220
|
-
|
221
|
-
return None
|
222
|
-
|
223
|
-
def _detect_from_system_user(self, env_var: EnvVariable) -> Optional[str]:
|
224
|
-
"""Wykrywa z informacji o użytkowniku systemu."""
|
225
|
-
|
226
|
-
if env_var.type == "email":
|
227
|
-
username = os.getenv("USER") or os.getenv("USERNAME")
|
228
|
-
if username:
|
229
|
-
# Spróbuj utworzyć email na podstawie nazwy użytkownika
|
230
|
-
common_domains = ["gmail.com", "outlook.com", "company.com"]
|
231
|
-
for domain in common_domains:
|
232
|
-
potential_email = f"{username}@{domain}"
|
233
|
-
if self._validate_env_value(potential_email, env_var):
|
234
|
-
return potential_email
|
235
|
-
|
236
|
-
return None
|
237
|
-
|
238
|
-
def _detect_common_providers(self, env_var: EnvVariable) -> Optional[str]:
|
239
|
-
"""Wykrywa z listy popularnych dostawców."""
|
240
|
-
|
241
|
-
if env_var.name == "IMAP_SERVER":
|
242
|
-
# Lista popularnych serwerów IMAP
|
243
|
-
common_servers = [
|
244
|
-
"imap.gmail.com",
|
245
|
-
"imap.outlook.com",
|
246
|
-
"imap.mail.yahoo.com",
|
247
|
-
"localhost"
|
248
|
-
]
|
249
|
-
|
250
|
-
# Sprawdź czy któryś jest dostępny
|
251
|
-
for server in common_servers:
|
252
|
-
if self._test_server_connectivity(server, 993) or self._test_server_connectivity(server, 143):
|
253
|
-
return server
|
254
|
-
|
255
|
-
return None
|
256
|
-
|
257
|
-
def _detect_via_dns(self, env_var: EnvVariable) -> Optional[str]:
|
258
|
-
"""Wykrywa przez zapytania DNS."""
|
259
|
-
|
260
|
-
# Implementacja sprawdzania rekordów MX dla domen
|
261
|
-
return None
|
262
|
-
|
263
|
-
def _detect_from_docker_compose(self, env_var: EnvVariable) -> Optional[str]:
|
264
|
-
"""Wykrywa z plików docker-compose."""
|
265
|
-
|
266
|
-
compose_files = ["docker-compose.yml", "docker-compose.yaml"]
|
267
|
-
|
268
|
-
for compose_file in compose_files:
|
269
|
-
if Path(compose_file).exists():
|
270
|
-
try:
|
271
|
-
import yaml
|
272
|
-
with open(compose_file, 'r') as f:
|
273
|
-
compose_data = yaml.safe_load(f)
|
274
|
-
|
275
|
-
# Szukaj baz danych w serwisach
|
276
|
-
services = compose_data.get("services", {})
|
277
|
-
for service_name, service_config in services.items():
|
278
|
-
if "postgres" in service_name.lower() or service_config.get("image", "").startswith("postgres"):
|
279
|
-
return f"postgresql://user:password@localhost:5432/dbname"
|
280
|
-
elif "mysql" in service_name.lower() or service_config.get("image", "").startswith("mysql"):
|
281
|
-
return f"mysql://user:password@localhost:3306/dbname"
|
282
|
-
|
283
|
-
except:
|
284
|
-
pass
|
285
|
-
|
286
|
-
return None
|
287
|
-
|
288
|
-
def _detect_local_services(self, env_var: EnvVariable) -> Optional[str]:
|
289
|
-
"""Wykrywa lokalne usługi."""
|
290
|
-
|
291
|
-
if env_var.name == "DATABASE_URL":
|
292
|
-
# Sprawdź popularne porty baz danych
|
293
|
-
db_ports = {
|
294
|
-
5432: "postgresql://user:password@localhost:5432/dbname",
|
295
|
-
3306: "mysql://user:password@localhost:3306/dbname",
|
296
|
-
6379: "redis://localhost:6379"
|
297
|
-
}
|
298
|
-
|
299
|
-
for port, url in db_ports.items():
|
300
|
-
if self._test_server_connectivity("localhost", port):
|
301
|
-
return url
|
302
|
-
|
303
|
-
return None
|
304
|
-
|
305
|
-
def _detect_from_current_dir(self, env_var: EnvVariable) -> Optional[str]:
|
306
|
-
"""Wykrywa z bieżącego katalogu."""
|
307
|
-
|
308
|
-
if env_var.type == "path":
|
309
|
-
current_dir = Path.cwd()
|
310
|
-
|
311
|
-
if env_var.name == "INPUT_DIR":
|
312
|
-
candidates = ["input", "data", "src/data", "inputs"]
|
313
|
-
elif env_var.name == "OUTPUT_DIR":
|
314
|
-
candidates = ["output", "results", "out", "outputs"]
|
315
|
-
else:
|
316
|
-
return str(current_dir)
|
317
|
-
|
318
|
-
for candidate in candidates:
|
319
|
-
path = current_dir / candidate
|
320
|
-
if path.exists():
|
321
|
-
return str(path)
|
322
|
-
|
323
|
-
# Zwróć domyślną wartość względem bieżącego katalogu
|
324
|
-
return str(current_dir / env_var.default_value.lstrip("./")) if env_var.default_value else None
|
325
|
-
|
326
|
-
return None
|
327
|
-
|
328
|
-
def _detect_common_paths(self, env_var: EnvVariable) -> Optional[str]:
|
329
|
-
"""Wykrywa z popularnych ścieżek."""
|
330
|
-
|
331
|
-
if env_var.type == "path":
|
332
|
-
if platform.system() == "Windows":
|
333
|
-
common_paths = ["C:\\Data", "C:\\Users\\%USERNAME%\\Documents"]
|
334
|
-
else:
|
335
|
-
common_paths = ["/home/$USER/data", "/tmp", "/var/data"]
|
336
|
-
|
337
|
-
for path_template in common_paths:
|
338
|
-
path = os.path.expandvars(path_template)
|
339
|
-
if Path(path).exists():
|
340
|
-
return path
|
341
|
-
|
342
|
-
return None
|
343
|
-
|
344
|
-
def _detect_from_env_files(self, env_var: EnvVariable) -> Optional[str]:
|
345
|
-
"""Wykrywa z istniejących plików .env."""
|
346
|
-
|
347
|
-
env_files = [".env", ".env.local", ".env.example"]
|
348
|
-
|
349
|
-
for env_file in env_files:
|
350
|
-
if Path(env_file).exists():
|
351
|
-
try:
|
352
|
-
with open(env_file, 'r') as f:
|
353
|
-
for line in f:
|
354
|
-
line = line.strip()
|
355
|
-
if line.startswith(f"{env_var.name}="):
|
356
|
-
value = line.split("=", 1)[1]
|
357
|
-
return value
|
358
|
-
except:
|
359
|
-
pass
|
360
|
-
|
361
|
-
return None
|
362
|
-
|
363
|
-
def _detect_from_keyring(self, env_var: EnvVariable) -> Optional[str]:
|
364
|
-
"""Wykrywa z systemowego keyring."""
|
365
|
-
|
366
|
-
try:
|
367
|
-
import keyring
|
368
|
-
return keyring.get_password("dune", env_var.name)
|
369
|
-
except ImportError:
|
370
|
-
return None
|
371
|
-
except:
|
372
|
-
return None
|
373
|
-
|
374
|
-
def _test_server_connectivity(self, host: str, port: int, timeout: int = 3) -> bool:
|
375
|
-
"""Testuje połączenie z serwerem."""
|
376
|
-
|
377
|
-
import socket
|
378
|
-
|
379
|
-
try:
|
380
|
-
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
381
|
-
sock.settimeout(timeout)
|
382
|
-
result = sock.connect_ex((host, port))
|
383
|
-
sock.close()
|
384
|
-
return result == 0
|
385
|
-
except:
|
386
|
-
return False
|
387
|
-
|
388
|
-
def _validate_env_value(self, value: str, env_var: EnvVariable) -> bool:
|
389
|
-
"""Waliduje wartość zmiennej środowiskowej."""
|
390
|
-
|
391
|
-
if not value:
|
392
|
-
return False
|
393
|
-
|
394
|
-
# Walidacja przez pattern
|
395
|
-
if env_var.validation_pattern:
|
396
|
-
if not re.match(env_var.validation_pattern, value):
|
397
|
-
return False
|
398
|
-
|
399
|
-
# Walidacja przez typ
|
400
|
-
if env_var.type == "int":
|
401
|
-
try:
|
402
|
-
int(value)
|
403
|
-
except ValueError:
|
404
|
-
return False
|
405
|
-
elif env_var.type == "bool":
|
406
|
-
if value.lower() not in ["true", "false", "1", "0", "yes", "no"]:
|
407
|
-
return False
|
408
|
-
elif env_var.type == "path":
|
409
|
-
# Sprawdź czy ścieżka jest sensowna
|
410
|
-
if not re.match(r"^[a-zA-Z0-9._/\\-]+$", value):
|
411
|
-
return False
|
412
|
-
elif env_var.type == "url":
|
413
|
-
if not value.startswith(("http://", "https://", "ftp://", "file://")):
|
414
|
-
return False
|
415
|
-
|
416
|
-
return True
|
417
|
-
|
418
|
-
def interactive_env_collection(self, required_vars: List[str],
|
419
|
-
optional_vars: List[str] = None) -> Dict[str, str]:
|
420
|
-
"""Interaktywnie zbiera zmienne środowiskowe."""
|
421
|
-
|
422
|
-
print(f"\n🔧 KONFIGURACJA ZMIENNYCH ŚRODOWISKOWYCH")
|
423
|
-
print("=" * 50)
|
424
|
-
|
425
|
-
# Najpierw spróbuj auto-detekcji
|
426
|
-
auto_detected = self.auto_detect_environment_variables(required_vars)
|
427
|
-
|
428
|
-
collected = {}
|
429
|
-
|
430
|
-
# Zbierz wymagane zmienne
|
431
|
-
for var_name in required_vars:
|
432
|
-
value = self._collect_single_env_var(var_name, auto_detected.get(var_name), required=True)
|
433
|
-
if value:
|
434
|
-
collected[var_name] = value
|
435
|
-
|
436
|
-
# Zbierz opcjonalne zmienne
|
437
|
-
if optional_vars:
|
438
|
-
print(f"\n🔧 Zmienne opcjonalne:")
|
439
|
-
for var_name in optional_vars:
|
440
|
-
if self._ask_yes_no(f"Skonfigurować {var_name}?"):
|
441
|
-
value = self._collect_single_env_var(var_name, auto_detected.get(var_name), required=False)
|
442
|
-
if value:
|
443
|
-
collected[var_name] = value
|
444
|
-
|
445
|
-
return collected
|
446
|
-
|
447
|
-
def _collect_single_env_var(self, var_name: str, auto_value: Optional[str],
|
448
|
-
required: bool = True) -> Optional[str]:
|
449
|
-
"""Zbiera pojedynczą zmienną środowiskową."""
|
450
|
-
|
451
|
-
env_def = self.env_definitions.get(var_name)
|
452
|
-
if not env_def:
|
453
|
-
# Stwórz podstawową definicję
|
454
|
-
env_def = EnvVariable(var_name, f"Zmienna {var_name}", "str", required)
|
455
|
-
|
456
|
-
# Sprawdź obecną wartość
|
457
|
-
current_value = os.getenv(var_name) or auto_value
|
458
|
-
|
459
|
-
prompt = f"📌 {var_name}"
|
460
|
-
if env_def.description:
|
461
|
-
prompt += f" ({env_def.description})"
|
462
|
-
|
463
|
-
if current_value:
|
464
|
-
prompt += f" [obecna: {current_value}]"
|
465
|
-
elif env_def.default_value:
|
466
|
-
prompt += f" [domyślna: {env_def.default_value}]"
|
467
|
-
|
468
|
-
if not required:
|
469
|
-
prompt += " [opcjonalna]"
|
470
|
-
|
471
|
-
# Pokaż przykłady
|
472
|
-
if env_def.examples:
|
473
|
-
print(f" 💡 Przykłady: {', '.join(env_def.examples[:3])}")
|
474
|
-
|
475
|
-
while True:
|
476
|
-
try:
|
477
|
-
user_input = input(f"{prompt}: ").strip()
|
478
|
-
|
479
|
-
# Użyj obecnej wartości jeśli nic nie podano
|
480
|
-
if not user_input:
|
481
|
-
if current_value:
|
482
|
-
return current_value
|
483
|
-
elif env_def.default_value:
|
484
|
-
return env_def.default_value
|
485
|
-
elif not required:
|
486
|
-
return None
|
487
|
-
else:
|
488
|
-
print("❌ Ta zmienna jest wymagana!")
|
489
|
-
continue
|
490
|
-
|
491
|
-
# Waliduj wartość
|
492
|
-
if self._validate_env_value(user_input, env_def):
|
493
|
-
return user_input
|
494
|
-
else:
|
495
|
-
print(f"❌ Nieprawidłowa wartość dla {env_def.type}")
|
496
|
-
if env_def.validation_pattern:
|
497
|
-
print(f" Wzorzec: {env_def.validation_pattern}")
|
498
|
-
continue
|
499
|
-
|
500
|
-
except KeyboardInterrupt:
|
501
|
-
print("\n⚠️ Przerwano przez użytkownika")
|
502
|
-
return None
|
503
|
-
|
504
|
-
def _ask_yes_no(self, question: str, default: bool = None) -> bool:
|
505
|
-
"""Zadaje pytanie tak/nie."""
|
506
|
-
|
507
|
-
if default is True:
|
508
|
-
prompt = f"{question} [T/n]: "
|
509
|
-
elif default is False:
|
510
|
-
prompt = f"{question} [t/N]: "
|
511
|
-
else:
|
512
|
-
prompt = f"{question} [t/n]: "
|
513
|
-
|
514
|
-
while True:
|
515
|
-
try:
|
516
|
-
answer = input(prompt).strip().lower()
|
517
|
-
|
518
|
-
if not answer and default is not None:
|
519
|
-
return default
|
520
|
-
|
521
|
-
if answer in ["t", "tak", "y", "yes", "1", "true"]:
|
522
|
-
return True
|
523
|
-
elif answer in ["n", "nie", "no", "0", "false"]:
|
524
|
-
return False
|
525
|
-
else:
|
526
|
-
print("Odpowiedz 't' (tak) lub 'n' (nie)")
|
527
|
-
|
528
|
-
except KeyboardInterrupt:
|
529
|
-
return False
|
530
|
-
|
531
|
-
def save_to_env_file(self, env_vars: Dict[str, str], filename: str = ".env") -> None:
|
532
|
-
"""Zapisuje zmienne do pliku .env."""
|
533
|
-
|
534
|
-
logger.info(f"💾 Zapisywanie zmiennych do {filename}")
|
535
|
-
|
536
|
-
# Wczytaj istniejące zmienne
|
537
|
-
existing_vars = {}
|
538
|
-
if Path(filename).exists():
|
539
|
-
with open(filename, 'r') as f:
|
540
|
-
for line in f:
|
541
|
-
line = line.strip()
|
542
|
-
if '=' in line and not line.startswith('#'):
|
543
|
-
key, value = line.split('=', 1)
|
544
|
-
existing_vars[key] = value
|
545
|
-
|
546
|
-
# Połącz ze nowymi
|
547
|
-
all_vars = {**existing_vars, **env_vars}
|
548
|
-
|
549
|
-
# Zapisz
|
550
|
-
with open(filename, 'w') as f:
|
551
|
-
f.write("# Dune Environment Configuration\n")
|
552
|
-
f.write("# Auto-generated and user-provided variables\n\n")
|
553
|
-
|
554
|
-
for key, value in sorted(all_vars.items()):
|
555
|
-
f.write(f"{key}={value}\n")
|
556
|
-
|
557
|
-
logger.success(f"✅ Zapisano {len(env_vars)} zmiennych do {filename}")
|
558
|
-
|
559
|
-
def validate_environment(self, required_vars: List[str]) -> Tuple[bool, List[str]]:
|
560
|
-
"""Waliduje kompletność środowiska."""
|
561
|
-
|
562
|
-
missing_vars = []
|
563
|
-
|
564
|
-
for var_name in required_vars:
|
565
|
-
value = os.getenv(var_name)
|
566
|
-
if not value:
|
567
|
-
missing_vars.append(var_name)
|
568
|
-
else:
|
569
|
-
env_def = self.env_definitions.get(var_name)
|
570
|
-
if env_def and not self._validate_env_value(value, env_def):
|
571
|
-
missing_vars.append(f"{var_name} (nieprawidłowa wartość)")
|
572
|
-
|
573
|
-
return len(missing_vars) == 0, missing_vars
|