0
0

初步给项目、飞行器、容器页面添加了git拉取功能

This commit is contained in:
xubing
2025-12-05 20:17:05 +08:00
parent a7edfb82c5
commit 2c314b9b0b
19 changed files with 2557 additions and 156 deletions

View File

@@ -27,6 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GitService = void 0;
// src/panels/services/GitService.ts
const fs = __importStar(require("fs"));
const isomorphic_git_1 = __importDefault(require("isomorphic-git"));
const node_1 = __importDefault(require("isomorphic-git/http/node"));
@@ -255,16 +256,25 @@ class GitService {
}
/**
* 构建文件树
* 这里显式忽略:
* - .git 目录
* - .dcsp-data.json
* - 其它以 . 开头的隐藏文件/目录
*/
static async buildFileTree(dir, relativePath = '') {
try {
const files = await fs.promises.readdir(dir);
const tree = [];
for (const file of files) {
if (file.startsWith('.') && file !== '.git')
// 1. 不要解析 .git
if (file === '.git')
continue;
// 2. 不要解析项目数据文件
if (file === '.dcsp-data.json')
continue;
// 3. 其它所有隐藏文件/目录统统忽略
if (file.startsWith('.'))
continue;
const filePath = path.join(dir, file);
const stats = await fs.promises.stat(filePath);
const currentRelativePath = path.join(relativePath, file);

File diff suppressed because one or more lines are too long

View File

@@ -58,8 +58,8 @@ class ProjectService {
getProjectPath(projectId) {
return this.projectPaths.get(projectId);
}
setProjectPath(projectId, path) {
this.projectPaths.set(projectId, path);
setProjectPath(projectId, pathStr) {
this.projectPaths.set(projectId, pathStr);
}
async createProject(name) {
const newId = this.generateUniqueId('p', this.projects);
@@ -124,7 +124,7 @@ class ProjectService {
const aircraft = this.aircrafts.find(a => a.id === aircraftId);
if (!aircraft)
return false;
// ⚠️ 修正点:先在删除 containers 之前,算出要删的 containerIds
// ⚠️ 算出要删的 containerIds
const relatedContainers = this.containers.filter(c => c.aircraftId === aircraftId);
const containerIds = relatedContainers.map(c => c.id);
// 删除飞机自身和容器
@@ -135,7 +135,50 @@ class ProjectService {
this.moduleFolders = this.moduleFolders.filter(folder => !containerIds.includes(folder.containerId));
return true;
}
/**
* 从已存在的磁盘目录导入飞行器
* 不会创建/删除任何文件,只在内存中补充 Aircraft / Container / ModuleFolder 数据
*/
async importAircraftFromExistingFolder(projectId, aircraftName) {
// 已存在同名飞行器直接返回
const existed = this.getAircraftsByProject(projectId).find(a => a.name === aircraftName);
if (existed) {
return existed.id;
}
const newId = this.generateUniqueId('a', this.aircrafts);
const aircraft = {
id: newId,
name: aircraftName,
projectId
};
this.aircrafts.push(aircraft);
const projectPath = this.projectPaths.get(projectId);
if (!projectPath) {
return newId;
}
const aircraftDir = path.join(projectPath, aircraftName);
if (!fs.existsSync(aircraftDir)) {
// 目录不存在就不再解析子目录
return newId;
}
// 每个子目录视为一个容器(排除 .git
const entries = await fs.promises.readdir(aircraftDir, { withFileTypes: true });
for (const entry of entries) {
if (!entry.isDirectory())
continue;
if (entry.name === '.git')
continue;
await this.importContainerFromExistingFolder(newId, entry.name);
}
return newId;
}
// =============== 容器相关方法 ===============
/**
* ⚠️ 这里不再做 .git 过滤:
* - 我们只会通过 createContainer / importContainerFromExistingFolder 创建容器
* - importContainerFromExistingFolder 内部已经排除了 .git
* 所以不会出现名字叫 ".git" 的容器
*/
getContainersByAircraft(aircraftId) {
return this.containers.filter(c => c.aircraftId === aircraftId);
}
@@ -148,6 +191,7 @@ class ProjectService {
};
this.containers.push(newContainer);
await this.createContainerDirectory(newContainer);
// UI 手动创建的容器,仍然保留“默认两个配置”的行为
await this.createDefaultConfigs(newContainer);
return newId;
}
@@ -168,6 +212,73 @@ class ProjectService {
this.moduleFolders = this.moduleFolders.filter(folder => folder.containerId !== containerId);
return true;
}
/**
* 从已存在的磁盘目录导入容器
*
* ✅ 你的最新需求:
* - 不创建“默认两个配置”
* - 自动扫描容器目录下的『子文件夹』
* - 每个子文件夹创建一个 ModuleFoldertype: 'local'
* - 排除 `.git` 子文件夹
*/
async importContainerFromExistingFolder(aircraftId, containerName) {
if (containerName === '.git') {
throw new Error('不能将 .git 导入为容器');
}
const existed = this.getContainersByAircraft(aircraftId).find(c => c.name === containerName);
if (existed) {
return existed.id;
}
const newId = this.generateUniqueId('c', this.containers);
const container = {
id: newId,
name: containerName,
aircraftId
};
this.containers.push(container);
// 🚩 关键逻辑:扫描容器目录下的子文件夹 -> 创建 ModuleFolder
await this.scanContainerModuleFolders(container);
// 不再创建默认两个配置(不调用 createDefaultConfigs
// 也不创建目录(目录是 Git 克隆出来的,本来就存在)
return newId;
}
/**
* 扫描容器目录中的子文件夹(不含 .git将其作为本地模块文件夹记录
*/
async scanContainerModuleFolders(container) {
try {
const aircraft = this.aircrafts.find(a => a.id === container.aircraftId);
if (!aircraft)
return;
const projectPath = this.projectPaths.get(aircraft.projectId);
if (!projectPath)
return;
const containerDir = path.join(projectPath, aircraft.name, container.name);
if (!fs.existsSync(containerDir)) {
return;
}
const entries = await fs.promises.readdir(containerDir, { withFileTypes: true });
for (const entry of entries) {
if (!entry.isDirectory())
continue;
if (entry.name === '.git')
continue;
const folderId = this.generateUniqueId('local-', this.moduleFolders);
const relativePath = `/${aircraft.projectId}/${aircraft.name}/${container.name}/${entry.name}`;
const moduleFolder = {
id: folderId,
name: entry.name,
type: 'local',
localPath: relativePath,
containerId: container.id
};
this.moduleFolders.push(moduleFolder);
}
}
catch (error) {
console.error('扫描容器目录生成模块文件夹失败:', error);
}
}
// =============== 配置相关方法 ===============
getConfigsByContainer(containerId) {
return this.configs.filter(cfg => cfg.containerId === containerId);
@@ -295,6 +406,10 @@ class ProjectService {
console.error(`确保容器目录存在失败: ${error}`);
}
}
/**
* 仅用于「新建容器」时的默认两个配置
* (导入容器时不会调用)
*/
async createDefaultConfigs(container) {
this.configs.push({
id: this.generateUniqueId('cfg', this.configs),
@@ -346,10 +461,11 @@ class ProjectService {
this.containers = this.containers.filter(c => !aircraftIds.includes(c.aircraftId));
this.configs = this.configs.filter(cfg => !containerIds.includes(cfg.containerId));
this.moduleFolders = this.moduleFolders.filter(folder => !containerIds.includes(folder.containerId));
// 加载新数据
// ⭐ 载入新数据时顺便过滤掉名字为 ".git" 的容器(避免历史数据带进来)
const cleanedContainers = data.containers.filter(c => c.name !== '.git');
this.projects.push(...data.projects);
this.aircrafts.push(...data.aircrafts);
this.containers.push(...data.containers);
this.containers.push(...cleanedContainers);
this.configs.push(...data.configs);
this.moduleFolders.push(...data.moduleFolders);
this.projectPaths.set(projectId, projectPath);

File diff suppressed because one or more lines are too long