2025-05-20 22:34:02 +00:00
|
|
|
|
import os
|
|
|
|
|
import re
|
2025-05-29 09:37:39 +00:00
|
|
|
|
from dataclasses import dataclass
|
2025-05-20 22:34:02 +00:00
|
|
|
|
from pathlib import Path
|
2025-05-29 09:37:39 +00:00
|
|
|
|
from typing import Dict, List, Optional, Set
|
|
|
|
|
|
2025-05-16 06:23:48 +00:00
|
|
|
|
from redis import Redis
|
2025-05-29 09:37:39 +00:00
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
from settings import REDIS_URL, ROOT_DIR
|
2025-05-16 06:23:48 +00:00
|
|
|
|
from utils.logger import root_logger as logger
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
class EnvVariable:
|
|
|
|
|
key: str
|
|
|
|
|
value: str
|
|
|
|
|
description: Optional[str] = None
|
|
|
|
|
type: str = "string"
|
|
|
|
|
is_secret: bool = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
class EnvSection:
|
|
|
|
|
name: str
|
|
|
|
|
variables: List[EnvVariable]
|
|
|
|
|
description: Optional[str] = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EnvManager:
|
|
|
|
|
"""
|
2025-05-20 22:34:02 +00:00
|
|
|
|
Менеджер переменных окружения с хранением в Redis и синхронизацией с .env файлом
|
2025-05-16 06:23:48 +00:00
|
|
|
|
"""
|
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
# Стандартные переменные окружения, которые следует исключить
|
|
|
|
|
EXCLUDED_ENV_VARS: Set[str] = {
|
2025-05-29 09:37:39 +00:00
|
|
|
|
"PATH",
|
|
|
|
|
"SHELL",
|
|
|
|
|
"USER",
|
|
|
|
|
"HOME",
|
|
|
|
|
"PWD",
|
|
|
|
|
"TERM",
|
|
|
|
|
"LANG",
|
|
|
|
|
"PYTHONPATH",
|
|
|
|
|
"_",
|
|
|
|
|
"TMPDIR",
|
|
|
|
|
"TERM_PROGRAM",
|
|
|
|
|
"TERM_SESSION_ID",
|
|
|
|
|
"XPC_SERVICE_NAME",
|
|
|
|
|
"XPC_FLAGS",
|
|
|
|
|
"SHLVL",
|
|
|
|
|
"SECURITYSESSIONID",
|
|
|
|
|
"LOGNAME",
|
|
|
|
|
"OLDPWD",
|
|
|
|
|
"ZSH",
|
|
|
|
|
"PAGER",
|
|
|
|
|
"LESS",
|
|
|
|
|
"LC_CTYPE",
|
|
|
|
|
"LSCOLORS",
|
|
|
|
|
"SSH_AUTH_SOCK",
|
|
|
|
|
"DISPLAY",
|
|
|
|
|
"COLORTERM",
|
|
|
|
|
"EDITOR",
|
|
|
|
|
"VISUAL",
|
|
|
|
|
"PYTHONDONTWRITEBYTECODE",
|
|
|
|
|
"VIRTUAL_ENV",
|
|
|
|
|
"PYTHONUNBUFFERED",
|
2025-05-20 22:34:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Секции для группировки переменных
|
|
|
|
|
SECTIONS = {
|
|
|
|
|
"AUTH": {
|
|
|
|
|
"pattern": r"^(JWT|AUTH|SESSION|OAUTH|GITHUB|GOOGLE|FACEBOOK)_",
|
|
|
|
|
"name": "Авторизация",
|
2025-05-29 09:37:39 +00:00
|
|
|
|
"description": "Настройки системы авторизации",
|
2025-05-20 22:34:02 +00:00
|
|
|
|
},
|
|
|
|
|
"DATABASE": {
|
|
|
|
|
"pattern": r"^(DB|DATABASE|POSTGRES|MYSQL|SQL)_",
|
|
|
|
|
"name": "База данных",
|
2025-05-29 09:37:39 +00:00
|
|
|
|
"description": "Настройки подключения к базам данных",
|
2025-05-20 22:34:02 +00:00
|
|
|
|
},
|
|
|
|
|
"CACHE": {
|
|
|
|
|
"pattern": r"^(REDIS|CACHE|MEMCACHED)_",
|
|
|
|
|
"name": "Кэширование",
|
2025-05-29 09:37:39 +00:00
|
|
|
|
"description": "Настройки систем кэширования",
|
2025-05-20 22:34:02 +00:00
|
|
|
|
},
|
|
|
|
|
"SEARCH": {
|
|
|
|
|
"pattern": r"^(ELASTIC|SEARCH|OPENSEARCH)_",
|
|
|
|
|
"name": "Поиск",
|
2025-05-29 09:37:39 +00:00
|
|
|
|
"description": "Настройки поисковых систем",
|
2025-05-20 22:34:02 +00:00
|
|
|
|
},
|
|
|
|
|
"APP": {
|
|
|
|
|
"pattern": r"^(APP|PORT|HOST|DEBUG|DOMAIN|ENVIRONMENT|ENV|FRONTEND)_",
|
2025-05-22 01:34:30 +00:00
|
|
|
|
"name": "Общие настройки",
|
2025-05-29 09:37:39 +00:00
|
|
|
|
"description": "Общие настройки приложения",
|
2025-05-20 22:34:02 +00:00
|
|
|
|
},
|
|
|
|
|
"LOGGING": {
|
|
|
|
|
"pattern": r"^(LOG|LOGGING|SENTRY|GLITCH|GLITCHTIP)_",
|
2025-05-22 01:34:30 +00:00
|
|
|
|
"name": "Мониторинг",
|
2025-05-29 09:37:39 +00:00
|
|
|
|
"description": "Настройки логирования и мониторинга",
|
2025-05-20 22:34:02 +00:00
|
|
|
|
},
|
|
|
|
|
"EMAIL": {
|
2025-05-22 01:34:30 +00:00
|
|
|
|
"pattern": r"^(MAIL|EMAIL|SMTP|IMAP|POP3|POST)_",
|
2025-05-20 22:34:02 +00:00
|
|
|
|
"name": "Электронная почта",
|
2025-05-29 09:37:39 +00:00
|
|
|
|
"description": "Настройки отправки электронной почты",
|
2025-05-20 22:34:02 +00:00
|
|
|
|
},
|
|
|
|
|
"ANALYTICS": {
|
|
|
|
|
"pattern": r"^(GA|GOOGLE_ANALYTICS|ANALYTICS)_",
|
|
|
|
|
"name": "Аналитика",
|
2025-05-29 09:37:39 +00:00
|
|
|
|
"description": "Настройки систем аналитики",
|
2025-05-20 22:34:02 +00:00
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Переменные, которые следует всегда помечать как секретные
|
|
|
|
|
SECRET_VARS_PATTERNS = [
|
2025-05-29 09:37:39 +00:00
|
|
|
|
r".*TOKEN.*",
|
|
|
|
|
r".*SECRET.*",
|
|
|
|
|
r".*PASSWORD.*",
|
|
|
|
|
r".*KEY.*",
|
|
|
|
|
r".*PWD.*",
|
|
|
|
|
r".*PASS.*",
|
|
|
|
|
r".*CRED.*",
|
|
|
|
|
r".*_DSN.*",
|
|
|
|
|
r".*JWT.*",
|
|
|
|
|
r".*SESSION.*",
|
|
|
|
|
r".*OAUTH.*",
|
|
|
|
|
r".*GITHUB.*",
|
|
|
|
|
r".*GOOGLE.*",
|
|
|
|
|
r".*FACEBOOK.*",
|
2025-05-20 22:34:02 +00:00
|
|
|
|
]
|
|
|
|
|
|
2025-05-16 06:23:48 +00:00
|
|
|
|
def __init__(self):
|
|
|
|
|
self.redis = Redis.from_url(REDIS_URL)
|
|
|
|
|
self.prefix = "env:"
|
2025-05-29 09:37:39 +00:00
|
|
|
|
self.env_file_path = os.path.join(ROOT_DIR, ".env")
|
2025-05-16 06:23:48 +00:00
|
|
|
|
|
|
|
|
|
def get_all_variables(self) -> List[EnvSection]:
|
|
|
|
|
"""
|
|
|
|
|
Получение всех переменных окружения, сгруппированных по секциям
|
|
|
|
|
"""
|
2025-05-20 22:34:02 +00:00
|
|
|
|
try:
|
|
|
|
|
# Получаем все переменные окружения из системы
|
|
|
|
|
system_env = self._get_system_env_vars()
|
|
|
|
|
|
|
|
|
|
# Получаем переменные из .env файла, если он существует
|
|
|
|
|
dotenv_vars = self._get_dotenv_vars()
|
|
|
|
|
|
|
|
|
|
# Получаем все переменные из Redis
|
|
|
|
|
redis_vars = self._get_redis_env_vars()
|
|
|
|
|
|
|
|
|
|
# Объединяем переменные, при этом redis_vars имеют наивысший приоритет,
|
|
|
|
|
# за ними следуют переменные из .env, затем системные
|
|
|
|
|
env_vars = {**system_env, **dotenv_vars, **redis_vars}
|
|
|
|
|
|
|
|
|
|
# Группируем переменные по секциям
|
|
|
|
|
return self._group_variables_by_sections(env_vars)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logger.error(f"Ошибка получения переменных: {e}")
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
def _get_system_env_vars(self) -> Dict[str, str]:
|
|
|
|
|
"""
|
|
|
|
|
Получает переменные окружения из системы, исключая стандартные
|
|
|
|
|
"""
|
|
|
|
|
env_vars = {}
|
|
|
|
|
for key, value in os.environ.items():
|
|
|
|
|
# Пропускаем стандартные переменные
|
|
|
|
|
if key in self.EXCLUDED_ENV_VARS:
|
|
|
|
|
continue
|
|
|
|
|
# Пропускаем переменные с пустыми значениями
|
|
|
|
|
if not value:
|
|
|
|
|
continue
|
|
|
|
|
env_vars[key] = value
|
|
|
|
|
return env_vars
|
|
|
|
|
|
|
|
|
|
def _get_dotenv_vars(self) -> Dict[str, str]:
|
|
|
|
|
"""
|
|
|
|
|
Получает переменные из .env файла, если он существует
|
|
|
|
|
"""
|
|
|
|
|
env_vars = {}
|
|
|
|
|
if os.path.exists(self.env_file_path):
|
|
|
|
|
try:
|
2025-05-29 09:37:39 +00:00
|
|
|
|
with open(self.env_file_path, "r") as f:
|
2025-05-20 22:34:02 +00:00
|
|
|
|
for line in f:
|
|
|
|
|
line = line.strip()
|
|
|
|
|
# Пропускаем пустые строки и комментарии
|
2025-05-29 09:37:39 +00:00
|
|
|
|
if not line or line.startswith("#"):
|
2025-05-20 22:34:02 +00:00
|
|
|
|
continue
|
|
|
|
|
# Разделяем строку на ключ и значение
|
2025-05-29 09:37:39 +00:00
|
|
|
|
if "=" in line:
|
|
|
|
|
key, value = line.split("=", 1)
|
2025-05-20 22:34:02 +00:00
|
|
|
|
key = key.strip()
|
|
|
|
|
value = value.strip()
|
|
|
|
|
# Удаляем кавычки, если они есть
|
|
|
|
|
if value.startswith('"') and value.endswith('"'):
|
|
|
|
|
value = value[1:-1]
|
|
|
|
|
env_vars[key] = value
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logger.error(f"Ошибка чтения .env файла: {e}")
|
|
|
|
|
return env_vars
|
|
|
|
|
|
|
|
|
|
def _get_redis_env_vars(self) -> Dict[str, str]:
|
|
|
|
|
"""
|
|
|
|
|
Получает переменные окружения из Redis
|
|
|
|
|
"""
|
|
|
|
|
redis_vars = {}
|
2025-05-16 06:23:48 +00:00
|
|
|
|
try:
|
|
|
|
|
# Получаем все ключи с префиксом env:
|
|
|
|
|
keys = self.redis.keys(f"{self.prefix}*")
|
|
|
|
|
for key in keys:
|
|
|
|
|
var_key = key.decode("utf-8").replace(self.prefix, "")
|
|
|
|
|
value = self.redis.get(key)
|
|
|
|
|
if value:
|
2025-05-20 22:34:02 +00:00
|
|
|
|
redis_vars[var_key] = value.decode("utf-8")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logger.error(f"Ошибка получения переменных из Redis: {e}")
|
|
|
|
|
return redis_vars
|
2025-05-16 06:23:48 +00:00
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
def _is_secret_variable(self, key: str) -> bool:
|
|
|
|
|
"""
|
2025-05-26 10:31:25 +00:00
|
|
|
|
Проверяет, является ли переменная секретной.
|
|
|
|
|
Секретными считаются:
|
|
|
|
|
- переменные, подходящие под SECRET_VARS_PATTERNS
|
|
|
|
|
- переменные с ключами DATABASE_URL, REDIS_URL, DB_URL (точное совпадение, без учета регистра)
|
|
|
|
|
|
|
|
|
|
>>> EnvManager()._is_secret_variable('MY_SECRET_TOKEN')
|
|
|
|
|
True
|
|
|
|
|
>>> EnvManager()._is_secret_variable('database_url')
|
|
|
|
|
True
|
|
|
|
|
>>> EnvManager()._is_secret_variable('REDIS_URL')
|
|
|
|
|
True
|
|
|
|
|
>>> EnvManager()._is_secret_variable('DB_URL')
|
|
|
|
|
True
|
|
|
|
|
>>> EnvManager()._is_secret_variable('SOME_PUBLIC_KEY')
|
|
|
|
|
True
|
|
|
|
|
>>> EnvManager()._is_secret_variable('SOME_PUBLIC_VAR')
|
|
|
|
|
False
|
2025-05-20 22:34:02 +00:00
|
|
|
|
"""
|
|
|
|
|
key_upper = key.upper()
|
2025-05-26 10:31:25 +00:00
|
|
|
|
if key_upper in {"DATABASE_URL", "REDIS_URL", "DB_URL"}:
|
|
|
|
|
return True
|
2025-05-20 22:34:02 +00:00
|
|
|
|
return any(re.match(pattern, key_upper) for pattern in self.SECRET_VARS_PATTERNS)
|
|
|
|
|
|
|
|
|
|
def _determine_variable_type(self, value: str) -> str:
|
|
|
|
|
"""
|
|
|
|
|
Определяет тип переменной на основе ее значения
|
|
|
|
|
"""
|
2025-05-29 09:37:39 +00:00
|
|
|
|
if value.lower() in ("true", "false"):
|
2025-05-20 22:34:02 +00:00
|
|
|
|
return "boolean"
|
|
|
|
|
if value.isdigit():
|
|
|
|
|
return "integer"
|
|
|
|
|
if re.match(r"^\d+\.\d+$", value):
|
|
|
|
|
return "float"
|
|
|
|
|
# Проверяем на JSON объект или массив
|
2025-05-29 09:37:39 +00:00
|
|
|
|
if (value.startswith("{") and value.endswith("}")) or (value.startswith("[") and value.endswith("]")):
|
2025-05-20 22:34:02 +00:00
|
|
|
|
return "json"
|
|
|
|
|
# Проверяем на URL
|
2025-05-29 09:37:39 +00:00
|
|
|
|
if value.startswith(("http://", "https://", "redis://", "postgresql://")):
|
2025-05-20 22:34:02 +00:00
|
|
|
|
return "url"
|
|
|
|
|
return "string"
|
|
|
|
|
|
|
|
|
|
def _group_variables_by_sections(self, variables: Dict[str, str]) -> List[EnvSection]:
|
|
|
|
|
"""
|
|
|
|
|
Группирует переменные по секциям
|
|
|
|
|
"""
|
|
|
|
|
# Создаем словарь для группировки переменных
|
|
|
|
|
sections_dict = {section: [] for section in self.SECTIONS}
|
|
|
|
|
other_variables = [] # Для переменных, которые не попали ни в одну секцию
|
|
|
|
|
|
|
|
|
|
# Распределяем переменные по секциям
|
|
|
|
|
for key, value in variables.items():
|
|
|
|
|
is_secret = self._is_secret_variable(key)
|
|
|
|
|
var_type = self._determine_variable_type(value)
|
2025-05-29 09:37:39 +00:00
|
|
|
|
|
|
|
|
|
var = EnvVariable(key=key, value=value, type=var_type, is_secret=is_secret)
|
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
# Определяем секцию для переменной
|
|
|
|
|
placed = False
|
|
|
|
|
for section_id, section_config in self.SECTIONS.items():
|
|
|
|
|
if re.match(section_config["pattern"], key, re.IGNORECASE):
|
|
|
|
|
sections_dict[section_id].append(var)
|
|
|
|
|
placed = True
|
|
|
|
|
break
|
2025-05-29 09:37:39 +00:00
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
# Если переменная не попала ни в одну секцию
|
2025-05-21 07:35:27 +00:00
|
|
|
|
# if not placed:
|
|
|
|
|
# other_variables.append(var)
|
2025-05-20 22:34:02 +00:00
|
|
|
|
|
|
|
|
|
# Формируем результат
|
|
|
|
|
result = []
|
|
|
|
|
for section_id, variables in sections_dict.items():
|
|
|
|
|
if variables: # Добавляем только непустые секции
|
|
|
|
|
section_config = self.SECTIONS[section_id]
|
|
|
|
|
result.append(
|
|
|
|
|
EnvSection(
|
2025-05-29 09:37:39 +00:00
|
|
|
|
name=section_config["name"], description=section_config["description"], variables=variables
|
2025-05-20 22:34:02 +00:00
|
|
|
|
)
|
|
|
|
|
)
|
2025-05-29 09:37:39 +00:00
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
# Добавляем прочие переменные, если они есть
|
|
|
|
|
if other_variables:
|
|
|
|
|
result.append(
|
2025-05-16 06:23:48 +00:00
|
|
|
|
EnvSection(
|
2025-05-20 22:34:02 +00:00
|
|
|
|
name="Прочие переменные",
|
|
|
|
|
description="Переменные, не вошедшие в основные категории",
|
2025-05-29 09:37:39 +00:00
|
|
|
|
variables=other_variables,
|
2025-05-20 22:34:02 +00:00
|
|
|
|
)
|
|
|
|
|
)
|
2025-05-29 09:37:39 +00:00
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
return result
|
2025-05-16 06:23:48 +00:00
|
|
|
|
|
|
|
|
|
def update_variable(self, key: str, value: str) -> bool:
|
|
|
|
|
"""
|
2025-05-20 22:34:02 +00:00
|
|
|
|
Обновление значения переменной в Redis и .env файле
|
2025-05-16 06:23:48 +00:00
|
|
|
|
"""
|
|
|
|
|
try:
|
2025-05-20 22:34:02 +00:00
|
|
|
|
# Сохраняем в Redis
|
2025-05-16 06:23:48 +00:00
|
|
|
|
full_key = f"{self.prefix}{key}"
|
|
|
|
|
self.redis.set(full_key, value)
|
2025-05-29 09:37:39 +00:00
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
# Обновляем значение в .env файле
|
|
|
|
|
self._update_dotenv_var(key, value)
|
2025-05-29 09:37:39 +00:00
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
# Обновляем переменную в текущем процессе
|
|
|
|
|
os.environ[key] = value
|
2025-05-29 09:37:39 +00:00
|
|
|
|
|
2025-05-16 06:23:48 +00:00
|
|
|
|
return True
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logger.error(f"Ошибка обновления переменной {key}: {e}")
|
|
|
|
|
return False
|
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
def _update_dotenv_var(self, key: str, value: str) -> bool:
|
|
|
|
|
"""
|
|
|
|
|
Обновляет переменную в .env файле
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
# Если файл .env не существует, создаем его
|
|
|
|
|
if not os.path.exists(self.env_file_path):
|
2025-05-29 09:37:39 +00:00
|
|
|
|
with open(self.env_file_path, "w") as f:
|
2025-05-20 22:34:02 +00:00
|
|
|
|
f.write(f"{key}={value}\n")
|
|
|
|
|
return True
|
2025-05-29 09:37:39 +00:00
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
# Если файл существует, читаем его содержимое
|
|
|
|
|
lines = []
|
|
|
|
|
found = False
|
2025-05-29 09:37:39 +00:00
|
|
|
|
|
|
|
|
|
with open(self.env_file_path, "r") as f:
|
2025-05-20 22:34:02 +00:00
|
|
|
|
for line in f:
|
2025-05-29 09:37:39 +00:00
|
|
|
|
if line.strip() and not line.strip().startswith("#"):
|
2025-05-20 22:34:02 +00:00
|
|
|
|
if line.strip().startswith(f"{key}="):
|
|
|
|
|
# Экранируем значение, если необходимо
|
2025-05-29 09:37:39 +00:00
|
|
|
|
if " " in value or "," in value or '"' in value or "'" in value:
|
2025-05-20 22:34:02 +00:00
|
|
|
|
escaped_value = f'"{value}"'
|
|
|
|
|
else:
|
|
|
|
|
escaped_value = value
|
|
|
|
|
lines.append(f"{key}={escaped_value}\n")
|
|
|
|
|
found = True
|
|
|
|
|
else:
|
|
|
|
|
lines.append(line)
|
|
|
|
|
else:
|
|
|
|
|
lines.append(line)
|
2025-05-29 09:37:39 +00:00
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
# Если переменной не было в файле, добавляем ее
|
|
|
|
|
if not found:
|
|
|
|
|
# Экранируем значение, если необходимо
|
2025-05-29 09:37:39 +00:00
|
|
|
|
if " " in value or "," in value or '"' in value or "'" in value:
|
2025-05-20 22:34:02 +00:00
|
|
|
|
escaped_value = f'"{value}"'
|
|
|
|
|
else:
|
|
|
|
|
escaped_value = value
|
|
|
|
|
lines.append(f"{key}={escaped_value}\n")
|
2025-05-29 09:37:39 +00:00
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
# Записываем обновленный файл
|
2025-05-29 09:37:39 +00:00
|
|
|
|
with open(self.env_file_path, "w") as f:
|
2025-05-20 22:34:02 +00:00
|
|
|
|
f.writelines(lines)
|
2025-05-29 09:37:39 +00:00
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
return True
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logger.error(f"Ошибка обновления .env файла: {e}")
|
|
|
|
|
return False
|
|
|
|
|
|
2025-05-16 06:23:48 +00:00
|
|
|
|
def update_variables(self, variables: List[EnvVariable]) -> bool:
|
|
|
|
|
"""
|
|
|
|
|
Массовое обновление переменных
|
|
|
|
|
"""
|
|
|
|
|
try:
|
2025-05-20 22:34:02 +00:00
|
|
|
|
# Обновляем переменные в Redis
|
2025-05-16 06:23:48 +00:00
|
|
|
|
pipe = self.redis.pipeline()
|
|
|
|
|
for var in variables:
|
|
|
|
|
full_key = f"{self.prefix}{var.key}"
|
|
|
|
|
pipe.set(full_key, var.value)
|
|
|
|
|
pipe.execute()
|
2025-05-29 09:37:39 +00:00
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
# Обновляем переменные в .env файле
|
|
|
|
|
for var in variables:
|
|
|
|
|
self._update_dotenv_var(var.key, var.value)
|
2025-05-29 09:37:39 +00:00
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
# Обновляем переменную в текущем процессе
|
|
|
|
|
os.environ[var.key] = var.value
|
2025-05-29 09:37:39 +00:00
|
|
|
|
|
2025-05-16 06:23:48 +00:00
|
|
|
|
return True
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logger.error(f"Ошибка массового обновления переменных: {e}")
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
env_manager = EnvManager()
|