Files
toolbox/app/Services/EnvService.php
2025-12-18 10:18:25 +08:00

348 lines
9.6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
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.
<?php
namespace App\Services;
use Carbon\Carbon;
use Illuminate\Support\Facades\File;
use InvalidArgumentException;
use RuntimeException;
class EnvService
{
private string $projectsPath;
private string $envStoragePath;
private string $backupStoragePath;
public function __construct(private readonly ConfigService $configService)
{
$this->projectsPath = $this->resolveProjectsPath();
$this->envStoragePath = storage_path('app/env');
$this->backupStoragePath = storage_path('app/env/backups');
if (!File::exists($this->envStoragePath)) {
File::makeDirectory($this->envStoragePath, 0755, true);
}
if (!File::exists($this->backupStoragePath)) {
File::makeDirectory($this->backupStoragePath, 0755, true);
}
}
private function resolveProjectsPath(): string
{
$path = $this->configService->get('workspace.projects_path');
if (empty($path)) {
throw new RuntimeException('configs 表未设置 workspace.projects_path。');
}
return rtrim($path, '/');
}
/**
* 获取所有项目列表
*/
public function getProjects(): array
{
if (!File::exists($this->projectsPath)) {
return [];
}
$projects = [];
$directories = File::directories($this->projectsPath);
foreach ($directories as $directory) {
$projectName = basename($directory);
$projects[] = [
'name' => $projectName,
'path' => $directory,
'has_env' => File::exists($directory . '/.env'),
'envs' => $this->getProjectEnvs($projectName)
];
}
return $projects;
}
/**
* 获取指定项目的所有环境配置
*/
public function getProjectEnvs(string $projectName): array
{
$projectEnvPath = $this->envStoragePath . '/' . $projectName;
if (!File::exists($projectEnvPath)) {
return [];
}
$envs = [];
$files = File::files($projectEnvPath);
foreach ($files as $file) {
if ($file->getExtension() === 'env') {
$envName = $file->getFilenameWithoutExtension();
$envs[] = [
'name' => $envName,
'file_path' => $file->getPathname(),
'size' => $file->getSize(),
'modified_at' => Carbon::createFromTimestamp($file->getMTime())->format('Y-m-d H:i:s')
];
}
}
return $envs;
}
/**
* 保存环境配置文件
*/
public function saveEnv(string $projectName, string $env, string $content): bool
{
$projectEnvPath = $this->envStoragePath . '/' . $projectName;
if (!File::exists($projectEnvPath)) {
File::makeDirectory($projectEnvPath, 0755, true);
}
$filePath = $projectEnvPath . '/' . $env . '.env';
return File::put($filePath, $content) !== false;
}
/**
* 获取环境配置文件内容
*/
public function getEnvContent(string $projectName, string $env): string
{
$filePath = $this->envStoragePath . '/' . $projectName . '/' . $env . '.env';
if (!File::exists($filePath)) {
throw new InvalidArgumentException("环境配置文件不存在: {$env}");
}
return File::get($filePath);
}
/**
* 应用环境配置到项目
*/
public function applyEnv(string $projectName, string $env): bool
{
$projectPath = $this->projectsPath . '/' . $projectName;
if (!File::exists($projectPath)) {
throw new InvalidArgumentException("项目不存在: {$projectName}");
}
$envContent = $this->getEnvContent($projectName, $env);
$targetEnvPath = $projectPath . '/.env';
// 备份现有的.env文件到当前项目的storage目录
if (File::exists($targetEnvPath)) {
$this->backupCurrentEnv($projectName);
}
return File::put($targetEnvPath, $envContent) !== false;
}
/**
* 删除环境配置文件
*/
public function deleteEnv(string $projectName, string $env): bool
{
$filePath = $this->envStoragePath . '/' . $projectName . '/' . $env . '.env';
if (!File::exists($filePath)) {
return true; // 文件不存在,视为删除成功
}
return File::delete($filePath);
}
/**
* 从项目导入当前.env文件
*/
public function importFromProject(string $projectName, string $env): bool
{
$projectEnvPath = $this->projectsPath . '/' . $projectName . '/.env';
if (!File::exists($projectEnvPath)) {
throw new InvalidArgumentException("项目 {$projectName} 没有.env文件");
}
$content = File::get($projectEnvPath);
return $this->saveEnv($projectName, $env, $content);
}
/**
* 获取项目当前.env文件内容
*/
public function getCurrentProjectEnv(string $projectName): ?string
{
$projectEnvPath = $this->projectsPath . '/' . $projectName . '/.env';
if (!File::exists($projectEnvPath)) {
return null;
}
return File::get($projectEnvPath);
}
/**
* 获取存储路径
*/
public function getStoragePath(): string
{
return $this->envStoragePath;
}
/**
* 获取项目路径
*/
public function getProjectsPath(): string
{
return $this->projectsPath;
}
/**
* 创建新的环境配置文件
*/
public function createNewEnv(string $projectName, string $envName): bool
{
$projectEnvPath = $this->envStoragePath . '/' . $projectName;
if (!File::exists($projectEnvPath)) {
File::makeDirectory($projectEnvPath, 0755, true);
}
$filePath = $projectEnvPath . '/' . $envName . '.env';
// 检查文件是否已存在
if (File::exists($filePath)) {
throw new InvalidArgumentException("环境配置文件已存在: {$envName}");
}
// 创建空的配置文件
$defaultContent = "# {$envName} 环境配置\n# 创建时间: " . Carbon::now()->format('Y-m-d H:i:s') . "\n\n";
return File::put($filePath, $defaultContent) !== false;
}
/**
* 备份项目当前的.env文件到storage目录
*/
private function backupCurrentEnv(string $projectName): bool
{
$projectPath = $this->projectsPath . '/' . $projectName;
$currentEnvPath = $projectPath . '/.env';
if (!File::exists($currentEnvPath)) {
return true; // 没有.env文件无需备份
}
// 创建项目备份目录
$projectBackupPath = $this->backupStoragePath . '/' . $projectName;
if (!File::exists($projectBackupPath)) {
File::makeDirectory($projectBackupPath, 0755, true);
}
// 生成备份文件名
$timestamp = Carbon::now()->format('Y-m-d-H-i-s');
$backupFileName = "env-backup-{$timestamp}.env";
$backupPath = $projectBackupPath . '/' . $backupFileName;
return File::copy($currentEnvPath, $backupPath);
}
/**
* 获取项目的所有备份文件
*/
public function getProjectBackups(string $projectName): array
{
$projectBackupPath = $this->backupStoragePath . '/' . $projectName;
if (!File::exists($projectBackupPath)) {
return [];
}
$backups = [];
$files = File::files($projectBackupPath);
foreach ($files as $file) {
if ($file->getExtension() === 'env' && str_starts_with($file->getFilename(), 'env-backup-')) {
$backups[] = [
'name' => $file->getFilenameWithoutExtension(),
'file_path' => $file->getPathname(),
'size' => $file->getSize(),
'created_at' => Carbon::createFromTimestamp($file->getMTime())->format('Y-m-d H:i:s')
];
}
}
// 按创建时间倒序排列
usort($backups, function ($a, $b) {
return strcmp($b['created_at'], $a['created_at']);
});
return $backups;
}
/**
* 恢复备份文件到项目
*/
public function restoreBackup(string $projectName, string $backupName): bool
{
$projectPath = $this->projectsPath . '/' . $projectName;
if (!File::exists($projectPath)) {
throw new InvalidArgumentException("项目不存在: {$projectName}");
}
$backupPath = $this->backupStoragePath . '/' . $projectName . '/' . $backupName . '.env';
if (!File::exists($backupPath)) {
throw new InvalidArgumentException("备份文件不存在: {$backupName}");
}
$targetEnvPath = $projectPath . '/.env';
// 在恢复前先备份当前的.env文件
if (File::exists($targetEnvPath)) {
$this->backupCurrentEnv($projectName);
}
$backupContent = File::get($backupPath);
return File::put($targetEnvPath, $backupContent) !== false;
}
/**
* 删除备份文件
*/
public function deleteBackup(string $projectName, string $backupName): bool
{
$backupPath = $this->backupStoragePath . '/' . $projectName . '/' . $backupName . '.env';
if (!File::exists($backupPath)) {
return true; // 文件不存在,视为删除成功
}
return File::delete($backupPath);
}
/**
* 获取备份存储路径
*/
public function getBackupStoragePath(): string
{
return $this->backupStoragePath;
}
}