From c4de790602133dda1e9cf2633bc63071a9ed218a Mon Sep 17 00:00:00 2001
From: worksofliam
Date: Wed, 28 Aug 2024 10:49:54 -0400
Subject: [PATCH 1/7] Extend the base API to allow other extensions to add
their own components.
Signed-off-by: worksofliam
---
src/api/IBMi.ts | 4 +--
src/components/component.ts | 50 +++----------------------------------
src/components/manager.ts | 49 ++++++++++++++++++++++++++++++++++++
src/extension.ts | 9 ++++++-
src/typings.ts | 4 ++-
5 files changed, 66 insertions(+), 50 deletions(-)
create mode 100644 src/components/manager.ts
diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts
index b53ba312f..4317e81c9 100644
--- a/src/api/IBMi.ts
+++ b/src/api/IBMi.ts
@@ -6,7 +6,6 @@ import { parse } from 'csv-parse/sync';
import { existsSync } from "fs";
import os from "os";
import path from 'path';
-import { ComponentId, ComponentManager } from "../components/component";
import { CopyToImport } from "../components/copyToImport";
import { instance } from "../instantiate";
import { CommandData, CommandResult, ConnectionData, IBMiMember, RemoteCommand, SpecialAuthorities, WrapResult } from "../typings";
@@ -17,6 +16,7 @@ import { Tools } from './Tools';
import * as configVars from './configVars';
import { DebugConfiguration } from "./debug/config";
import { debugPTFInstalled } from "./debug/server";
+import { ComponentManager } from "../components/manager";
export interface MemberParts extends IBMiMember {
basename: string
@@ -1341,7 +1341,7 @@ export default class IBMi {
}
}
- getComponent(id: ComponentId) {
+ getComponent(id: string) {
return this.components.get(id);
}
diff --git a/src/components/component.ts b/src/components/component.ts
index e40002c62..4f5518d17 100644
--- a/src/components/component.ts
+++ b/src/components/component.ts
@@ -1,7 +1,4 @@
import IBMi from "../api/IBMi";
-import { CopyToImport } from "./copyToImport";
-import { GetMemberInfo } from "./getMemberInfo";
-import { GetNewLibl } from "./getNewLibl";
export enum ComponentState {
NotChecked = `NotChecked`,
@@ -9,53 +6,14 @@ export enum ComponentState {
Installed = `Installed`,
Error = `Error`,
}
-interface ComponentRegistry {
- GetNewLibl?: GetNewLibl;
- CopyToImport?: CopyToImport;
- GetMemberInfo?: GetMemberInfo;
-}
-
-export type ComponentId = keyof ComponentRegistry;
-export abstract class ComponentT {
+export class ComponentT {
public state: ComponentState = ComponentState.NotChecked;
public currentVersion: number = 0;
constructor(public connection: IBMi) { }
- abstract getInstalledVersion(): Promise;
- abstract checkState(): Promise
- abstract getState(): ComponentState;
-}
-
-export class ComponentManager {
- private registered: ComponentRegistry = {};
-
- public async startup(connection: IBMi) {
- this.registered.GetNewLibl = new GetNewLibl(connection);
- await ComponentManager.checkState(this.registered.GetNewLibl);
-
- this.registered.CopyToImport = new CopyToImport(connection);
- await ComponentManager.checkState(this.registered.CopyToImport);
-
- this.registered.GetMemberInfo = new GetMemberInfo(connection);
- await ComponentManager.checkState(this.registered.GetMemberInfo);
- }
-
- // TODO: return type based on ComponentIds
- get(id: ComponentId): T | undefined {
- const component = this.registered[id];
- if (component && component.getState() === ComponentState.Installed) {
- return component as T;
- }
- }
-
- private static async checkState(component: ComponentT) {
- try {
- await component.checkState();
- } catch (e) {
- console.log(component);
- console.log(`Error checking state for ${component.constructor.name}`, e);
- }
- }
+ async getInstalledVersion(): Promise {return};
+ async checkState(): Promise {return false}
+ getState(): ComponentState {return this.state};
}
\ No newline at end of file
diff --git a/src/components/manager.ts b/src/components/manager.ts
new file mode 100644
index 000000000..bf66cea0b
--- /dev/null
+++ b/src/components/manager.ts
@@ -0,0 +1,49 @@
+import IBMi from "../api/IBMi";
+import { ComponentState, ComponentT } from "./component";
+import { CopyToImport } from "./copyToImport";
+import { GetMemberInfo } from "./getMemberInfo";
+import { GetNewLibl } from "./getNewLibl";
+
+export class ComponentRegistry {
+ private allComponents: (typeof ComponentT)[] = [GetNewLibl, CopyToImport, GetMemberInfo];
+
+ public registerComponent(component: typeof ComponentT) {
+ this.allComponents.push(component);
+ }
+
+ public getComponents() {
+ return this.allComponents;
+ }
+}
+
+export const ExtensionComponentRegistry = new ComponentRegistry();
+
+interface ComponentList {[name: string]: ComponentT};
+
+export class ComponentManager {
+ private registered: ComponentList = {};
+
+ public async startup(connection: IBMi) {
+ for (const Component of ExtensionComponentRegistry.getComponents()) {
+ const instance = new Component(connection);
+ this.registered[Component.name] = instance;
+ await ComponentManager.checkState(instance);
+ }
+ }
+
+ get(id: string): T | undefined {
+ const component = this.registered[id];
+ if (component && component.getState() === ComponentState.Installed) {
+ return component as T;
+ }
+ }
+
+ private static async checkState(component: ComponentT) {
+ try {
+ await component.checkState();
+ } catch (e) {
+ console.log(component);
+ console.log(`Error checking state for ${component.constructor.name}`, e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/extension.ts b/src/extension.ts
index a2b4c97bc..67f89f50f 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -31,6 +31,7 @@ import { initializeIFSBrowser } from "./views/ifsBrowser";
import { initializeObjectBrowser } from "./views/objectBrowser";
import { initializeSearchView } from "./views/searchView";
import { SettingsUI } from "./webviews/settings";
+import { ExtensionComponentRegistry } from "./components/manager";
export async function activate(context: ExtensionContext): Promise {
// Use the console to output diagnostic information (console.log) and errors (console.error)
@@ -125,7 +126,13 @@ export async function activate(context: ExtensionContext): Promise
commands.executeCommand("code-for-ibmi.refreshProfileView");
});
- return { instance, customUI: () => new CustomUI(), deployTools: DeployTools, evfeventParser: parseErrors, tools: Tools };
+ return {
+ instance, customUI: () => new CustomUI(),
+ deployTools: DeployTools,
+ evfeventParser: parseErrors,
+ tools: Tools,
+ componentRegistry: ExtensionComponentRegistry
+ };
}
async function fixLoginSettings() {
diff --git a/src/typings.ts b/src/typings.ts
index cceef76f0..381b4e6cb 100644
--- a/src/typings.ts
+++ b/src/typings.ts
@@ -5,13 +5,15 @@ import { CustomUI } from "./api/CustomUI";
import Instance from "./api/Instance";
import { Tools } from "./api/Tools";
import { DeployTools } from "./api/local/deployTools";
+import { ComponentRegistry } from './components/manager';
export interface CodeForIBMi {
instance: Instance,
customUI: () => CustomUI,
deployTools: typeof DeployTools,
evfeventParser: (lines: string[]) => Map,
- tools: typeof Tools
+ tools: typeof Tools,
+ componentRegistry: ComponentRegistry
}
export type DeploymentMethod = "all" | "staged" | "unstaged" | "changed" | "compare";
From 51e55df71ef1b2900d1b62156398c26f6d6787c3 Mon Sep 17 00:00:00 2001
From: Seb Julliand
Date: Wed, 18 Sep 2024 17:47:53 +0200
Subject: [PATCH 2/7] Code cleanup
Signed-off-by: Seb Julliand
---
src/components/manager.ts | 14 ++++++--------
src/extension.ts | 4 ++--
2 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/src/components/manager.ts b/src/components/manager.ts
index bf66cea0b..a34ccf12a 100644
--- a/src/components/manager.ts
+++ b/src/components/manager.ts
@@ -5,7 +5,7 @@ import { GetMemberInfo } from "./getMemberInfo";
import { GetNewLibl } from "./getNewLibl";
export class ComponentRegistry {
- private allComponents: (typeof ComponentT)[] = [GetNewLibl, CopyToImport, GetMemberInfo];
+ private readonly allComponents: (typeof ComponentT)[] = [GetNewLibl, CopyToImport, GetMemberInfo];
public registerComponent(component: typeof ComponentT) {
this.allComponents.push(component);
@@ -16,23 +16,21 @@ export class ComponentRegistry {
}
}
-export const ExtensionComponentRegistry = new ComponentRegistry();
-
-interface ComponentList {[name: string]: ComponentT};
+export const extensionComponentRegistry = new ComponentRegistry();
export class ComponentManager {
- private registered: ComponentList = {};
+ private readonly registered: Map = new Map;
public async startup(connection: IBMi) {
- for (const Component of ExtensionComponentRegistry.getComponents()) {
+ for (const Component of extensionComponentRegistry.getComponents()) {
const instance = new Component(connection);
- this.registered[Component.name] = instance;
+ this.registered.set(Component.name, instance);
await ComponentManager.checkState(instance);
}
}
get(id: string): T | undefined {
- const component = this.registered[id];
+ const component = this.registered.get(id);
if (component && component.getState() === ComponentState.Installed) {
return component as T;
}
diff --git a/src/extension.ts b/src/extension.ts
index 67f89f50f..0f0965f4d 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -16,6 +16,7 @@ import * as Debug from './api/debug';
import { parseErrors } from "./api/errors/parser";
import { DeployTools } from "./api/local/deployTools";
import { Deployment } from "./api/local/deployment";
+import { extensionComponentRegistry } from "./components/manager";
import { IFSFS } from "./filesystems/ifsFs";
import { LocalActionCompletionItemProvider } from "./languages/actions/completion";
import { updateLocale } from "./locale";
@@ -31,7 +32,6 @@ import { initializeIFSBrowser } from "./views/ifsBrowser";
import { initializeObjectBrowser } from "./views/objectBrowser";
import { initializeSearchView } from "./views/searchView";
import { SettingsUI } from "./webviews/settings";
-import { ExtensionComponentRegistry } from "./components/manager";
export async function activate(context: ExtensionContext): Promise {
// Use the console to output diagnostic information (console.log) and errors (console.error)
@@ -131,7 +131,7 @@ export async function activate(context: ExtensionContext): Promise
deployTools: DeployTools,
evfeventParser: parseErrors,
tools: Tools,
- componentRegistry: ExtensionComponentRegistry
+ componentRegistry: extensionComponentRegistry
};
}
From d440c7286f495265f385afb7609a88b42d2870d3 Mon Sep 17 00:00:00 2001
From: Seb Julliand
Date: Wed, 18 Sep 2024 23:41:37 +0200
Subject: [PATCH 3/7] Components management refactoring
Signed-off-by: Seb Julliand
---
src/api/IBMi.ts | 13 ++--
src/components/component.ts | 77 +++++++++++++++++---
src/components/copyToImport.ts | 35 ++++-----
src/components/getMemberInfo.ts | 122 ++++++++++++--------------------
src/components/getNewLibl.ts | 84 +++++++++-------------
src/components/manager.ts | 31 ++++----
src/instantiate.ts | 14 ++--
src/testing/components.ts | 4 +-
src/views/ProfilesView.ts | 2 +-
9 files changed, 192 insertions(+), 190 deletions(-)
diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts
index 4317e81c9..599bf0104 100644
--- a/src/api/IBMi.ts
+++ b/src/api/IBMi.ts
@@ -6,7 +6,9 @@ import { parse } from 'csv-parse/sync';
import { existsSync } from "fs";
import os from "os";
import path from 'path';
+import { IBMiComponent, IBMiComponentType } from "../components/component";
import { CopyToImport } from "../components/copyToImport";
+import { ComponentManager } from "../components/manager";
import { instance } from "../instantiate";
import { CommandData, CommandResult, ConnectionData, IBMiMember, RemoteCommand, SpecialAuthorities, WrapResult } from "../typings";
import { CompileTools } from "./CompileTools";
@@ -16,7 +18,6 @@ import { Tools } from './Tools';
import * as configVars from './configVars';
import { DebugConfiguration } from "./debug/config";
import { debugPTFInstalled } from "./debug/server";
-import { ComponentManager } from "../components/manager";
export interface MemberParts extends IBMiMember {
basename: string
@@ -55,7 +56,7 @@ export default class IBMi {
/** User default CCSID is job default CCSID */
private userDefaultCCSID: number = 0;
- private components: ComponentManager = new ComponentManager();
+ private componentManager = new ComponentManager(this);
client: node_ssh.NodeSSH;
currentHost: string = ``;
@@ -927,7 +928,7 @@ export default class IBMi {
}
progress.report({ message: `Checking Code for IBM i components.` });
- await this.components.startup(this);
+ await this.componentManager.startup();
if (!reconnecting) {
vscode.workspace.getConfiguration().update(`workbench.editor.enablePreview`, false, true);
@@ -1341,8 +1342,8 @@ export default class IBMi {
}
}
- getComponent(id: string) {
- return this.components.get(id);
+ getComponent(type: IBMiComponentType): T | undefined {
+ return this.componentManager.get(type);
}
/**
@@ -1372,7 +1373,7 @@ export default class IBMi {
if (lastStmt) {
if ((asUpper?.startsWith(`SELECT`) || asUpper?.startsWith(`WITH`))) {
- const copyToImport = this.getComponent(`CopyToImport`);
+ const copyToImport = this.getComponent(CopyToImport);
if (copyToImport) {
returningAsCsv = copyToImport.wrap(lastStmt);
list.push(...returningAsCsv.newStatements);
diff --git a/src/components/component.ts b/src/components/component.ts
index 4f5518d17..f7ca0b92d 100644
--- a/src/components/component.ts
+++ b/src/components/component.ts
@@ -1,19 +1,80 @@
import IBMi from "../api/IBMi";
-export enum ComponentState {
+export const enum ComponentState {
NotChecked = `NotChecked`,
NotInstalled = `NotInstalled`,
Installed = `Installed`,
+ NeedUpdate = `NeedUpdate`,
Error = `Error`,
}
+export type IBMiComponentType = new (c: IBMi) => T;
-export class ComponentT {
- public state: ComponentState = ComponentState.NotChecked;
- public currentVersion: number = 0;
+/**
+ * Defines a component that is managed per IBM i.
+ *
+ * Any class extending {@link IBMiComponent} needs to register itself in the Component Registry.
+ *
+ * For example, this class:
+ * ```
+ * class MyIBMIComponent extends IBMiComponent {
+ * //implements getName(), getRemoteState() and update()
+ * }
+ * ```
+ * Must be registered like this:
+ * ```
+ * const codeForIBMiExtension = vscode.extensions.getExtension('halcyontechltd.code-for-ibmi');
+ * if (codeForIBMiExtension) {
+ * codeForIBMi = codeForIBMiExtension.isActive ? codeForIBMiExtension.exports : await codeForIBMiExtension.activate();
+ * codeForIBMi.componentRegistry.registerComponent(MyIBMIComponent);
+ * }
+ * ```
+ *
+ */
+export abstract class IBMiComponent {
+ private state = ComponentState.NotChecked;
- constructor(public connection: IBMi) { }
+ constructor(protected readonly connection: IBMi) {
- async getInstalledVersion(): Promise {return};
- async checkState(): Promise {return false}
- getState(): ComponentState {return this.state};
+ }
+
+ getState() {
+ return this.state;
+ }
+
+ async check() {
+ try {
+ this.state = await this.getRemoteState();
+ if (this.state !== ComponentState.Installed) {
+ this.state = await this.update();
+ }
+ }
+ catch (error) {
+ console.log(`Error occurred while checking component ${this.getName()}`);
+ console.log(error);
+ this.state = ComponentState.Error;
+ }
+
+ return this;
+ }
+
+ /**
+ * The name of this component; mainly used for display and logging purposes
+ *
+ * @returns a human-readable name
+ */
+ abstract getName(): string;
+
+ /**
+ * @returns the component's {@link ComponentState state} on the IBM i
+ */
+ protected abstract getRemoteState(): ComponentState | Promise;
+
+ /**
+ * Called whenever the components needs to be installed or updated, depending on its {@link ComponentState state}.
+ *
+ * The Component Manager is responsible for calling this, so the {@link ComponentState state} doesn't need to be checked here.
+ *
+ * @returns the component's {@link ComponentState state} after the update is done
+ */
+ protected abstract update(): ComponentState | Promise
}
\ No newline at end of file
diff --git a/src/components/copyToImport.ts b/src/components/copyToImport.ts
index ca1b57d4a..24b2d0458 100644
--- a/src/components/copyToImport.ts
+++ b/src/components/copyToImport.ts
@@ -1,27 +1,8 @@
-import IBMi from "../api/IBMi";
import { Tools } from "../api/Tools";
import { WrapResult } from "../typings";
-import { ComponentState, ComponentT } from "./component";
-
-export class CopyToImport implements ComponentT {
- private readonly name = 'CPYTOIMPF';
- public state: ComponentState = ComponentState.Installed;
- public currentVersion: number = 1;
-
- constructor(public connection: IBMi) { }
-
- async getInstalledVersion(): Promise {
- return 1;
- }
-
- async checkState(): Promise {
- return true;
- }
-
- getState(): ComponentState {
- return this.state;
- }
+import { ComponentState, IBMiComponent } from "./component";
+export class CopyToImport extends IBMiComponent {
static isSimple(statement: string): boolean {
statement = statement.trim();
if (statement.endsWith(';')) {
@@ -32,6 +13,18 @@ export class CopyToImport implements ComponentT {
return parts.length === 4 && parts[0].toUpperCase() === `SELECT` && parts[1] === `*` && parts[2].toUpperCase() === `FROM` && parts[3].includes(`.`);
}
+ getName() {
+ return 'CPYTOIMPF';
+ }
+
+ protected getRemoteState() {
+ return ComponentState.Installed;
+ }
+
+ protected update(): ComponentState | Promise {
+ return this.getRemoteState();
+ }
+
wrap(statement: string): WrapResult {
const outStmf = this.connection.getTempRemote(Tools.makeid())!;
diff --git a/src/components/getMemberInfo.ts b/src/components/getMemberInfo.ts
index 7ec9834c7..c78aeb258 100644
--- a/src/components/getMemberInfo.ts
+++ b/src/components/getMemberInfo.ts
@@ -1,107 +1,79 @@
import { posix } from "path";
-import IBMi from "../api/IBMi";
import { Tools } from "../api/Tools";
-import { instance } from "../instantiate";
import { IBMiMember } from "../typings";
-import { ComponentState, ComponentT } from "./component";
+import { ComponentState, IBMiComponent } from "./component";
-export class GetMemberInfo implements ComponentT {
- public readonly name = 'GETMBRINFO';
- public state: ComponentState = ComponentState.NotInstalled;
- public currentVersion: number = 1;
+export class GetMemberInfo extends IBMiComponent {
+ private readonly currentVersion = 1;
- constructor(public connection: IBMi) { }
+ getName() {
+ return "GETMBRINFO";
+ }
- async getInstalledVersion(): Promise {
- const config = this.connection.config!
- const lib = config.tempLibrary!;
- const sql = `select LONG_COMMENT from qsys2.sysroutines where routine_schema = '${lib.toUpperCase()}' and routine_name = '${this.name}'`
- const [result] = await this.connection.runSQL(sql);
- if (result && result.LONG_COMMENT) {
+ protected async getRemoteState(): Promise {
+ let installedVersion = 0;
+ const [result] = await this.connection.runSQL(`select LONG_COMMENT from qsys2.sysroutines where routine_schema = '${this.connection.config?.tempLibrary.toUpperCase()}' and routine_name = 'GETMBRINFO'`);
+ if (result.LONG_COMMENT) {
const comment = result.LONG_COMMENT as string;
const dash = comment.indexOf('-');
if (dash > -1) {
- const version = comment.substring(0, dash).trim();
- return parseInt(version);
+ installedVersion = Number(comment.substring(0, dash).trim());
}
}
-
- return 0;
- }
-
- async checkState(): Promise {
- const installedVersion = await this.getInstalledVersion();
-
- if (installedVersion === this.currentVersion) {
- this.state = ComponentState.Installed;
- return true;
+ if (installedVersion < this.currentVersion) {
+ return ComponentState.NeedUpdate;
}
- const config = this.connection.config!
- const content = instance.getContent();
+ return ComponentState.Installed;
+ }
+ protected async update() {
+ const config = this.connection.config!;
return this.connection.withTempDirectory(async tempDir => {
const tempSourcePath = posix.join(tempDir, `getMemberInfo.sql`);
-
- await content!.writeStreamfileRaw(tempSourcePath, getSource(config.tempLibrary, this.name, this.currentVersion));
+ await this.connection.content.writeStreamfileRaw(tempSourcePath, getSource(config.tempLibrary, this.getName(), this.currentVersion));
const result = await this.connection.runCommand({
command: `RUNSQLSTM SRCSTMF('${tempSourcePath}') COMMIT(*NONE) NAMING(*SQL)`,
cwd: `/`,
noLibList: true
});
- if (result.code === 0) {
- this.state = ComponentState.Installed;
+ if (result.code) {
+ return ComponentState.Error;
} else {
- this.state = ComponentState.Error;
+ return ComponentState.Installed;
}
-
- return this.state === ComponentState.Installed;
});
}
- getState(): ComponentState {
- return this.state;
- }
-
-
- /**
- *
- * @param filter: the criterias used to list the members
- * @returns
- */
async getMemberInfo(library: string, sourceFile: string, member: string): Promise {
- if (this.state === ComponentState.Installed) {
- const config = this.connection.config!;
- const tempLib = config.tempLibrary;
- const statement = `select * from table(${tempLib}.GETMBRINFO('${library}', '${sourceFile}', '${member}'))`;
-
- let results: Tools.DB2Row[] = [];
- if (config.enableSQL) {
- try {
- results = await this.connection.runSQL(statement);
- } catch (e) { }; // Ignore errors, will return undefined.
- }
- else {
- results = await this.connection.content.getQTempTable([`create table QTEMP.MEMBERINFO as (${statement}) with data`], "MEMBERINFO");
- }
+ const config = this.connection.config!;
+ const tempLib = config.tempLibrary;
+ const statement = `select * from table(${tempLib}.${this.getName()}('${library}', '${sourceFile}', '${member}'))`;
+
+ let results: Tools.DB2Row[] = [];
+ if (config.enableSQL) {
+ try {
+ results = await this.connection.runSQL(statement);
+ } catch (e) { } // Ignore errors, will return undefined.
+ }
+ else {
+ results = await this.connection.content.getQTempTable([`create table QTEMP.MEMBERINFO as (${statement}) with data`], "MEMBERINFO");
+ }
- if (results.length === 1 && results[0].ISSOURCE === 'Y') {
- const result = results[0];
- const asp = this.connection.aspInfo[Number(results[0].ASP)];
- return {
- library: result.LIBRARY,
- file: result.FILE,
- name: result.MEMBER,
- extension: result.EXTENSION,
- text: result.DESCRIPTION,
- created: new Date(result.CREATED ? Number(result.CREATED) : 0),
- changed: new Date(result.CHANGED ? Number(result.CHANGED) : 0)
- } as IBMiMember
- }
- else {
- return undefined;
- }
+ if (results.length === 1 && results[0].ISSOURCE === 'Y') {
+ const result = results[0];
+ const asp = this.connection.aspInfo[Number(results[0].ASP)];
+ return {
+ asp,
+ library: result.LIBRARY,
+ file: result.FILE,
+ name: result.MEMBER,
+ extension: result.EXTENSION,
+ text: result.DESCRIPTION,
+ created: new Date(result.CREATED ? Number(result.CREATED) : 0),
+ changed: new Date(result.CHANGED ? Number(result.CHANGED) : 0)
+ } as IBMiMember
}
}
}
diff --git a/src/components/getNewLibl.ts b/src/components/getNewLibl.ts
index 914d1dc51..06d0928a9 100644
--- a/src/components/getNewLibl.ts
+++ b/src/components/getNewLibl.ts
@@ -1,26 +1,19 @@
import { posix } from "path";
-import IBMi from "../api/IBMi";
import { instance } from "../instantiate";
-import { ComponentState, ComponentT } from "./component";
+import { ComponentState, IBMiComponent } from "./component";
-export class GetNewLibl implements ComponentT {
- public state: ComponentState = ComponentState.NotInstalled;
- public currentVersion: number = 1;
+export class GetNewLibl extends IBMiComponent {
+ private readonly currentVersion = 1;
- constructor(public connection: IBMi) { }
-
- async getInstalledVersion(): Promise {
- return (this.connection.remoteFeatures[`GETNEWLIBL.PGM`] ? 1 : 0);
+ getName() {
+ return 'GETNEWLIBL';
}
- async checkState(): Promise {
- const installedVersion = await this.getInstalledVersion();
-
- if (installedVersion === this.currentVersion) {
- this.state = ComponentState.Installed;
- return true;
- }
+ protected async getRemoteState() {
+ return this.connection.remoteFeatures[`GETNEWLIBL.PGM`] ? ComponentState.Installed : ComponentState.NotInstalled;
+ }
+ protected update() {
const config = this.connection.config!
const content = instance.getContent();
return this.connection.withTempDirectory(async tempDir => {
@@ -33,48 +26,37 @@ export class GetNewLibl implements ComponentT {
noLibList: true
});
- if (result.code === 0) {
- this.state = ComponentState.Installed;
+ if (!result.code) {
+ return ComponentState.Installed;
} else {
- this.state = ComponentState.Error;
+ return ComponentState.Error;
}
-
- return this.state === ComponentState.Installed;
});
}
- getState(): ComponentState {
- return this.state;
- }
-
- async getLibraryListFromCommand(ileCommand: string): Promise<{ currentLibrary: string; libraryList: string[]; } | undefined> {
- if (this.state === ComponentState.Installed) {
- const tempLib = this.connection.config!.tempLibrary;
- const resultSet = await this.connection.runSQL(`CALL ${tempLib}.GETNEWLIBL('${ileCommand.replace(new RegExp(`'`, 'g'), `''`)}')`);
-
- const result = {
- currentLibrary: `QGPL`,
- libraryList: [] as string[]
- };
-
- resultSet.forEach(row => {
- const libraryName = String(row.SYSTEM_SCHEMA_NAME);
- switch (row.PORTION) {
- case `CURRENT`:
- result.currentLibrary = libraryName;
- break;
- case `USER`:
- result.libraryList.push(libraryName);
- break;
- }
- })
-
- return result;
- }
+ async getLibraryListFromCommand(ileCommand: string) {
+ const tempLib = this.connection.config!.tempLibrary;
+ const resultSet = await this.connection.runSQL(`CALL ${tempLib}.GETNEWLIBL('${ileCommand.replace(new RegExp(`'`, 'g'), `''`)}')`);
+
+ const result = {
+ currentLibrary: `QGPL`,
+ libraryList: [] as string[]
+ };
+
+ resultSet.forEach(row => {
+ const libraryName = String(row.SYSTEM_SCHEMA_NAME);
+ switch (row.PORTION) {
+ case `CURRENT`:
+ result.currentLibrary = libraryName;
+ break;
+ case `USER`:
+ result.libraryList.push(libraryName);
+ break;
+ }
+ })
- return undefined;
+ return result;
}
-
}
function getSource(library: string) {
diff --git a/src/components/manager.ts b/src/components/manager.ts
index a34ccf12a..40fc00e59 100644
--- a/src/components/manager.ts
+++ b/src/components/manager.ts
@@ -1,13 +1,13 @@
import IBMi from "../api/IBMi";
-import { ComponentState, ComponentT } from "./component";
+import { ComponentState, IBMiComponent, IBMiComponentType } from "./component";
import { CopyToImport } from "./copyToImport";
import { GetMemberInfo } from "./getMemberInfo";
import { GetNewLibl } from "./getNewLibl";
export class ComponentRegistry {
- private readonly allComponents: (typeof ComponentT)[] = [GetNewLibl, CopyToImport, GetMemberInfo];
+ private readonly allComponents: (IBMiComponentType)[] = [GetNewLibl, CopyToImport, GetMemberInfo];
- public registerComponent(component: typeof ComponentT) {
+ public registerComponent(component: IBMiComponentType) {
this.allComponents.push(component);
}
@@ -19,29 +19,22 @@ export class ComponentRegistry {
export const extensionComponentRegistry = new ComponentRegistry();
export class ComponentManager {
- private readonly registered: Map = new Map;
+ private readonly registered: Map, IBMiComponent> = new Map;
- public async startup(connection: IBMi) {
+ constructor(private readonly connection: IBMi) {
+
+ }
+
+ public async startup() {
for (const Component of extensionComponentRegistry.getComponents()) {
- const instance = new Component(connection);
- this.registered.set(Component.name, instance);
- await ComponentManager.checkState(instance);
+ this.registered.set(Component, await new Component(this.connection).check());
}
}
- get(id: string): T | undefined {
- const component = this.registered.get(id);
+ get(type: IBMiComponentType): T | undefined {
+ const component = this.registered.get(type);
if (component && component.getState() === ComponentState.Installed) {
return component as T;
}
}
-
- private static async checkState(component: ComponentT) {
- try {
- await component.checkState();
- } catch (e) {
- console.log(component);
- console.log(`Error checking state for ${component.constructor.name}`, e);
- }
- }
}
\ No newline at end of file
diff --git a/src/instantiate.ts b/src/instantiate.ts
index dd90c0c62..b74d1b1e4 100644
--- a/src/instantiate.ts
+++ b/src/instantiate.ts
@@ -466,25 +466,25 @@ export async function loadAllofExtension(context: vscode.ExtensionContext) {
const selectionSplit = connection!.upperCaseName(selection).split('/')
if (selectionSplit.length === 3 || selection.startsWith(`/`)) {
- const infoComponent = connection?.getComponent(`GetMemberInfo`);
+ const infoComponent = connection?.getComponent(GetMemberInfo);
// When selection is QSYS path
- if (!selection.startsWith(`/`) && infoComponent) {
- const lib = selectionSplit[0];
+ if (!selection.startsWith(`/`) && infoComponent && connection) {
+ const library = selectionSplit[0];
const file = selectionSplit[1];
const member = path.parse(selectionSplit[2]);
member.ext = member.ext.substring(1);
- const memberInfo = await infoComponent.getMemberInfo(lib, file, member.name);
+ const memberInfo = await infoComponent.getMemberInfo(library, file, member.name);
if (!memberInfo) {
- vscode.window.showWarningMessage(`Source member ${lib}/${file}/${member.base} does not exist.`);
+ vscode.window.showWarningMessage(`Source member ${library}/${file}/${member.base} does not exist.`);
return;
} else if (memberInfo.name !== member.name || (member.ext && memberInfo.extension !== member.ext)) {
- vscode.window.showWarningMessage(`Member ${lib}/${file}/${member.name} of type ${member.ext} does not exist.`);
+ vscode.window.showWarningMessage(`Member ${library}/${file}/${member.name} of type ${member.ext} does not exist.`);
return;
}
member.base = `${member.name}.${member.ext || memberInfo.extension}`;
- selection = `${lib}/${file}/${member.base}`;
+ selection = `${library}/${file}/${member.base}`;
};
// When select is IFS path
diff --git a/src/testing/components.ts b/src/testing/components.ts
index 491351a83..0893c70a8 100644
--- a/src/testing/components.ts
+++ b/src/testing/components.ts
@@ -16,7 +16,7 @@ export const ComponentSuite: TestSuite = {
{
name: `Get new libl`, test: async () => {
const connection = instance.getConnection()!
- const component = connection.getComponent(`GetNewLibl`);
+ const component = connection.getComponent(GetNewLibl);
if (component) {
const newLibl = await component.getLibraryListFromCommand(`CHGLIBL CURLIB(SYSTOOLS)`);
@@ -31,7 +31,7 @@ export const ComponentSuite: TestSuite = {
{
name: `Check getMemberInfo`, test: async () => {
const connection = instance.getConnection();
- const component = connection?.getComponent(`GetMemberInfo`)!;
+ const component = connection?.getComponent(GetMemberInfo)!;
assert.ok(component);
diff --git a/src/views/ProfilesView.ts b/src/views/ProfilesView.ts
index f9c6e00be..c77005c93 100644
--- a/src/views/ProfilesView.ts
+++ b/src/views/ProfilesView.ts
@@ -121,7 +121,7 @@ export class ProfilesView {
if (storedProfile) {
try {
- const component = connection?.getComponent(`GetNewLibl`)
+ const component = connection?.getComponent(GetNewLibl)
const newSettings = await component?.getLibraryListFromCommand(storedProfile.command);
if (newSettings) {
From 5e5e0af4a674c6f38d69954d74b34b39c01c5a28 Mon Sep 17 00:00:00 2001
From: Seb Julliand
Date: Thu, 19 Sep 2024 11:12:02 +0200
Subject: [PATCH 4/7] Require context to register a component + display
components list
Signed-off-by: Seb Julliand
---
src/api/IBMi.ts | 4 ++--
src/components/component.ts | 18 ++++++++++--------
src/components/manager.ts | 26 ++++++++++++++++----------
src/extension.ts | 19 +++++++++++++------
src/webviews/settings/index.ts | 23 +++++++++++++++++++++--
5 files changed, 62 insertions(+), 28 deletions(-)
diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts
index d1f713f55..29c923057 100644
--- a/src/api/IBMi.ts
+++ b/src/api/IBMi.ts
@@ -1354,8 +1354,8 @@ export default class IBMi {
}
}
- getComponent(type: IBMiComponentType): T | undefined {
- return this.componentManager.get(type);
+ getComponent(type: IBMiComponentType, ignoreState?:boolean): T | undefined {
+ return this.componentManager.get(type, ignoreState);
}
/**
diff --git a/src/components/component.ts b/src/components/component.ts
index f7ca0b92d..7ed33838b 100644
--- a/src/components/component.ts
+++ b/src/components/component.ts
@@ -1,10 +1,10 @@
import IBMi from "../api/IBMi";
export const enum ComponentState {
- NotChecked = `NotChecked`,
- NotInstalled = `NotInstalled`,
+ NotChecked = `Not checked`,
+ NotInstalled = `Not installed`,
Installed = `Installed`,
- NeedUpdate = `NeedUpdate`,
+ NeedUpdate = `Need update`,
Error = `Error`,
}
export type IBMiComponentType = new (c: IBMi) => T;
@@ -20,12 +20,14 @@ export type IBMiComponentType = new (c: IBMi) => T;
* //implements getName(), getRemoteState() and update()
* }
* ```
- * Must be registered like this:
+ * Must be registered like this, when the extension providing the component gets activated:
* ```
- * const codeForIBMiExtension = vscode.extensions.getExtension('halcyontechltd.code-for-ibmi');
- * if (codeForIBMiExtension) {
- * codeForIBMi = codeForIBMiExtension.isActive ? codeForIBMiExtension.exports : await codeForIBMiExtension.activate();
- * codeForIBMi.componentRegistry.registerComponent(MyIBMIComponent);
+ * export async function activate(context: ExtensionContext) {
+ * const codeForIBMiExtension = vscode.extensions.getExtension('halcyontechltd.code-for-ibmi');
+ * if (codeForIBMiExtension) {
+ * codeForIBMi = codeForIBMiExtension.isActive ? codeForIBMiExtension.exports : await codeForIBMiExtension.activate();
+ * codeForIBMi.componentRegistry.registerComponent(context, MyIBMIComponent);
+ * }
* }
* ```
*
diff --git a/src/components/manager.ts b/src/components/manager.ts
index 40fc00e59..ec0c19152 100644
--- a/src/components/manager.ts
+++ b/src/components/manager.ts
@@ -1,18 +1,23 @@
+import vscode from "vscode";
import IBMi from "../api/IBMi";
import { ComponentState, IBMiComponent, IBMiComponentType } from "./component";
-import { CopyToImport } from "./copyToImport";
-import { GetMemberInfo } from "./getMemberInfo";
-import { GetNewLibl } from "./getNewLibl";
export class ComponentRegistry {
- private readonly allComponents: (IBMiComponentType)[] = [GetNewLibl, CopyToImport, GetMemberInfo];
+ private readonly components: Map)[]> = new Map;
- public registerComponent(component: IBMiComponentType) {
- this.allComponents.push(component);
+ public registerComponent(context: vscode.ExtensionContext, component: IBMiComponentType) {
+ const key = context.extension.id;
+ const extensionComponents = this.components.get(key);
+ if (extensionComponents) {
+ extensionComponents.push(component);
+ }
+ else {
+ this.components.set(key, [component]);
+ }
}
public getComponents() {
- return this.allComponents;
+ return this.components;
}
}
@@ -26,14 +31,15 @@ export class ComponentManager {
}
public async startup() {
- for (const Component of extensionComponentRegistry.getComponents()) {
+ const components = Array.from(extensionComponentRegistry.getComponents().values()).flatMap(a => a.flat());
+ for (const Component of components) {
this.registered.set(Component, await new Component(this.connection).check());
}
}
- get(type: IBMiComponentType): T | undefined {
+ get(type: IBMiComponentType, ignoreState?: boolean): T | undefined {
const component = this.registered.get(type);
- if (component && component.getState() === ComponentState.Installed) {
+ if (component && (ignoreState || component.getState() === ComponentState.Installed)) {
return component as T;
}
}
diff --git a/src/extension.ts b/src/extension.ts
index 0f0965f4d..f4e04ab97 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -16,6 +16,9 @@ import * as Debug from './api/debug';
import { parseErrors } from "./api/errors/parser";
import { DeployTools } from "./api/local/deployTools";
import { Deployment } from "./api/local/deployment";
+import { CopyToImport } from "./components/copyToImport";
+import { GetMemberInfo } from "./components/getMemberInfo";
+import { GetNewLibl } from "./components/getNewLibl";
import { extensionComponentRegistry } from "./components/manager";
import { IFSFS } from "./filesystems/ifsFs";
import { LocalActionCompletionItemProvider } from "./languages/actions/completion";
@@ -126,12 +129,16 @@ export async function activate(context: ExtensionContext): Promise
commands.executeCommand("code-for-ibmi.refreshProfileView");
});
- return {
- instance, customUI: () => new CustomUI(),
- deployTools: DeployTools,
- evfeventParser: parseErrors,
- tools: Tools,
- componentRegistry: extensionComponentRegistry
+ extensionComponentRegistry.registerComponent(context, GetNewLibl);
+ extensionComponentRegistry.registerComponent(context, GetMemberInfo);
+ extensionComponentRegistry.registerComponent(context, CopyToImport);
+
+ return {
+ instance, customUI: () => new CustomUI(),
+ deployTools: DeployTools,
+ evfeventParser: parseErrors,
+ tools: Tools,
+ componentRegistry: extensionComponentRegistry
};
}
diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts
index 7694d390d..80b7e4130 100644
--- a/src/webviews/settings/index.ts
+++ b/src/webviews/settings/index.ts
@@ -6,6 +6,8 @@ import { Tools } from "../../api/Tools";
import { isManaged } from "../../api/debug";
import * as certificates from "../../api/debug/certificates";
import { isSEPSupported } from "../../api/debug/server";
+import { IBMiComponent } from "../../components/component";
+import { extensionComponentRegistry } from "../../components/manager";
import { instance } from "../../instantiate";
import { t } from "../../locale";
import { ConnectionData, Server } from '../../typings';
@@ -215,12 +217,29 @@ export class SettingsUI {
debuggerTab.addParagraph('Connect to the server to see these settings.');
}
- let tabs: ComplexTab[] = [
+ const componentsTab = new Section();
+ if (connection) {
+ componentsTab.addParagraph(`The following extensions contribute these components:`);
+ extensionComponentRegistry.getComponents().forEach((components, extensionId) => {
+ const extension = vscode.extensions.getExtension(extensionId);
+ componentsTab.addParagraph(`
+
${extension?.packageJSON.displayName || extension?.id || "Unnamed extension"}
+
+ ${components.map(type => connection.getComponent(type, true)).map(component => `${component?.getName()}
: ${component?.getState()} `).join(``)}
+
+
`);
+ })
+ } else {
+ componentsTab.addParagraph('Connect to the server to see these settings.');
+ }
+
+ const tabs: ComplexTab[] = [
{ label: `Features`, fields: featuresTab.fields },
{ label: `Source Code`, fields: sourceTab.fields },
{ label: `Terminals`, fields: terminalsTab.fields },
{ label: `Debugger`, fields: debuggerTab.fields },
{ label: `Temporary Data`, fields: tempDataTab.fields },
+ { label: `Components`, fields: componentsTab.fields },
];
const ui = new CustomUI();
@@ -380,7 +399,7 @@ export class SettingsUI {
await ConnectionManager.deleteStoredPassword(context, name);
vscode.window.showInformationMessage(t(`login.privateKey.updated`, name));
}
- else{
+ else {
delete data.privateKeyPath;
}
break;
From 56427caef3c89ea28899c6da5b51b783dcd9a5b7 Mon Sep 17 00:00:00 2001
From: Seb Julliand
Date: Thu, 19 Sep 2024 15:29:27 +0200
Subject: [PATCH 5/7] Show version of each component
Signed-off-by: Seb Julliand
---
src/components/component.ts | 15 ++++++-
src/components/copyToImport.ts | 4 +-
src/components/getMemberInfo.ts | 80 ++++++++++++++++-----------------
src/components/getNewLibl.ts | 6 +--
src/webviews/settings/index.ts | 2 +-
5 files changed, 56 insertions(+), 51 deletions(-)
diff --git a/src/components/component.ts b/src/components/component.ts
index 7ed33838b..0612c6f11 100644
--- a/src/components/component.ts
+++ b/src/components/component.ts
@@ -7,6 +7,12 @@ export const enum ComponentState {
NeedUpdate = `Need update`,
Error = `Error`,
}
+
+export type ComponentIdentification = {
+ name: string
+ version: number
+}
+
export type IBMiComponentType = new (c: IBMi) => T;
/**
@@ -51,7 +57,7 @@ export abstract class IBMiComponent {
}
}
catch (error) {
- console.log(`Error occurred while checking component ${this.getName()}`);
+ console.log(`Error occurred while checking component ${this.toString()}`);
console.log(error);
this.state = ComponentState.Error;
}
@@ -59,12 +65,17 @@ export abstract class IBMiComponent {
return this;
}
+ toString() {
+ const identification = this.getIdentification();
+ return `${identification.name} (version ${identification.version})`
+ }
+
/**
* The name of this component; mainly used for display and logging purposes
*
* @returns a human-readable name
*/
- abstract getName(): string;
+ abstract getIdentification(): ComponentIdentification;
/**
* @returns the component's {@link ComponentState state} on the IBM i
diff --git a/src/components/copyToImport.ts b/src/components/copyToImport.ts
index 24b2d0458..7232acc18 100644
--- a/src/components/copyToImport.ts
+++ b/src/components/copyToImport.ts
@@ -13,8 +13,8 @@ export class CopyToImport extends IBMiComponent {
return parts.length === 4 && parts[0].toUpperCase() === `SELECT` && parts[1] === `*` && parts[2].toUpperCase() === `FROM` && parts[3].includes(`.`);
}
- getName() {
- return 'CPYTOIMPF';
+ getIdentification() {
+ return { name: 'CopyToImport', version: 1 };
}
protected getRemoteState() {
diff --git a/src/components/getMemberInfo.ts b/src/components/getMemberInfo.ts
index 1d1b7126c..2f86720e2 100644
--- a/src/components/getMemberInfo.ts
+++ b/src/components/getMemberInfo.ts
@@ -4,23 +4,24 @@ import { IBMiMember } from "../typings";
import { ComponentState, IBMiComponent } from "./component";
export class GetMemberInfo extends IBMiComponent {
+ private readonly procedureName = 'GETMBRINFO';
private readonly currentVersion = 1;
+ private installedVersion = 0;
- getName() {
- return "GETMBRINFO";
+ getIdentification() {
+ return { name: 'GetMemberInfo', version: this.installedVersion };
}
protected async getRemoteState(): Promise {
- let installedVersion = 0;
- const [result] = await this.connection.runSQL(`select LONG_COMMENT from qsys2.sysroutines where routine_schema = '${this.connection.config?.tempLibrary.toUpperCase()}' and routine_name = 'GETMBRINFO'`);
+ const [result] = await this.connection.runSQL(`select LONG_COMMENT from qsys2.sysroutines where routine_schema = '${this.connection.config?.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) {
- installedVersion = Number(comment.substring(0, dash).trim());
+ this.installedVersion = Number(comment.substring(0, dash).trim());
}
}
- if (installedVersion < this.currentVersion) {
+ if (this.installedVersion < this.currentVersion) {
return ComponentState.NeedUpdate;
}
@@ -31,7 +32,7 @@ export class GetMemberInfo extends IBMiComponent {
const config = this.connection.config!;
return this.connection.withTempDirectory(async tempDir => {
const tempSourcePath = posix.join(tempDir, `getMemberInfo.sql`);
- await this.connection.content.writeStreamfileRaw(tempSourcePath, getSource(config.tempLibrary, this.getName(), this.currentVersion));
+ await this.connection.content.writeStreamfileRaw(tempSourcePath, getSource(config.tempLibrary, this.procedureName, this.currentVersion));
const result = await this.connection.runCommand({
command: `RUNSQLSTM SRCSTMF('${tempSourcePath}') COMMIT(*NONE) NAMING(*SQL)`,
cwd: `/`,
@@ -49,7 +50,7 @@ export class GetMemberInfo extends IBMiComponent {
async getMemberInfo(library: string, sourceFile: string, member: string): Promise {
const config = this.connection.config!;
const tempLib = config.tempLibrary;
- const statement = `select * from table(${tempLib}.${this.getName()}('${library}', '${sourceFile}', '${member}'))`;
+ const statement = `select * from table(${tempLib}.${this.procedureName}('${library}', '${sourceFile}', '${member}'))`;
let results: Tools.DB2Row[] = [];
if (config.enableSQL) {
@@ -77,41 +78,36 @@ export class GetMemberInfo extends IBMiComponent {
}
}
- async getMultipleMemberInfo(members: IBMiMember[]): Promise {
- if (this.state === ComponentState.Installed) {
- const config = this.connection.config!;
- const tempLib = config.tempLibrary;
- const statement = members
- .map(member => `select * from table(${this.connection.config!.tempLibrary}.GETMBRINFO('${member.library}', '${member.file}', '${member.name}'))`)
- .join(' union all ');
-
- let results: Tools.DB2Row[] = [];
- if (config.enableSQL) {
- try {
- results = await this.connection.runSQL(statement);
- } catch (e) { }; // Ignore errors, will return undefined.
- }
- else {
- results = await this.connection.content.getQTempTable([`create table QTEMP.MEMBERINFO as (${statement}) with data`], "MEMBERINFO");
- }
-
- return results.filter(row => row.ISSOURCE === 'Y').map(result => {
- const asp = this.connection.aspInfo[Number(result.ASP)];
- return {
- asp,
- library: result.LIBRARY,
- file: result.FILE,
- name: result.MEMBER,
- extension: result.EXTENSION,
- text: result.DESCRIPTION,
- created: new Date(result.CREATED ? Number(result.CREATED) : 0),
- changed: new Date(result.CHANGED ? Number(result.CHANGED) : 0)
- } as IBMiMember
- });
+ async getMultipleMemberInfo(members: IBMiMember[]): Promise {
+ const config = this.connection.config!;
+ const tempLib = config.tempLibrary;
+ const statement = members
+ .map(member => `select * from table(${tempLib}.${this.procedureName}('${member.library}', '${member.file}', '${member.name}'))`)
+ .join(' union all ');
- } else {
- return undefined;
+ let results: Tools.DB2Row[] = [];
+ if (config.enableSQL) {
+ try {
+ results = await this.connection.runSQL(statement);
+ } catch (e) { }; // Ignore errors, will return undefined.
+ }
+ else {
+ results = await this.connection.content.getQTempTable([`create table QTEMP.MEMBERINFO as (${statement}) with data`], "MEMBERINFO");
}
+
+ return results.filter(row => row.ISSOURCE === 'Y').map(result => {
+ const asp = this.connection.aspInfo[Number(result.ASP)];
+ return {
+ asp,
+ library: result.LIBRARY,
+ file: result.FILE,
+ name: result.MEMBER,
+ extension: result.EXTENSION,
+ text: result.DESCRIPTION,
+ created: new Date(result.CREATED ? Number(result.CREATED) : 0),
+ changed: new Date(result.CHANGED ? Number(result.CHANGED) : 0)
+ } as IBMiMember
+ });
}
}
@@ -142,7 +138,7 @@ function getSource(library: string, name: string, version: number) {
`, Description varchar( 50 )`,
`, isSource char( 1 )`,
`)`,
- `specific GETMBRINFO`,
+ `specific ${name}`,
`modifies sql data`,
`begin`,
` declare buffer char( 135 ) for bit data not null default '';`,
diff --git a/src/components/getNewLibl.ts b/src/components/getNewLibl.ts
index 06d0928a9..64014eef7 100644
--- a/src/components/getNewLibl.ts
+++ b/src/components/getNewLibl.ts
@@ -3,10 +3,8 @@ import { instance } from "../instantiate";
import { ComponentState, IBMiComponent } from "./component";
export class GetNewLibl extends IBMiComponent {
- private readonly currentVersion = 1;
-
- getName() {
- return 'GETNEWLIBL';
+ getIdentification() {
+ return { name: 'GetNewLibl', version: 1 };
}
protected async getRemoteState() {
diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts
index 80b7e4130..e3d660b5c 100644
--- a/src/webviews/settings/index.ts
+++ b/src/webviews/settings/index.ts
@@ -225,7 +225,7 @@ export class SettingsUI {
componentsTab.addParagraph(`
${extension?.packageJSON.displayName || extension?.id || "Unnamed extension"}
- ${components.map(type => connection.getComponent(type, true)).map(component => `${component?.getName()}
: ${component?.getState()} `).join(``)}
+ ${components.map(type => connection.getComponent(type, true)).map(component => `${component?.toString()}
: ${component?.getState()} `).join(``)}
`);
})
From 226d0ce05f6201b88c7cd64f74d4b0cb2cf9c868 Mon Sep 17 00:00:00 2001
From: Seb Julliand
Date: Thu, 3 Oct 2024 18:06:34 +0200
Subject: [PATCH 6/7] Fixed wrong import
Signed-off-by: Seb Julliand
---
src/api/IBMi.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts
index 838bce179..06ec6b5d8 100644
--- a/src/api/IBMi.ts
+++ b/src/api/IBMi.ts
@@ -4,7 +4,7 @@ import * as node_ssh from "node-ssh";
import os from "os";
import path, { parse as parsePath } from 'path';
import * as vscode from "vscode";
-import { IBMiComponent, IBMiComponentType } from "../components/componen
+import { IBMiComponent, IBMiComponentType } from "../components/component";
import { CopyToImport } from "../components/copyToImport";
import { ComponentManager } from "../components/manager";
import { instance } from "../instantiate";
@@ -1353,7 +1353,7 @@ export default class IBMi {
}
}
- getComponent(type: IBMiComponentType, ignoreState?:boolean): T | undefined {
+ getComponent(type: IBMiComponentType, ignoreState?: boolean): T | undefined {
return this.componentManager.get(type, ignoreState);
}
From f79e370e08962acc2a8032ca719257dbbced4144 Mon Sep 17 00:00:00 2001
From: worksofliam
Date: Fri, 4 Oct 2024 13:35:44 -0400
Subject: [PATCH 7/7] Use type for component state instead of enum
Signed-off-by: worksofliam
---
src/components/component.ts | 14 ++++----------
src/components/copyToImport.ts | 4 ++--
src/components/getMemberInfo.ts | 10 +++++-----
src/components/getNewLibl.ts | 12 ++++++------
src/components/manager.ts | 2 +-
5 files changed, 18 insertions(+), 24 deletions(-)
diff --git a/src/components/component.ts b/src/components/component.ts
index 0612c6f11..74e2d1e47 100644
--- a/src/components/component.ts
+++ b/src/components/component.ts
@@ -1,12 +1,6 @@
import IBMi from "../api/IBMi";
-export const enum ComponentState {
- NotChecked = `Not checked`,
- NotInstalled = `Not installed`,
- Installed = `Installed`,
- NeedUpdate = `Need update`,
- Error = `Error`,
-}
+export type ComponentState = `NotChecked` | `NotInstalled` | `Installed` | `NeedsUpdate` | `Error`;
export type ComponentIdentification = {
name: string
@@ -39,7 +33,7 @@ export type IBMiComponentType = new (c: IBMi) => T;
*
*/
export abstract class IBMiComponent {
- private state = ComponentState.NotChecked;
+ private state: ComponentState = `NotChecked`;
constructor(protected readonly connection: IBMi) {
@@ -52,14 +46,14 @@ export abstract class IBMiComponent {
async check() {
try {
this.state = await this.getRemoteState();
- if (this.state !== ComponentState.Installed) {
+ if (this.state !== `Installed`) {
this.state = await this.update();
}
}
catch (error) {
console.log(`Error occurred while checking component ${this.toString()}`);
console.log(error);
- this.state = ComponentState.Error;
+ this.state = `Error`;
}
return this;
diff --git a/src/components/copyToImport.ts b/src/components/copyToImport.ts
index 7232acc18..854b73062 100644
--- a/src/components/copyToImport.ts
+++ b/src/components/copyToImport.ts
@@ -17,8 +17,8 @@ export class CopyToImport extends IBMiComponent {
return { name: 'CopyToImport', version: 1 };
}
- protected getRemoteState() {
- return ComponentState.Installed;
+ protected getRemoteState(): ComponentState {
+ return `Installed`;
}
protected update(): ComponentState | Promise {
diff --git a/src/components/getMemberInfo.ts b/src/components/getMemberInfo.ts
index 2f86720e2..0caa3bcb0 100644
--- a/src/components/getMemberInfo.ts
+++ b/src/components/getMemberInfo.ts
@@ -22,13 +22,13 @@ export class GetMemberInfo extends IBMiComponent {
}
}
if (this.installedVersion < this.currentVersion) {
- return ComponentState.NeedUpdate;
+ return `NeedsUpdate`;
}
- return ComponentState.Installed;
+ return `Installed`;
}
- protected async update() {
+ protected async update(): Promise {
const config = this.connection.config!;
return this.connection.withTempDirectory(async tempDir => {
const tempSourcePath = posix.join(tempDir, `getMemberInfo.sql`);
@@ -40,9 +40,9 @@ export class GetMemberInfo extends IBMiComponent {
});
if (result.code) {
- return ComponentState.Error;
+ return `Error`;
} else {
- return ComponentState.Installed;
+ return `Installed`;
}
});
}
diff --git a/src/components/getNewLibl.ts b/src/components/getNewLibl.ts
index 64014eef7..7d0b98860 100644
--- a/src/components/getNewLibl.ts
+++ b/src/components/getNewLibl.ts
@@ -7,14 +7,14 @@ export class GetNewLibl extends IBMiComponent {
return { name: 'GetNewLibl', version: 1 };
}
- protected async getRemoteState() {
- return this.connection.remoteFeatures[`GETNEWLIBL.PGM`] ? ComponentState.Installed : ComponentState.NotInstalled;
+ protected async getRemoteState(): Promise {
+ return this.connection.remoteFeatures[`GETNEWLIBL.PGM`] ? `Installed` : `NotInstalled`;
}
- protected update() {
+ protected update(): Promise {
const config = this.connection.config!
const content = instance.getContent();
- return this.connection.withTempDirectory(async tempDir => {
+ return this.connection.withTempDirectory(async (tempDir): Promise => {
const tempSourcePath = posix.join(tempDir, `getnewlibl.sql`);
await content!.writeStreamfileRaw(tempSourcePath, getSource(config.tempLibrary));
@@ -25,9 +25,9 @@ export class GetNewLibl extends IBMiComponent {
});
if (!result.code) {
- return ComponentState.Installed;
+ return `Installed`;
} else {
- return ComponentState.Error;
+ return `Error`;
}
});
}
diff --git a/src/components/manager.ts b/src/components/manager.ts
index ec0c19152..60b8d9e0e 100644
--- a/src/components/manager.ts
+++ b/src/components/manager.ts
@@ -39,7 +39,7 @@ export class ComponentManager {
get(type: IBMiComponentType, ignoreState?: boolean): T | undefined {
const component = this.registered.get(type);
- if (component && (ignoreState || component.getState() === ComponentState.Installed)) {
+ if (component && (ignoreState || component.getState() === `Installed`)) {
return component as T;
}
}