Skip to content

Commit

Permalink
Merge branch 'master' into cleanup/seperate_frontend
Browse files Browse the repository at this point in the history
Signed-off-by: worksofliam <[email protected]>
  • Loading branch information
worksofliam committed Jan 15, 2025
2 parents bb83734 + c00f861 commit 38993af
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 29 deletions.
8 changes: 4 additions & 4 deletions src/api/IBMi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface MemberParts extends IBMiMember {
}

export type ConnectionMessageType = 'info' | 'warning' | 'error';
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`;
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`;

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

type DisconnectCallback = (conn: IBMi) => Promise<void>;
interface ConnectionCallbacks{
interface ConnectionCallbacks {
onConnectedOperations?: Function[],
timeoutCallback?: (conn: IBMi) => Promise<void>,
uiErrorHandler: (connection: IBMi, error: ConnectionErrorCode, data?: any) => Promise<boolean>,
progress: (detail: {message: string}) => void,
progress: (detail: { message: string }) => void,
message: (type: ConnectionMessageType, message: string) => void,
cancelEmitter?: EventEmitter,
}
Expand Down Expand Up @@ -678,7 +678,7 @@ export default class IBMi {
reason = "/QOpenSys/pkgs/bin is not in the right position in your $PATH shell environment variable";
missingPath = "/QOpenSys/pkgs/bin"
}

if (reason) {
callbacks.uiErrorHandler(this, `invalid_bashrc`, { missingPath, bashrcFile, bashrcExists, reason });
}
Expand Down
3 changes: 2 additions & 1 deletion src/api/Tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ export namespace Tools {
*/

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

slideBytesBy += extendedBytes;
if (extendedBytes > 0) {
Expand Down
3 changes: 1 addition & 2 deletions src/api/components/getMemberInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ export class GetMemberInfo implements IBMiComponent {
}

async update(connection: IBMi): Promise<ComponentState> {
const config = connection.config!;
return connection.withTempDirectory(async tempDir => {
const tempSourcePath = posix.join(tempDir, `getMemberInfo.sql`);
await connection.content.writeStreamfileRaw(tempSourcePath, getSource(config.tempLibrary, this.procedureName, this.currentVersion));
await connection.getContent().writeStreamfileRaw(tempSourcePath, getSource(connection.getConfig().tempLibrary, this.procedureName, this.currentVersion));
const result = await connection.runCommand({
command: `RUNSQLSTM SRCSTMF('${tempSourcePath}') COMMIT(*NONE) NAMING(*SQL)`,
cwd: `/`,
Expand Down
63 changes: 42 additions & 21 deletions src/api/components/getNewLibl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,40 @@ import { ComponentState, IBMiComponent } from "./component";

export class GetNewLibl implements IBMiComponent {
static ID = "GetNewLibl";
private readonly procedureName = 'GETNEWLIBL';
private readonly currentVersion = 1;
private installedVersion = 0;

reset() {
this.installedVersion = 0;
}

getIdentification() {
return { name: GetNewLibl.ID, version: 1 };
return { name: GetNewLibl.ID, version: this.installedVersion };
}

async getRemoteState(connection: IBMi): Promise<ComponentState> {
return connection.remoteFeatures[`GETNEWLIBL.PGM`] ? `Installed` : `NotInstalled`;
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}'`);
if (result?.LONG_COMMENT) {
const comment = result.LONG_COMMENT as string;
const dash = comment.indexOf('-');
if (dash > -1) {
this.installedVersion = Number(comment.substring(0, dash).trim());
}
}
if (this.installedVersion < this.currentVersion) {
return `NeedsUpdate`;
}

return `Installed`;
}

update(connection: IBMi): Promise<ComponentState> {
const config = connection.config!
const content = connection.getContent();
const config = connection.getConfig();
return connection.withTempDirectory(async (tempDir): Promise<ComponentState> => {
const tempSourcePath = posix.join(tempDir, `getnewlibl.sql`);

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

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

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

return result;
}
}

function getSource(library: string) {
return Buffer.from([
`CREATE OR REPLACE PROCEDURE ${library}.GETNEWLIBL(IN COMMAND VARCHAR(2000))`,
`DYNAMIC RESULT SETS 1 `,
`BEGIN`,
` DECLARE clibl CURSOR FOR `,
` SELECT ORDINAL_POSITION, TYPE as PORTION, SYSTEM_SCHEMA_NAME`,
` FROM QSYS2.LIBRARY_LIST_INFO;`,
` CALL QSYS2.QCMDEXC(COMMAND);`,
` OPEN clibl;`,
`END;`,
``,
`call QSYS2.QCMDEXC( 'grtobjaut ${library}/GETNEWLIBL *PGM *PUBLIC *ALL' );`
].join(`\n`), "utf8");
private getSource(library: string) {
return Buffer.from([
`CREATE OR REPLACE PROCEDURE ${library}.${this.procedureName}(IN COMMAND VARCHAR(2000))`,
`DYNAMIC RESULT SETS 1 `,
`BEGIN`,
` DECLARE clibl CURSOR FOR `,
` SELECT ORDINAL_POSITION, TYPE as PORTION, SYSTEM_SCHEMA_NAME`,
` FROM QSYS2.LIBRARY_LIST_INFO;`,
` CALL QSYS2.QCMDEXC(COMMAND);`,
` OPEN clibl;`,
`END;`,
``,
`comment on procedure ${library}.${this.procedureName} is '${this.currentVersion} - Validate member information';`,
``,
`call QSYS2.QCMDEXC( 'grtobjaut ${library}/${this.procedureName} *PGM *PUBLIC *ALL' );`
].join(`\n`), "utf8");
}
}
37 changes: 36 additions & 1 deletion src/testing/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,41 @@ export const ToolsSuite: TestSuite = {
assert.strictEqual(rows[0].CHANGED, 1713453741000);
}
},
{
name: `Db2 results with bad character`, test: async () => {
const lines = [
`DB2>`,
` ?>`,
``,
`LIBRARY NAME TYPE ATTRIBUTE TEXT IS_SOURCE SOURCE_LENGTH IASP_NUMBER `,
`---------- ---------- ----- ---------- -------------------------------------------------- ----------- -------------- ------------`,
`LOGOMATE QCLSRC *FILE PF LogoMate� - Sourcen CL 1 112 0`,
`LOGOMATE QCMDSRC *FILE PF LogoMate� - Sourcen CMD 1 112 0`,
`LOGOMATE QMNUSRC *FILE PF LogoMate� - Sourcen MNU 1 112 0`,
`LOGOMATE QPNLSRC *FILE PF LogoMate� - Sourcen PNLGRP 1 112 0`,
`LOGOMATE QRPGLECPY *FILE PF LogoMate� - Sourcen RPGLECPY 1 112 0`,
`LOGOMATE QRPGLEH *FILE PF LogoMate� - Sourcen RPGLEH 1 112 0`,
`LOGOMATE QRPGLESRC *FILE PF LogoMate� - Sourcen RPGLE 1 112 0`,
`LOGOMATE QSQDSRC *FILE PF SQL PROCEDURES 1 160 0`,
`LOGOMATE QSQLSRC *FILE PF LogoMate� - Sourcen SQL 1 112 0`,
`LOGOMATE QSRVSRC *FILE PF LogoMate� - Sourcen SRV 1 112 0`,
``,
` 10 RECORD(S) SELECTED.`,
]

const rows = Tools.db2Parse(lines.join(`\n`));
assert.strictEqual(rows.length, 10);

assert.strictEqual(rows[0].LIBRARY, `LOGOMATE`);
assert.strictEqual(rows[0].NAME, `QCLSRC`);
assert.strictEqual(rows[0].TYPE, `*FILE`);
assert.strictEqual(rows[0].ATTRIBUTE, `PF`);
assert.strictEqual(rows[0].TEXT, `LogoMate� - Sourcen CL`);
assert.strictEqual(rows[0].IS_SOURCE, 1);
assert.strictEqual(rows[0].SOURCE_LENGTH, 112);
assert.strictEqual(rows[0].IASP_NUMBER, 0);
}
},
{
name: "Date attr parsing", test: async () => {
const date1Epoch = Tools.parseAttrDate(`Fri Apr 5 09:00:10 2024`);
Expand All @@ -346,6 +381,6 @@ export const ToolsSuite: TestSuite = {
assert.strictEqual(date2.getUTCMinutes(), 47);
assert.strictEqual(date2.getUTCSeconds(), 2);
}
}
},
]
};

0 comments on commit 38993af

Please sign in to comment.