From e2dd0536e0f7737ae464d838bd9dcbd671ce90a6 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Sat, 9 Nov 2024 17:28:16 -0500 Subject: [PATCH 01/16] Fetch additional ASP information and lookup current iASP by RDB name Signed-off-by: worksofliam --- package.json | 8 ------- src/api/IBMi.ts | 58 +++++++++++++++++++++++++++++++++++++++++++------ src/typings.ts | 7 ++++++ 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 937891e90..15efd8922 100644 --- a/package.json +++ b/package.json @@ -209,14 +209,6 @@ "default": "QTEMP", "description": "Library used as the current library and &CURLIB variable when running actions." }, - "sourceASP": { - "type": [ - "string", - "null" - ], - "default": null, - "description": "If source files live within a specific ASP, please specify it here. Leave blank/null otherwise. You can ignore this column if you have access to `QSYS2.ASP_INFO` as Code for IBM i will fetch ASP information automatically." - }, "sourceFileCCSID": { "type": "string", "default": "*FILE", diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index f8d1d0fab..0b37455b9 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -8,7 +8,7 @@ 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 { AspInfo, CommandData, CommandResult, ConnectionData, IBMiMember, RemoteCommand, SpecialAuthorities, WrapResult } from "../typings"; import { CompileTools } from "./CompileTools"; import { ConnectionConfiguration } from "./Configuration"; import IBMiContent from "./IBMiContent"; @@ -71,7 +71,8 @@ export default class IBMi { * Their names usually maps up to a directory in * the root of the IFS, thus why we store it. */ - aspInfo: { [id: number]: string } = {}; + private iAspInfo: AspInfo[] = []; + private currentAsp: string|undefined; remoteFeatures: { [name: string]: string | undefined }; variantChars: { american: string, local: string }; @@ -622,11 +623,11 @@ export default class IBMi { }; // Check for ASP information? - if (quickConnect === true && cachedServerSettings?.aspInfo) { - this.aspInfo = cachedServerSettings.aspInfo; + if (quickConnect === true && cachedServerSettings?.iAspInfo) { + this.iAspInfo = cachedServerSettings.iAspInfo; } else { progress.report({ - message: `Checking for ASP information.` + message: `Checking for iASP information.` }); //This is mostly a nice to have. We grab the ASP info so user's do @@ -634,8 +635,14 @@ export default class IBMi { try { const resultSet = await runSQL(`SELECT * FROM QSYS2.ASP_INFO`); resultSet.forEach(row => { + // Does not ever include SYSBAS/SYSTEM, only iASPs if (row.DEVICE_DESCRIPTION_NAME && row.DEVICE_DESCRIPTION_NAME && row.DEVICE_DESCRIPTION_NAME !== `null`) { - this.aspInfo[Number(row.ASP_NUMBER)] = String(row.DEVICE_DESCRIPTION_NAME); + this.iAspInfo[Number(row.ASP_NUMBER)] = { + id: Number(row.ASP_NUMBER), + name: String(row.DEVICE_DESCRIPTION_NAME), + type: String(row.ASP_TYPE), + rdbName: String(row.RDB_NAME) + }; } }); } catch (e) { @@ -646,6 +653,22 @@ export default class IBMi { } } + progress.report({ + message: `Fetching current iASP information.` + }); + + const [currentRdb] = await runSQL(`values current_server`); + + if (currentRdb) { + const key = Object.keys(currentRdb)[0]; + const rdbName = currentRdb[key]; + const currentAsp = this.iAspInfo.find(asp => asp.rdbName === rdbName); + + if (currentAsp) { + this.currentAsp = currentAsp.name; + } + } + // Fetch conversion values? if (quickConnect === true && cachedServerSettings?.jobCcsid !== null && cachedServerSettings?.variantChars && cachedServerSettings?.userDefaultCCSID && cachedServerSettings?.qccsid) { this.qccsid = cachedServerSettings.qccsid; @@ -958,7 +981,7 @@ export default class IBMi { instance.fire(`connected`); GlobalStorage.get().setServerSettingsCache(this.currentConnectionName, { - aspInfo: this.aspInfo, + iAspInfo: this.iAspInfo, qccsid: this.qccsid, jobCcsid: this.jobCcsid, remoteFeatures: this.remoteFeatures, @@ -1177,6 +1200,27 @@ export default class IBMi { return this.remoteFeatures[`QZDFMDB2.PGM`] !== undefined; } + getAllIAsps() { + return this.iAspInfo; + } + + getIAspName(by: string|number): string|undefined { + let asp: AspInfo|undefined; + if (typeof by === 'string') { + asp = this.iAspInfo.find(asp => asp.name === by); + } else { + asp = this.iAspInfo.find(asp => asp.id === by); + } + + if (asp) { + return asp.name; + } + } + + getCurrentIAspName() { + return this.currentAsp; + } + /** * Generates path to a temp file on the IBM i * @param {string} key Key to the temp file to be re-used diff --git a/src/typings.ts b/src/typings.ts index 381b4e6cb..1d3cf05f7 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -16,6 +16,13 @@ export interface CodeForIBMi { componentRegistry: ComponentRegistry } +export interface AspInfo { + id: number; + name: string; + type: string; + rdbName: string; +} + export type DeploymentMethod = "all" | "staged" | "unstaged" | "changed" | "compare"; export interface DeploymentParameters { From b122920087774ed1ac70dde86b15ef187073ab13 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Sat, 9 Nov 2024 17:28:35 -0500 Subject: [PATCH 02/16] Refactor ASP handling to use current iASP name instead of deprecated sourceASP property Signed-off-by: worksofliam --- src/api/Configuration.ts | 2 -- src/api/IBMiContent.ts | 18 +++++++++++------- src/api/Search.ts | 12 +++++++----- src/api/Storage.ts | 4 ++-- src/api/errors/diagnostics.ts | 2 +- src/components/getMemberInfo.ts | 4 ++-- src/filesystems/qsys/QSysFs.ts | 4 ++-- src/instantiate.ts | 4 +++- src/views/objectBrowser.ts | 6 ++++-- src/webviews/settings/index.ts | 4 ++-- 10 files changed, 34 insertions(+), 26 deletions(-) diff --git a/src/api/Configuration.ts b/src/api/Configuration.ts index 4a551f247..219369b91 100644 --- a/src/api/Configuration.ts +++ b/src/api/Configuration.ts @@ -112,7 +112,6 @@ export namespace ConnectionConfiguration { autoSortIFSShortcuts: boolean; tempLibrary: string; tempDir: string; - sourceASP: string; sourceFileCCSID: string; autoConvertIFSccsid: boolean; hideCompileErrors: string[]; @@ -192,7 +191,6 @@ export namespace ConnectionConfiguration { tempLibrary: parameters.tempLibrary || `ILEDITOR`, tempDir: parameters.tempDir || `/tmp`, currentLibrary: parameters.currentLibrary || ``, - sourceASP: parameters.sourceASP || ``, sourceFileCCSID: parameters.sourceFileCCSID || `*FILE`, autoConvertIFSccsid: (parameters.autoConvertIFSccsid === true), hideCompileErrors: parameters.hideCompileErrors || [], diff --git a/src/api/IBMiContent.ts b/src/api/IBMiContent.ts index 65c5956c6..2cf8fe222 100644 --- a/src/api/IBMiContent.ts +++ b/src/api/IBMiContent.ts @@ -142,7 +142,7 @@ export default class IBMiContent { * Download the contents of a source member */ async downloadMemberContent(asp: string | undefined, library: string, sourceFile: string, member: string, localPath?: string) { - asp = asp || this.config.sourceASP; + asp = asp || this.ibmi.getCurrentIAspName(); library = this.ibmi.upperCaseName(library); sourceFile = this.ibmi.upperCaseName(sourceFile); member = this.ibmi.upperCaseName(member); @@ -210,7 +210,7 @@ export default class IBMiContent { * Upload to a member */ async uploadMemberContent(asp: string | undefined, library: string, sourceFile: string, member: string, content: string | Uint8Array) { - asp = asp || this.config.sourceASP; + asp = asp || this.ibmi.getCurrentIAspName(); library = this.ibmi.upperCaseName(library); sourceFile = this.ibmi.upperCaseName(sourceFile); member = this.ibmi.upperCaseName(member); @@ -377,6 +377,8 @@ export default class IBMiContent { `; const results = await this.ibmi.runSQL(statement); + const asp = this.ibmi.getIAspName(Number(results[0].IASP_NUMBER)); + objects = results.map(object => ({ library: 'QSYS', name: this.ibmi.sysNameInLocal(String(object.NAME)), @@ -390,7 +392,7 @@ export default class IBMiContent { changed: new Date(Number(object.CHANGED)), created_by: object.CREATED_BY, owner: object.OWNER, - asp: this.ibmi.aspInfo[Number(object.IASP_NUMBER)] + asp } as IBMiObject)); } else { let results = await this.getQTempTable(libraries.map(library => `@DSPOBJD OBJ(QSYS/${library}) OBJTYPE(*LIB) DETAIL(*TEXTATR) OUTPUT(*OUTFILE) OUTFILE(QTEMP/LIBLIST) OUTMBR(*FIRST *ADD)`), "LIBLIST"); @@ -578,6 +580,8 @@ export default class IBMiContent { const objects = (await this.runStatements(createOBJLIST.join(`\n`))); + const asp = this.ibmi.getIAspName(Number(objects[0].IASP_NUMBER)); + return objects.map(object => ({ library, name: sourceFilesOnly ? this.ibmi.sysNameInLocal(String(object.NAME)) : String(object.NAME), @@ -591,7 +595,7 @@ export default class IBMiContent { changed: new Date(Number(object.CHANGED)), created_by: object.CREATED_BY, owner: object.OWNER, - asp: this.ibmi.aspInfo[Number(object.IASP_NUMBER)] + asp } as IBMiObject)) .filter(object => !typeFilter || typeFilter(object.type)) .filter(object => objectFilter || nameFilter.test(object.name)) @@ -650,7 +654,7 @@ export default class IBMiContent { const results = await this.ibmi.runSQL(statement); if (results.length) { - const asp = this.ibmi.aspInfo[Number(results[0].ASP)]; + const asp = this.ibmi.getIAspName(Number(results[0].ASP)); return results.map(result => ({ asp, library, @@ -693,7 +697,7 @@ export default class IBMiContent { if (results.length === 1 && results[0].ISSOURCE === 'Y') { const result = results[0]; - const asp = this.ibmi.aspInfo[Number(results[0].ASP)]; + const asp = this.ibmi.getIAspName(Number(results[0].ASP)); return { library: result.LIBRARY, file: result.FILE, @@ -799,7 +803,7 @@ export default class IBMiContent { // Escape names for shell const pathList = files .map(file => { - const asp = file.asp || this.config.sourceASP; + const asp = file.asp || this.ibmi.getCurrentIAspName(); if (asp && asp.length > 0) { return [ Tools.qualifyPath(inAmerican(file.library), inAmerican(file.name), inAmerican(member), asp, true), diff --git a/src/api/Search.ts b/src/api/Search.ts index ce2254c5c..764473153 100644 --- a/src/api/Search.ts +++ b/src/api/Search.ts @@ -29,14 +29,16 @@ export namespace Search { // First, let's fetch the ASP info let asp = ``; - if (config.sourceASP) { - asp = `/${config.sourceASP}`; + const definedAsp = connection.getCurrentIAspName(); + if (definedAsp) { + asp = `/${definedAsp}`; } else if (connection.enableSQL) { try { const [row] = await content.runSQL(`SELECT IASP_NUMBER FROM TABLE(QSYS2.LIBRARY_INFO('${library}'))`); - const iaspNumber = row?.IASP_NUMBER; - if (iaspNumber && typeof iaspNumber === 'number' && connection.aspInfo[iaspNumber]) { - asp = `/${connection.aspInfo[iaspNumber]}`; + const iaspNumber = Number(row?.IASP_NUMBER); + const aspName = connection.getIAspName(iaspNumber); + if (aspName) { + asp = `/${aspName}`; } } catch (e) { } } diff --git a/src/api/Storage.ts b/src/api/Storage.ts index e994653a6..8d1ecc707 100644 --- a/src/api/Storage.ts +++ b/src/api/Storage.ts @@ -1,5 +1,5 @@ import vscode from 'vscode'; -import { ConnectionData } from '../typings'; +import { AspInfo, ConnectionData } from '../typings'; const PREVIOUS_CUR_LIBS_KEY = `prevCurLibs`; const LAST_PROFILE_KEY = `currentProfile`; @@ -52,7 +52,7 @@ export type LastConnection = { }; export type CachedServerSettings = { - aspInfo: { [id: number]: string } + iAspInfo: AspInfo[]; qccsid: number | null; jobCcsid: number | null remoteFeatures: { [name: string]: string | undefined } diff --git a/src/api/errors/diagnostics.ts b/src/api/errors/diagnostics.ts index b029a18a1..dcc66eceb 100644 --- a/src/api/errors/diagnostics.ts +++ b/src/api/errors/diagnostics.ts @@ -151,7 +151,7 @@ export function handleEvfeventLines(lines: string[], instance: Instance, evfeven if (relativeCompilePath) { if (connection) { // Belive it or not, sometimes if the deploy directory is symlinked into as ASP, this can be a problem - const aspNames = Object.values(connection.aspInfo); + const aspNames = connection.getAllIAsps().map(asp => asp.name); for (const aspName of aspNames) { const aspRoot = `/${aspName}`; if (relativeCompilePath.startsWith(aspRoot)) { diff --git a/src/components/getMemberInfo.ts b/src/components/getMemberInfo.ts index 0caa3bcb0..13f52489f 100644 --- a/src/components/getMemberInfo.ts +++ b/src/components/getMemberInfo.ts @@ -64,7 +64,7 @@ export class GetMemberInfo extends IBMiComponent { if (results.length === 1 && results[0].ISSOURCE === 'Y') { const result = results[0]; - const asp = this.connection.aspInfo[Number(results[0].ASP)]; + const asp = this.connection.getIAspName(Number(results[0].ASP)) return { asp, library: result.LIBRARY, @@ -96,7 +96,7 @@ export class GetMemberInfo extends IBMiComponent { } return results.filter(row => row.ISSOURCE === 'Y').map(result => { - const asp = this.connection.aspInfo[Number(result.ASP)]; + const asp = this.connection.getIAspName(Number(result.ASP)); return { asp, library: result.LIBRARY, diff --git a/src/filesystems/qsys/QSysFs.ts b/src/filesystems/qsys/QSysFs.ts index 5e8010286..768390c60 100644 --- a/src/filesystems/qsys/QSysFs.ts +++ b/src/filesystems/qsys/QSysFs.ts @@ -138,8 +138,8 @@ export class QSysFS implements vscode.FileSystemProvider { path.asp = path.asp || this.getLibraryASP(connection, path.library); let attributes = await loadAttributes(); if (!attributes && !path.asp) { - for (const asp of Object.values(connection.aspInfo)) { - path.asp = asp; + for (const asp of connection.getAllIAsps()) { + path.asp = asp.name; attributes = await loadAttributes(); if (attributes) { this.setLibraryASP(connection, path.library, path.asp); diff --git a/src/instantiate.ts b/src/instantiate.ts index c8fbfea57..5414ae974 100644 --- a/src/instantiate.ts +++ b/src/instantiate.ts @@ -612,6 +612,7 @@ export async function loadAllofExtension(context: vscode.ExtensionContext) { const editor = vscode.window.activeTextEditor; if (editor) { + const connection = instance.getConnection()!; const config = instance.getConfig()!; const uri = editor.document.uri; @@ -628,7 +629,8 @@ export async function loadAllofExtension(context: vscode.ExtensionContext) { } break; case `streamfile`: - detail.asp = (config.sourceASP && config.sourceASP.length > 0) ? config.sourceASP : undefined; + const asp = connection.getCurrentIAspName(); + detail.asp = asp; detail.lib = config.currentLibrary; break; } diff --git a/src/views/objectBrowser.ts b/src/views/objectBrowser.ts index 949a623a7..a134a9cf7 100644 --- a/src/views/objectBrowser.ts +++ b/src/views/objectBrowser.ts @@ -913,8 +913,9 @@ Do you want to replace it?`, item.name), skipAllLabel, overwriteLabel, overwrite filter: node?.filter } + const connection = getConnection(); + if (!parameters.path) { - const connection = getConnection(); const input = await vscode.window.showInputBox({ prompt: vscode.l10n.t(`Enter LIB/SPF/member.ext to search (member.ext is optional and can contain wildcards)`), title: vscode.l10n.t(`Search source file`), @@ -954,7 +955,8 @@ Do you want to replace it?`, item.name), skipAllLabel, overwriteLabel, overwrite const pathParts = parameters.path.split(`/`); if (pathParts[1] !== `*ALL`) { - const aspText = ((config.sourceASP && config.sourceASP.length > 0) ? vscode.l10n.t(`(in ASP {0})`, config.sourceASP) : ``); + const selectedAsp = connection.getCurrentIAspName(); + const aspText = (selectedAsp ? vscode.l10n.t(`(in ASP {0})`, selectedAsp) : ``); const list = GlobalStorage.get().getPreviousSearchTerms(); const listHeader: vscode.QuickPickItem[] = [ diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 6a68c7667..8f33918e9 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -77,7 +77,7 @@ export class SettingsUI { const sourceTab = new Section(); sourceTab - .addInput(`sourceASP`, `Source ASP`, `If source files live within a specific ASP, please specify it here. Leave blank otherwise. You can ignore this if you have access to QSYS2.ASP_INFO as Code for IBM i will fetch ASP information automatically.`, { default: config.sourceASP }) + .addInput(`sourceASP`, `Source ASP`, `Current ASP is based on the user profile job description and cannot be changed here.`, { default: connection?.getCurrentIAspName() || `*SYSBAS`, readonly: true }) .addInput(`sourceFileCCSID`, `Source file CCSID`, `The CCSID of source files on your system. You should only change this setting from *FILE if you have a source file that is 65535 - otherwise use *FILE. Note that this config is used to fetch all members. If you have any source files using 65535, you have bigger problems.`, { default: config.sourceFileCCSID, minlength: 1, maxlength: 5 }) .addHorizontalRule() .addCheckbox(`enableSourceDates`, `Enable Source Dates`, `When enabled, source dates will be retained and updated when editing source members. Requires restart when changed.`, config.enableSourceDates) @@ -288,7 +288,7 @@ export class SettingsUI { //In case we need to play with the data switch (key) { case `sourceASP`: - if (data[key].trim() === ``) data[key] = null; + data[key] = null; break; case `hideCompileErrors`: data[key] = String(data[key]).split(`,`) From d44876954a9dc6b7df9423d17dd0c4aa33f88211 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Sat, 9 Nov 2024 17:55:22 -0500 Subject: [PATCH 03/16] Standardise library ASP lookups Signed-off-by: worksofliam --- src/api/IBMi.ts | 16 ++++++++++++++++ src/api/Search.ts | 15 +++------------ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index 0b37455b9..3a209166a 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -1221,6 +1221,22 @@ export default class IBMi { return this.currentAsp; } + private libraryAsps: { [library: string]: number } = {}; + async getLibraryIAsp(library: string) { + let foundNumber: number|undefined = this.libraryAsps[library]; + + if (!foundNumber) { + const [row] = await this.runSQL(`SELECT IASP_NUMBER FROM TABLE(QSYS2.LIBRARY_INFO('${this.sysNameInAmerican(library)}'))`); + const iaspNumber = Number(row?.IASP_NUMBER); + if (iaspNumber) { + this.libraryAsps[library] = iaspNumber; + foundNumber = iaspNumber; + } + } + + return this.getIAspName(foundNumber); + } + /** * Generates path to a temp file on the IBM i * @param {string} key Key to the temp file to be re-used diff --git a/src/api/Search.ts b/src/api/Search.ts index 764473153..ac9d137dd 100644 --- a/src/api/Search.ts +++ b/src/api/Search.ts @@ -28,19 +28,10 @@ export namespace Search { } // First, let's fetch the ASP info + const foundAsp = await connection.getLibraryIAsp(library); let asp = ``; - const definedAsp = connection.getCurrentIAspName(); - if (definedAsp) { - asp = `/${definedAsp}`; - } else if (connection.enableSQL) { - try { - const [row] = await content.runSQL(`SELECT IASP_NUMBER FROM TABLE(QSYS2.LIBRARY_INFO('${library}'))`); - const iaspNumber = Number(row?.IASP_NUMBER); - const aspName = connection.getIAspName(iaspNumber); - if (aspName) { - asp = `/${aspName}`; - } - } catch (e) { } + if (foundAsp) { + asp = `/${foundAsp}`; } // Then search the members From 0068818e06574bcabe96d0ff3f9e3b85c2f1e6c9 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Sat, 9 Nov 2024 18:02:27 -0500 Subject: [PATCH 04/16] Remove ASP cache from QsysFs Signed-off-by: worksofliam --- src/api/IBMi.ts | 9 ++++++++- src/api/Search.ts | 2 +- src/filesystems/qsys/QSysFs.ts | 27 ++------------------------- 3 files changed, 11 insertions(+), 27 deletions(-) diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index 3a209166a..2a2bd98e0 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -1222,7 +1222,7 @@ export default class IBMi { } private libraryAsps: { [library: string]: number } = {}; - async getLibraryIAsp(library: string) { + async lookupLibraryIAsp(library: string) { let foundNumber: number|undefined = this.libraryAsps[library]; if (!foundNumber) { @@ -1237,6 +1237,13 @@ export default class IBMi { return this.getIAspName(foundNumber); } + getLibraryIAsp(library: string) { + const found = this.libraryAsps[library]; + if (found) { + return this.getIAspName(found); + } + } + /** * Generates path to a temp file on the IBM i * @param {string} key Key to the temp file to be re-used diff --git a/src/api/Search.ts b/src/api/Search.ts index ac9d137dd..2b56dd65d 100644 --- a/src/api/Search.ts +++ b/src/api/Search.ts @@ -28,7 +28,7 @@ export namespace Search { } // First, let's fetch the ASP info - const foundAsp = await connection.getLibraryIAsp(library); + const foundAsp = await connection.lookupLibraryIAsp(library); let asp = ``; if (foundAsp) { asp = `/${foundAsp}`; diff --git a/src/filesystems/qsys/QSysFs.ts b/src/filesystems/qsys/QSysFs.ts index 768390c60..65ec6fe5e 100644 --- a/src/filesystems/qsys/QSysFs.ts +++ b/src/filesystems/qsys/QSysFs.ts @@ -44,7 +44,6 @@ export function isProtectedFilter(filter?: string): boolean { } export class QSysFS implements vscode.FileSystemProvider { - private readonly libraryASP: Map = new Map; private readonly savedAsMembers: Set = new Set; private readonly sourceDateHandler: SourceDateHandler; private readonly extendedContent: ExtendedIBMiContent; @@ -71,7 +70,6 @@ export class QSysFS implements vscode.FileSystemProvider { 'disconnected', `Update member support & clear library ASP cache`, () => { - this.libraryASP.clear(); this.updateMemberSupport(); }); } @@ -135,35 +133,17 @@ export class QSysFS implements vscode.FileSystemProvider { async getMemberAttributes(connection: IBMi, path: QsysPath & { member?: string }) { const loadAttributes = async () => await connection.content.getAttributes(path, "CREATE_TIME", "MODIFY_TIME", "DATA_SIZE"); - path.asp = path.asp || this.getLibraryASP(connection, path.library); + path.asp = path.asp || await connection.lookupLibraryIAsp(path.library); let attributes = await loadAttributes(); - if (!attributes && !path.asp) { - for (const asp of connection.getAllIAsps()) { - path.asp = asp.name; - attributes = await loadAttributes(); - if (attributes) { - this.setLibraryASP(connection, path.library, path.asp); - break; - } - } - } return attributes; } parseMemberPath(connection: IBMi, path: string) { const memberParts = connection.parserMemberPath(path); - memberParts.asp = memberParts.asp || this.getLibraryASP(connection, memberParts.library); + memberParts.asp = memberParts.asp || connection.getLibraryIAsp(memberParts.library); return memberParts; } - setLibraryASP(connection: IBMi, library: string, asp: string) { - this.libraryASP.set(connection.upperCaseName(library), asp); - } - - getLibraryASP(connection: IBMi, library: string) { - return this.libraryASP.get(connection.upperCaseName(library)); - } - async readFile(uri: vscode.Uri, retrying?: boolean): Promise { const contentApi = instance.getContent(); const connection = instance.getConnection(); @@ -183,9 +163,6 @@ export class QSysFS implements vscode.FileSystemProvider { throw error; } if (memberContent !== undefined) { - if (asp && !this.getLibraryASP(connection, library)) { - this.setLibraryASP(connection, library, asp); - } return new Uint8Array(Buffer.from(memberContent, `utf8`)); } else { From 0cf05f383144778beb0401230f1245ee133051b8 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Sat, 9 Nov 2024 18:11:47 -0500 Subject: [PATCH 05/16] Fetch ASP at time of read/write Signed-off-by: worksofliam --- src/api/IBMi.ts | 4 ++-- src/api/IBMiContent.ts | 2 -- src/filesystems/qsys/QSysFs.ts | 8 ++++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index 2a2bd98e0..0c5ce1eaf 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -1228,7 +1228,7 @@ export default class IBMi { if (!foundNumber) { const [row] = await this.runSQL(`SELECT IASP_NUMBER FROM TABLE(QSYS2.LIBRARY_INFO('${this.sysNameInAmerican(library)}'))`); const iaspNumber = Number(row?.IASP_NUMBER); - if (iaspNumber) { + if (iaspNumber >= 0) { this.libraryAsps[library] = iaspNumber; foundNumber = iaspNumber; } @@ -1239,7 +1239,7 @@ export default class IBMi { getLibraryIAsp(library: string) { const found = this.libraryAsps[library]; - if (found) { + if (found >= 0) { return this.getIAspName(found); } } diff --git a/src/api/IBMiContent.ts b/src/api/IBMiContent.ts index 2cf8fe222..86e8b45cb 100644 --- a/src/api/IBMiContent.ts +++ b/src/api/IBMiContent.ts @@ -142,7 +142,6 @@ export default class IBMiContent { * Download the contents of a source member */ async downloadMemberContent(asp: string | undefined, library: string, sourceFile: string, member: string, localPath?: string) { - asp = asp || this.ibmi.getCurrentIAspName(); library = this.ibmi.upperCaseName(library); sourceFile = this.ibmi.upperCaseName(sourceFile); member = this.ibmi.upperCaseName(member); @@ -210,7 +209,6 @@ export default class IBMiContent { * Upload to a member */ async uploadMemberContent(asp: string | undefined, library: string, sourceFile: string, member: string, content: string | Uint8Array) { - asp = asp || this.ibmi.getCurrentIAspName(); library = this.ibmi.upperCaseName(library); sourceFile = this.ibmi.upperCaseName(sourceFile); member = this.ibmi.upperCaseName(member); diff --git a/src/filesystems/qsys/QSysFs.ts b/src/filesystems/qsys/QSysFs.ts index 65ec6fe5e..4fb22a0cc 100644 --- a/src/filesystems/qsys/QSysFs.ts +++ b/src/filesystems/qsys/QSysFs.ts @@ -148,7 +148,8 @@ export class QSysFS implements vscode.FileSystemProvider { const contentApi = instance.getContent(); const connection = instance.getConnection(); if (connection && contentApi) { - const { asp, library, file, name: member } = this.parseMemberPath(connection, uri.path); + let { asp, library, file, name: member } = this.parseMemberPath(connection, uri.path); + asp = asp || await connection.lookupLibraryIAsp(library); let memberContent; try { @@ -189,7 +190,9 @@ export class QSysFS implements vscode.FileSystemProvider { const contentApi = instance.getContent(); const connection = instance.getConnection(); if (connection && contentApi) { - const { asp, library, file, name: member, extension } = this.parseMemberPath(connection, uri.path); + let { asp, library, file, name: member, extension } = this.parseMemberPath(connection, uri.path); + asp = asp || await connection.lookupLibraryIAsp(library); + if (!content.length) { //Coming from "Save as" const addMember = await connection.runCommand({ command: `ADDPFM FILE(${library}/${file}) MBR(${member}) SRCTYPE(${extension || '*NONE'})`, @@ -202,6 +205,7 @@ export class QSysFS implements vscode.FileSystemProvider { throw new FileSystemError(addMember.stderr); } } + else { this.savedAsMembers.delete(uri.path); this.extendedMemberSupport ? From 63efdcb49caf23fdb384c6584127fd13fc603eda Mon Sep 17 00:00:00 2001 From: worksofliam Date: Sat, 9 Nov 2024 21:24:38 -0500 Subject: [PATCH 06/16] Add null captures Signed-off-by: worksofliam --- src/api/IBMiContent.ts | 8 ++++---- src/components/getMemberInfo.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/api/IBMiContent.ts b/src/api/IBMiContent.ts index 86e8b45cb..169b140cb 100644 --- a/src/api/IBMiContent.ts +++ b/src/api/IBMiContent.ts @@ -375,7 +375,7 @@ export default class IBMiContent { `; const results = await this.ibmi.runSQL(statement); - const asp = this.ibmi.getIAspName(Number(results[0].IASP_NUMBER)); + const asp = this.ibmi.getIAspName(Number(results[0]?.IASP_NUMBER)); objects = results.map(object => ({ library: 'QSYS', @@ -578,7 +578,7 @@ export default class IBMiContent { const objects = (await this.runStatements(createOBJLIST.join(`\n`))); - const asp = this.ibmi.getIAspName(Number(objects[0].IASP_NUMBER)); + const asp = this.ibmi.getIAspName(Number(objects[0]?.IASP_NUMBER)); return objects.map(object => ({ library, @@ -652,7 +652,7 @@ export default class IBMiContent { const results = await this.ibmi.runSQL(statement); if (results.length) { - const asp = this.ibmi.getIAspName(Number(results[0].ASP)); + const asp = this.ibmi.getIAspName(Number(results[0]?.ASP)); return results.map(result => ({ asp, library, @@ -695,7 +695,7 @@ export default class IBMiContent { if (results.length === 1 && results[0].ISSOURCE === 'Y') { const result = results[0]; - const asp = this.ibmi.getIAspName(Number(results[0].ASP)); + const asp = this.ibmi.getIAspName(Number(results[0]?.ASP)); return { library: result.LIBRARY, file: result.FILE, diff --git a/src/components/getMemberInfo.ts b/src/components/getMemberInfo.ts index 13f52489f..6aa97d60a 100644 --- a/src/components/getMemberInfo.ts +++ b/src/components/getMemberInfo.ts @@ -64,7 +64,7 @@ export class GetMemberInfo extends IBMiComponent { if (results.length === 1 && results[0].ISSOURCE === 'Y') { const result = results[0]; - const asp = this.connection.getIAspName(Number(results[0].ASP)) + const asp = this.connection.getIAspName(Number(results[0]?.ASP)) return { asp, library: result.LIBRARY, From 1f629284ddcadabf6fec5868f514650d6e0477eb Mon Sep 17 00:00:00 2001 From: worksofliam Date: Sat, 9 Nov 2024 21:38:50 -0500 Subject: [PATCH 07/16] Simple testcase for SYSBAS Signed-off-by: worksofliam --- src/testing/connection.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/testing/connection.ts b/src/testing/connection.ts index cbe3a556d..3a5fe6935 100644 --- a/src/testing/connection.ts +++ b/src/testing/connection.ts @@ -328,6 +328,16 @@ export const ConnectionSuite: TestSuite = { connection.variantChars.local = variantsBackup; } } + }, + { + name: `Test getLibraryIAsp against QSYSINC`, test: async () => { + const connection = instance.getConnection()!; + + const library = `QSYSINC`; + + const asp = await connection.lookupLibraryIAsp(library); + assert.strictEqual(asp, undefined); // Because QSYSINC is not an iASP + } } ] }; From e7561c868b4628e972c2bacc04fd302b981348b6 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Mon, 13 Jan 2025 16:26:14 -0500 Subject: [PATCH 08/16] Assume client is defined Signed-off-by: worksofliam --- src/api/IBMiContent.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/IBMiContent.ts b/src/api/IBMiContent.ts index dee7d1b06..bb4337bff 100644 --- a/src/api/IBMiContent.ts +++ b/src/api/IBMiContent.ts @@ -1096,19 +1096,19 @@ export default class IBMiContent { } async uploadFiles(files: { local: string | Uri, remote: string }[], options?: node_ssh.SSHPutFilesOptions) { - await this.ibmi.client.putFiles(files.map(f => { return { local: Tools.fileToPath(f.local), remote: f.remote } }), options); + await this.ibmi.client!.putFiles(files.map(f => { return { local: Tools.fileToPath(f.local), remote: f.remote } }), options); } async downloadFile(localFile: string | Uri, remoteFile: string) { - await this.ibmi.client.getFile(Tools.fileToPath(localFile), remoteFile); + await this.ibmi.client!.getFile(Tools.fileToPath(localFile), remoteFile); } async uploadDirectory(localDirectory: string | Uri, remoteDirectory: string, options?: node_ssh.SSHGetPutDirectoryOptions) { - await this.ibmi.client.putDirectory(Tools.fileToPath(localDirectory), remoteDirectory, options); + await this.ibmi.client!.putDirectory(Tools.fileToPath(localDirectory), remoteDirectory, options); } async downloadDirectory(localDirectory: string | Uri, remoteDirectory: string, options?: node_ssh.SSHGetPutDirectoryOptions) { - await this.ibmi.client.getDirectory(Tools.fileToPath(localDirectory), remoteDirectory, options); + await this.ibmi.client!.getDirectory(Tools.fileToPath(localDirectory), remoteDirectory, options); } } From 6fcb4d2f7d2051d2e1a0ed2865dc55cdd585273f Mon Sep 17 00:00:00 2001 From: worksofliam Date: Mon, 13 Jan 2025 16:59:57 -0500 Subject: [PATCH 09/16] Refactor file upload and download methods to return promises instead of awaiting them Signed-off-by: worksofliam --- src/api/IBMiContent.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/api/IBMiContent.ts b/src/api/IBMiContent.ts index bb4337bff..f7a519094 100644 --- a/src/api/IBMiContent.ts +++ b/src/api/IBMiContent.ts @@ -1095,20 +1095,20 @@ export default class IBMiContent { } } - async uploadFiles(files: { local: string | Uri, remote: string }[], options?: node_ssh.SSHPutFilesOptions) { - await this.ibmi.client!.putFiles(files.map(f => { return { local: Tools.fileToPath(f.local), remote: f.remote } }), options); + uploadFiles(files: { local: string | Uri, remote: string }[], options?: node_ssh.SSHPutFilesOptions) { + return this.ibmi.client!.putFiles(files.map(f => { return { local: Tools.fileToPath(f.local), remote: f.remote } }), options); } - async downloadFile(localFile: string | Uri, remoteFile: string) { - await this.ibmi.client!.getFile(Tools.fileToPath(localFile), remoteFile); + downloadFile(localFile: string | Uri, remoteFile: string) { + return this.ibmi.client!.getFile(Tools.fileToPath(localFile), remoteFile); } - async uploadDirectory(localDirectory: string | Uri, remoteDirectory: string, options?: node_ssh.SSHGetPutDirectoryOptions) { - await this.ibmi.client!.putDirectory(Tools.fileToPath(localDirectory), remoteDirectory, options); + uploadDirectory(localDirectory: string | Uri, remoteDirectory: string, options?: node_ssh.SSHGetPutDirectoryOptions) { + return this.ibmi.client!.putDirectory(Tools.fileToPath(localDirectory), remoteDirectory, options); } - async downloadDirectory(localDirectory: string | Uri, remoteDirectory: string, options?: node_ssh.SSHGetPutDirectoryOptions) { - await this.ibmi.client!.getDirectory(Tools.fileToPath(localDirectory), remoteDirectory, options); + downloadDirectory(localDirectory: string | Uri, remoteDirectory: string, options?: node_ssh.SSHGetPutDirectoryOptions) { + return this.ibmi.client!.getDirectory(Tools.fileToPath(localDirectory), remoteDirectory, options); } } From 1927af7b368266d20cd9897c8b46649643f24c9b Mon Sep 17 00:00:00 2001 From: worksofliam Date: Mon, 13 Jan 2025 18:34:53 -0500 Subject: [PATCH 10/16] Deprecate old file and directory upload/download methods in favor of new content methods Signed-off-by: worksofliam --- src/api/IBMi.ts | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index 5b0f4824b..7df953575 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -931,12 +931,12 @@ export default class IBMi { resultSet.forEach(row => { // Does not ever include SYSBAS/SYSTEM, only iASPs if (row.DEVICE_DESCRIPTION_NAME && row.DEVICE_DESCRIPTION_NAME && row.DEVICE_DESCRIPTION_NAME !== `null`) { - this.iAspInfo[Number(row.ASP_NUMBER)] = { + this.iAspInfo.push({ id: Number(row.ASP_NUMBER), name: String(row.DEVICE_DESCRIPTION_NAME), type: String(row.ASP_TYPE), rdbName: String(row.RDB_NAME) - }; + }); } }); } catch (e) { @@ -1656,4 +1656,32 @@ export default class IBMi { sshdCcsid: this.sshdCcsid }; } + + /** + * @deprecated Use {@link IBMiContent.uploadFiles} instead. + */ + uploadFiles(files: { local: string | vscode.Uri, remote: string }[], options?: node_ssh.SSHPutFilesOptions) { + return this.content.uploadFiles(files, options); + } + + /** + * @deprecated Use {@link IBMiContent.downloadFiles} instead. + */ + async downloadFile(localFile: string | vscode.Uri, remoteFile: string) { + await this.content.downloadFile(localFile, remoteFile); + } + + /** + * @deprecated Use {@link IBMiContent.uploadDirectory} instead. + */ + async uploadDirectory(localDirectory: string | vscode.Uri, remoteDirectory: string, options?: node_ssh.SSHGetPutDirectoryOptions) { + await this.content.uploadDirectory(localDirectory, remoteDirectory, options); + } + + /** + * @deprecated Use {@link IBMiContent.downloadDirectory} instead. + */ + async downloadDirectory(localDirectory: string | vscode.Uri, remoteDirectory: string, options?: node_ssh.SSHGetPutDirectoryOptions) { + await this.content.downloadDirectory(localDirectory, remoteDirectory, options); + } } \ No newline at end of file From 57a4c999a8760bbc0f050ee369dd4900107646b5 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 10:22:42 -0500 Subject: [PATCH 11/16] Start of test cases Signed-off-by: worksofliam --- src/api/IBMi.ts | 13 ++++++++ src/testing/asp.ts | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 src/testing/asp.ts diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index 7df953575..c7305b657 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -1306,6 +1306,19 @@ export default class IBMi { return this.iAspInfo; } + getIAspDetail(by: string|number) { + let asp: AspInfo|undefined; + if (typeof by === 'string') { + asp = this.iAspInfo.find(asp => asp.name === by); + } else { + asp = this.iAspInfo.find(asp => asp.id === by); + } + + if (asp) { + return asp; + } + } + getIAspName(by: string|number): string|undefined { let asp: AspInfo|undefined; if (typeof by === 'string') { diff --git a/src/testing/asp.ts b/src/testing/asp.ts new file mode 100644 index 000000000..ad5fe4864 --- /dev/null +++ b/src/testing/asp.ts @@ -0,0 +1,76 @@ +import assert from "assert"; +import { randomInt } from "crypto"; +import { posix } from "path"; +import tmp from 'tmp'; +import util, { TextDecoder } from 'util'; +import { Uri, workspace } from "vscode"; +import { TestSuite } from "."; +import { Tools } from "../api/Tools"; +import { getMemberUri } from "../filesystems/qsys/QSysFs"; +import { instance } from "../instantiate"; +import { CommandResult } from "../typings"; +import IBMi from "../api/IBMi"; +import { Search } from "../api/Search"; + +const LIBNAME = `VSCODELIBT`; +const SPFNAME = `VSCODESPFT`; +const MBRNAME = `VSCODEMBRT`; + +function checkAsps(connection: IBMi) { + const asps = connection.getAllIAsps(); + assert.ok(asps?.length, `ASP list is empty`); + + const currentAsp = connection.getCurrentIAspName(); + assert.ok(currentAsp, `Current ASP not defined`); +} + +async function ensureLibExists(connection: IBMi) { + const detail = connection.getIAspDetail(connection.getCurrentIAspName()!)!; + const res = await connection.runCommand({command: `CRTLIB LIB(${LIBNAME}) ASP(${detail.id})`}); +} + +async function createTempRpgle(connection: IBMi) { + const content = connection.getContent(); + + await connection.runCommand({ + command: `CRTSRCPF ${LIBNAME}/${SPFNAME} MBR(*NONE)`, + environment: `ile` + }); + + await connection.runCommand({ + command: `ADDPFM FILE(${LIBNAME}/${SPFNAME}) MBR(${MBRNAME}) `, + environment: `ile` + }); + + const baseContent = `**FREE\ndsply 'hello world';`; + + const uploadResult = await content?.uploadMemberContent(undefined, LIBNAME, SPFNAME, MBRNAME, baseContent); + assert.ok(uploadResult); +} + +export const AspSuite: TestSuite = { + name: `ASP API tests`, + before: async () => { + const connection = instance.getConnection()!; + checkAsps(connection); + await ensureLibExists(connection); + }, + tests: [ + { + name: `Read members in ASP and base`, test: async () => { + const connection = instance.getConnection()!; + checkAsps(connection); + + await ensureLibExists(connection); + await createTempRpgle(connection); + + const aspUri = getMemberUri({ asp: connection.getCurrentIAspName(), library: LIBNAME, file: SPFNAME, name: MBRNAME, extension: `rpgle` }); + + // We have to read it first to create the alias! + const aspMbrContents = await workspace.fs.readFile(aspUri); + + assert.ok(aspMbrContents); + } + }, + ] +}; From db51bb71f9d6f36495e7492edd15b3050d72d6e3 Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Wed, 15 Jan 2025 14:00:47 +0100 Subject: [PATCH 12/16] Removed unused variables Signed-off-by: Seb Julliand --- src/views/objectBrowser.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/views/objectBrowser.ts b/src/views/objectBrowser.ts index c0b33bd52..3eb5989b2 100644 --- a/src/views/objectBrowser.ts +++ b/src/views/objectBrowser.ts @@ -960,8 +960,6 @@ Do you want to replace it?`, item.name), skipAllLabel, overwriteLabel, overwrite } if (parameters.path) { - const config = getConfig(); - const pathParts = parameters.path.split(`/`); if (pathParts[1] !== `*ALL`) { const selectedAsp = connection.getCurrentIAspName(); @@ -1350,7 +1348,6 @@ function storeMemberList(path: string, list: string[]) { } async function doSearchInSourceFile(searchTerm: string, path: string, filter?: ConnectionConfiguration.ObjectFilters) { - const content = getContent(); const [library, sourceFile] = path.split(`/`); try { await vscode.window.withProgress({ From ea0ead1556489fed17833e9197a4d379f7e2b704 Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Wed, 15 Jan 2025 14:18:32 +0100 Subject: [PATCH 13/16] Use getContent Signed-off-by: Seb Julliand --- src/testing/search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testing/search.ts b/src/testing/search.ts index b2a732b97..63790561b 100644 --- a/src/testing/search.ts +++ b/src/testing/search.ts @@ -42,7 +42,7 @@ export const SearchSuite: TestSuite = { const filter = parseFilter(memberFilter); const checkNames = (names: string[]) => names.every(filter.test); - const members = await getConnection().content.getMemberList({ library, sourceFile, members: memberFilter }); + const members = await getConnection().getContent().getMemberList({ library, sourceFile, members: memberFilter }); assert.ok(checkNames(members.map(member => member.name))); const result = await Search.searchMembers(instance, "QSYSINC", "QRPGLESRC", "SQL", members); From 1953ac7f735dabd8ec1584bfb5a924cc5a97c069 Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Wed, 15 Jan 2025 14:18:46 +0100 Subject: [PATCH 14/16] Fixed members search on iASP Signed-off-by: Seb Julliand --- src/api/Search.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/api/Search.ts b/src/api/Search.ts index 959b9db27..4c896d2bb 100644 --- a/src/api/Search.ts +++ b/src/api/Search.ts @@ -28,16 +28,12 @@ export namespace Search { } // First, let's fetch the ASP info - const foundAsp = await connection.lookupLibraryIAsp(library); - let asp = ``; - if (foundAsp) { - asp = `/${foundAsp}`; - } + const asp = await connection.lookupLibraryIAsp(library); // Then search the members const result = await connection.sendQsh({ command: `/usr/bin/grep -inHR -F "${sanitizeSearchTerm(searchTerm)}" ${memberFilter}`, - directory: connection.sysNameInAmerican(`${asp}/QSYS.LIB/${library}.LIB/${sourceFile}.FILE`) + directory: connection.sysNameInAmerican(`${asp ? `/${asp}` : ``}/QSYS.LIB/${library}.LIB/${sourceFile}.FILE`) }); if (!result.stderr) { @@ -80,13 +76,13 @@ export namespace Search { const foundMember = detailedMembers?.find(member => member.name === name && member.library === lib && member.file === spf); if (foundMember) { - hit.path = connection.sysNameInLocal(`${lib}/${spf}/${name}.${foundMember.extension}`); + hit.path = connection.sysNameInLocal(`${asp ? `${asp}/` : ``}${lib}/${spf}/${name}.${foundMember.extension}`); } } return { term: searchTerm, - hits: hits + hits } } else { From 59e8e88983ee6dfa724cc9229089fff5dbfca543 Mon Sep 17 00:00:00 2001 From: LJ <3708366+worksofliam@users.noreply.github.com> Date: Wed, 15 Jan 2025 09:25:45 -0500 Subject: [PATCH 15/16] Update src/api/IBMi.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Julliand --- src/api/IBMi.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index c7305b657..4ad427939 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -1320,16 +1320,7 @@ export default class IBMi { } getIAspName(by: string|number): string|undefined { - let asp: AspInfo|undefined; - if (typeof by === 'string') { - asp = this.iAspInfo.find(asp => asp.name === by); - } else { - asp = this.iAspInfo.find(asp => asp.id === by); - } - - if (asp) { - return asp.name; - } + return getIAspDetail(by)?.name; } getCurrentIAspName() { From cc73879f084c8c4b5c34e84094c33f5409ddb6a5 Mon Sep 17 00:00:00 2001 From: LJ <3708366+worksofliam@users.noreply.github.com> Date: Wed, 15 Jan 2025 09:26:02 -0500 Subject: [PATCH 16/16] Update src/filesystems/qsys/QSysFs.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Julliand --- src/filesystems/qsys/QSysFs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/filesystems/qsys/QSysFs.ts b/src/filesystems/qsys/QSysFs.ts index 15c22cda0..8e38617d1 100644 --- a/src/filesystems/qsys/QSysFs.ts +++ b/src/filesystems/qsys/QSysFs.ts @@ -127,7 +127,7 @@ export class QSysFS implements vscode.FileSystemProvider { } async getMemberAttributes(connection: IBMi, path: QsysPath & { member?: string }) { - const loadAttributes = async () => await connection.content.getAttributes(path, "CREATE_TIME", "MODIFY_TIME", "DATA_SIZE"); + const loadAttributes = async () => await connection.getContent().getAttributes(path, "CREATE_TIME", "MODIFY_TIME", "DATA_SIZE"); path.asp = path.asp || await connection.lookupLibraryIAsp(path.library); let attributes = await loadAttributes();