初步给项目、飞行器、容器页面添加了git拉取功能
This commit is contained in:
@@ -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
@@ -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;
|
||||
}
|
||||
/**
|
||||
* 从已存在的磁盘目录导入容器
|
||||
*
|
||||
* ✅ 你的最新需求:
|
||||
* - 不创建“默认两个配置”
|
||||
* - 自动扫描容器目录下的『子文件夹』
|
||||
* - 每个子文件夹创建一个 ModuleFolder(type: '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
Reference in New Issue
Block a user