Files
configure_nginx_manager/Makefile

897 lines
53 KiB
Makefile
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ==============================================================================
# Makefile для установки и удаления скрипта управления SSL сертификатами
# Let's Encrypt с DNS-валидацией через API reg.ru
# ==============================================================================
# Подгружаем локальные переменные окружения (не коммитятся в git)
ifneq (,$(wildcard .env))
include .env
endif
# Переменные (переопределяемые через окружение или аргументы make)
INSTALL_DIR ?= /opt/letsencrypt-regru
SCRIPT_NAME = letsencrypt_regru_api.py
CONFIG_EXAMPLE = config.json.example
SERVICE_NAME = letsencrypt-regru
SERVICE_FILE = $(SERVICE_NAME).service
TIMER_FILE = $(SERVICE_NAME).timer
CONFIG_DIR ?= /etc/letsencrypt
CONFIG_FILE ?= $(CONFIG_DIR)/regru_config.json
LOG_DIR ?= /var/log
LOG_FILE = $(LOG_DIR)/letsencrypt_regru.log
CRON_LOG = $(LOG_DIR)/letsencrypt_cron.log
SYSTEMD_DIR ?= /etc/systemd/system
PYTHON ?= python3
# Цвета для вывода
RED = \033[0;31m
GREEN = \033[0;32m
YELLOW = \033[1;33m
BLUE = \033[0;34m
CYAN = \033[0;36m
NC = \033[0m # No Color
.PHONY: help install uninstall status check-root setup-dirs install-script \
install-service install-cron install-dependencies install-pyinstaller \
check-config test-run test-cert logs run obtain renew \
remove-service remove-cron remove-files \
clean clean-build build build-linux build-windows build-all \
package-linux package-windows release test-build build-info \
wiki-sync ci-release deploy-service
# Переменные для сборки
PYINSTALLER = pyinstaller
APP_NAME = letsencrypt-regru
DIST_DIR = dist
BUILD_DIR_PY = build
SPEC_FILE = $(APP_NAME).spec
# Переменные для запуска Gitea Actions workflows
DFGIT_URL ?= https://gitea.example.com
WORKFLOW_DISPATCH_SCRIPT ?= scripts/wiki_sync_dispatch.py
DFGIT_REPO ?= your_username/configure_nginx_manager
GIT_TOKEN ?=
GITEA_TOKEN ?=
GITEA_ACCESS_TOKEN ?=
AUTH_TOKEN := $(or $(DFGIT_TOKEN),$(GIT_TOKEN),$(GITEA_TOKEN),$(GITEA_ACCESS_TOKEN))
WIKI_SYNC_WORKFLOW ?= wiki-sync.yml
WIKI_SYNC_REF ?= master
RELEASE_WORKFLOW ?= release.yml
RELEASE_REF ?= master
RELEASE_TAG := $(if $(TAG),$(TAG),$(if $(filter v%,$(VERSION)),$(VERSION),v$(VERSION)))
DEPLOY_SERVICE_WORKFLOW ?= deploy-service.yml
DEPLOY_SERVICE_REF ?= master
# ==============================================================================
# Помощь
# ==============================================================================
help:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Makefile для управления Let's Encrypt SSL сертификатами ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(GREEN)Команды для установки:$(NC)"
@echo ""
@echo " $(YELLOW)make install$(NC) - Установить скрипт и настроить автоматизацию"
@echo " $(YELLOW)make uninstall$(NC) - Удалить скрипт и очистить систему"
@echo " $(YELLOW)make status$(NC) - Проверить статус установки"
@echo " $(YELLOW)make check-config$(NC) - Проверить конфигурацию"
@echo " $(YELLOW)make test-run$(NC) - Тестовый запуск скрипта"
@echo " $(YELLOW)make test-cert$(NC) - Создать тестовый самоподписанный сертификат"
@echo " $(YELLOW)make logs$(NC) - Показать логи"
@echo ""
@echo "$(GREEN)Команды для сборки (PyInstaller):$(NC)"
@echo ""
@echo " $(YELLOW)make build$(NC) - Собрать исполняемый файл для текущей ОС"
@echo " $(YELLOW)make build-linux$(NC) - Собрать исполняемый файл для Linux"
@echo " $(YELLOW)make build-windows$(NC) - Собрать исполняемый файл для Windows"
@echo " $(YELLOW)make build-all$(NC) - Собрать для всех платформ"
@echo " $(YELLOW)make package-linux$(NC) - Создать tar.gz пакет для Linux"
@echo " $(YELLOW)make package-windows$(NC) - Создать zip пакет для Windows"
@echo " $(YELLOW)make release$(NC) - Полный цикл релиза (build + package)"
@echo " $(YELLOW)make clean-build$(NC) - Очистить артефакты сборки"
@echo ""
@echo "$(GREEN)CI / Wiki:$(NC)"
@echo ""
@echo " $(YELLOW)make wiki-sync$(NC) - Запустить workflow wiki-sync.yml на $(DFGIT_URL)"
@echo " $(YELLOW)make ci-release$(NC) - Запустить workflow release.yml на $(DFGIT_URL) (нужен TAG или VERSION)"
@echo " $(YELLOW)make deploy-service$(NC) - Запустить workflow deploy-service.yml на $(DFGIT_URL)"
@echo ""
@echo " $(YELLOW)make help$(NC) - Показать эту справку"
@echo ""
# ==============================================================================
# Проверка прав root
# ==============================================================================
check-root:
@if [ "$$(id -u)" != "0" ]; then \
echo "$(RED)✗ Ошибка: Требуются права root$(NC)"; \
echo "$(YELLOW)Запустите: sudo make install$(NC)"; \
exit 1; \
fi
# ==============================================================================
# Установка
# ==============================================================================
install: check-root
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Установка Let's Encrypt SSL Manager ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@$(MAKE) setup-dirs
@$(MAKE) install-dependencies
@$(MAKE) install-script
@$(MAKE) install-service
@echo ""
@echo "$(YELLOW) Для дополнительного резервирования через cron (опционально):$(NC)"
@echo " $(CYAN)sudo make install-cron$(NC)"
@echo ""
@echo "$(GREEN)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(GREEN)║ ✓ Установка завершена успешно! ║$(NC)"
@echo "$(GREEN)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)Следующие шаги:$(NC)"
@echo " 1. Отредактируйте конфигурацию:"
@echo " $(BLUE)sudo nano $(CONFIG_FILE)$(NC)"
@echo ""
@echo " 2. Проверьте конфигурацию:"
@echo " $(BLUE)make check-config$(NC)"
@echo ""
@echo " 3. Запустите тестовую проверку:"
@echo " $(BLUE)make test-run$(NC)"
@echo ""
@echo " 4. Проверьте статус службы:"
@echo " $(BLUE)make status$(NC)"
@echo ""
# Создание директорий
setup-dirs:
@echo "$(YELLOW)→ Создание директорий...$(NC)"
@mkdir -p $(INSTALL_DIR)
@mkdir -p $(CONFIG_DIR)
@mkdir -p $(LOG_DIR)
@echo "$(GREEN)✓ Директории созданы$(NC)"
# Установка зависимостей
install-dependencies:
@echo "$(YELLOW)→ Установка зависимостей Python...$(NC)"
@if command -v pip3 >/dev/null 2>&1; then \
pip3 install -q requests cryptography 2>/dev/null || pip3 install requests cryptography; \
elif command -v pip >/dev/null 2>&1; then \
pip install -q requests cryptography 2>/dev/null || pip install requests cryptography; \
elif command -v python3 >/dev/null 2>&1; then \
if python3 -m pip --version >/dev/null 2>&1; then \
python3 -m pip install -q requests cryptography 2>/dev/null || python3 -m pip install requests cryptography; \
else \
echo "$(RED)✗ pip не установлен. Выполните:$(NC)"; \
echo " $(CYAN)sudo apt-get update && sudo apt-get install -y python3-pip$(NC)"; \
echo " или"; \
echo " $(CYAN)curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && python3 get-pip.py$(NC)"; \
exit 1; \
fi; \
elif command -v python >/dev/null 2>&1; then \
if python -m pip --version >/dev/null 2>&1; then \
python -m pip install -q requests cryptography 2>/dev/null || python -m pip install requests cryptography; \
else \
echo "$(RED)✗ pip не установлен. Выполните:$(NC)"; \
echo " $(CYAN)sudo apt-get update && sudo apt-get install -y python3-pip$(NC)"; \
exit 1; \
fi; \
else \
echo "$(RED)✗ Python не найден. Установите Python 3:$(NC)"; \
echo " $(CYAN)sudo apt-get update && sudo apt-get install -y python3 python3-pip$(NC)"; \
exit 1; \
fi
@echo "$(GREEN)✓ Зависимости установлены$(NC)"
# Копирование скрипта
install-script:
@echo "$(YELLOW)→ Установка скрипта...$(NC)"
@if [ ! -f "$(SCRIPT_NAME)" ]; then \
echo "$(RED)✗ Файл $(SCRIPT_NAME) не найден!$(NC)"; \
exit 1; \
fi
@cp $(SCRIPT_NAME) $(INSTALL_DIR)/
@chmod +x $(INSTALL_DIR)/$(SCRIPT_NAME)
@echo "$(GREEN)✓ Скрипт установлен в $(INSTALL_DIR)/$(NC)"
@echo ""
@echo "$(YELLOW)→ Создание конфигурации...$(NC)"
@if [ ! -f "$(CONFIG_FILE)" ]; then \
if [ -f "$(CONFIG_EXAMPLE)" ]; then \
cp $(CONFIG_EXAMPLE) $(CONFIG_FILE); \
chmod 600 $(CONFIG_FILE); \
echo "$(GREEN)✓ Создан файл конфигурации: $(CONFIG_FILE)$(NC)"; \
echo "$(YELLOW)⚠ ВНИМАНИЕ: Отредактируйте конфигурацию перед использованием!$(NC)"; \
else \
echo "$(YELLOW)⚠ Файл config.json.example не найден$(NC)"; \
$(PYTHON) $(INSTALL_DIR)/$(SCRIPT_NAME) --create-config $(CONFIG_FILE); \
chmod 600 $(CONFIG_FILE); \
echo "$(GREEN)✓ Создана конфигурация по умолчанию$(NC)"; \
fi \
else \
echo "$(GREEN)✓ Конфигурация уже существует: $(CONFIG_FILE)$(NC)"; \
fi
# Установка systemd service и timer
install-service:
@echo "$(YELLOW)→ Создание systemd service...$(NC)"
@echo "[Unit]" > $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "Description=Let's Encrypt Certificate Manager with reg.ru DNS" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "After=network-online.target" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "Wants=network-online.target" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "[Service]" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "Type=oneshot" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "ExecStart=$(PYTHON) $(INSTALL_DIR)/$(SCRIPT_NAME) -c $(CONFIG_FILE) --auto" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "StandardOutput=journal" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "StandardError=journal" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "User=root" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "SyslogIdentifier=$(SERVICE_NAME)" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "[Install]" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "WantedBy=multi-user.target" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "$(GREEN)✓ Service файл создан$(NC)"
@echo ""
@echo "$(YELLOW)→ Создание systemd timer...$(NC)"
@echo "[Unit]" > $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "Description=Let's Encrypt Certificate Auto-Renewal Timer" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "Requires=$(SERVICE_FILE)" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "[Timer]" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "OnBootSec=15min" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "OnUnitActiveSec=12h" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "RandomizedDelaySec=1h" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "Persistent=true" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "[Install]" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "WantedBy=timers.target" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "$(GREEN)✓ Timer файл создан$(NC)"
@echo ""
@echo "$(YELLOW)→ Активация systemd службы...$(NC)"
@systemctl daemon-reload
@systemctl enable $(SERVICE_FILE) 2>/dev/null || true
@systemctl enable $(TIMER_FILE) 2>/dev/null || true
@systemctl start $(TIMER_FILE) 2>/dev/null || true
@echo "$(GREEN)✓ Systemd служба активирована$(NC)"
# Установка cron задачи
install-cron:
@echo "$(YELLOW)→ Настройка cron задачи...$(NC)"
@CRON_CMD="0 3 * * * $(PYTHON) $(INSTALL_DIR)/$(SCRIPT_NAME) -c $(CONFIG_FILE) >> $(CRON_LOG) 2>&1"; \
(crontab -l 2>/dev/null | grep -v "$(SCRIPT_NAME)" ; echo "$$CRON_CMD") | crontab -
@echo "$(GREEN)✓ Cron задача добавлена (ежедневно в 3:00 AM)$(NC)"
# ==============================================================================
# Удаление
# ==============================================================================
uninstall: check-root
@echo "$(RED)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(RED)║ Удаление Let's Encrypt SSL Manager ║$(NC)"
@echo "$(RED)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@printf "Вы уверены? Это удалит все файлы и настройки [y/N]: "; \
read REPLY; \
case "$$REPLY" in \
[Yy]* ) \
$(MAKE) remove-service; \
$(MAKE) remove-cron; \
$(MAKE) remove-files; \
echo ""; \
echo "$(GREEN)✓ Удаление завершено$(NC)"; \
;; \
* ) \
echo "$(YELLOW)Удаление отменено$(NC)"; \
;; \
esac
# Удаление systemd service
remove-service:
@echo "$(YELLOW)→ Остановка и удаление systemd служб...$(NC)"
@systemctl stop $(TIMER_FILE) 2>/dev/null || true
@systemctl stop $(SERVICE_FILE) 2>/dev/null || true
@systemctl disable $(TIMER_FILE) 2>/dev/null || true
@systemctl disable $(SERVICE_FILE) 2>/dev/null || true
@rm -f $(SYSTEMD_DIR)/$(SERVICE_FILE)
@rm -f $(SYSTEMD_DIR)/$(TIMER_FILE)
@systemctl daemon-reload
@echo "$(GREEN)✓ Systemd службы удалены$(NC)"
# Удаление cron задачи
remove-cron:
@echo "$(YELLOW)→ Удаление cron задачи...$(NC)"
@crontab -l 2>/dev/null | grep -v "$(SCRIPT_NAME)" | crontab - 2>/dev/null || true
@echo "$(GREEN)✓ Cron задача удалена$(NC)"
# Удаление файлов
remove-files:
@echo "$(YELLOW)→ Удаление файлов...$(NC)"
@rm -rf $(INSTALL_DIR)
@echo "$(GREEN)✓ Директория $(INSTALL_DIR) удалена$(NC)"
@echo ""
@printf "Удалить конфигурацию $(CONFIG_FILE)? [y/N]: "; \
read REPLY; \
case "$$REPLY" in \
[Yy]* ) \
rm -f $(CONFIG_FILE); \
echo "$(GREEN)✓ Конфигурация удалена$(NC)"; \
;; \
* ) \
echo "$(YELLOW)Конфигурация сохранена$(NC)"; \
;; \
esac
@echo ""
@printf "Удалить логи? [y/N]: "; \
read REPLY; \
case "$$REPLY" in \
[Yy]* ) \
rm -f $(LOG_FILE) $(CRON_LOG); \
echo "$(GREEN)✓ Логи удалены$(NC)"; \
;; \
* ) \
echo "$(YELLOW)Логи сохранены$(NC)"; \
;; \
esac
# ==============================================================================
# Утилиты
# ==============================================================================
# Проверка статуса
status:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Статус Let's Encrypt SSL Manager ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)→ Установка:$(NC)"
@if [ -d "$(INSTALL_DIR)" ]; then \
echo " $(GREEN)✓ Директория: $(INSTALL_DIR)$(NC)"; \
else \
echo " $(RED)✗ Директория не найдена$(NC)"; \
fi
@if [ -f "$(INSTALL_DIR)/$(SCRIPT_NAME)" ]; then \
echo " $(GREEN)✓ Скрипт установлен$(NC)"; \
else \
echo " $(RED)✗ Скрипт не найден$(NC)"; \
fi
@if [ -f "$(CONFIG_FILE)" ]; then \
echo " $(GREEN)✓ Конфигурация: $(CONFIG_FILE)$(NC)"; \
else \
echo " $(YELLOW)⚠ Конфигурация не найдена$(NC)"; \
fi
@echo ""
@echo "$(YELLOW)→ Systemd служба:$(NC)"
@systemctl is-enabled $(SERVICE_FILE) 2>/dev/null && echo " $(GREEN)✓ Service включен$(NC)" || echo " $(RED)✗ Service отключен$(NC)"
@systemctl is-active $(SERVICE_FILE) 2>/dev/null && echo " $(GREEN)✓ Service активен$(NC)" || echo " $(YELLOW)⚠ Service неактивен (oneshot)$(NC)"
@echo ""
@echo "$(YELLOW)→ Systemd timer:$(NC)"
@systemctl is-enabled $(TIMER_FILE) 2>/dev/null && echo " $(GREEN)✓ Timer включен$(NC)" || echo " $(RED)✗ Timer отключен$(NC)"
@systemctl is-active $(TIMER_FILE) 2>/dev/null && echo " $(GREEN)✓ Timer активен$(NC)" || echo " $(RED)✗ Timer неактивен$(NC)"
@echo ""
@echo "$(YELLOW)→ Следующий запуск:$(NC)"
@systemctl list-timers $(TIMER_FILE) --no-pager 2>/dev/null || echo " $(RED)✗ Timer не найден$(NC)"
@echo ""
@echo "$(YELLOW)→ Cron задача:$(NC)"
@if crontab -l 2>/dev/null | grep -q "$(SCRIPT_NAME)"; then \
echo " $(GREEN)✓ Cron задача настроена$(NC)"; \
crontab -l 2>/dev/null | grep "$(SCRIPT_NAME)"; \
else \
echo " $(RED)✗ Cron задача не найдена$(NC)"; \
fi
# Проверка конфигурации
check-config:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Проверка конфигурации ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@if [ ! -f "$(CONFIG_FILE)" ]; then \
echo "$(RED)✗ Конфигурация не найдена: $(CONFIG_FILE)$(NC)"; \
echo "$(YELLOW)Совет: Скопируйте config.json.example в $(CONFIG_FILE)$(NC)"; \
echo " $(CYAN)sudo cp config.json.example $(CONFIG_FILE)$(NC)"; \
echo " $(CYAN)sudo chmod 600 $(CONFIG_FILE)$(NC)"; \
exit 1; \
fi
@echo "$(GREEN)✓ Конфигурация найдена$(NC)"
@if [ ! -r "$(CONFIG_FILE)" ]; then \
echo "$(RED)✗ Нет прав для чтения: $(CONFIG_FILE)$(NC)"; \
echo "$(YELLOW)Решение: Запустите команду с sudo:$(NC)"; \
echo " $(CYAN)sudo make check-config$(NC)"; \
exit 1; \
fi
@echo ""
@$(PYTHON) -c "import json; print(json.dumps(json.load(open('$(CONFIG_FILE)')), indent=2, ensure_ascii=False))" 2>&1 || \
(echo "$(RED)✗ Ошибка: Неверный формат JSON$(NC)"; \
echo "$(YELLOW)Подробности:$(NC)"; \
$(PYTHON) -c "import json; json.load(open('$(CONFIG_FILE)'))" 2>&1 | head -5; \
exit 1)
@echo ""
@echo "$(YELLOW)→ Проверка обязательных параметров:$(NC)"
@$(PYTHON) -c "import json; c=json.load(open('$(CONFIG_FILE)')); assert c.get('regru_username'), 'regru_username не задан'" && echo " $(GREEN)✓ regru_username$(NC)" || echo " $(RED)✗ regru_username$(NC)"
@$(PYTHON) -c "import json; c=json.load(open('$(CONFIG_FILE)')); assert c.get('regru_password'), 'regru_password не задан'" && echo " $(GREEN)✓ regru_password$(NC)" || echo " $(RED)✗ regru_password$(NC)"
@$(PYTHON) -c "import json; c=json.load(open('$(CONFIG_FILE)')); assert c.get('domain'), 'domain не задан'" && echo " $(GREEN)✓ domain$(NC)" || echo " $(RED)✗ domain$(NC)"
@$(PYTHON) -c "import json; c=json.load(open('$(CONFIG_FILE)')); assert c.get('email'), 'email не задан'" && echo " $(GREEN)✓ email$(NC)" || echo " $(RED)✗ email$(NC)"
# Тестовый запуск
test-run: check-root
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Тестовый запуск скрипта ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@if [ ! -f "$(CONFIG_FILE)" ]; then \
echo "$(RED)✗ Конфигурация не найдена. Запустите: make install$(NC)"; \
exit 1; \
fi
@echo "$(YELLOW)→ Запуск проверки сертификата...$(NC)"
@echo ""
@$(PYTHON) $(INSTALL_DIR)/$(SCRIPT_NAME) -c $(CONFIG_FILE) --check -v
# Просмотр логов
logs:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Логи Let's Encrypt SSL Manager ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)→ Основной лог скрипта:$(NC)"
@if [ -f "$(LOG_FILE)" ]; then \
tail -n 50 $(LOG_FILE); \
else \
echo "$(YELLOW)Лог файл не найден$(NC)"; \
fi
@echo ""
@echo "$(YELLOW)→ Лог cron задачи:$(NC)"
@if [ -f "$(CRON_LOG)" ]; then \
tail -n 50 $(CRON_LOG); \
else \
echo "$(YELLOW)Лог cron не найден$(NC)"; \
fi
@echo ""
@echo "$(YELLOW)→ Логи systemd:$(NC)"
@journalctl -u $(SERVICE_FILE) -n 50 --no-pager 2>/dev/null || echo "$(YELLOW)Логи systemd не найдены$(NC)"
# Запуск workflow синхронизации wiki на $(DFGIT_URL)
ifeq ($(OS),Windows_NT)
wiki-sync:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Запуск wiki-sync workflow на $(DFGIT_URL)$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
$(if $(AUTH_TOKEN),,$(error Токен не задан. Укажите DFGIT_TOKEN или GIT_TOKEN/GITEA_TOKEN/GITEA_ACCESS_TOKEN))
@powershell -NoProfile -ExecutionPolicy Bypass -Command "$$ErrorActionPreference='Stop'; Write-Host '>>> Запуск wiki-sync workflow (ref=$(WIKI_SYNC_REF))...'; Invoke-RestMethod -Method Post -Uri '$(DFGIT_URL)/api/v1/repos/$(DFGIT_REPO)/actions/workflows/$(WIKI_SYNC_WORKFLOW)/dispatches' -Headers @{ Authorization = 'token $(AUTH_TOKEN)'; 'Content-Type' = 'application/json' } -Body '{\"ref\": \"$(WIKI_SYNC_REF)\", \"inputs\": {\"ref\": \"$(WIKI_SYNC_REF)\"}}' -ErrorAction Stop | Out-Null; Write-Host '>>> Workflow запущен. Статус: $(DFGIT_URL)/$(DFGIT_REPO)/actions'"
else
wiki-sync:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Запуск wiki-sync workflow на $(DFGIT_URL)$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
$(if $(AUTH_TOKEN),,$(error Токен не задан. Укажите DFGIT_TOKEN или GIT_TOKEN/GITEA_TOKEN/GITEA_ACCESS_TOKEN))
@echo ">>> Запуск wiki-sync workflow (ref=$(WIKI_SYNC_REF))..."
@curl -sf -X POST \
-H "Authorization: token $(AUTH_TOKEN)" \
-H "Content-Type: application/json" \
"$(DFGIT_URL)/api/v1/repos/$(DFGIT_REPO)/actions/workflows/$(WIKI_SYNC_WORKFLOW)/dispatches" \
-d '{"ref": "$(WIKI_SYNC_REF)", "inputs": {"ref": "$(WIKI_SYNC_REF)"}}' \
&& echo ">>> Workflow запущен. Статус: $(DFGIT_URL)/$(DFGIT_REPO)/actions"
endif
ifeq ($(OS),Windows_NT)
ci-release:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Запуск release workflow на $(DFGIT_URL)$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
ifndef TAG
ifndef VERSION
$(error Укажите TAG=vX.Y.Z или VERSION=X.Y.Z. Пример: make ci-release TAG=v1.0.0)
endif
endif
$(if $(AUTH_TOKEN),,$(error Токен не задан. Укажите DFGIT_TOKEN или GIT_TOKEN/GITEA_TOKEN/GITEA_ACCESS_TOKEN))
@powershell -NoProfile -ExecutionPolicy Bypass -Command "$$ErrorActionPreference='Stop'; Write-Host '>>> Запуск release workflow (ref=$(RELEASE_REF), tag=$(RELEASE_TAG))...'; Invoke-RestMethod -Method Post -Uri '$(DFGIT_URL)/api/v1/repos/$(DFGIT_REPO)/actions/workflows/$(RELEASE_WORKFLOW)/dispatches' -Headers @{ Authorization = 'token $(AUTH_TOKEN)'; 'Content-Type' = 'application/json' } -Body '{\"ref\": \"$(RELEASE_REF)\", \"inputs\": {\"tag\": \"$(RELEASE_TAG)\"}}' -ErrorAction Stop | Out-Null; Write-Host '>>> Workflow запущен. Статус: $(DFGIT_URL)/$(DFGIT_REPO)/actions'"
else
ci-release:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Запуск release workflow на $(DFGIT_URL)$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
ifndef TAG
ifndef VERSION
$(error Укажите TAG=vX.Y.Z или VERSION=X.Y.Z. Пример: make ci-release TAG=v1.0.0)
endif
endif
$(if $(AUTH_TOKEN),,$(error Токен не задан. Укажите DFGIT_TOKEN или GIT_TOKEN/GITEA_TOKEN/GITEA_ACCESS_TOKEN))
@echo ">>> Запуск release workflow (ref=$(RELEASE_REF), tag=$(RELEASE_TAG))..."
@curl -sf -X POST \
-H "Authorization: token $(AUTH_TOKEN)" \
-H "Content-Type: application/json" \
"$(DFGIT_URL)/api/v1/repos/$(DFGIT_REPO)/actions/workflows/$(RELEASE_WORKFLOW)/dispatches" \
-d '{"ref": "$(RELEASE_REF)", "inputs": {"tag": "$(RELEASE_TAG)"}}' \
&& echo ">>> Workflow запущен. Статус: $(DFGIT_URL)/$(DFGIT_REPO)/actions"
endif
ifeq ($(OS),Windows_NT)
deploy-service:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Запуск deploy-service workflow на $(DFGIT_URL)$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
$(if $(AUTH_TOKEN),,$(error Токен не задан. Укажите DFGIT_TOKEN или GIT_TOKEN/GITEA_TOKEN/GITEA_ACCESS_TOKEN))
@powershell -NoProfile -ExecutionPolicy Bypass -Command "$$ErrorActionPreference='Stop'; Write-Host '>>> Запуск deploy-service workflow (ref=$(if $(REF),$(REF),$(DEPLOY_SERVICE_REF)))...'; Invoke-RestMethod -Method Post -Uri '$(DFGIT_URL)/api/v1/repos/$(DFGIT_REPO)/actions/workflows/$(DEPLOY_SERVICE_WORKFLOW)/dispatches' -Headers @{ Authorization = 'token $(AUTH_TOKEN)'; 'Content-Type' = 'application/json' } -Body '{\"ref\": \"$(if $(REF),$(REF),$(DEPLOY_SERVICE_REF))\", \"inputs\": {\"ref\": \"$(if $(REF),$(REF),$(DEPLOY_SERVICE_REF))\"}}' -ErrorAction Stop | Out-Null; Write-Host '>>> Workflow запущен. Статус: $(DFGIT_URL)/$(DFGIT_REPO)/actions'"
else
deploy-service:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Запуск deploy-service workflow на $(DFGIT_URL)$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
$(if $(AUTH_TOKEN),,$(error Токен не задан. Укажите DFGIT_TOKEN или GIT_TOKEN/GITEA_TOKEN/GITEA_ACCESS_TOKEN))
@echo ">>> Запуск deploy-service workflow (ref=$(if $(REF),$(REF),$(DEPLOY_SERVICE_REF)))..."
@curl -sf -X POST \
-H "Authorization: token $(AUTH_TOKEN)" \
-H "Content-Type: application/json" \
"$(DFGIT_URL)/api/v1/repos/$(DFGIT_REPO)/actions/workflows/$(DEPLOY_SERVICE_WORKFLOW)/dispatches" \
-d '{"ref": "$(if $(REF),$(REF),$(DEPLOY_SERVICE_REF))", "inputs": {"ref": "$(if $(REF),$(REF),$(DEPLOY_SERVICE_REF))"}}' \
&& echo ">>> Workflow запущен. Статус: $(DFGIT_URL)/$(DFGIT_REPO)/actions"
endif
# Ручной запуск обновления
run: check-root
@echo "$(YELLOW)→ Запуск обновления сертификата...$(NC)"
@$(PYTHON) $(INSTALL_DIR)/$(SCRIPT_NAME) -c $(CONFIG_FILE) -v
# Принудительное получение сертификата
obtain: check-root
@echo "$(YELLOW)→ Принудительное получение нового сертификата...$(NC)"
@$(PYTHON) $(INSTALL_DIR)/$(SCRIPT_NAME) -c $(CONFIG_FILE) --obtain -v
# Принудительное обновление сертификата
renew: check-root
@echo "$(YELLOW)→ Принудительное обновление сертификата...$(NC)"
@$(PYTHON) $(INSTALL_DIR)/$(SCRIPT_NAME) -c $(CONFIG_FILE) --renew -v
# Создание тестового самоподписанного сертификата
test-cert: check-root
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Создание тестового самоподписанного сертификата ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)⚠️ ВНИМАНИЕ: Это тестовый сертификат для разработки!$(NC)"
@echo "$(YELLOW) Браузеры будут показывать предупреждение безопасности.$(NC)"
@echo "$(YELLOW) Для production используйте Let's Encrypt сертификаты.$(NC)"
@echo ""
@if [ ! -f "$(CONFIG_FILE)" ]; then \
echo "$(RED)✗ Конфигурация не найдена. Запустите: make install$(NC)"; \
exit 1; \
fi
@echo "$(YELLOW)→ Генерация самоподписанного сертификата...$(NC)"
@echo ""
@$(PYTHON) $(INSTALL_DIR)/$(SCRIPT_NAME) -c $(CONFIG_FILE) --test-cert -v
@echo ""
@echo "$(GREEN)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(GREEN)║ ✓ Тестовый сертификат создан ║$(NC)"
@echo "$(GREEN)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)Преимущества тестового сертификата:$(NC)"
@echo " • Нет ограничений Let's Encrypt (5 сертификатов в неделю)"
@echo " • Мгновенное создание без DNS-валидации"
@echo " • Идеально для тестирования интеграции с NPM"
@echo " • Можно создавать неограниченное количество раз"
@echo ""
@echo "$(YELLOW)Примечание:$(NC)"
@echo " Тестовый сертификат НЕ доверяется браузерами."
@echo " Используйте только для локальной разработки и тестирования."
@echo ""
# Очистка временных файлов
clean:
@echo "$(YELLOW)→ Очистка временных файлов...$(NC)"
@find . -type f -name "*.pyc" -delete
@find . -type d -name "__pycache__" -delete
@echo "$(GREEN)✓ Очистка завершена$(NC)"
# ==============================================================================
# Сборка исполняемых файлов с PyInstaller
# ==============================================================================
# Установка PyInstaller
install-pyinstaller:
@echo "$(YELLOW)→ Установка PyInstaller...$(NC)"
@if command -v pip3 >/dev/null 2>&1; then \
pip3 install --upgrade pyinstaller; \
elif command -v pip >/dev/null 2>&1; then \
pip install --upgrade pyinstaller; \
else \
echo "$(RED)✗ pip не найден. Установите pip сначала.$(NC)"; \
exit 1; \
fi
@echo "$(GREEN)✓ PyInstaller установлен$(NC)"
# Сборка для текущей ОС
build:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Сборка исполняемого файла для текущей ОС$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@if ! command -v $(PYINSTALLER) >/dev/null 2>&1; then \
echo "$(YELLOW)PyInstaller не найден. Установка...$(NC)"; \
$(MAKE) install-pyinstaller; \
fi
@echo "$(YELLOW)→ Компиляция $(SCRIPT_NAME) в исполняемый файл...$(NC)"
@UNAME=$$(uname -s 2>/dev/null || echo "Windows"); \
SEPARATOR=":"; \
case "$$UNAME" in MINGW*|MSYS*|CYGWIN*|Windows*) SEPARATOR=";";; esac; \
echo "$(YELLOW)→ Используем разделитель add-data: $$SEPARATOR$(NC)"; \
$(PYINSTALLER) --onefile \
--name $(APP_NAME) \
--add-data "README.md$${SEPARATOR}." \
--hidden-import requests \
--hidden-import certbot \
--hidden-import cryptography \
--collect-all certbot \
--noconfirm \
$(SCRIPT_NAME)
@echo ""
@echo "$(GREEN)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(GREEN)║ ✓ Сборка завершена успешно! ║$(NC)"
@echo "$(GREEN)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)Исполняемый файл:$(NC)"
@ls -lh $(DIST_DIR)/$(APP_NAME) 2>/dev/null || dir $(DIST_DIR)\$(APP_NAME).exe 2>/dev/null || echo " $(DIST_DIR)/$(APP_NAME)"
@echo ""
@echo "$(YELLOW)Размер файла:$(NC)"
@du -h $(DIST_DIR)/$(APP_NAME) 2>/dev/null || echo " ~40-60 MB (включая Python runtime и все библиотеки)"
@echo ""
@echo "$(YELLOW)Примечание:$(NC)"
@echo " • Исполняемый файл содержит весь Python runtime"
@echo " • Certbot все равно должен быть установлен в системе"
@echo " • Запускайте с sudo для работы с сертификатами"
# Сборка для Linux
build-linux:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Сборка исполняемого файла для Linux ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@UNAME=$$(uname -s 2>/dev/null || echo "Unknown"); \
if [ "$$UNAME" != "Linux" ]; then \
echo "$(RED)ВНИМАНИЕ: Сборка на $$UNAME, но целевая ОС - Linux$(NC)"; \
echo "$(YELLOW)Рекомендуется собирать на Linux для лучшей совместимости$(NC)"; \
echo ""; \
fi
@if ! command -v $(PYINSTALLER) >/dev/null 2>&1; then \
echo "$(YELLOW)PyInstaller не найден. Установка...$(NC)"; \
$(MAKE) install-pyinstaller; \
fi
@echo "$(YELLOW)→ Компиляция для Linux (x86_64)...$(NC)"
@$(PYINSTALLER) --onefile \
--name $(APP_NAME) \
--add-data "README.md:." \
--hidden-import requests \
--hidden-import certbot \
--hidden-import cryptography \
--collect-all certbot \
--noconfirm \
$(SCRIPT_NAME)
@echo ""
@echo "$(GREEN)✓ Сборка для Linux завершена!$(NC)"
@echo ""
@echo "$(YELLOW)Исполняемый файл:$(NC) $(DIST_DIR)/$(APP_NAME)"
@file $(DIST_DIR)/$(APP_NAME) 2>/dev/null || echo " ELF 64-bit executable"
@ls -lh $(DIST_DIR)/$(APP_NAME) 2>/dev/null || echo ""
# Сборка для Windows
build-windows:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Сборка исполняемого файла для Windows ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@UNAME=$$(uname -s 2>/dev/null || echo "Windows"); \
SEPARATOR=";"; \
if [ "$$UNAME" = "Linux" ] || [ "$$UNAME" = "Darwin" ]; then \
echo "$(RED)ВНИМАНИЕ: Кросс-компиляция для Windows из $$UNAME$(NC)"; \
echo "$(YELLOW)Используем разделитель ':' вместо ';' для PyInstaller$(NC)"; \
echo "$(YELLOW)Рекомендуется: собирайте на нативной Windows для лучших результатов$(NC)"; \
echo ""; \
SEPARATOR=":"; \
fi; \
if ! command -v $(PYINSTALLER) >/dev/null 2>&1; then \
echo "$(YELLOW)PyInstaller не найден. Установка...$(NC)"; \
$(MAKE) install-pyinstaller; \
fi; \
echo "$(YELLOW)→ Компиляция для Windows (x86_64) с разделителем $$SEPARATOR...$(NC)"; \
$(PYINSTALLER) --onefile \
--name $(APP_NAME) \
--add-data "README.md$${SEPARATOR}." \
--hidden-import requests \
--hidden-import certbot \
--hidden-import cryptography \
--collect-all certbot \
--icon NONE \
--noconfirm \
$(SCRIPT_NAME)
@echo ""
@echo "$(GREEN)✓ Сборка для Windows завершена!$(NC)"
@echo ""
@echo "$(YELLOW)Исполняемый файл:$(NC) $(DIST_DIR)/$(APP_NAME).exe"
@ls -lh $(DIST_DIR)/$(APP_NAME).exe 2>/dev/null || dir $(DIST_DIR)\$(APP_NAME).exe 2>/dev/null || echo ""
# Сборка для всех платформ
build-all:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Сборка для всех платформ ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(RED)⚠️ ВНИМАНИЕ: Кросс-компиляция Windows из Linux НЕ РАБОТАЕТ!$(NC)"
@echo "$(YELLOW)→ PyInstaller не может создать .exe файл на Linux/macOS$(NC)"
@echo "$(YELLOW)→ Для Windows сборки используйте нативную Windows систему$(NC)"
@echo ""
@echo "$(YELLOW)Рекомендации:$(NC)"
@echo " • Собирать Linux версию на Linux (работает ✓)"
@echo " • Собирать Windows версию на Windows (обязательно!)"
@echo " • Использовать GitHub Actions для автоматической сборки"
@echo ""
@$(MAKE) build-linux
@echo ""
@UNAME=$$(uname -s 2>/dev/null || echo "Windows"); \
case "$$UNAME" in Windows*|MINGW*|MSYS*|CYGWIN*) IS_WIN=1;; *) IS_WIN=0;; esac; \
if [ "$$IS_WIN" = "0" ]; then \
echo "$(YELLOW)Пропускаем Windows сборку (текущая ОС: $$UNAME)$(NC)"; \
echo "$(YELLOW)Используйте Windows для создания .exe файла$(NC)"; \
else \
$(MAKE) build-windows; \
fi
@echo ""
@echo "$(GREEN)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(GREEN)║ ✓ Сборка завершена! ║$(NC)"
@echo "$(GREEN)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)Файлы в директории $(DIST_DIR)/:$(NC)"
@ls -lh $(DIST_DIR)/ 2>/dev/null || dir $(DIST_DIR) 2>/dev/null || echo " Проверьте $(DIST_DIR)/"
# Создание пакета для Linux (tar.gz)
package-linux: build-linux
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Создание пакета для Linux ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)→ Подготовка файлов...$(NC)"
@mkdir -p $(DIST_DIR)/package
@cp $(DIST_DIR)/$(APP_NAME) $(DIST_DIR)/package/
@cp README.md $(DIST_DIR)/package/ 2>/dev/null || true
@cp -r systemd $(DIST_DIR)/package/ 2>/dev/null || true
@if [ -f "config.json.example" ]; then \
cp config.json.example $(DIST_DIR)/package/; \
fi
@echo "$(YELLOW)→ Создание архива...$(NC)"
@cd $(DIST_DIR)/package && tar -czf ../$(APP_NAME)-linux-x86_64.tar.gz *
@rm -rf $(DIST_DIR)/package
@echo ""
@echo "$(GREEN)✓ Пакет создан:$(NC) $(DIST_DIR)/$(APP_NAME)-linux-x86_64.tar.gz"
@ls -lh $(DIST_DIR)/$(APP_NAME)-linux-x86_64.tar.gz
@echo ""
@echo "$(YELLOW)Содержимое пакета:$(NC)"
@tar -tzf $(DIST_DIR)/$(APP_NAME)-linux-x86_64.tar.gz | head -10
# Создание пакета для Windows (zip)
package-windows: build-windows
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Создание пакета для Windows ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@if [ ! -f "$(DIST_DIR)/$(APP_NAME).exe" ]; then \
echo "$(RED)✗ Ошибка: Файл $(APP_NAME).exe не найден$(NC)"; \
echo "$(YELLOW)⚠️ Кросс-компиляция для Windows из Linux/macOS не создает .exe файл!$(NC)"; \
echo "$(YELLOW)→ Используйте нативную Windows систему для сборки Windows версии$(NC)"; \
echo ""; \
exit 1; \
fi
@echo "$(YELLOW)→ Подготовка файлов...$(NC)"
@mkdir -p $(DIST_DIR)/package
@cp $(DIST_DIR)/$(APP_NAME).exe $(DIST_DIR)/package/
@cp README.md $(DIST_DIR)/package/ 2>/dev/null || true
@if [ -f "config.json.example" ]; then cp config.json.example $(DIST_DIR)/package/; fi
@echo "$(YELLOW)→ Создание архива (zip)...$(NC)"
@cd $(DIST_DIR)/package && $(PYTHON) -m zipfile -c ../$(APP_NAME)-windows-x86_64.zip . \
|| (cd $(DIST_DIR)/package && zip -r ../$(APP_NAME)-windows-x86_64.zip *) \
|| (cd $(DIST_DIR)/package && tar -czf ../$(APP_NAME)-windows-x86_64.tar.gz *)
@rm -rf $(DIST_DIR)/package
@echo ""
@echo "$(GREEN)✓ Пакет создан:$(NC)"
@ls -lh $(DIST_DIR)/$(APP_NAME)-windows-x86_64.zip 2>/dev/null || ls -lh $(DIST_DIR)/$(APP_NAME)-windows-x86_64.tar.gz 2>/dev/null
# Полный цикл релиза
release:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ ПОЛНЫЙ ЦИКЛ РЕЛИЗА ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@$(MAKE) clean-build
@$(MAKE) install-pyinstaller
@$(MAKE) build-all
@$(MAKE) package-linux
@$(MAKE) package-windows
@echo ""
@echo "$(GREEN)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(GREEN)║ ✓ РЕЛИЗ ГОТОВ! ║$(NC)"
@echo "$(GREEN)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)Артефакты релиза:$(NC)"
@ls -lh $(DIST_DIR)/$(APP_NAME)-*.tar.gz $(DIST_DIR)/$(APP_NAME)-*.zip 2>/dev/null || dir $(DIST_DIR)\$(APP_NAME)-*.* 2>/dev/null || echo " Проверьте $(DIST_DIR)/"
@echo ""
@echo "$(YELLOW)Контрольные суммы SHA256:$(NC)"
@cd $(DIST_DIR) && sha256sum $(APP_NAME)-*.tar.gz $(APP_NAME)-*.zip 2>/dev/null || \
$(PYTHON) -c "import hashlib,glob,os; [print(hashlib.sha256(open(f,'rb').read()).hexdigest()+' '+os.path.basename(f)) for f in sorted(glob.glob('$(DIST_DIR)/$(APP_NAME)-*.*'))]" 2>/dev/null || \
echo " Используйте sha256sum или Python для проверки контрольных сумм"
@echo ""
@echo "$(YELLOW)Следующие шаги:$(NC)"
@echo " 1. Протестируйте исполняемые файлы"
@echo " 2. Создайте GitHub Release"
@echo " 3. Загрузите пакеты как Assets"
# Тестирование собранного файла
test-build:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Тестирование собранного файла ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@if [ -f "$(DIST_DIR)/$(APP_NAME)" ]; then \
echo "$(YELLOW)→ Тестирование Linux версии...$(NC)"; \
chmod +x $(DIST_DIR)/$(APP_NAME); \
$(DIST_DIR)/$(APP_NAME) --help; \
echo ""; \
echo "$(GREEN)✓ Linux версия работает$(NC)"; \
elif [ -f "$(DIST_DIR)/$(APP_NAME).exe" ]; then \
echo "$(YELLOW)→ Тестирование Windows версии...$(NC)"; \
$(DIST_DIR)/$(APP_NAME).exe --help; \
echo ""; \
echo "$(GREEN)✓ Windows версия работает$(NC)"; \
else \
echo "$(RED)✗ Исполняемый файл не найден$(NC)"; \
echo "$(YELLOW)Запустите 'make build' сначала$(NC)"; \
exit 1; \
fi
# Очистка артефактов сборки
clean-build:
@echo "$(YELLOW)→ Очистка артефактов сборки...$(NC)"
@rm -rf $(BUILD_DIR_PY) $(DIST_DIR) $(SPEC_FILE) __pycache__ *.pyc
@echo "$(GREEN)✓ Артефакты сборки удалены$(NC)"
# Информация о среде сборки
build-info:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Информация о среде сборки ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)Система:$(NC)"
@echo " ОС: $$(uname -s 2>/dev/null || echo 'Windows')"
@echo " Архитектура: $$(uname -m 2>/dev/null || echo 'x86_64')"
@echo " Ядро: $$(uname -r 2>/dev/null || echo 'N/A')"
@echo ""
@echo "$(YELLOW)Python:$(NC)"
@echo " Версия: $$($(PYTHON) --version 2>&1)"
@echo " Путь: $$(which $(PYTHON) 2>/dev/null || where $(PYTHON) 2>/dev/null || echo 'N/A')"
@echo ""
@echo "$(YELLOW)PyInstaller:$(NC)"
@if command -v $(PYINSTALLER) >/dev/null 2>&1; then \
echo " Версия: $$($(PYINSTALLER) --version 2>&1)"; \
echo " Путь: $$(which $(PYINSTALLER) 2>/dev/null || where $(PYINSTALLER) 2>/dev/null)"; \
echo " $(GREEN)✓ Установлен$(NC)"; \
else \
echo " $(RED)Не установлен$(NC)"; \
echo " Установите: make install-pyinstaller"; \
fi
@echo ""
@echo "$(YELLOW)Конфигурация сборки:$(NC)"
@echo " Исходный файл: $(SCRIPT_NAME)"
@echo " Название приложения: $(APP_NAME)"
@echo " Директория сборки: $(DIST_DIR)/"
@echo ""
# По умолчанию показываем помощь
.DEFAULT_GOAL := help