Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
754 changes: 261 additions & 493 deletions package-lock.json

Large diffs are not rendered by default.

18 changes: 8 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3600,20 +3600,19 @@
"webpack": "webpack --mode development",
"webpack-dev": "webpack --mode development --watch",
"types": "npx -p typescript tsc ./src/extension.ts --declaration --allowJs --emitDeclarationOnly --outDir types --esModuleInterop -t es2022 --moduleResolution node --resolveJsonModule",
"postinstall": "npx tsx tools/downloadMapepire",
"sqlsignature": "npx tsx tools/sqlSignature"
},
"devDependencies": {
"@octokit/rest": "22.0.1",
"@types/adm-zip": "0.5.7",
"@types/node": "22.19.7",
"@types/ssh2": "^1.15.5",
"@types/tar": "6.1.13",
"@types/tmp": "0.2.5",
"@types/vscode": "^1.90.0",
"@types/ws": "^8.18.2",
"@vscode/vsce": "^3.9.1",
"esbuild": "^0.27.0",
"esbuild-loader": "^4.4.2",
"esbuild": "0.28.2",
"esbuild-loader": "4.5.0",
"eslint": "^8.57.1",
"ssh2-streams": "^0.4.10",
"ts-loader": "^9.3.1",
Expand All @@ -3625,22 +3624,21 @@
},
"dependencies": {
"@ibm/ibmi-eventf-parser": "2.0.2",
"@ibm/mapepire-js": "0.6.1",
"@ibm/mapepire-js": "1.0.1",
"@vscode-elements/elements": "2.5.1",
"@vscode/codicons": "0.0.45",
"adm-zip": "0.5.16",
"adm-zip": "0.6.1",
"crc-32": "https://cdn.sheetjs.com/crc-32-latest/crc-32-latest.tgz",
"csv": "6.4.1",
"escape-string-regexp": "5.0.0",
"ignore": "7.0.5",
"node-ssh": "13.2.1",
"tar": "^7.5.13",
"tmp": "0.2.6",
"tar": "7.5.22",
"tmp": "0.2.7",
"vscode-diff": "3.0.1"
},
"extensionDependencies": [
"barrettotte.ibmi-languages",
"halcyontechltd.vscode-ibmi-walkthroughs",
"vscode.git"
]
}
}
42 changes: 23 additions & 19 deletions src/api/IBMi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -624,13 +624,14 @@ export default class IBMi {
callbacks.progress({ message: `Loading remote configuration files.` });
await this.loadAndApplyRemoteConfigs();

callbacks.progress({ message: `Checking Mapepire status.` });
callbacks.progress({ message: `Checking temporary directory.` });
const tempDirSet = await this.checkOrCreateTempDirectory();
if (!tempDirSet) {
this.config.tempDir = `~/.vscode/tmp`;
}

// We always start up Mapepire first
callbacks.progress({ message: `Checking Mapepire status.` });
let mapepireState;
try {
mapepireState = await this.componentManager.startupComponent(Mapepire.ID, quickConnect() ? cachedServerSettings?.installedComponents : []);
Expand All @@ -646,26 +647,29 @@ export default class IBMi {

callbacks.progress({ message: `Starting Mapepire.` });
const mapepire = await this.getComponent<Mapepire>(Mapepire.ID);
if (mapepire) {
const hasJavaInstalled = (this.remoteFeatures.jdk21 || this.remoteFeatures.jdk17 || this.remoteFeatures.jdk11 || this.remoteFeatures.jdk80);
if (hasJavaInstalled) {
try {
this.sqlJob = await mapepire.newJob(this);
if (this.sqlJob.id) {
this.splfUserData = `C4I${this.sqlJob.id.substring(0, this.sqlJob.id.indexOf('/'))}`;
await this.sqlJob.execute(`CALL QSYS2.QCMDEXC('OVRPRTF FILE(*PRTF) SPOOL(*YES) HOLD(*YES) USRDTA(${this.splfUserData}) SPLFOWN(*CURUSRPRF) OVRSCOPE(*JOB)')`);
}
} catch (e: any) {
callbacks.message(`error`, `Failed to start Mapepire SQL job: ${e.message || e}`);
this.appendOutput(`Mapepire error: ${e.message || e}\n`);

try {
if (mapepire) {
const hasJavaInstalled = (this.remoteFeatures.jdk21 || this.remoteFeatures.jdk17 || this.remoteFeatures.jdk11 || this.remoteFeatures.jdk80);
if (!this.getConfig().mapepireUseServer && !hasJavaInstalled) {
throw new Error(`No Java installation found. SQL operations will not be available. Please install Java 8, 11, 17 or 21.`);
}

this.sqlJob = await mapepire.newJob(this);
if (this.sqlJob.id) {
this.splfUserData = `C4I${this.sqlJob.id.substring(0, this.sqlJob.id.indexOf('/'))}`;
await this.sqlJob.execute(`CALL QSYS2.QCMDEXC('OVRPRTF FILE(*PRTF) SPOOL(*YES) HOLD(*YES) USRDTA(${this.splfUserData}) SPLFOWN(*CURUSRPRF) OVRSCOPE(*JOB)')`);
}
} else {
callbacks.message(`warning`, `No Java installation found. SQL operations will not be available. Please install Java 8, 11, or 17.`);
this.appendOutput(`Warning: No Java found for Mapepire\n`);
}
} else {
callbacks.message(`warning`, `Mapepire component failed to start. SQL operations will not be available.`);
this.appendOutput(`Warning: Mapepire component not available\n`);
else {
throw new Error(`Mapepire component failed to start.`);
}
}
catch (e: any) {
const error = e.message || e;
callbacks.message(`error`, `Failed to start Mapepire SQL job: ${error}`);
this.appendOutput(`Mapepire error: ${error}\n`);
throw e;
}

try {
Expand Down
59 changes: 1 addition & 58 deletions src/api/IBMiContent.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import crypto from 'crypto';
import { parse } from 'csv-parse/sync';
import escapeStringRegexp from 'escape-string-regexp';
import fs from 'fs';
import * as node_ssh from "node-ssh";
import path from 'path';
import tmp from 'tmp';
import util from 'util';
import escapeStringRegexp from 'escape-string-regexp';
import { FilterType, parseFilter, singleGenericName } from './Filter';
import { default as IBMi } from './IBMi';
import { Tools } from './Tools';
Expand Down Expand Up @@ -427,62 +426,6 @@ export default class IBMiContent {
return this.ibmi.runSQL(statements);
}

/**
* Download the contents of a member from a table.
* @param library
* @param file
* @param member Will default to file provided
* @param deleteTable Will delete the table after download
*/
async getTable(library: string, file: string, member?: string, deleteTable?: boolean): Promise<Tools.DB2Row[]> {
Comment thread
SanjulaGanepola marked this conversation as resolved.
if (!member) member = file; //Incase mbr is the same file

const tempRmt = Tools.ensureFullPath(this.getTempRemote(Tools.qualifyPath(library, file, member)), this.config.homeDirectory);
const copyResult = await this.ibmi.runCommand({
command: `QSYS/CPYTOIMPF FROMFILE(${library}/${file} ${member}) ` +
`TOSTMF('${tempRmt}') ` +
`MBROPT(*REPLACE) STMFCCSID(1208) STMFCODPAG(*STMF) RCDDLM(*CRLF) DTAFMT(*DLM) RMVBLANK(*TRAILING) ADDCOLNAM(*SQL) FLDDLM(',') DECPNT(*PERIOD)`,
noLibList: true
});

if (copyResult.code === 0) {
let result = await this.downloadStreamfileRaw(tempRmt);

if (this.config.autoClearTempData) {
Promise.allSettled([
this.ibmi.sendCommand({ command: `rm -rf ${tempRmt}`, directory: `.` }),
deleteTable ? this.ibmi.runCommand({ command: `QSYS/DLTOBJ OBJ(${library}/${file}) OBJTYPE(*FILE)`, noLibList: true }) : Promise.resolve()
]);
}

return parse(result, {
columns: true,
skip_empty_lines: true,
cast: true,
onRecord(record) {
for (const key of Object.keys(record)) {
record[key] = record[key] === ` ` ? `` : record[key];
}
return record;
}
});

} else {
throw new Error(`Failed fetching table: ${copyResult.stderr}`);
}

}

/**
* Prepare a table in QTEMP using any number of preparation queries and return its content.
* @param prepareQueries : SQL statements that should create a table in QTEMP
* @param table : the name of the table expected to be found in QTEMP
* @returns : the table's content
*/
getQTempTable(prepareQueries: string[], table: string): Promise<Tools.DB2Row[]> {
return this.runStatements(...prepareQueries, `select * from QTEMP.${table}`);
}

/**
* Get list of libraries with description and attribute
* @param libraries Array of libraries to retrieve
Expand Down
2 changes: 1 addition & 1 deletion src/api/components/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export class ComponentManager {
if (component) {
component.component.reset?.();

const state = component.handleState(await component.component.getRemoteState(this.connection, await component.getInstallDirectory()));
const state = component.handleState(await component.component.getRemoteState(this.connection, component.getInstallDirectory()));
component.overrideState(state);
return state;
}
Expand Down
Loading
Loading