添加了本地和git的区分
This commit is contained in:
@@ -218,10 +218,10 @@ class ConfigPanel {
|
|||||||
await this.deleteModuleFolder(data.folderId);
|
await this.deleteModuleFolder(data.folderId);
|
||||||
break;
|
break;
|
||||||
case 'openMergedFolderInVSCode':
|
case 'openMergedFolderInVSCode':
|
||||||
await this.openTheModuleFolder('merged', data.folderId);
|
await this.openTheModuleFolder('local', data.folderId);
|
||||||
break;
|
break;
|
||||||
case 'loadMergedFolder':
|
case 'loadMergedFolder':
|
||||||
await this.openTheModuleFolder('merged', data.folderId);
|
await this.openTheModuleFolder('local', data.folderId);
|
||||||
break;
|
break;
|
||||||
case 'openTheModuleFolder':
|
case 'openTheModuleFolder':
|
||||||
await this.openTheModuleFolder(data.moduleType, data.id);
|
await this.openTheModuleFolder(data.moduleType, data.id);
|
||||||
@@ -317,7 +317,7 @@ class ConfigPanel {
|
|||||||
/**
|
/**
|
||||||
* 添加 Git 模块文件夹到容器目录
|
* 添加 Git 模块文件夹到容器目录
|
||||||
*/
|
*/
|
||||||
async addGitModuleFolder(url, name, branch) {
|
async addGitModuleFolder(url, displayName, folderName, branch) {
|
||||||
try {
|
try {
|
||||||
// 验证 URL
|
// 验证 URL
|
||||||
if (!url || !url.startsWith('http')) {
|
if (!url || !url.startsWith('http')) {
|
||||||
@@ -345,40 +345,49 @@ class ConfigPanel {
|
|||||||
vscode.window.showErrorMessage('未找到项目路径');
|
vscode.window.showErrorMessage('未找到项目路径');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 构建相对路径(从项目路径开始)
|
// 构建相对路径(从项目路径开始)- 使用 folderName 作为实际文件夹名
|
||||||
const relativePath = `/${aircraft.projectId}/${aircraft.name}/${container.name}/${name}`;
|
const relativePath = `/${aircraft.projectId}/${aircraft.name}/${container.name}/${folderName}`;
|
||||||
// 完整路径用于实际操作
|
// 完整路径用于实际操作 - 使用 folderName 作为实际文件夹名
|
||||||
const localPath = path.join(projectPath, aircraft.name, container.name, name);
|
const localPath = path.join(projectPath, aircraft.name, container.name, folderName);
|
||||||
console.log(`📁 Git模块文件夹将保存到: ${localPath}`);
|
console.log(`📁 准备克隆仓库: ${displayName}, 分支: ${branch}, 路径: ${localPath}`);
|
||||||
console.log(`📁 相对路径: ${relativePath}`);
|
console.log(`📁 相对路径: ${relativePath}`);
|
||||||
// 检查是否已存在相同名称的模块文件夹
|
// 修复:检查是否已存在相同实际路径的模块文件夹,而不是显示名称
|
||||||
const existingFolder = this.moduleFolders.find(folder => folder.name === name && folder.containerId === this.currentContainerId);
|
const existingFolder = this.moduleFolders.find(folder => folder.localPath === relativePath && folder.containerId === this.currentContainerId);
|
||||||
if (existingFolder) {
|
if (existingFolder) {
|
||||||
vscode.window.showWarningMessage('该名称的模块文件夹已存在');
|
vscode.window.showWarningMessage(`该路径的模块文件夹已存在: ${folderName}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const newFolder = {
|
const newFolder = {
|
||||||
id: folderId,
|
id: folderId,
|
||||||
name: name,
|
name: displayName,
|
||||||
type: 'git',
|
type: 'git',
|
||||||
localPath: relativePath,
|
localPath: relativePath,
|
||||||
containerId: this.currentContainerId
|
containerId: this.currentContainerId
|
||||||
};
|
};
|
||||||
console.log(`📁 准备克隆仓库: ${name}, 分支: ${branch}, 路径: ${localPath}`);
|
|
||||||
// 显示进度
|
// 显示进度
|
||||||
await vscode.window.withProgress({
|
await vscode.window.withProgress({
|
||||||
location: vscode.ProgressLocation.Notification,
|
location: vscode.ProgressLocation.Notification,
|
||||||
title: `正在克隆仓库: ${name}`,
|
title: `正在克隆仓库: ${displayName}`,
|
||||||
cancellable: false
|
cancellable: false
|
||||||
}, async (progress) => {
|
}, async (progress) => {
|
||||||
progress.report({ increment: 0 });
|
progress.report({ increment: 0 });
|
||||||
try {
|
try {
|
||||||
// 确保目录存在
|
// 确保父目录存在
|
||||||
await fs.promises.mkdir(localPath, { recursive: true });
|
const parentDir = path.dirname(localPath);
|
||||||
// 检查目录是否为空
|
await fs.promises.mkdir(parentDir, { recursive: true });
|
||||||
|
// 检查目标目录是否已存在
|
||||||
|
let dirExists = false;
|
||||||
|
try {
|
||||||
|
await fs.promises.access(localPath);
|
||||||
|
dirExists = true;
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
dirExists = false;
|
||||||
|
}
|
||||||
|
if (dirExists) {
|
||||||
const dirContents = await fs.promises.readdir(localPath);
|
const dirContents = await fs.promises.readdir(localPath);
|
||||||
if (dirContents.length > 0) {
|
if (dirContents.length > 0) {
|
||||||
const confirm = await vscode.window.showWarningMessage(`目标目录不为空,确定要覆盖吗?`, { modal: true }, '确定覆盖', '取消');
|
const confirm = await vscode.window.showWarningMessage(`目标目录 "${folderName}" 不为空,确定要覆盖吗?`, { modal: true }, '确定覆盖', '取消');
|
||||||
if (confirm !== '确定覆盖') {
|
if (confirm !== '确定覆盖') {
|
||||||
vscode.window.showInformationMessage('克隆操作已取消');
|
vscode.window.showInformationMessage('克隆操作已取消');
|
||||||
return;
|
return;
|
||||||
@@ -391,6 +400,8 @@ class ConfigPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
console.log(`🚀 开始克隆: ${url} -> ${localPath}, 分支: ${branch}`);
|
||||||
// 克隆仓库
|
// 克隆仓库
|
||||||
await isomorphic_git_1.default.clone({
|
await isomorphic_git_1.default.clone({
|
||||||
fs: fs,
|
fs: fs,
|
||||||
@@ -401,17 +412,31 @@ class ConfigPanel {
|
|||||||
depth: 1,
|
depth: 1,
|
||||||
ref: branch || 'main',
|
ref: branch || 'main',
|
||||||
onProgress: (event) => {
|
onProgress: (event) => {
|
||||||
|
console.log(`📊 克隆进度: ${event.phase} - ${event.loaded}/${event.total}`);
|
||||||
if (event.total) {
|
if (event.total) {
|
||||||
const percent = (event.loaded / event.total) * 100;
|
const percent = (event.loaded / event.total) * 100;
|
||||||
progress.report({ increment: percent, message: `${event.phase}...` });
|
progress.report({
|
||||||
|
increment: percent,
|
||||||
|
message: `${event.phase}... (${Math.round(percent)}%)`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
progress.report({ message: `${event.phase}...` });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log('✅ Git克隆成功完成');
|
console.log('✅ Git克隆成功完成');
|
||||||
|
// 验证克隆是否真的成功
|
||||||
|
const clonedContents = await fs.promises.readdir(localPath);
|
||||||
|
console.log(`📁 克隆后的目录内容:`, clonedContents);
|
||||||
|
if (clonedContents.length === 0) {
|
||||||
|
throw new Error('克隆后目录为空,可能克隆失败');
|
||||||
|
}
|
||||||
|
// 只有在克隆成功后才添加到列表
|
||||||
this.moduleFolders.push(newFolder);
|
this.moduleFolders.push(newFolder);
|
||||||
await this.saveCurrentProjectData();
|
await this.saveCurrentProjectData();
|
||||||
console.log('✅ Git模块文件夹数据已保存到项目文件');
|
console.log('✅ Git模块文件夹数据已保存到项目文件');
|
||||||
vscode.window.showInformationMessage(`Git 仓库克隆成功: ${name}`);
|
vscode.window.showInformationMessage(`Git 仓库克隆成功: ${displayName}`);
|
||||||
// 检查 Webview 状态后再加载文件树
|
// 检查 Webview 状态后再加载文件树
|
||||||
if (!this.isWebviewDisposed) {
|
if (!this.isWebviewDisposed) {
|
||||||
console.log('🌳 开始加载模块文件夹文件树...');
|
console.log('🌳 开始加载模块文件夹文件树...');
|
||||||
@@ -426,7 +451,19 @@ class ConfigPanel {
|
|||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('❌ 在克隆过程中捕获错误:', error);
|
console.error('❌ 在克隆过程中捕获错误:', error);
|
||||||
|
// 清理:如果克隆失败,删除可能创建的不完整目录
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(localPath)) {
|
||||||
|
await fs.promises.rm(localPath, { recursive: true, force: true });
|
||||||
|
console.log('🧹 已清理克隆失败的目录');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (cleanupError) {
|
||||||
|
console.error('清理失败目录时出错:', cleanupError);
|
||||||
|
}
|
||||||
vscode.window.showErrorMessage(`克隆仓库失败: ${error}`);
|
vscode.window.showErrorMessage(`克隆仓库失败: ${error}`);
|
||||||
|
// 重新抛出错误,让外部知道克隆失败
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1191,9 +1228,19 @@ class ConfigPanel {
|
|||||||
});
|
});
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
generateModuleFolderName(url, branch) {
|
||||||
|
const repoName = url.split('/').pop()?.replace('.git', '') || 'unknown-repo';
|
||||||
|
const branchSafeName = branch.replace(/[^a-zA-Z0-9-_]/g, '-');
|
||||||
|
return {
|
||||||
|
displayName: repoName,
|
||||||
|
folderName: branchSafeName // 实际文件夹名称(只显示分支名)
|
||||||
|
};
|
||||||
|
}
|
||||||
async cloneBranches(url, branches) {
|
async cloneBranches(url, branches) {
|
||||||
try {
|
try {
|
||||||
console.log('🚀 开始克隆分支:', { url, branches });
|
console.log('🚀 开始克隆分支:', { url, branches });
|
||||||
|
let successCount = 0;
|
||||||
|
let failCount = 0;
|
||||||
// 显示总进度
|
// 显示总进度
|
||||||
await vscode.window.withProgress({
|
await vscode.window.withProgress({
|
||||||
location: vscode.ProgressLocation.Notification,
|
location: vscode.ProgressLocation.Notification,
|
||||||
@@ -1207,22 +1254,33 @@ class ConfigPanel {
|
|||||||
increment: progressPercent,
|
increment: progressPercent,
|
||||||
message: `克隆分支: ${branch} (${i + 1}/${branches.length})`
|
message: `克隆分支: ${branch} (${i + 1}/${branches.length})`
|
||||||
});
|
});
|
||||||
console.log(`📥 克隆分支: ${branch}`);
|
console.log(`📥 开始克隆分支: ${branch}`);
|
||||||
await this.addGitModuleFolder(url, this.generateModuleFolderName(url, branch), branch);
|
try {
|
||||||
|
const folderNames = this.generateModuleFolderName(url, branch);
|
||||||
|
await this.addGitModuleFolder(url, folderNames.displayName, folderNames.folderName, branch);
|
||||||
|
successCount++;
|
||||||
|
console.log(`✅ 分支克隆成功: ${branch}`);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
failCount++;
|
||||||
|
console.error(`❌ 分支克隆失败: ${branch}`, error);
|
||||||
|
// 继续克隆其他分支,不中断整个流程
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
vscode.window.showInformationMessage(`成功克隆 ${branches.length} 个分支`);
|
// 显示最终结果
|
||||||
|
if (failCount === 0) {
|
||||||
|
vscode.window.showInformationMessage(`成功克隆 ${successCount} 个分支`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vscode.window.showWarningMessage(`克隆完成: ${successCount} 个成功, ${failCount} 个失败`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('❌ 克隆分支失败:', error);
|
console.error('❌ 克隆分支失败:', error);
|
||||||
vscode.window.showErrorMessage(`克隆分支失败: ${error}`);
|
vscode.window.showErrorMessage(`克隆分支失败: ${error}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
generateModuleFolderName(url, branch) {
|
|
||||||
const repoName = url.split('/').pop()?.replace('.git', '') || 'unknown-repo';
|
|
||||||
const branchSafeName = branch.replace(/[^a-zA-Z0-9-_]/g, '-');
|
|
||||||
return `${repoName}-${branchSafeName}`;
|
|
||||||
}
|
|
||||||
// 更新视图
|
// 更新视图
|
||||||
updateWebview() {
|
updateWebview() {
|
||||||
// 检查 Webview 是否仍然有效
|
// 检查 Webview 是否仍然有效
|
||||||
@@ -1408,9 +1466,9 @@ class ConfigPanel {
|
|||||||
const relativePath = `/${aircraft.projectId}/${aircraft.name}/${container.name}/${folderName}`;
|
const relativePath = `/${aircraft.projectId}/${aircraft.name}/${container.name}/${folderName}`;
|
||||||
// 创建合并文件夹记录
|
// 创建合并文件夹记录
|
||||||
const newFolder = {
|
const newFolder = {
|
||||||
id: 'merged-' + Date.now(),
|
id: 'local-' + Date.now(),
|
||||||
name: displayName,
|
name: displayName,
|
||||||
type: 'merged',
|
type: 'local',
|
||||||
localPath: relativePath,
|
localPath: relativePath,
|
||||||
containerId: this.currentContainerId
|
containerId: this.currentContainerId
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -19,6 +19,7 @@ class ConfigView extends BaseView_1.BaseView {
|
|||||||
<input type="checkbox" class="config-checkbox" data-id="${config.id}" data-type="config">
|
<input type="checkbox" class="config-checkbox" data-id="${config.id}" data-type="config">
|
||||||
<span class="editable" onclick="editConfigName('${config.id}', '${config.name}')">🔧 ${config.name}</span>
|
<span class="editable" onclick="editConfigName('${config.id}', '${config.name}')">🔧 ${config.name}</span>
|
||||||
</td>
|
</td>
|
||||||
|
<td>local</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="clickable" onclick="openConfigFileInVSCode('${config.id}')">📄 ${config.fileName}</span>
|
<span class="clickable" onclick="openConfigFileInVSCode('${config.id}')">📄 ${config.fileName}</span>
|
||||||
</td>
|
</td>
|
||||||
@@ -27,14 +28,17 @@ class ConfigView extends BaseView_1.BaseView {
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
`).join('');
|
`).join('');
|
||||||
// 生成模块文件夹的 HTML - 统一显示 Git 和合并文件夹
|
// 生成模块文件夹的 HTML - 按类别分类显示
|
||||||
const moduleFoldersHtml = moduleFolders.map((folder) => {
|
const moduleFoldersHtml = moduleFolders.map((folder) => {
|
||||||
const icon = folder.type === 'git' ? '📁' : '📁';
|
const icon = folder.type === 'git' ? '📁' : '📁';
|
||||||
|
// 根据类型确定类别显示
|
||||||
|
const category = folder.type === 'git' ? 'git' : 'local';
|
||||||
return `
|
return `
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<span class="editable">${icon} ${folder.name}</span>
|
<span class="editable">${icon} ${folder.name}</span>
|
||||||
</td>
|
</td>
|
||||||
|
<td>${category}</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="clickable" onclick="openTheModuleFolder('${folder.id}', '${folder.type}')">${folder.localPath.split('/').pop()}</span>
|
<span class="clickable" onclick="openTheModuleFolder('${folder.id}', '${folder.type}')">${folder.localPath.split('/').pop()}</span>
|
||||||
</td>
|
</td>
|
||||||
@@ -224,6 +228,17 @@ class ConfigView extends BaseView_1.BaseView {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--vscode-descriptionForeground);
|
color: var(--vscode-descriptionForeground);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 类别标签样式 */
|
||||||
|
.category-git {
|
||||||
|
color: var(--vscode-gitDecoration-untrackedResourceForeground);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-local {
|
||||||
|
color: var(--vscode-charts-orange);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -245,9 +260,10 @@ class ConfigView extends BaseView_1.BaseView {
|
|||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th width="30%">配置</th>
|
<th width="25%">配置</th>
|
||||||
<th width="40%">文件/文件夹</th>
|
<th width="15%">类别</th>
|
||||||
<th width="30%">操作</th>
|
<th width="35%">文件/文件夹</th>
|
||||||
|
<th width="25%">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -7,6 +7,7 @@ import { ProjectView } from './views/ProjectView';
|
|||||||
import { AircraftView } from './views/AircraftView';
|
import { AircraftView } from './views/AircraftView';
|
||||||
import { ContainerView } from './views/ContainerView';
|
import { ContainerView } from './views/ContainerView';
|
||||||
import { ConfigView } from './views/ConfigView';
|
import { ConfigView } from './views/ConfigView';
|
||||||
|
import { ModuleFolder } from './types/DataTypes';
|
||||||
|
|
||||||
// 数据模型接口
|
// 数据模型接口
|
||||||
interface Project {
|
interface Project {
|
||||||
@@ -34,15 +35,6 @@ interface Config {
|
|||||||
containerId: string;
|
containerId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 统一的模块文件夹接口,合并 gitRepos 和 mergedFolders
|
|
||||||
interface ModuleFolder {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
type: 'git' | 'merged'; // 类型标识
|
|
||||||
localPath: string; // 相对路径,如 "/项目1/飞行器1/容器1/test-code"
|
|
||||||
containerId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GitFileTree {
|
interface GitFileTree {
|
||||||
name: string;
|
name: string;
|
||||||
type: 'file' | 'folder';
|
type: 'file' | 'folder';
|
||||||
@@ -309,11 +301,11 @@ export class ConfigPanel {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'openMergedFolderInVSCode':
|
case 'openMergedFolderInVSCode':
|
||||||
await this.openTheModuleFolder('merged', data.folderId);
|
await this.openTheModuleFolder('local', data.folderId);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'loadMergedFolder':
|
case 'loadMergedFolder':
|
||||||
await this.openTheModuleFolder('merged', data.folderId);
|
await this.openTheModuleFolder('local', data.folderId);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'openTheModuleFolder':
|
case 'openTheModuleFolder':
|
||||||
@@ -421,7 +413,7 @@ export class ConfigPanel {
|
|||||||
/**
|
/**
|
||||||
* 添加 Git 模块文件夹到容器目录
|
* 添加 Git 模块文件夹到容器目录
|
||||||
*/
|
*/
|
||||||
private async addGitModuleFolder(url: string, name: string, branch?: string): Promise<void> {
|
private async addGitModuleFolder(url: string, displayName: string, folderName: string, branch?: string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
// 验证 URL
|
// 验证 URL
|
||||||
if (!url || !url.startsWith('http')) {
|
if (!url || !url.startsWith('http')) {
|
||||||
@@ -455,51 +447,59 @@ export class ConfigPanel {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建相对路径(从项目路径开始)
|
// 构建相对路径(从项目路径开始)- 使用 folderName 作为实际文件夹名
|
||||||
const relativePath = `/${aircraft.projectId}/${aircraft.name}/${container.name}/${name}`;
|
const relativePath = `/${aircraft.projectId}/${aircraft.name}/${container.name}/${folderName}`;
|
||||||
|
|
||||||
// 完整路径用于实际操作
|
// 完整路径用于实际操作 - 使用 folderName 作为实际文件夹名
|
||||||
const localPath = path.join(projectPath, aircraft.name, container.name, name);
|
const localPath = path.join(projectPath, aircraft.name, container.name, folderName);
|
||||||
|
|
||||||
console.log(`📁 Git模块文件夹将保存到: ${localPath}`);
|
console.log(`📁 准备克隆仓库: ${displayName}, 分支: ${branch}, 路径: ${localPath}`);
|
||||||
console.log(`📁 相对路径: ${relativePath}`);
|
console.log(`📁 相对路径: ${relativePath}`);
|
||||||
|
|
||||||
// 检查是否已存在相同名称的模块文件夹
|
// 修复:检查是否已存在相同实际路径的模块文件夹,而不是显示名称
|
||||||
const existingFolder = this.moduleFolders.find(folder =>
|
const existingFolder = this.moduleFolders.find(folder =>
|
||||||
folder.name === name && folder.containerId === this.currentContainerId
|
folder.localPath === relativePath && folder.containerId === this.currentContainerId
|
||||||
);
|
);
|
||||||
if (existingFolder) {
|
if (existingFolder) {
|
||||||
vscode.window.showWarningMessage('该名称的模块文件夹已存在');
|
vscode.window.showWarningMessage(`该路径的模块文件夹已存在: ${folderName}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newFolder: ModuleFolder = {
|
const newFolder: ModuleFolder = {
|
||||||
id: folderId,
|
id: folderId,
|
||||||
name: name,
|
name: displayName, // 使用显示名称
|
||||||
type: 'git',
|
type: 'git',
|
||||||
localPath: relativePath, // 存储相对路径
|
localPath: relativePath, // 存储相对路径
|
||||||
containerId: this.currentContainerId
|
containerId: this.currentContainerId
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(`📁 准备克隆仓库: ${name}, 分支: ${branch}, 路径: ${localPath}`);
|
|
||||||
|
|
||||||
// 显示进度
|
// 显示进度
|
||||||
await vscode.window.withProgress({
|
await vscode.window.withProgress({
|
||||||
location: vscode.ProgressLocation.Notification,
|
location: vscode.ProgressLocation.Notification,
|
||||||
title: `正在克隆仓库: ${name}`,
|
title: `正在克隆仓库: ${displayName}`,
|
||||||
cancellable: false
|
cancellable: false
|
||||||
}, async (progress) => {
|
}, async (progress) => {
|
||||||
progress.report({ increment: 0 });
|
progress.report({ increment: 0 });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 确保目录存在
|
// 确保父目录存在
|
||||||
await fs.promises.mkdir(localPath, { recursive: true });
|
const parentDir = path.dirname(localPath);
|
||||||
|
await fs.promises.mkdir(parentDir, { recursive: true });
|
||||||
|
|
||||||
// 检查目录是否为空
|
// 检查目标目录是否已存在
|
||||||
|
let dirExists = false;
|
||||||
|
try {
|
||||||
|
await fs.promises.access(localPath);
|
||||||
|
dirExists = true;
|
||||||
|
} catch {
|
||||||
|
dirExists = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dirExists) {
|
||||||
const dirContents = await fs.promises.readdir(localPath);
|
const dirContents = await fs.promises.readdir(localPath);
|
||||||
if (dirContents.length > 0) {
|
if (dirContents.length > 0) {
|
||||||
const confirm = await vscode.window.showWarningMessage(
|
const confirm = await vscode.window.showWarningMessage(
|
||||||
`目标目录不为空,确定要覆盖吗?`,
|
`目标目录 "${folderName}" 不为空,确定要覆盖吗?`,
|
||||||
{ modal: true },
|
{ modal: true },
|
||||||
'确定覆盖',
|
'确定覆盖',
|
||||||
'取消'
|
'取消'
|
||||||
@@ -518,6 +518,9 @@ export class ConfigPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`🚀 开始克隆: ${url} -> ${localPath}, 分支: ${branch}`);
|
||||||
|
|
||||||
// 克隆仓库
|
// 克隆仓库
|
||||||
await git.clone({
|
await git.clone({
|
||||||
@@ -529,20 +532,35 @@ export class ConfigPanel {
|
|||||||
depth: 1,
|
depth: 1,
|
||||||
ref: branch || 'main',
|
ref: branch || 'main',
|
||||||
onProgress: (event: any) => {
|
onProgress: (event: any) => {
|
||||||
|
console.log(`📊 克隆进度: ${event.phase} - ${event.loaded}/${event.total}`);
|
||||||
if (event.total) {
|
if (event.total) {
|
||||||
const percent = (event.loaded / event.total) * 100;
|
const percent = (event.loaded / event.total) * 100;
|
||||||
progress.report({ increment: percent, message: `${event.phase}...` });
|
progress.report({
|
||||||
|
increment: percent,
|
||||||
|
message: `${event.phase}... (${Math.round(percent)}%)`
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
progress.report({ message: `${event.phase}...` });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('✅ Git克隆成功完成');
|
console.log('✅ Git克隆成功完成');
|
||||||
|
|
||||||
|
// 验证克隆是否真的成功
|
||||||
|
const clonedContents = await fs.promises.readdir(localPath);
|
||||||
|
console.log(`📁 克隆后的目录内容:`, clonedContents);
|
||||||
|
|
||||||
|
if (clonedContents.length === 0) {
|
||||||
|
throw new Error('克隆后目录为空,可能克隆失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只有在克隆成功后才添加到列表
|
||||||
this.moduleFolders.push(newFolder);
|
this.moduleFolders.push(newFolder);
|
||||||
await this.saveCurrentProjectData();
|
await this.saveCurrentProjectData();
|
||||||
console.log('✅ Git模块文件夹数据已保存到项目文件');
|
console.log('✅ Git模块文件夹数据已保存到项目文件');
|
||||||
|
|
||||||
vscode.window.showInformationMessage(`Git 仓库克隆成功: ${name}`);
|
vscode.window.showInformationMessage(`Git 仓库克隆成功: ${displayName}`);
|
||||||
|
|
||||||
// 检查 Webview 状态后再加载文件树
|
// 检查 Webview 状态后再加载文件树
|
||||||
if (!this.isWebviewDisposed) {
|
if (!this.isWebviewDisposed) {
|
||||||
@@ -557,7 +575,21 @@ export class ConfigPanel {
|
|||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ 在克隆过程中捕获错误:', error);
|
console.error('❌ 在克隆过程中捕获错误:', error);
|
||||||
|
|
||||||
|
// 清理:如果克隆失败,删除可能创建的不完整目录
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(localPath)) {
|
||||||
|
await fs.promises.rm(localPath, { recursive: true, force: true });
|
||||||
|
console.log('🧹 已清理克隆失败的目录');
|
||||||
|
}
|
||||||
|
} catch (cleanupError) {
|
||||||
|
console.error('清理失败目录时出错:', cleanupError);
|
||||||
|
}
|
||||||
|
|
||||||
vscode.window.showErrorMessage(`克隆仓库失败: ${error}`);
|
vscode.window.showErrorMessage(`克隆仓库失败: ${error}`);
|
||||||
|
|
||||||
|
// 重新抛出错误,让外部知道克隆失败
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -565,7 +597,7 @@ export class ConfigPanel {
|
|||||||
console.error('❌ 在addGitModuleFolder外部捕获错误:', error);
|
console.error('❌ 在addGitModuleFolder外部捕获错误:', error);
|
||||||
vscode.window.showErrorMessage(`添加 Git 模块文件夹失败: ${error}`);
|
vscode.window.showErrorMessage(`添加 Git 模块文件夹失败: ${error}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载模块文件夹
|
* 加载模块文件夹
|
||||||
@@ -1457,10 +1489,23 @@ export class ConfigPanel {
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private generateModuleFolderName(url: string, branch: string): { displayName: string; folderName: string } {
|
||||||
|
const repoName = url.split('/').pop()?.replace('.git', '') || 'unknown-repo';
|
||||||
|
const branchSafeName = branch.replace(/[^a-zA-Z0-9-_]/g, '-');
|
||||||
|
|
||||||
|
return {
|
||||||
|
displayName: repoName, // 配置栏显示的名称(只显示仓库名)
|
||||||
|
folderName: branchSafeName // 实际文件夹名称(只显示分支名)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private async cloneBranches(url: string, branches: string[]): Promise<void> {
|
private async cloneBranches(url: string, branches: string[]): Promise<void> {
|
||||||
try {
|
try {
|
||||||
console.log('🚀 开始克隆分支:', { url, branches });
|
console.log('🚀 开始克隆分支:', { url, branches });
|
||||||
|
|
||||||
|
let successCount = 0;
|
||||||
|
let failCount = 0;
|
||||||
|
|
||||||
// 显示总进度
|
// 显示总进度
|
||||||
await vscode.window.withProgress({
|
await vscode.window.withProgress({
|
||||||
location: vscode.ProgressLocation.Notification,
|
location: vscode.ProgressLocation.Notification,
|
||||||
@@ -1475,24 +1520,32 @@ export class ConfigPanel {
|
|||||||
message: `克隆分支: ${branch} (${i + 1}/${branches.length})`
|
message: `克隆分支: ${branch} (${i + 1}/${branches.length})`
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`📥 克隆分支: ${branch}`);
|
console.log(`📥 开始克隆分支: ${branch}`);
|
||||||
await this.addGitModuleFolder(url, this.generateModuleFolderName(url, branch), branch);
|
try {
|
||||||
|
const folderNames = this.generateModuleFolderName(url, branch);
|
||||||
|
await this.addGitModuleFolder(url, folderNames.displayName, folderNames.folderName, branch);
|
||||||
|
successCount++;
|
||||||
|
console.log(`✅ 分支克隆成功: ${branch}`);
|
||||||
|
} catch (error) {
|
||||||
|
failCount++;
|
||||||
|
console.error(`❌ 分支克隆失败: ${branch}`, error);
|
||||||
|
// 继续克隆其他分支,不中断整个流程
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
vscode.window.showInformationMessage(`成功克隆 ${branches.length} 个分支`);
|
// 显示最终结果
|
||||||
|
if (failCount === 0) {
|
||||||
|
vscode.window.showInformationMessage(`成功克隆 ${successCount} 个分支`);
|
||||||
|
} else {
|
||||||
|
vscode.window.showWarningMessage(`克隆完成: ${successCount} 个成功, ${failCount} 个失败`);
|
||||||
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ 克隆分支失败:', error);
|
console.error('❌ 克隆分支失败:', error);
|
||||||
vscode.window.showErrorMessage(`克隆分支失败: ${error}`);
|
vscode.window.showErrorMessage(`克隆分支失败: ${error}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateModuleFolderName(url: string, branch: string): string {
|
|
||||||
const repoName = url.split('/').pop()?.replace('.git', '') || 'unknown-repo';
|
|
||||||
const branchSafeName = branch.replace(/[^a-zA-Z0-9-_]/g, '-');
|
|
||||||
return `${repoName}-${branchSafeName}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新视图
|
// 更新视图
|
||||||
private updateWebview() {
|
private updateWebview() {
|
||||||
@@ -1704,9 +1757,9 @@ export class ConfigPanel {
|
|||||||
|
|
||||||
// 创建合并文件夹记录
|
// 创建合并文件夹记录
|
||||||
const newFolder: ModuleFolder = {
|
const newFolder: ModuleFolder = {
|
||||||
id: 'merged-' + Date.now(),
|
id: 'local-' + Date.now(),
|
||||||
name: displayName,
|
name: displayName,
|
||||||
type: 'merged',
|
type: 'local',
|
||||||
localPath: relativePath,
|
localPath: relativePath,
|
||||||
containerId: this.currentContainerId
|
containerId: this.currentContainerId
|
||||||
};
|
};
|
||||||
@@ -1801,7 +1854,7 @@ export class ConfigPanel {
|
|||||||
* @param type 模块类型:'git' 或 'merged'
|
* @param type 模块类型:'git' 或 'merged'
|
||||||
* @param id 模块 ID
|
* @param id 模块 ID
|
||||||
*/
|
*/
|
||||||
private async openTheModuleFolder(type: 'git' | 'merged', id: string): Promise<void> {
|
private async openTheModuleFolder(type: 'git' | 'local', id: string): Promise<void> {
|
||||||
const folder = this.moduleFolders.find(f => f.id === id);
|
const folder = this.moduleFolders.find(f => f.id === id);
|
||||||
if (!folder) {
|
if (!folder) {
|
||||||
vscode.window.showErrorMessage('未找到指定的模块文件夹');
|
vscode.window.showErrorMessage('未找到指定的模块文件夹');
|
||||||
|
|||||||
2
src/panels/types/DataModel.ts
Normal file → Executable file
2
src/panels/types/DataModel.ts
Normal file → Executable file
@@ -31,7 +31,7 @@ export interface Config {
|
|||||||
export interface ModuleFolder {
|
export interface ModuleFolder {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
type: 'git' | 'merged'; // 类型标识
|
type: 'git' | 'local'; // 类型标识
|
||||||
localPath: string; // 相对路径,如 "/项目1/飞行器1/容器1/test-code"
|
localPath: string; // 相对路径,如 "/项目1/飞行器1/容器1/test-code"
|
||||||
containerId: string;
|
containerId: string;
|
||||||
}
|
}
|
||||||
2
src/panels/types/DataTypes.ts
Normal file → Executable file
2
src/panels/types/DataTypes.ts
Normal file → Executable file
@@ -4,7 +4,7 @@
|
|||||||
export interface ModuleFolder {
|
export interface ModuleFolder {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
type: 'git' | 'merged'; // 类型标识
|
type: 'git' | 'local'; // 类型标识
|
||||||
localPath: string; // 相对路径,如 "/项目1/飞行器1/容器1/test-code"
|
localPath: string; // 相对路径,如 "/项目1/飞行器1/容器1/test-code"
|
||||||
containerId: string;
|
containerId: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export interface ContainerConfigData {
|
|||||||
export interface ModuleFolderData {
|
export interface ModuleFolderData {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
type: 'git' | 'merged';
|
type: 'git' | 'local';
|
||||||
localPath: string;
|
localPath: string;
|
||||||
containerId: string;
|
containerId: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ export class ConfigView extends BaseView {
|
|||||||
<input type="checkbox" class="config-checkbox" data-id="${config.id}" data-type="config">
|
<input type="checkbox" class="config-checkbox" data-id="${config.id}" data-type="config">
|
||||||
<span class="editable" onclick="editConfigName('${config.id}', '${config.name}')">🔧 ${config.name}</span>
|
<span class="editable" onclick="editConfigName('${config.id}', '${config.name}')">🔧 ${config.name}</span>
|
||||||
</td>
|
</td>
|
||||||
|
<td>local</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="clickable" onclick="openConfigFileInVSCode('${config.id}')">📄 ${config.fileName}</span>
|
<span class="clickable" onclick="openConfigFileInVSCode('${config.id}')">📄 ${config.fileName}</span>
|
||||||
</td>
|
</td>
|
||||||
@@ -72,15 +73,18 @@ export class ConfigView extends BaseView {
|
|||||||
</tr>
|
</tr>
|
||||||
`).join('');
|
`).join('');
|
||||||
|
|
||||||
// 生成模块文件夹的 HTML - 统一显示 Git 和合并文件夹
|
// 生成模块文件夹的 HTML - 按类别分类显示
|
||||||
const moduleFoldersHtml = moduleFolders.map((folder: ModuleFolder) => {
|
const moduleFoldersHtml = moduleFolders.map((folder: ModuleFolder) => {
|
||||||
const icon = folder.type === 'git' ? '📁' : '📁';
|
const icon = folder.type === 'git' ? '📁' : '📁';
|
||||||
|
// 根据类型确定类别显示
|
||||||
|
const category = folder.type === 'git' ? 'git' : 'local';
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<span class="editable">${icon} ${folder.name}</span>
|
<span class="editable">${icon} ${folder.name}</span>
|
||||||
</td>
|
</td>
|
||||||
|
<td>${category}</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="clickable" onclick="openTheModuleFolder('${folder.id}', '${folder.type}')">${folder.localPath.split('/').pop()}</span>
|
<span class="clickable" onclick="openTheModuleFolder('${folder.id}', '${folder.type}')">${folder.localPath.split('/').pop()}</span>
|
||||||
</td>
|
</td>
|
||||||
@@ -272,6 +276,17 @@ export class ConfigView extends BaseView {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--vscode-descriptionForeground);
|
color: var(--vscode-descriptionForeground);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 类别标签样式 */
|
||||||
|
.category-git {
|
||||||
|
color: var(--vscode-gitDecoration-untrackedResourceForeground);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-local {
|
||||||
|
color: var(--vscode-charts-orange);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -293,9 +308,10 @@ export class ConfigView extends BaseView {
|
|||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th width="30%">配置</th>
|
<th width="25%">配置</th>
|
||||||
<th width="40%">文件/文件夹</th>
|
<th width="15%">类别</th>
|
||||||
<th width="30%">操作</th>
|
<th width="35%">文件/文件夹</th>
|
||||||
|
<th width="25%">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|||||||
Reference in New Issue
Block a user