Достижение: Добавлены скрипты и документация для релиза PDF Compressor.

- Добавлен release-body.md для подробных заметок о релизе на русском языке.
- Реализован release-gitea.ps1 для автоматизированного релиза Gitea с помощью PowerShell.
- Создан release-gitea.sh для автоматизированного релиза Gitea с помощью Bash.
- Добавлен release.sh для сборки и маркировки релизов с поддержкой нескольких платформ.
- Улучшен пользовательский интерфейс благодаря информативному логированию и обработке ошибок.
- Добавлена ​​поддержка переменных окружения и управления конфигурацией.
- Добавлена ​​функция создания архивов и загрузки ресурсов в Gitea.
This commit is contained in:
Dmitriy Fofanov
2025-11-05 09:33:12 +03:00
parent f328d67080
commit ec65cfd05a
43 changed files with 5792 additions and 2 deletions

109
cmd/main.go Normal file
View File

@@ -0,0 +1,109 @@
package main
import (
"log"
"compressor/internal/domain/entities"
"compressor/internal/domain/repositories"
"compressor/internal/infrastructure/compressors"
"compressor/internal/infrastructure/config"
"compressor/internal/infrastructure/logging"
infraRepos "compressor/internal/infrastructure/repositories"
"compressor/internal/presentation/tui"
usecases "compressor/internal/usecase"
)
func main() {
// Загрузка конфигурации
configRepo := config.NewRepository()
appConfig, err := configRepo.Load("config.yaml")
if err != nil {
log.Fatalf("Ошибка загрузки конфигурации: %v", err)
}
// Инициализация базового логгера (в файл)
fileLogger, err := logging.NewFileLogger(
appConfig.Output.LogFileName,
appConfig.Output.LogLevel,
appConfig.Output.LogMaxSizeMB,
appConfig.Output.LogToFile,
)
if err != nil {
log.Printf("Предупреждение: не удалось инициализировать логгер: %v", err)
}
if fileLogger != nil {
defer fileLogger.Close()
}
// Инициализация TUI
tuiManager := tui.NewManager()
tuiManager.Initialize()
// Оборачиваем логгер адаптером, чтобы видеть логи в TUI
var logger repositories.Logger
logger = tui.NewUILogger(fileLogger, tuiManager)
// Инициализация репозиториев
fileRepo := infraRepos.NewFileSystemRepository()
compressionConfigRepo := infraRepos.NewConfigRepository()
// Выбираем компрессор на основе конфигурации
var compressor repositories.PDFCompressor
switch appConfig.Compression.Algorithm {
case "unipdf":
compressor = compressors.NewUniPDFCompressor()
default:
compressor = compressors.NewPDFCPUCompressor()
}
// Инициализация компрессора изображений
imageCompressor := compressors.NewImageCompressor()
// Инициализация use cases
processUseCase := usecases.NewProcessPDFsUseCase(
compressor,
fileRepo,
compressionConfigRepo,
logger,
)
imageUseCase := usecases.NewCompressImageUseCase(logger, imageCompressor)
// Создаем объединенный процессор для всех типов файлов
allFilesUseCase := usecases.NewProcessAllFilesUseCase(processUseCase, imageUseCase, logger)
// Подключаем репортер прогресса к TUI
processUseCase.SetProgressReporter(func(s entities.ProcessingStatus) {
tuiManager.SendStatusUpdate(s)
})
// Создание процессора для обработки команд
processor := NewApplicationProcessor(
processUseCase,
allFilesUseCase,
appConfig,
tuiManager,
logger,
)
defer processor.Shutdown()
// Привязываем запуск обработки к TUI
tuiManager.SetOnStartProcessing(func() {
// Получаем актуальную конфигурацию из TUI
processor.config = tuiManager.GetConfig()
go processor.StartProcessing()
})
// Автозапуск, если включен в конфигурации
if appConfig.Compression.AutoStart {
go processor.StartProcessing()
}
// Запуск TUI
if err := tuiManager.Run(); err != nil {
log.Fatalf("Ошибка запуска TUI: %v", err)
}
// Cleanup при выходе
tuiManager.Cleanup()
}

74
cmd/processor.go Normal file
View File

@@ -0,0 +1,74 @@
package main
import (
"compressor/internal/domain/entities"
"compressor/internal/domain/repositories"
"compressor/internal/presentation/tui"
usecases "compressor/internal/usecase"
"context"
"sync"
)
// ApplicationProcessor обрабатывает команды приложения
type ApplicationProcessor struct {
processUseCase *usecases.ProcessPDFsUseCase
allFilesUseCase *usecases.ProcessAllFilesUseCase
config *entities.Config
tuiManager *tui.Manager
logger repositories.Logger
// Graceful shutdown
ctx context.Context
cancel context.CancelFunc
wg sync.WaitGroup
}
// NewApplicationProcessor создает новый процессор приложения
func NewApplicationProcessor(
processUseCase *usecases.ProcessPDFsUseCase,
allFilesUseCase *usecases.ProcessAllFilesUseCase,
config *entities.Config,
tuiManager *tui.Manager,
logger repositories.Logger,
) *ApplicationProcessor {
ctx, cancel := context.WithCancel(context.Background())
return &ApplicationProcessor{
processUseCase: processUseCase,
allFilesUseCase: allFilesUseCase,
config: config,
tuiManager: tuiManager,
logger: logger,
ctx: ctx,
cancel: cancel,
}
}
// StartProcessing запускает обработку всех поддерживаемых файлов
func (p *ApplicationProcessor) StartProcessing() {
p.wg.Add(1)
defer p.wg.Done()
if p.logger != nil {
supportedTypes := p.allFilesUseCase.GetSupportedFileTypes(p.config)
p.logger.Info("Запуск обработки файлов. Поддерживаемые типы: %v", supportedTypes)
}
// Запускаем обработку всех поддерживаемых файлов
if err := p.allFilesUseCase.Execute(p.config); err != nil {
if p.logger != nil {
p.logger.Error("Ошибка обработки: %v", err)
}
return
}
if p.logger != nil {
p.logger.Success("Обработка файлов завершена успешно")
}
}
// Shutdown корректно завершает работу процессора
func (p *ApplicationProcessor) Shutdown() {
p.cancel()
p.wg.Wait()
}