Skip to content

Commit

Permalink
Merge pull request #1728 from codefori/fix/correct_error_catching
Browse files Browse the repository at this point in the history
Correct all places where it was expected runCommand to crash
  • Loading branch information
worksofliam authored Dec 15, 2023
2 parents 5138ca2 + 783c09d commit 2b09767
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 245 deletions.
9 changes: 7 additions & 2 deletions src/api/CompileTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ export namespace CompileTools {
/**
* Execute a command
*/
export async function runCommand(instance: Instance, options: RemoteCommand, writeEvent?: EventEmitter<string>): Promise<CommandResult | null> {
export async function runCommand(instance: Instance, options: RemoteCommand, writeEvent?: EventEmitter<string>): Promise<CommandResult> {
const connection = instance.getConnection();
const config = instance.getConfig();
if (config && connection) {
Expand Down Expand Up @@ -677,7 +677,12 @@ export namespace CompileTools {
throw new Error("Please connect to an IBM i");
}

return null;
return {
code: 1,
command: options.command,
stdout: ``,
stderr: `Command execution failed. (Internal)`,
};
}

/**
Expand Down
98 changes: 48 additions & 50 deletions src/api/IBMi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,16 +344,16 @@ export default class IBMi {
});

//Next, we need to check the temp lib (where temp outfile data lives) exists
try {
await this.runCommand({
command: `CRTLIB LIB(` + this.config.tempLibrary + `) TEXT('Code for i temporary objects. May be cleared.')`,
noLibList: true
});
const createdTempLib = await this.runCommand({
command: `CRTLIB LIB(` + this.config.tempLibrary + `) TEXT('Code for i temporary objects. May be cleared.')`,
noLibList: true
});

if (createdTempLib.code === 0) {
tempLibrarySet = true;

} catch (e: any) {
let [errorcode, errortext] = e.split(`:`);
} else {
let [errorcode, errortext] = createdTempLib?.stderr.split(`:`);

switch (errorcode) {
case `CPF2158`: //Library X exists in ASP device ASP X.
Expand All @@ -362,15 +362,16 @@ export default class IBMi {
break;

case `CPD0032`: //Can't use CRTLIB
try {
await this.runCommand({
command: `CHKOBJ OBJ(QSYS/${this.config.tempLibrary}) OBJTYPE(*LIB)`,
noLibList: true
});
const tempLibExists = await this.runCommand({
command: `CHKOBJ OBJ(QSYS/${this.config.tempLibrary}) OBJTYPE(*LIB)`,
noLibList: true
});

if (tempLibExists?.code === 0) {
//We're all good if no errors
tempLibrarySet = true;
} catch (e) {

} else {
if (currentLibrary) {
if (currentLibrary.startsWith(`Q`)) {
//Temporary library not created. Some parts of the extension will not run without a temporary library.
Expand All @@ -387,7 +388,7 @@ export default class IBMi {
break;
}

console.log(e);
console.log(createdTempLib?.stderr);
}

progress.report({
Expand Down Expand Up @@ -431,18 +432,17 @@ export default class IBMi {
})
.then(result => {
// All good!
})
.catch(e => {
// CPF2125: No objects deleted.
if (!e.startsWith(`CPF2125`)) {
// @ts-ignore We know the config exists.
vscode.window.showErrorMessage(`Temporary data not cleared from ${this.config.tempLibrary}.`, `View log`).then(async choice => {
if (choice === `View log`) {
this.outputChannel!.show();
}
});
if (result && result.stderr) {
if (!result.stderr.startsWith(`CPF2125`)) {
// @ts-ignore We know the config exists.
vscode.window.showErrorMessage(`Temporary data not cleared from ${this.config.tempLibrary}.`, `View log`).then(async choice => {
if (choice === `View log`) {
this.outputChannel!.show();
}
});
}
}
});
})

this.sendCommand({
command: `rm -f ${path.posix.join(this.config.tempDir, `vscodetemp*`)}`
Expand All @@ -469,12 +469,12 @@ export default class IBMi {
message: `Checking for bad data areas.`
});

try {
await this.runCommand({
command: `CHKOBJ OBJ(QSYS/QCPTOIMPF) OBJTYPE(*DTAARA)`,
noLibList: true
});
const QCPTOIMPF = await this.runCommand({
command: `CHKOBJ OBJ(QSYS/QCPTOIMPF) OBJTYPE(*DTAARA)`,
noLibList: true
});

if (QCPTOIMPF?.code === 0) {
vscode.window.showWarningMessage(`The data area QSYS/QCPTOIMPF exists on this system and may impact Code for IBM i functionality.`, {
detail: `For V5R3, the code for the command CPYTOIMPF had a major design change to increase functionality and performance. The QSYS/QCPTOIMPF data area lets developers keep the pre-V5R2 version of CPYTOIMPF. Code for IBM i cannot function correctly while this data area exists.`,
modal: true,
Expand All @@ -485,28 +485,27 @@ export default class IBMi {
command: `DLTOBJ OBJ(QSYS/QCPTOIMPF) OBJTYPE(*DTAARA)`,
noLibList: true
})
.then(() => {
vscode.window.showInformationMessage(`The data area QSYS/QCPTOIMPF has been deleted.`);
.then((result) => {
if (result?.code === 0) {
vscode.window.showInformationMessage(`The data area QSYS/QCPTOIMPF has been deleted.`);
} else {
vscode.window.showInformationMessage(`Failed to delete the data area QSYS/QCPTOIMPF. Code for IBM i may not work as intended.`);
}
})
.catch(e => {
vscode.window.showInformationMessage(`Failed to delete the data area QSYS/QCPTOIMPF. Code for IBM i may not work as intended.`);
});
break;
case `Read more`:
vscode.env.openExternal(vscode.Uri.parse(`https://github.com/codefori/vscode-ibmi/issues/476#issuecomment-1018908018`));
break;
}
});
} catch (e) {
// It doesn't exist, we're all good.
}

try {
await this.runCommand({
command: `CHKOBJ OBJ(QSYS/QCPFRMIMPF) OBJTYPE(*DTAARA)`,
noLibList: true
});
const QCPFRMIMPF = await await this.runCommand({
command: `CHKOBJ OBJ(QSYS/QCPFRMIMPF) OBJTYPE(*DTAARA)`,
noLibList: true
});

if (QCPFRMIMPF?.code === 0) {
vscode.window.showWarningMessage(`The data area QSYS/QCPFRMIMPF exists on this system and may impact Code for IBM i functionality.`, {
modal: false,
}, `Delete`, `Read more`).then(choice => {
Expand All @@ -516,20 +515,19 @@ export default class IBMi {
command: `DLTOBJ OBJ(QSYS/QCPFRMIMPF) OBJTYPE(*DTAARA)`,
noLibList: true
})
.then(() => {
vscode.window.showInformationMessage(`The data area QSYS/QCPFRMIMPF has been deleted.`);
.then((result) => {
if (result?.code === 0) {
vscode.window.showInformationMessage(`The data area QSYS/QCPFRMIMPF has been deleted.`);
} else {
vscode.window.showInformationMessage(`Failed to delete the data area QSYS/QCPFRMIMPF. Code for IBM i may not work as intended.`);
}
})
.catch(e => {
vscode.window.showInformationMessage(`Failed to delete the data area QSYS/QCPFRMIMPF. Code for IBM i may not work as intended.`);
});
break;
case `Read more`:
vscode.env.openExternal(vscode.Uri.parse(`https://github.com/codefori/vscode-ibmi/issues/476#issuecomment-1018908018`));
break;
}
});
} catch (e) {
// It doesn't exist, we're all good.
}
}

Expand Down
74 changes: 39 additions & 35 deletions src/api/IBMiContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,21 +121,20 @@ export default class IBMiContent {
let path = Tools.qualifyPath(library, sourceFile, member, asp);
const tempRmt = this.getTempRemote(path);
while (true) {
try {
await this.ibmi.runCommand({
command: `CPYTOSTMF FROMMBR('${path}') TOSTMF('${tempRmt}') STMFOPT(*REPLACE) STMFCCSID(1208) DBFCCSID(${this.config.sourceFileCCSID})`,
noLibList: true
});
const copyResult = await this.ibmi.runCommand({
command: `CPYTOSTMF FROMMBR('${path}') TOSTMF('${tempRmt}') STMFOPT(*REPLACE) STMFCCSID(1208) DBFCCSID(${this.config.sourceFileCCSID})`,
noLibList: true
});

if (copyResult.code === 0) {
if (!localPath) {
localPath = await tmpFile();
}
await this.ibmi.downloadFile(localPath, tempRmt);
return await readFileAsync(localPath, `utf8`);
}
catch (e) {
} else {
if (!retry) {
const messageID = String(e).substring(0, 7);
const messageID = String(copyResult.stdout).substring(0, 7);
switch (messageID) {
case "CPDA08A":
//We need to try again after we delete the temp remote
Expand All @@ -156,7 +155,7 @@ export default class IBMiContent {
}

if (!retry) {
throw e
throw new Error(`Failed downloading member: ${copyResult.stderr}`);
}
}
}
Expand All @@ -182,16 +181,16 @@ export default class IBMiContent {
await client.putFile(tmpobj, tempRmt);

while (true) {
try {
await this.ibmi.runCommand({
command: `QSYS/CPYFRMSTMF FROMSTMF('${tempRmt}') TOMBR('${path}') MBROPT(*REPLACE) STMFCCSID(1208) DBFCCSID(${this.config.sourceFileCCSID})`,
noLibList: true
});
const copyResult = await this.ibmi.runCommand({
command: `QSYS/CPYFRMSTMF FROMSTMF('${tempRmt}') TOMBR('${path}') MBROPT(*REPLACE) STMFCCSID(1208) DBFCCSID(${this.config.sourceFileCCSID})`,
noLibList: true
});

if (copyResult.code === 0) {
return true;
}
catch (e) {
} else {
if (!retry) {
const messageID = String(e).substring(0, 7);
const messageID = String(copyResult.stderr).substring(0, 7);
switch (messageID) {
case "CPFA0A9":
//The member may be located on SYSBAS
Expand All @@ -201,7 +200,7 @@ export default class IBMiContent {
}
break;
default:
throw e;
throw new Error(`Failed uploading member: ${copyResult.stderr}`);
}
}
}
Expand Down Expand Up @@ -300,33 +299,38 @@ export default class IBMiContent {

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

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

if (this.config.autoClearTempData) {
await this.ibmi.sendCommand({ command: `rm -f ${tempRmt}`, directory: `.` });
if (deleteTable) {
await this.ibmi.runCommand({ command: `DLTOBJ OBJ(${library}/${file}) OBJTYPE(*FILE)`, noLibList: true });
if (this.config.autoClearTempData) {
Promise.allSettled([
this.ibmi.sendCommand({ command: `rm -f ${tempRmt}`, directory: `.` }),
deleteTable ? this.ibmi.runCommand({ command: `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 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;
}
return record;
}
});
});

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

}
Expand Down
6 changes: 5 additions & 1 deletion src/filesystems/qsys/extendedContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,15 @@ export class ExtendedIBMiContent {
await connection.sendCommand({ command: `${setccsid} 1208 ${tempRmt}` });
}

await connection.runCommand({
const insertResult = await connection.runCommand({
command: `QSYS/RUNSQLSTM SRCSTMF('${tempRmt}') COMMIT(*NONE) NAMING(*SQL)`,
noLibList: true
});

if (insertResult.code !== 0) {
throw new Error(`Failed to save member: ` + insertResult.stderr);
}

if (this.sourceDateHandler.sourceDateMode === `diff`) {
this.sourceDateHandler.baseSource.set(alias, body);
this.sourceDateHandler.baseDates.set(alias, sourceDates);
Expand Down
13 changes: 7 additions & 6 deletions src/languages/clle/clApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,16 @@ async function install() {

const tempLib = config.tempLibrary;

try {
await connection.runCommand({ command: `CRTSRCPF ${tempLib}/QTOOLS`, noLibList: true })
} catch (e) {
//It may exist already so we just ignore the error
}
//It may exist already so we just ignore the error
await connection.runCommand({ command: `CRTSRCPF ${tempLib}/QTOOLS`, noLibList: true })

await content.uploadMemberContent(undefined, tempLib, `QTOOLS`, `GENCMDXML`, gencmdxml.content.join(`\n`));
await connection.runCommand({
const createResult = await connection.runCommand({
command: `CRTBNDCL PGM(${tempLib}/GENCMDXML) SRCFILE(${tempLib}/QTOOLS) DBGVIEW(*SOURCE) TEXT('vscode-ibmi xml generator for commands')`,
noLibList: true
});

if (createResult.code !== 0) {
throw new Error(`Failed to create GENCMDXML program.`);
}
}
11 changes: 6 additions & 5 deletions src/languages/clle/getnewlibl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ export async function initGetNewLibl(instance: Instance) {
cwd: `/`,
noLibList: true
})
.then(() => {
connection.remoteFeatures[`GETNEWLIBL.PGM`] = `${config.tempLibrary}.GETNEWLIBL`;
})
.catch(() => {
window.showWarningMessage(`Unable to install GETNEWLIBL. See Code for IBM i output for details.`);
.then((result) => {
if (result.code === 0) {
connection.remoteFeatures[`GETNEWLIBL.PGM`] = `${config.tempLibrary}.GETNEWLIBL`;
} else {
window.showWarningMessage(`Unable to install GETNEWLIBL. See Code for IBM i output for details.`);
}
})
})
}
Expand Down
Loading

0 comments on commit 2b09767

Please sign in to comment.