Skip to content

Commit 38993af

Browse files
committed
Merge branch 'master' into cleanup/seperate_frontend
Signed-off-by: worksofliam <[email protected]>
2 parents bb83734 + c00f861 commit 38993af

File tree

5 files changed

+85
-29
lines changed

5 files changed

+85
-29
lines changed

src/api/IBMi.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export interface MemberParts extends IBMiMember {
2222
}
2323

2424
export type ConnectionMessageType = 'info' | 'warning' | 'error';
25-
export type ConnectionErrorCode = `shell_config`|`home_directory_creation`|`QCPTOIMPF_exists`|`QCPFRMIMPF_exists`|`default_not_bash`|`invalid_bashrc`|`invalid_temp_lib`|`no_auto_conv_ebcdic`|`not_loaded_debug_config`|`no_sql_runner`|`ccsid_warning`;
25+
export type ConnectionErrorCode = `shell_config` | `home_directory_creation` | `QCPTOIMPF_exists` | `QCPFRMIMPF_exists` | `default_not_bash` | `invalid_bashrc` | `invalid_temp_lib` | `no_auto_conv_ebcdic` | `not_loaded_debug_config` | `no_sql_runner` | `ccsid_warning`;
2626

2727
export interface ConnectionResult {
2828
success: boolean,
@@ -54,11 +54,11 @@ const remoteApps = [ // All names MUST also be defined as key in 'remoteFeatures
5454
];
5555

5656
type DisconnectCallback = (conn: IBMi) => Promise<void>;
57-
interface ConnectionCallbacks{
57+
interface ConnectionCallbacks {
5858
onConnectedOperations?: Function[],
5959
timeoutCallback?: (conn: IBMi) => Promise<void>,
6060
uiErrorHandler: (connection: IBMi, error: ConnectionErrorCode, data?: any) => Promise<boolean>,
61-
progress: (detail: {message: string}) => void,
61+
progress: (detail: { message: string }) => void,
6262
message: (type: ConnectionMessageType, message: string) => void,
6363
cancelEmitter?: EventEmitter,
6464
}
@@ -678,7 +678,7 @@ export default class IBMi {
678678
reason = "/QOpenSys/pkgs/bin is not in the right position in your $PATH shell environment variable";
679679
missingPath = "/QOpenSys/pkgs/bin"
680680
}
681-
681+
682682
if (reason) {
683683
callbacks.uiErrorHandler(this, `invalid_bashrc`, { missingPath, bashrcFile, bashrcExists, reason });
684684
}

src/api/Tools.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ export namespace Tools {
120120
121121
*/
122122

123-
const extendedBytes = strValue.split(``).map(c => Buffer.byteLength(c) < 3 ? 0 : 1).reduce((a: number, b: number) => a + b, 0);
123+
// 65533 = � (not a double byte character!)
124+
const extendedBytes = strValue.split(``).map(c => (Buffer.byteLength(c) < 3 || c.charCodeAt(0) === 65533) ? 0 : 1).reduce((a: number, b: number) => a + b, 0);
124125

125126
slideBytesBy += extendedBytes;
126127
if (extendedBytes > 0) {

src/api/components/getMemberInfo.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,9 @@ export class GetMemberInfo implements IBMiComponent {
3535
}
3636

3737
async update(connection: IBMi): Promise<ComponentState> {
38-
const config = connection.config!;
3938
return connection.withTempDirectory(async tempDir => {
4039
const tempSourcePath = posix.join(tempDir, `getMemberInfo.sql`);
41-
await connection.content.writeStreamfileRaw(tempSourcePath, getSource(config.tempLibrary, this.procedureName, this.currentVersion));
40+
await connection.getContent().writeStreamfileRaw(tempSourcePath, getSource(connection.getConfig().tempLibrary, this.procedureName, this.currentVersion));
4241
const result = await connection.runCommand({
4342
command: `RUNSQLSTM SRCSTMF('${tempSourcePath}') COMMIT(*NONE) NAMING(*SQL)`,
4443
cwd: `/`,

src/api/components/getNewLibl.ts

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,40 @@ import { ComponentState, IBMiComponent } from "./component";
44

55
export class GetNewLibl implements IBMiComponent {
66
static ID = "GetNewLibl";
7+
private readonly procedureName = 'GETNEWLIBL';
8+
private readonly currentVersion = 1;
9+
private installedVersion = 0;
10+
11+
reset() {
12+
this.installedVersion = 0;
13+
}
14+
715
getIdentification() {
8-
return { name: GetNewLibl.ID, version: 1 };
16+
return { name: GetNewLibl.ID, version: this.installedVersion };
917
}
1018

1119
async getRemoteState(connection: IBMi): Promise<ComponentState> {
12-
return connection.remoteFeatures[`GETNEWLIBL.PGM`] ? `Installed` : `NotInstalled`;
20+
const [result] = await connection.runSQL(`select cast(LONG_COMMENT as VarChar(200)) LONG_COMMENT from qsys2.sysprocs where routine_schema = '${connection.getConfig().tempLibrary.toUpperCase()}' and routine_name = '${this.procedureName}'`);
21+
if (result?.LONG_COMMENT) {
22+
const comment = result.LONG_COMMENT as string;
23+
const dash = comment.indexOf('-');
24+
if (dash > -1) {
25+
this.installedVersion = Number(comment.substring(0, dash).trim());
26+
}
27+
}
28+
if (this.installedVersion < this.currentVersion) {
29+
return `NeedsUpdate`;
30+
}
31+
32+
return `Installed`;
1333
}
1434

1535
update(connection: IBMi): Promise<ComponentState> {
16-
const config = connection.config!
17-
const content = connection.getContent();
36+
const config = connection.getConfig();
1837
return connection.withTempDirectory(async (tempDir): Promise<ComponentState> => {
1938
const tempSourcePath = posix.join(tempDir, `getnewlibl.sql`);
2039

21-
await content!.writeStreamfileRaw(tempSourcePath, getSource(config.tempLibrary));
40+
await connection.getContent().writeStreamfileRaw(tempSourcePath, this.getSource(config.tempLibrary));
2241
const result = await connection.runCommand({
2342
command: `RUNSQLSTM SRCSTMF('${tempSourcePath}') COMMIT(*NONE) NAMING(*SQL)`,
2443
cwd: `/`,
@@ -35,7 +54,7 @@ export class GetNewLibl implements IBMiComponent {
3554

3655
async getLibraryListFromCommand(connection: IBMi, ileCommand: string) {
3756
const tempLib = connection.config!.tempLibrary;
38-
const resultSet = await connection.runSQL(`CALL ${tempLib}.GETNEWLIBL('${ileCommand.replace(new RegExp(`'`, 'g'), `''`)}')`);
57+
const resultSet = await connection.runSQL(`CALL ${tempLib}.${this.procedureName}('${ileCommand.replace(new RegExp(`'`, 'g'), `''`)}')`);
3958

4059
const result = {
4160
currentLibrary: `QGPL`,
@@ -56,20 +75,22 @@ export class GetNewLibl implements IBMiComponent {
5675

5776
return result;
5877
}
59-
}
6078

61-
function getSource(library: string) {
62-
return Buffer.from([
63-
`CREATE OR REPLACE PROCEDURE ${library}.GETNEWLIBL(IN COMMAND VARCHAR(2000))`,
64-
`DYNAMIC RESULT SETS 1 `,
65-
`BEGIN`,
66-
` DECLARE clibl CURSOR FOR `,
67-
` SELECT ORDINAL_POSITION, TYPE as PORTION, SYSTEM_SCHEMA_NAME`,
68-
` FROM QSYS2.LIBRARY_LIST_INFO;`,
69-
` CALL QSYS2.QCMDEXC(COMMAND);`,
70-
` OPEN clibl;`,
71-
`END;`,
72-
``,
73-
`call QSYS2.QCMDEXC( 'grtobjaut ${library}/GETNEWLIBL *PGM *PUBLIC *ALL' );`
74-
].join(`\n`), "utf8");
79+
private getSource(library: string) {
80+
return Buffer.from([
81+
`CREATE OR REPLACE PROCEDURE ${library}.${this.procedureName}(IN COMMAND VARCHAR(2000))`,
82+
`DYNAMIC RESULT SETS 1 `,
83+
`BEGIN`,
84+
` DECLARE clibl CURSOR FOR `,
85+
` SELECT ORDINAL_POSITION, TYPE as PORTION, SYSTEM_SCHEMA_NAME`,
86+
` FROM QSYS2.LIBRARY_LIST_INFO;`,
87+
` CALL QSYS2.QCMDEXC(COMMAND);`,
88+
` OPEN clibl;`,
89+
`END;`,
90+
``,
91+
`comment on procedure ${library}.${this.procedureName} is '${this.currentVersion} - Validate member information';`,
92+
``,
93+
`call QSYS2.QCMDEXC( 'grtobjaut ${library}/${this.procedureName} *PGM *PUBLIC *ALL' );`
94+
].join(`\n`), "utf8");
95+
}
7596
}

src/testing/tools.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,41 @@ export const ToolsSuite: TestSuite = {
324324
assert.strictEqual(rows[0].CHANGED, 1713453741000);
325325
}
326326
},
327+
{
328+
name: `Db2 results with bad character`, test: async () => {
329+
const lines = [
330+
`DB2>`,
331+
` ?>`,
332+
``,
333+
`LIBRARY NAME TYPE ATTRIBUTE TEXT IS_SOURCE SOURCE_LENGTH IASP_NUMBER `,
334+
`---------- ---------- ----- ---------- -------------------------------------------------- ----------- -------------- ------------`,
335+
`LOGOMATE QCLSRC *FILE PF LogoMate� - Sourcen CL 1 112 0`,
336+
`LOGOMATE QCMDSRC *FILE PF LogoMate� - Sourcen CMD 1 112 0`,
337+
`LOGOMATE QMNUSRC *FILE PF LogoMate� - Sourcen MNU 1 112 0`,
338+
`LOGOMATE QPNLSRC *FILE PF LogoMate� - Sourcen PNLGRP 1 112 0`,
339+
`LOGOMATE QRPGLECPY *FILE PF LogoMate� - Sourcen RPGLECPY 1 112 0`,
340+
`LOGOMATE QRPGLEH *FILE PF LogoMate� - Sourcen RPGLEH 1 112 0`,
341+
`LOGOMATE QRPGLESRC *FILE PF LogoMate� - Sourcen RPGLE 1 112 0`,
342+
`LOGOMATE QSQDSRC *FILE PF SQL PROCEDURES 1 160 0`,
343+
`LOGOMATE QSQLSRC *FILE PF LogoMate� - Sourcen SQL 1 112 0`,
344+
`LOGOMATE QSRVSRC *FILE PF LogoMate� - Sourcen SRV 1 112 0`,
345+
``,
346+
` 10 RECORD(S) SELECTED.`,
347+
]
348+
349+
const rows = Tools.db2Parse(lines.join(`\n`));
350+
assert.strictEqual(rows.length, 10);
351+
352+
assert.strictEqual(rows[0].LIBRARY, `LOGOMATE`);
353+
assert.strictEqual(rows[0].NAME, `QCLSRC`);
354+
assert.strictEqual(rows[0].TYPE, `*FILE`);
355+
assert.strictEqual(rows[0].ATTRIBUTE, `PF`);
356+
assert.strictEqual(rows[0].TEXT, `LogoMate� - Sourcen CL`);
357+
assert.strictEqual(rows[0].IS_SOURCE, 1);
358+
assert.strictEqual(rows[0].SOURCE_LENGTH, 112);
359+
assert.strictEqual(rows[0].IASP_NUMBER, 0);
360+
}
361+
},
327362
{
328363
name: "Date attr parsing", test: async () => {
329364
const date1Epoch = Tools.parseAttrDate(`Fri Apr 5 09:00:10 2024`);
@@ -346,6 +381,6 @@ export const ToolsSuite: TestSuite = {
346381
assert.strictEqual(date2.getUTCMinutes(), 47);
347382
assert.strictEqual(date2.getUTCSeconds(), 2);
348383
}
349-
}
384+
},
350385
]
351386
};

0 commit comments

Comments
 (0)