0
0

修复了拉取出现的bug,完善了改名功能

This commit is contained in:
xubing
2025-12-06 18:05:35 +08:00
parent 46c184b920
commit 11c405f79a
10 changed files with 650 additions and 98 deletions

View File

@@ -274,15 +274,15 @@ class ConfigPanel {
'goBackToProjects': () => this.handleGoBackToProjects(),
'goBackToAircrafts': () => this.handleGoBackToAircrafts(),
'goBackToContainers': () => this.handleGoBackToContainers(),
// 项目管理
// 项目管理 (MODIFIED)
'updateProjectName': (data) => this.updateProjectName(data.projectId, data.name),
'createProject': (data) => this.createProject(data.name),
'deleteProject': (data) => this.deleteProject(data.projectId),
// 飞行器管理
// 飞行器管理 (MODIFIED)
'updateAircraftName': (data) => this.updateAircraftName(data.aircraftId, data.name),
'createAircraft': (data) => this.createAircraft(data.name),
'deleteAircraft': (data) => this.deleteAircraft(data.aircraftId),
// 容器管理
// 容器管理 (MODIFIED)
'updateContainerName': (data) => this.updateContainerName(data.containerId, data.name),
'createContainer': (data) => this.createContainer(data.name),
'deleteContainer': (data) => this.deleteContainer(data.containerId),
@@ -382,13 +382,35 @@ class ConfigPanel {
this.updateWebview();
}
// =============================================
// 项目管理方法
// 项目管理方法 (MODIFIED)
// =============================================
/**
* 重命名项目更新内存数据、重命名磁盘文件夹、更新项目路径MODIFIED
*/
async updateProjectName(projectId, newName) {
if (this.projectService.updateProjectName(projectId, newName)) {
vscode.window.showInformationMessage(`项目名称更新: ${newName}`);
await this.saveCurrentProjectData();
this.updateWebview();
const project = this.projectService.getProjects().find(p => p.id === projectId);
if (!project)
return;
const paths = this.projectService.getProjectOldAndNewPaths(projectId, newName);
if (!paths) {
vscode.window.showErrorMessage('无法获取项目路径');
return;
}
try {
// 1. 重命名磁盘文件夹
await this.projectService.renameDirectoryOnDisk(paths.oldPath, paths.newPath);
// 2. 更新内存中的项目名称和项目路径
if (this.projectService.updateProjectName(projectId, newName)) {
// 必须更新 projectPaths map
this.projectService.setProjectPath(projectId, paths.newPath);
// 3. 保存数据到新的项目路径下的 .dcsp-data.json
await this.saveCurrentProjectData();
vscode.window.showInformationMessage(`✅ 项目名称和文件夹已更新: ${newName}`);
this.updateWebview();
}
}
catch (error) {
vscode.window.showErrorMessage(`❌ 重命名项目文件夹失败: ${error}`);
}
}
async createProject(name) {
@@ -397,25 +419,71 @@ class ConfigPanel {
vscode.window.showInformationMessage(`新建项目: ${name}`);
this.updateWebview();
}
/**
* 删除项目,同时删除磁盘上的文件夹
*/
async deleteProject(projectId) {
if (this.projectService.deleteProject(projectId)) {
if (this.currentProjectId === projectId) {
this.currentProjectId = '';
this.currentView = 'projects';
const project = this.projectService.getProjects().find(p => p.id === projectId);
// 获取项目存储路径
const projectPath = this.projectService.getProjectPath(projectId);
if (!project)
return;
const confirm = await vscode.window.showWarningMessage(`确定要删除项目 "${project.name}" 吗?这将同时删除磁盘上的文件夹及其所有内容。`, { modal: true }, '确定删除', '取消');
if (confirm !== '确定删除') {
return;
}
try {
// 1. 删除磁盘上的文件夹
if (projectPath) {
await this.projectService.deleteDirectoryFromDisk(projectPath);
}
vscode.window.showInformationMessage('项目已删除');
await this.saveCurrentProjectData();
this.updateWebview();
// 2. 从内存中删除 (同时会清理所有子数据)
if (this.projectService.deleteProject(projectId)) {
// 如果删除的是当前正在查看的项目,则返回 Projects 视图
if (this.currentProjectId === projectId) {
this.currentProjectId = '';
this.currentView = 'projects';
}
vscode.window.showInformationMessage(`项目已删除: ${project.name}`);
// 如果还有其他项目在内存中,保存一下最新的数据状态
if (this.currentProjectId) {
await this.saveCurrentProjectData();
}
this.updateWebview();
}
}
catch (error) {
vscode.window.showErrorMessage(`删除项目文件夹失败: ${error}`);
}
}
// =============================================
// 飞行器管理方法
// 飞行器管理方法 (MODIFIED)
// =============================================
/**
* 重命名飞行器更新内存数据、重命名磁盘文件夹MODIFIED
*/
async updateAircraftName(aircraftId, newName) {
if (this.projectService.updateAircraftName(aircraftId, newName)) {
vscode.window.showInformationMessage(`飞行器名称更新: ${newName}`);
await this.saveCurrentProjectData();
this.updateWebview();
const aircraft = this.projectService.getAircraft(aircraftId);
if (!aircraft)
return;
const paths = this.projectService.getAircraftOldAndNewPaths(aircraftId, newName);
if (!paths) {
vscode.window.showErrorMessage('无法获取飞行器路径');
return;
}
try {
// 1. 重命名磁盘文件夹
await this.projectService.renameDirectoryOnDisk(paths.oldPath, paths.newPath);
// 2. 更新内存中的飞行器名称
if (this.projectService.updateAircraftName(aircraftId, newName)) {
// 3. 保存数据到 .dcsp-data.json
await this.saveCurrentProjectData();
vscode.window.showInformationMessage(`✅ 飞行器名称和文件夹已更新: ${newName}`);
this.updateWebview();
}
}
catch (error) {
vscode.window.showErrorMessage(`❌ 重命名飞行器文件夹失败: ${error}`);
}
}
async createAircraft(name) {
@@ -428,21 +496,63 @@ class ConfigPanel {
await this.saveCurrentProjectData();
this.updateWebview();
}
/**
* 删除飞行器,同时删除磁盘上的文件夹
*/
async deleteAircraft(aircraftId) {
if (this.projectService.deleteAircraft(aircraftId)) {
vscode.window.showInformationMessage('飞行器已删除');
await this.saveCurrentProjectData();
this.updateWebview();
const aircraft = this.projectService.getAircraftsByProject(this.currentProjectId)
.find(a => a.id === aircraftId);
if (!aircraft)
return;
const confirm = await vscode.window.showWarningMessage(`确定要删除飞行器 "${aircraft.name}" 吗?这将同时删除磁盘上的文件夹。`, { modal: true }, '确定删除', '取消');
if (confirm !== '确定删除') {
return;
}
const dirPath = this.projectService.getAircraftDirectoryPath(aircraftId);
try {
// 1. 删除磁盘上的文件夹
if (dirPath) {
await this.projectService.deleteDirectoryFromDisk(dirPath);
}
// 2. 从内存中删除 (同时会清理所有子数据)
if (this.projectService.deleteAircraft(aircraftId)) {
vscode.window.showInformationMessage(`飞行器已删除: ${aircraft.name}`);
await this.saveCurrentProjectData();
this.updateWebview();
}
}
catch (error) {
vscode.window.showErrorMessage(`删除飞行器文件夹失败: ${error}`);
}
}
// =============================================
// 容器管理方法
// 容器管理方法 (MODIFIED)
// =============================================
/**
* 重命名容器更新内存数据、重命名磁盘文件夹MODIFIED
*/
async updateContainerName(containerId, newName) {
if (this.projectService.updateContainerName(containerId, newName)) {
vscode.window.showInformationMessage(`容器名称更新: ${newName}`);
await this.saveCurrentProjectData();
this.updateWebview();
const container = this.projectService.getContainer(containerId);
if (!container)
return;
const paths = this.projectService.getContainerOldAndNewPaths(containerId, newName);
if (!paths) {
vscode.window.showErrorMessage('无法获取容器路径');
return;
}
try {
// 1. 重命名磁盘文件夹
await this.projectService.renameDirectoryOnDisk(paths.oldPath, paths.newPath);
// 2. 更新内存中的容器名称
if (this.projectService.updateContainerName(containerId, newName)) {
// 3. 保存数据到 .dcsp-data.json
await this.saveCurrentProjectData();
vscode.window.showInformationMessage(`✅ 容器名称和文件夹已更新: ${newName}`);
this.updateWebview();
}
}
catch (error) {
vscode.window.showErrorMessage(`❌ 重命名容器文件夹失败: ${error}`);
}
}
async createContainer(name) {
@@ -455,11 +565,33 @@ class ConfigPanel {
await this.saveCurrentProjectData();
this.updateWebview();
}
/**
* 删除容器,同时删除磁盘上的文件夹
*/
async deleteContainer(containerId) {
if (this.projectService.deleteContainer(containerId)) {
vscode.window.showInformationMessage('容器已删除');
await this.saveCurrentProjectData();
this.updateWebview();
const container = this.projectService.getContainersByAircraft(this.currentAircraftId)
.find(c => c.id === containerId);
if (!container)
return;
const confirm = await vscode.window.showWarningMessage(`确定要删除容器 "${container.name}" 吗?这将同时删除磁盘上的文件夹。`, { modal: true }, '确定删除', '取消');
if (confirm !== '确定删除') {
return;
}
const dirPath = this.projectService.getContainerDirectoryPath(containerId);
try {
// 1. 删除磁盘上的文件夹
if (dirPath) {
await this.projectService.deleteDirectoryFromDisk(dirPath);
}
// 2. 从内存中删除 (同时会清理所有子数据)
if (this.projectService.deleteContainer(containerId)) {
vscode.window.showInformationMessage(`容器已删除: ${container.name}`);
await this.saveCurrentProjectData();
this.updateWebview();
}
}
catch (error) {
vscode.window.showErrorMessage(`删除容器文件夹失败: ${error}`);
}
}
// =============================================
@@ -1117,17 +1249,14 @@ class ConfigPanel {
const aircraft = this.projectService.getAircraftsByProject(this.currentProjectId).find(a => a.id === id);
name = aircraft?.name || 'Aircraft';
if (aircraft) {
fullPath = path.join(this.projectService.getProjectPath(aircraft.projectId) || '', aircraft.name);
fullPath = this.projectService.getAircraftDirectoryPath(id);
}
}
else if (type === 'container') {
const container = this.projectService.getContainersByAircraft(this.currentAircraftId).find(c => c.id === id);
name = container?.name || 'Container';
if (container) {
const aircraft = this.projectService.getAircraftsByProject(this.currentProjectId).find(a => a.id === container.aircraftId);
if (aircraft) {
fullPath = path.join(this.projectService.getProjectPath(aircraft.projectId) || '', aircraft.name, container.name);
}
fullPath = this.projectService.getContainerDirectoryPath(id);
}
}
if (!fullPath || !require('fs').existsSync(fullPath)) {

File diff suppressed because one or more lines are too long

View File

@@ -83,7 +83,7 @@ class GitService {
static async cloneRepository(url, localPath, branch = 'main', onProgress, username, token) {
const parentDir = path.dirname(localPath);
await fs.promises.mkdir(parentDir, { recursive: true });
// 检查目录是否已存在且非空(不变)
// 检查目录是否已存在且非空
let dirExists = false;
try {
await fs.promises.access(localPath);
@@ -94,7 +94,10 @@ class GitService {
}
if (dirExists) {
const dirContents = await fs.promises.readdir(localPath);
if (dirContents.length > 0 && dirContents.some(item => item !== '.git')) {
// 修正后的逻辑:过滤掉所有以 "." 开头的隐藏文件/目录。
// 只有当存在非 "." 开头的文件或目录时,才阻止克隆。
const nonBenignFiles = dirContents.filter(item => !item.startsWith('.'));
if (nonBenignFiles.length > 0) {
throw new Error('目标目录不为空,请清空目录或选择其他路径');
}
}

File diff suppressed because one or more lines are too long

View File

@@ -100,6 +100,9 @@ class ProjectService {
getAircraftsByProject(projectId) {
return this.aircrafts.filter(a => a.projectId === projectId);
}
getAircraft(aircraftId) {
return this.aircrafts.find(a => a.id === aircraftId);
}
async createAircraft(name, projectId) {
const newId = this.generateUniqueId('a', this.aircrafts);
const newAircraft = {
@@ -182,6 +185,9 @@ class ProjectService {
getContainersByAircraft(aircraftId) {
return this.containers.filter(c => c.aircraftId === aircraftId);
}
getContainer(containerId) {
return this.containers.find(c => c.id === containerId);
}
async createContainer(name, aircraftId) {
const newId = this.generateUniqueId('c', this.containers);
const newContainer = {
@@ -216,10 +222,10 @@ class ProjectService {
* 从已存在的磁盘目录导入容器
*
* ✅ 你的最新需求:
* - 不创建“默认两个配置”
* - 自动扫描容器目录下的『子文件夹』
* - 每个子文件夹创建一个 ModuleFoldertype: 'local'
* - 排除 `.git` 子文件夹
* - 不创建“默认两个配置”
* - 自动扫描容器目录下的『子文件夹』
* - 每个子文件夹创建一个 ModuleFoldertype: 'local'
* - 排除 `.git` 子文件夹
*/
async importContainerFromExistingFolder(aircraftId, containerName) {
if (containerName === '.git') {
@@ -348,7 +354,120 @@ class ProjectService {
folder.localPath = folder.localPath.replace(/\/[^/]+$/, '/' + newName);
return true;
}
// =============== 文件系统操作 ===============
// =============== 文件系统操作 (新增/修改) ===============
/**
* 获取项目目录重命名所需的旧路径和新路径(新增)
*/
getProjectOldAndNewPaths(projectId, newName) {
const project = this.projects.find(p => p.id === projectId);
const oldPath = this.projectPaths.get(projectId);
if (!project || !oldPath)
return null;
const parentDir = path.dirname(oldPath);
// 新路径使用新的项目名称作为文件夹名
const newPath = path.join(parentDir, newName);
return { oldPath, newPath };
}
/**
* 获取飞行器目录的完整路径
*/
getAircraftDirectoryPath(aircraftId) {
const aircraft = this.getAircraft(aircraftId);
if (!aircraft)
return null;
const projectPath = this.projectPaths.get(aircraft.projectId);
if (!projectPath)
return null;
return path.join(projectPath, aircraft.name);
}
/**
* 获取飞行器目录重命名所需的旧路径和新路径(新增)
* 注意oldPath使用内存中当前的名称newPath使用将要更新的新名称
*/
getAircraftOldAndNewPaths(aircraftId, newName) {
const aircraft = this.aircrafts.find(a => a.id === aircraftId);
if (!aircraft)
return null;
const projectPath = this.projectPaths.get(aircraft.projectId);
if (!projectPath)
return null;
const oldPath = path.join(projectPath, aircraft.name);
const newPath = path.join(projectPath, newName);
return { oldPath, newPath };
}
/**
* 获取容器目录的完整路径
*/
getContainerDirectoryPath(containerId) {
const container = this.getContainer(containerId);
if (!container)
return null;
const aircraft = this.getAircraft(container.aircraftId);
if (!aircraft)
return null;
const projectPath = this.projectPaths.get(aircraft.projectId);
if (!projectPath)
return null;
return path.join(projectPath, aircraft.name, container.name);
}
/**
* 获取容器目录重命名所需的旧路径和新路径(新增)
* 注意oldPath使用内存中当前的名称newPath使用将要更新的新名称
*/
getContainerOldAndNewPaths(containerId, newName) {
const container = this.containers.find(c => c.id === containerId);
if (!container)
return null;
const aircraft = this.aircrafts.find(a => a.id === container.aircraftId);
if (!aircraft)
return null;
const projectPath = this.projectPaths.get(aircraft.projectId);
if (!projectPath)
return null;
const aircraftDir = path.join(projectPath, aircraft.name);
const oldPath = path.join(aircraftDir, container.name);
const newPath = path.join(aircraftDir, newName);
return { oldPath, newPath };
}
/**
* 递归删除目录
*/
async deleteDirectoryFromDisk(directoryPath) {
if (!directoryPath)
return false;
try {
if (fs.existsSync(directoryPath)) {
await fs.promises.rm(directoryPath, { recursive: true, force: true });
console.log(`✅ 已删除目录: ${directoryPath}`);
return true;
}
return false;
}
catch (error) {
console.error(`删除目录失败: ${error}`);
throw error; // Re-throw to be handled by ConfigPanel
}
}
/**
* 重命名磁盘上的目录(新增)
*/
async renameDirectoryOnDisk(oldPath, newPath) {
if (!oldPath || !newPath)
return false;
try {
if (fs.existsSync(oldPath)) {
await fs.promises.rename(oldPath, newPath);
console.log(`✅ 已重命名目录: ${oldPath} -> ${newPath}`);
return true;
}
console.warn(`目录不存在,跳过重命名: ${oldPath}`);
return false;
}
catch (error) {
console.error(`重命名目录失败: ${error}`);
throw error; // Re-throw to be handled by ConfigPanel
}
}
async createAircraftDirectory(aircraft) {
try {
const projectPath = this.projectPaths.get(aircraft.projectId);

File diff suppressed because one or more lines are too long