199 lines
5.6 KiB
TypeScript

import * as vscode from 'vscode';
import * as fs from 'fs';
import * as fspath from 'path';
import { AbsPath, opeParam } from '../global';
import { hdlDir, hdlFile, hdlPath } from '../hdlFs';
import { Library } from '../global/prjInfo';
import { LibraryState } from '../global/enum';
import { PathSet } from '../global/util';
import { hdlIgnore } from './ignore';
import { hdlParam } from '../hdlParser';
import { refreshArchTree } from '../function/treeView';
type Path = string;
interface LibFileChange {
add: AbsPath[],
del: AbsPath[],
}
interface LibStatus {
state?: LibraryState,
list: AbsPath[]
}
/**
* a与b的差集
* @param a
* @param b
* @returns
*/
function diffElement<T>(a: T[], b: T[]): T[] {
const bSet = new Set<T>(b);
return a.filter(el => !bSet.has(el));
}
function removeDuplicates<T>(a: T[]): T[] {
const aSet = new Set(a);
return [...aSet];
}
class LibManage {
curr: LibStatus;
next: LibStatus;
constructor() {
this.curr = { list : [] };
this.next = { list : [] };
}
public get customerPath(): AbsPath {
return opeParam.prjInfo.libCustomPath;
}
public get srcPath(): AbsPath {
return opeParam.prjInfo.hardwareSrcPath;
}
public get simPath(): AbsPath {
return opeParam.prjInfo.hardwareSimPath;
}
public get prjPath(): AbsPath {
return opeParam.prjInfo.arch.prjPath;
}
public get localLibPath(): AbsPath {
return hdlPath.join(this.srcPath, 'lib');
}
public get sourceLibPath(): AbsPath {
return hdlPath.join(opeParam.extensionPath, 'lib');
}
public async processLibFiles(library: Library): Promise<LibFileChange> {
this.next.list = this.getLibFiles();
if (library.state === LibraryState.Local) {
this.next.state = LibraryState.Local;
} else {
this.next.state = LibraryState.Remote;
}
// current disk situation
if (hdlFile.isDir(this.localLibPath)) {
this.curr.state = LibraryState.Local;
} else {
this.curr.state = LibraryState.Remote;
}
const add: AbsPath[] = [];
const del: AbsPath[] = [];
const statePair = this.curr.state + '-' + this.next.state;
switch (statePair) {
case 'remote-remote':
add.push(...diffElement(this.next.list, this.curr.list));
del.push(...diffElement(this.curr.list, this.next.list));
break;
case 'remote-local':
del.push(...this.curr.list);
// copy file from remote to local
const remotePathList = this.getLibFiles(LibraryState.Remote);
this.remote2Local(remotePathList, (src, dist) => {
hdlParam.deleteHdlFile(src);
hdlFile.copyFile(src, dist);
});
break;
case 'local-remote':
add.push(...this.next.list);
// delete local files & data structure in hdlParam (async)
await this.deleteLocalFiles();
break;
case 'local-local':
add.push(...diffElement(this.next.list, this.curr.list));
del.push(...diffElement(this.curr.list, this.next.list));
this.remote2Local(add, (src, dist) => {
hdlFile.copyFile(src, dist);
});
break;
default: break;
}
return { add, del };
}
public getLibFiles(state?: LibraryState): AbsPath[] {
const libPathSet = new PathSet();
for (const path of opeParam.prjInfo.getLibraryCommonPaths(true, state)) {
libPathSet.checkAdd(path);
}
for (const path of opeParam.prjInfo.getLibraryCustomPaths()) {
libPathSet.checkAdd(path);
}
const libPathList = hdlFile.getHDLFiles(libPathSet.files);
return libPathList;
}
public async deleteLocalFiles() {
if (fs.existsSync(this.localLibPath)) {
const needNotice = vscode.workspace.getConfiguration('digital-ide.prj.file.structure.notice');
if (needNotice) {
const res = await vscode.window.showWarningMessage(
`Local Lib (${this.localLibPath}) will be removed.`,
{ modal: true },
{ title: 'Yes', value: true },
{ title: 'No', value: false }
);
if (res?.value) {
this.deleteLocalLib();
}
} else {
this.deleteLocalLib();
}
}
}
public deleteLocalLib() {
const hdlFileList = hdlFile.getHDLFiles([this.localLibPath]);
for (const path of hdlFileList) {
hdlParam.deleteHdlFile(path);
}
refreshArchTree();
hdlDir.rmdir(this.localLibPath);
}
public remote2Local(remotes: Path[], callback: (src: AbsPath, dist: AbsPath) => void) {
const localLibPath = this.localLibPath;
const sourceLibPath = this.sourceLibPath;
const customerPath = this.customerPath;
const customerPathValid = hdlFile.isDir(customerPath);
for (const srcPath of remotes) {
const replacePath = ( customerPathValid && srcPath.includes(customerPath) ) ? customerPath : sourceLibPath;
const distPath = srcPath.replace(replacePath, localLibPath);
callback(srcPath, distPath);
}
}
};
const libManage = new LibManage();
export {
libManage,
LibManage
};