diff --git a/src/api/IBMiContent.ts b/src/api/IBMiContent.ts index 1dc5f02bf..e9f12bd15 100644 --- a/src/api/IBMiContent.ts +++ b/src/api/IBMiContent.ts @@ -103,7 +103,7 @@ export default class IBMiContent { * @param content Raw content * @param encoding Optional encoding to write. */ - async writeStreamfileRaw(originalPath: string, content: Uint8Array, encoding?: string) { + async writeStreamfileRaw(originalPath: string, content: string|Uint8Array, encoding?: string) { const client = this.ibmi.client!; const features = this.ibmi.remoteFeatures; const tmpobj = await tmpFile(); @@ -338,7 +338,7 @@ export default class IBMiContent { }); if (copyResult.code === 0) { - let result = await this.downloadStreamfile(tempRmt); + let result = await this.downloadStreamfileRaw(tempRmt); if (this.config.autoClearTempData) { Promise.allSettled([ diff --git a/src/api/components/copyToImport.ts b/src/api/components/copyToImport.ts index f46ae4f60..d57e5f86f 100644 --- a/src/api/components/copyToImport.ts +++ b/src/api/components/copyToImport.ts @@ -61,7 +61,7 @@ export class CopyToImport implements IBMiComponent { newStatements.push(`CREATE TABLE ${library}.${table} AS (${statement}) WITH DATA`); } - newStatements.push(`Call QSYS2.QCMDEXC('` + connection.content.toCl(`CPYTOIMPF`, { + newStatements.push(`Call QSYS2.QCMDEXC('` + connection.getContent().toCl(`CPYTOIMPF`, { FROMFILE: `${library!}/${table!} *FIRST`, TOSTMF: outStmf, MBROPT: `*REPLACE`, diff --git a/src/api/components/cqsh/index.ts b/src/api/components/cqsh/index.ts index d88b478c5..748846cf4 100644 --- a/src/api/components/cqsh/index.ts +++ b/src/api/components/cqsh/index.ts @@ -29,7 +29,7 @@ export class CustomQSh implements IBMiComponent { async getRemoteState(connection: IBMi, installDirectory: string): Promise { this.installPath = path.posix.join(installDirectory, this.getFileName()); - const result = await connection.content.testStreamFile(this.installPath, "x"); + const result = await connection.getContent().testStreamFile(this.installPath, "x"); if (!result) { return `NotInstalled`; diff --git a/src/api/components/getMemberInfo.ts b/src/api/components/getMemberInfo.ts index f27c9aaab..38851a3cc 100644 --- a/src/api/components/getMemberInfo.ts +++ b/src/api/components/getMemberInfo.ts @@ -19,7 +19,7 @@ export class GetMemberInfo implements IBMiComponent { } async getRemoteState(connection: IBMi): Promise { - const [result] = await connection.runSQL(`select cast(LONG_COMMENT as VarChar(200)) LONG_COMMENT from qsys2.sysroutines where routine_schema = '${connection.config?.tempLibrary.toUpperCase()}' and routine_name = '${this.procedureName}'`); + const [result] = await connection.runSQL(`select cast(LONG_COMMENT as VarChar(200)) LONG_COMMENT from qsys2.sysroutines where routine_schema = '${connection.getConfig().tempLibrary.toUpperCase()}' and routine_name = '${this.procedureName}'`); if (result?.LONG_COMMENT) { const comment = result.LONG_COMMENT as string; const dash = comment.indexOf('-'); @@ -72,7 +72,7 @@ export class GetMemberInfo implements IBMiComponent { } async getMemberInfo(connection: IBMi, library: string, sourceFile: string, member: string): Promise { - const config = connection.config!; + const config = connection.getConfig(); const tempLib = config.tempLibrary; const statement = `select * from table(${tempLib}.${this.procedureName}('${library}', '${sourceFile}', '${member}'))`; @@ -83,7 +83,7 @@ export class GetMemberInfo implements IBMiComponent { } catch (e) { } // Ignore errors, will return undefined. } else { - results = await connection.content.getQTempTable([`create table QTEMP.MEMBERINFO as (${statement}) with data`], "MEMBERINFO"); + results = await connection.getContent().getQTempTable([`create table QTEMP.MEMBERINFO as (${statement}) with data`], "MEMBERINFO"); } if (results.length === 1 && results[0].ISSOURCE === 'Y') { @@ -103,7 +103,7 @@ export class GetMemberInfo implements IBMiComponent { } async getMultipleMemberInfo(connection: IBMi, members: IBMiMember[]): Promise { - const config = connection.config!; + const config = connection.getConfig(); const tempLib = config.tempLibrary; const statement = members .map(member => `select * from table(${tempLib}.${this.procedureName}('${member.library}', '${member.file}', '${member.name}'))`) @@ -116,7 +116,7 @@ export class GetMemberInfo implements IBMiComponent { } catch (e) { }; // Ignore errors, will return undefined. } else { - results = await connection.content.getQTempTable([`create table QTEMP.MEMBERINFO as (${statement}) with data`], "MEMBERINFO"); + results = await connection.getContent().getQTempTable([`create table QTEMP.MEMBERINFO as (${statement}) with data`], "MEMBERINFO"); } return results.filter(row => row.ISSOURCE === 'Y').map(result => { diff --git a/src/api/components/getNewLibl.ts b/src/api/components/getNewLibl.ts index 20ff4a034..3052ff98b 100644 --- a/src/api/components/getNewLibl.ts +++ b/src/api/components/getNewLibl.ts @@ -54,7 +54,7 @@ export class GetNewLibl implements IBMiComponent { } async getLibraryListFromCommand(connection: IBMi, ileCommand: string) { - const tempLib = connection.config!.tempLibrary; + const tempLib = connection.getConfig().tempLibrary; const resultSet = await connection.runSQL(`CALL ${tempLib}.${this.procedureName}('${ileCommand.replace(new RegExp(`'`, 'g'), `''`)}')`); const result = { diff --git a/src/api/tests/suites/content.test.ts b/src/api/tests/suites/content.test.ts index 7f3375394..8353e96e8 100644 --- a/src/api/tests/suites/content.test.ts +++ b/src/api/tests/suites/content.test.ts @@ -526,7 +526,7 @@ describe('Content Tests', {concurrent: true}, () => { it('Test @clCommand + select statement', async () => { const content = connection.getContent(); - const [resultA] = await content.runSQL(`@CRTSAVF FILE(QTEMP/UNITTEST) TEXT('Code for i test');\nSelect * From Table(QSYS2.OBJECT_STATISTICS('QTEMP', '*FILE')) Where OBJATTRIBUTE = 'SAVF';`); + const [resultA] = await connection.runSQL(`@CRTSAVF FILE(QTEMP/UNITTEST) TEXT('Code for i test');\nSelect * From Table(QSYS2.OBJECT_STATISTICS('QTEMP', '*FILE')) Where OBJATTRIBUTE = 'SAVF';`); expect(resultA.OBJNAME).toBe('UNITTEST'); expect(resultA.OBJTEXT).toBe('Code for i test'); @@ -573,7 +573,7 @@ describe('Content Tests', {concurrent: true}, () => { it('should count members', async () => { const content = connection.getContent() - const tempLib = connection.config?.tempLibrary; + const tempLib = connection.getConfig().tempLibrary; if (tempLib) { const file = Tools.makeid(8); const deleteSPF = async () => await connection.runCommand({ command: `DLTF FILE(${tempLib}/${file})`, noLibList: true }); diff --git a/src/api/tests/suites/encoding.test.ts b/src/api/tests/suites/encoding.test.ts index f6fe4c3f2..30e5a6b17 100644 --- a/src/api/tests/suites/encoding.test.ts +++ b/src/api/tests/suites/encoding.test.ts @@ -18,7 +18,7 @@ const SHELL_CHARS = [`$`, `#`]; async function runCommandsWithCCSID(connection: IBMi, commands: string[], ccsid: number) { const testPgmSrcFile = Tools.makeid(6).toUpperCase(); - const config = connection.config!; + const config = connection.getConfig(); const tempLib = config.tempLibrary; const testPgmName = `T${commands.length}${ccsid}${Tools.makeid(2)}`.toUpperCase(); @@ -28,7 +28,7 @@ async function runCommandsWithCCSID(connection: IBMi, commands: string[], ccsid: const sourceFileCreated = await connection!.runCommand({ command: `CRTSRCPF FILE(${tempLib}/${testPgmSrcFile}) RCDLEN(112) CCSID(${ccsid})`, noLibList: true }); - await connection.content.uploadMemberContent(tempLib, testPgmSrcFile, testPgmName, commands.join(`\n`)); + await connection.getContent().uploadMemberContent(tempLib, testPgmSrcFile, testPgmName, commands.join(`\n`)); const compileCommand = `CRTBNDCL PGM(${tempLib}/${testPgmName}) SRCFILE(${tempLib}/${testPgmSrcFile}) SRCMBR(${testPgmName}) REPLACE(*YES)`; const compileResult = await connection.runCommand({ command: compileCommand, noLibList: true }); @@ -118,9 +118,9 @@ describe('Encoding tests', { concurrent: true }, () => { it('streamfileResolve with dollar', async () => { await connection.withTempDirectory(async tempDir => { const tempFile = path.posix.join(tempDir, `$hello`); - await connection.content.createStreamFile(tempFile); + await connection.getContent().createStreamFile(tempFile); - const resolved = await connection.content.streamfileResolve([tempFile], [`/`]); + const resolved = await connection.getContent().streamfileResolve([tempFile], [`/`]); expect(resolved).toBe(tempFile); }); @@ -133,12 +133,12 @@ describe('Encoding tests', { concurrent: true }, () => { await connection.withTempDirectory(async tempDir => { for (const name of nameCombos) { const tempFile = path.posix.join(tempDir, `${name}.txt`); - await connection.content.createStreamFile(tempFile); + await connection.getContent().createStreamFile(tempFile); - const resolved = await connection.content.streamfileResolve([tempFile], [`/`]); + const resolved = await connection.getContent().streamfileResolve([tempFile], [`/`]); expect(resolved).toBe(tempFile); - const attributes = await connection.content.getAttributes(resolved!, `CCSID`); + const attributes = await connection.getContent().getAttributes(resolved!, `CCSID`); expect(attributes).toBeTruthy(); } }); @@ -182,7 +182,7 @@ describe('Encoding tests', { concurrent: true }, () => { it('Listing objects with variants', { timeout: 15000 }, async () => { const content = connection.getContent(); if (connection && content) { - const tempLib = connection.config?.tempLibrary!; + const tempLib = connection.getConfig().tempLibrary!; const ccsid = connection.getCcsid(); let library = `TESTLIB${connection.variantChars.local}`; @@ -220,7 +220,7 @@ describe('Encoding tests', { concurrent: true }, () => { expect(expectedLibrary).toBeTruthy(); expect(library).toBe(expectedLibrary.name); - const validated = await connection.content.validateLibraryList([tempLib, library]); + const validated = await connection.getContent().validateLibraryList([tempLib, library]); expect(validated.length).toBe(0); const libl = await content.getLibraryList([library]); @@ -281,7 +281,7 @@ describe('Encoding tests', { concurrent: true }, () => { const addPf = await connection.runCommand({ command: `ADDPFM FILE(${library}/${sourceFile}) MBR(${member}) SRCTYPE(TXT)`, noLibList: true }); expect(addPf.code).toBe(0); - await connection.content.uploadMemberContent(library, sourceFile, member, [`**free`, `dsply 'Hello world';`, `return;`].join(`\n`)); + await connection.getContent().uploadMemberContent(library, sourceFile, member, [`**free`, `dsply 'Hello world';`, `return;`].join(`\n`)); const compileResultA = await connection.runCommand({ command: `CRTBNDRPG PGM(${library}/${member}) SRCFILE(${library}/${sourceFile}) SRCMBR(${member})`, env: { '&CURLIB': library } }); expect(compileResultA.code).toBe(0); @@ -309,35 +309,35 @@ describe('Encoding tests', { concurrent: true }, () => { const addPf = await connection.runCommand({ command: `ADDPFM FILE(${tempLib}/${testFile}) MBR(${testMember}) SRCTYPE(TXT)`, noLibList: true }); expect(addPf.code).toBe(0); - const attributes = await connection.content.getAttributes({ library: tempLib, name: testFile, member: testMember }, `CCSID`); + const attributes = await connection.getContent().getAttributes({ library: tempLib, name: testFile, member: testMember }, `CCSID`); expect(attributes).toBeTruthy(); expect(attributes![`CCSID`]).toBe(String(ccsidData.userDefaultCCSID)); const addPfB = await connection.runCommand({ command: `ADDPFM FILE(${tempLib}/${testFile}) MBR(${variantMember}) SRCTYPE(TXT)`, noLibList: true }); expect(addPfB.code).toBe(0); - const attributesB = await connection.content.getAttributes({ library: tempLib, name: testFile, member: variantMember }, `CCSID`); + const attributesB = await connection.getContent().getAttributes({ library: tempLib, name: testFile, member: variantMember }, `CCSID`); expect(attributesB).toBeTruthy(); expect(attributesB![`CCSID`]).toBe(String(ccsidData.userDefaultCCSID)); - const objects = await connection.content.getObjectList({ library: tempLib, types: [`*SRCPF`] }); + const objects = await connection.getContent().getObjectList({ library: tempLib, types: [`*SRCPF`] }); expect(objects.length).toBeTruthy(); expect(objects.some(obj => obj.name === testFile)).toBeTruthy(); - const members = await connection.content.getMemberList({ library: tempLib, sourceFile: testFile }); + const members = await connection.getContent().getMemberList({ library: tempLib, sourceFile: testFile }); expect(members.length).toBeTruthy(); expect(members.some(m => m.name === testMember)).toBeTruthy(); expect(members.some(m => m.file === testFile)).toBeTruthy(); - const smallFilter = await connection.content.getMemberList({ library: tempLib, sourceFile: testFile, members: `${varChar}*` }); + const smallFilter = await connection.getContent().getMemberList({ library: tempLib, sourceFile: testFile, members: `${varChar}*` }); expect(smallFilter.length).toBeTruthy(); - const files = await connection.content.getFileList(`/QSYS.LIB/${tempLib}.LIB/${connection.sysNameInAmerican(testFile)}.FILE`); + const files = await connection.getContent().getFileList(`/QSYS.LIB/${tempLib}.LIB/${connection.sysNameInAmerican(testFile)}.FILE`); expect(files.length).toBeTruthy(); expect(files.some(f => f.name === connection.sysNameInAmerican(variantMember) + `.MBR`)).toBeTruthy(); expect(files.some(f => f.name === connection.sysNameInAmerican(testMember) + `.MBR`)).toBeTruthy(); - await connection.content.uploadMemberContent(tempLib, testFile, testMember, [`**free`, `dsply 'Hello world';`, ` `, ` `, `return;`].join(`\n`)); + await connection.getContent().uploadMemberContent(tempLib, testFile, testMember, [`**free`, `dsply 'Hello world';`, ` `, ` `, `return;`].join(`\n`)); const compileResult = await connection.runCommand({ command: `CRTBNDRPG PGM(${tempLib}/${testMember}) SRCFILE(${tempLib}/${testFile}) SRCMBR(${testMember})`, noLibList: true }); console.log(compileResult); diff --git a/src/commands/open.ts b/src/commands/open.ts index bc34ffcb1..ad412086d 100644 --- a/src/commands/open.ts +++ b/src/commands/open.ts @@ -244,7 +244,7 @@ export function registerOpenCommands(instance: Instance): Disposable[] { }, ] - resultSet = await content!.runSQL(` + resultSet = await connection.runSQL(` select ifnull( cast( SYSTEM_TABLE_NAME as char( 10 ) for bit data ), '' ) as SYSTEM_TABLE_NAME , ifnull( TABLE_TEXT, '' ) as TABLE_TEXT from QSYS2.SYSTABLES @@ -286,7 +286,7 @@ export function registerOpenCommands(instance: Instance): Disposable[] { filterText = filterText.endsWith(`.`) ? filterText.substring(0, filterText.length - 1) : filterText; - resultSet = await content!.runSQL(` + resultSet = await connection.runSQL(` select cast( SYSTEM_TABLE_MEMBER as char( 10 ) for bit data ) as SYSTEM_TABLE_MEMBER , ifnull( PARTITION_TEXT, '' ) as PARTITION_TEXT , ifnull( SOURCE_TYPE, '' ) as SOURCE_TYPE diff --git a/src/debug/certificates.ts b/src/debug/certificates.ts index a568db53c..a79710362 100644 --- a/src/debug/certificates.ts +++ b/src/debug/certificates.ts @@ -123,7 +123,7 @@ export async function setup(connection: IBMi, imported?: ImportedCertificate) { }); try { if (!clientCertificate.code) { - instance.getContent()!.writeStreamfileRaw(debugConfig.getRemoteClientCertificatePath(), Buffer.from(clientCertificate.stdout), "utf-8"); + connection.getContent().writeStreamfileRaw(debugConfig.getRemoteClientCertificatePath(), Buffer.from(clientCertificate.stdout), "utf-8"); } else { throw clientCertificate.stderr; @@ -183,7 +183,7 @@ export async function setup(connection: IBMi, imported?: ImportedCertificate) { }); //Check if encryption key exists too...because the encryption script can return 0 and an error in stdout in some cases. - if (!encryptResult.code && await instance.getContent()?.testStreamFile(posix.join(debugConfig.getRemoteServiceWorkDir(), "key.properties"), "r")) { + if (!encryptResult.code && await connection.getContent().testStreamFile(posix.join(debugConfig.getRemoteServiceWorkDir(), "key.properties"), "r")) { //After the certificates are generated/imported and the password is encrypted, we make a copy of the encryption key //because it gets deleted each time the service starts. The CODE4IDEBUG variable is here to run the script that will restore the key //when the service starts. diff --git a/src/debug/index.ts b/src/debug/index.ts index 344accbb1..5f2c195e3 100644 --- a/src/debug/index.ts +++ b/src/debug/index.ts @@ -46,8 +46,8 @@ export async function initialize(context: ExtensionContext) { const startDebugging = async (type: DebugType, objectType: DebugObjectType, objectLibrary: string, objectName: string, env?: Env) => { if (debugExtensionAvailable()) { const connection = instance.getConnection(); - const config = instance.getConfig(); - if (connection && config) { + if (connection) { + const config = connection.getConfig(); if (connection.remoteFeatures[`startDebugService.sh`]) { const password = await getPassword(); @@ -120,9 +120,9 @@ export async function initialize(context: ExtensionContext) { if (cachedResolvedTypes[path]) { return cachedResolvedTypes[path]; } else { - const content = instance.getContent()!; + const connection = instance.getConnection()!; - const [row] = await content.runSQL(`select OBJTYPE from table(qsys2.object_statistics('${library}', '*PGM *SRVPGM', '${objectName}')) X`) as { OBJTYPE: DebugObjectType }[]; + const [row] = await connection.runSQL(`select OBJTYPE from table(qsys2.object_statistics('${library}', '*PGM *SRVPGM', '${objectName}')) X`) as { OBJTYPE: DebugObjectType }[]; if (row) { cachedResolvedTypes[path] = row.OBJTYPE; @@ -133,14 +133,14 @@ export async function initialize(context: ExtensionContext) { const getObjectFromUri = (uri: Uri, env?: Env) => { const connection = instance.getConnection(); - const configuration = instance.getConfig(); const qualifiedPath: { library: string | undefined, object: string | undefined } = { library: undefined, object: undefined }; - if (connection && configuration) { + if (connection) { + const configuration = connection.getConfig(); switch (uri.scheme) { case `member`: diff --git a/src/debug/server.ts b/src/debug/server.ts index 2098939c8..3968bcd31 100644 --- a/src/debug/server.ts +++ b/src/debug/server.ts @@ -117,7 +117,7 @@ export async function stopService(connection: IBMi) { export async function getDebugServiceJob() { const connection = instance.getConnection(); if (connection) { - const rows = await connection.runSQL(`select job_name, local_port from qsys2.netstat_job_info j where job_name = (select job_name from qsys2.netstat_job_info j where local_port = ${connection.config?.debugPort || 8005} and remote_address = '0.0.0.0' fetch first row only) and remote_address = '0.0.0.0'`); + const rows = await connection.runSQL(`select job_name, local_port from qsys2.netstat_job_info j where job_name = (select job_name from qsys2.netstat_job_info j where local_port = ${connection.getConfig().debugPort || 8005} and remote_address = '0.0.0.0' fetch first row only) and remote_address = '0.0.0.0'`); if (rows && rows.length) { return { name: String(rows[0].JOB_NAME), diff --git a/src/extension.ts b/src/extension.ts index 79a06c8f0..94c4596e1 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -77,7 +77,7 @@ export async function activate(context: ExtensionContext): Promise onCodeForIBMiConfigurationChange("connectionSettings", async () => { const connection = instance.getConnection(); if (connection) { - const config = instance.getConfig(); + const config = connection.getConfig(); if (config) { Object.assign(config, (await IBMi.connectionManager.load(config.name))); } diff --git a/src/filesystems/ifsFs.ts b/src/filesystems/ifsFs.ts index 29f7379fc..0f25736e5 100644 --- a/src/filesystems/ifsFs.ts +++ b/src/filesystems/ifsFs.ts @@ -14,8 +14,9 @@ export class IFSFS implements vscode.FileSystemProvider { } async readFile(uri: vscode.Uri, retrying?: boolean): Promise { - const contentApi = instance.getContent(); - if (contentApi) { + const connection = instance.getConnection(); + if (connection) { + const contentApi = connection.getContent(); const fileContent = await contentApi.downloadStreamfileRaw(uri.path); return fileContent; } @@ -35,8 +36,9 @@ export class IFSFS implements vscode.FileSystemProvider { } async stat(uri: vscode.Uri): Promise { - const content = instance.getContent(); - if (content) { + const connnection = instance.getConnection(); + if (connnection) { + const content = connnection.getContent(); const path = uri.path; if (await content.testStreamFile(path, "e")) { const attributes = await content.getAttributes(path, "CREATE_TIME", "MODIFY_TIME", "DATA_SIZE", "OBJTYPE"); @@ -66,8 +68,9 @@ export class IFSFS implements vscode.FileSystemProvider { async writeFile(uri: vscode.Uri, content: Uint8Array, options: { readonly create: boolean; readonly overwrite: boolean; }) { const path = uri.path; - const contentApi = instance.getContent(); - if (contentApi) { + const connection = instance.getConnection(); + if (connection) { + const contentApi = connection.getContent(); if (!content.length) { //Coming from "Save as" this.savedAsFiles.add(path); await contentApi.createStreamFile(path); @@ -92,8 +95,9 @@ export class IFSFS implements vscode.FileSystemProvider { } async readDirectory(uri: vscode.Uri): Promise<[string, vscode.FileType][]> { - const content = instance.getContent(); - if (content) { + const connection = instance.getConnection(); + if (connection) { + const content = connection.getContent(); return (await content.getFileList(uri.path)).map(ifsFile => ([ifsFile.name, ifsFile.type === "directory" ? FileType.Directory : FileType.File])); } else { @@ -105,7 +109,7 @@ export class IFSFS implements vscode.FileSystemProvider { const connection = instance.getConnection(); if (connection) { const path = uri.path; - if (await connection.content.testStreamFile(path, "d")) { + if (await connection.getContent().testStreamFile(path, "d")) { throw FileSystemError.FileExists(uri); } else { diff --git a/src/filesystems/local/deployTools.ts b/src/filesystems/local/deployTools.ts index 070df5317..e8867d126 100644 --- a/src/filesystems/local/deployTools.ts +++ b/src/filesystems/local/deployTools.ts @@ -77,7 +77,7 @@ export namespace DeployTools { methods.push({ method: "all" as DeploymentMethod, label: `All`, description: `Every file in the local workspace` }); - const defaultDeploymentMethod = instance.getConfig()?.defaultDeploymentMethod as DeploymentMethod + const defaultDeploymentMethod = instance.getConnection()?.getConfig().defaultDeploymentMethod as DeploymentMethod if (methods.find((element) => element.method === defaultDeploymentMethod)) { // default deploy method is usable method = defaultDeploymentMethod diff --git a/src/filesystems/local/deployment.ts b/src/filesystems/local/deployment.ts index 6cdabb5d1..0dc1190b2 100644 --- a/src/filesystems/local/deployment.ts +++ b/src/filesystems/local/deployment.ts @@ -9,6 +9,7 @@ import { Tools } from '../../api/Tools'; import { getLocalActions } from './actions'; import { DeployTools } from './deployTools'; import { DeploymentParameters } from '../../typings'; +import IBMiContent from '../../api/IBMiContent'; export namespace Deployment { export interface MD5Entry { @@ -52,10 +53,9 @@ export namespace Deployment { () => { const workspaces = vscode.workspace.workspaceFolders; const connection = instance.getConnection(); - const config = instance.getConfig(); const storage = instance.getStorage(); - if (workspaces && connection && storage && config) { + if (workspaces && connection && storage) { if (workspaces.length > 0) { button.show(); } @@ -111,12 +111,12 @@ export namespace Deployment { return connection; } - export function getContent() { - const content = instance.getContent(); - if (!content) { + export function getContent(): IBMiContent { + const connection = getConnection(); + if (!connection) { throw new Error("Please connect to an IBM i"); } - return content; + return connection.getContent(); } export async function createRemoteDirectory(remotePath: string) { @@ -223,7 +223,7 @@ export namespace Deployment { export async function sendCompressed(parameters: DeploymentParameters, files: vscode.Uri[], progress: vscode.Progress<{ message?: string }>) { const connection = getConnection(); const localTarball = tmp.fileSync({ postfix: ".tar" }); - const remoteTarball = path.posix.join(getConnection().config?.tempDir || '/tmp', `deploy_${Tools.makeid()}.tar`); + const remoteTarball = path.posix.join(getConnection().getConfig().tempDir || '/tmp', `deploy_${Tools.makeid()}.tar`); try { const toSend = files.map(file => path.relative(parameters.workspaceFolder.uri.fsPath, file.fsPath)); diff --git a/src/filesystems/local/git.ts b/src/filesystems/local/git.ts index 3680ac70d..231af2246 100644 --- a/src/filesystems/local/git.ts +++ b/src/filesystems/local/git.ts @@ -35,8 +35,8 @@ export function setupGitEventHandler(context: ExtensionContext) { if (currentBranch && currentBranch !== lastBranch[workspaceUri]) { if (connection) { - const content = instance.getContent()!; - const config = instance.getConfig()!; + const content = connection.getContent(); + const config = connection.getConfig(); if (currentBranch.includes(`/`)) { setupBranchLibrary(currentBranch, content, connection, config); diff --git a/src/filesystems/qsys/QSysFs.ts b/src/filesystems/qsys/QSysFs.ts index c34de3366..cbc3e1fc6 100644 --- a/src/filesystems/qsys/QSysFs.ts +++ b/src/filesystems/qsys/QSysFs.ts @@ -27,7 +27,7 @@ export function getUriFromPath(path: string, options?: QsysFsOptions) { export function getFilePermission(uri: vscode.Uri): FilePermission | undefined { const fsOptions = parseFSOptions(uri); - if (instance.getConfig()?.readOnlyMode || fsOptions.readonly) { + if (instance.getConnection()?.getConfig().readOnlyMode || fsOptions.readonly) { return FilePermission.Readonly; } } @@ -40,7 +40,7 @@ export function parseFSOptions(uri: vscode.Uri): QsysFsOptions { } export function isProtectedFilter(filter?: string): boolean { - return filter && instance.getConfig()?.objectFilters.find(f => f.name === filter)?.protected || false; + return filter && instance.getConnection()?.getConfig().objectFilters.find(f => f.name === filter)?.protected || false; } export class QSysFS implements vscode.FileSystemProvider { @@ -140,9 +140,9 @@ export class QSysFS implements vscode.FileSystemProvider { } async readFile(uri: vscode.Uri, retrying?: boolean): Promise { - const contentApi = instance.getContent(); const connection = instance.getConnection(); - if (connection && contentApi) { + if (connection) { + const contentApi = connection.getContent(); let { asp, library, file, name: member } = this.parseMemberPath(connection, uri.path); asp = asp || await connection.lookupLibraryIAsp(library); @@ -178,9 +178,9 @@ export class QSysFS implements vscode.FileSystemProvider { async writeFile(uri: vscode.Uri, content: Uint8Array, options: { readonly create: boolean; readonly overwrite: boolean; }) { const path = uri.path; - const contentApi = instance.getContent(); const connection = instance.getConnection(); - if (connection && contentApi) { + if (connection) { + const contentApi = connection.getContent(); let { asp, library, file, name: member, extension } = this.parseMemberPath(connection, uri.path); asp = asp || await connection.lookupLibraryIAsp(library); @@ -241,7 +241,7 @@ export class QSysFS implements vscode.FileSystemProvider { const connection = instance.getConnection(); if (connection) { const qsysPath = Tools.parseQSysPath(uri.path); - if (qsysPath.library && !await connection.content.checkObject({ library: "QSYS", name: qsysPath.library, type: "*LIB" })) { + if (qsysPath.library && !await connection.getContent().checkObject({ library: "QSYS", name: qsysPath.library, type: "*LIB" })) { const createLibrary = await connection.runCommand({ command: `CRTLIB LIB(${qsysPath.library})`, noLibList: true diff --git a/src/filesystems/qsys/extendedContent.ts b/src/filesystems/qsys/extendedContent.ts index de9b3ad62..84424d9a8 100644 --- a/src/filesystems/qsys/extendedContent.ts +++ b/src/filesystems/qsys/extendedContent.ts @@ -22,16 +22,16 @@ export class ExtendedIBMiContent { * @param {vscode.Uri} uri */ async downloadMemberContentWithDates(uri: vscode.Uri) { - const content = instance.getContent(); - const config = instance.getConfig(); const connection = instance.getConnection(); - if (connection && config && content) { + if (connection) { + const content = connection.getContent(); + const config = connection.getConfig(); const tempLib = config.tempLibrary; const alias = getAliasName(uri); const aliasPath = `${tempLib}.${alias}`; const { library, file, name } = connection.parserMemberPath(uri.path); try { - await content.runSQL(`CREATE OR REPLACE ALIAS ${aliasPath} for "${library}"."${file}"("${name}")`); + await connection.runSQL(`CREATE OR REPLACE ALIAS ${aliasPath} for "${library}"."${file}"("${name}")`); } catch (e) { console.log(e); } @@ -73,15 +73,15 @@ export class ExtendedIBMiContent { * @param {string} spf */ private async getRecordLength(aliasPath: string, lib: string, spf: string): Promise { - const content = instance.getContent(); + const connection = instance.getConnection(); let recordLength: number = DEFAULT_RECORD_LENGTH; - if (content) { - const result = await content.runSQL(`select length(SRCDTA) as LENGTH from ${aliasPath} limit 1`); + if (connection) { + const result = await connection.runSQL(`select length(SRCDTA) as LENGTH from ${aliasPath} limit 1`); if (result.length > 0) { recordLength = Number(result[0].LENGTH); } else { - const result = await content.runSQL(`select row_length-12 as LENGTH + const result = await connection.runSQL(`select row_length-12 as LENGTH from QSYS2.SYSTABLES where SYSTEM_TABLE_SCHEMA = '${lib}' and SYSTEM_TABLE_NAME = '${spf}' limit 1`); @@ -101,8 +101,8 @@ export class ExtendedIBMiContent { */ async uploadMemberContentWithDates(uri: vscode.Uri, body: string) { const connection = instance.getConnection(); - const config = instance.getConfig(); - if (connection && config) { + if (connection) { + const config = connection.getConfig(); const setccsid = connection.remoteFeatures.setccsid; const tempLib = config.tempLibrary; diff --git a/src/sandbox.ts b/src/sandbox.ts index 32c716fa9..68eef53fc 100644 --- a/src/sandbox.ts +++ b/src/sandbox.ts @@ -170,8 +170,9 @@ export async function handleStartup() { } async function initialSetup(username: string) { - const config = instance.getConfig(); - if (config) { + const connection = instance.getConnection(); + if (connection) { + const config = connection.getConfig(); const libraryList = config.libraryList; if (!libraryList.includes(username)) { config.libraryList = [...config.libraryList, username]; diff --git a/src/testing/action.ts b/src/testing/action.ts index bf4534012..fc5ca379f 100644 --- a/src/testing/action.ts +++ b/src/testing/action.ts @@ -35,12 +35,12 @@ export const ActionSuite: TestSuite = { name: `Action tests`, notConcurrent: true, before: async () => { - const config = instance.getConfig(); const storage = instance.getStorage(); - const connection = instance.getConnection(); + const connection = instance.getConnection()!; + const config = connection.getConfig(); const workspaceFolder = vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0] : undefined; - const tempDir = instance.getConfig()?.tempDir; + const tempDir = config.tempDir; assert.ok(workspaceFolder, "No workspace folder to work with"); assert.ok(tempDir, "Cannot run deploy tools tests: no remote temp directory defined"); @@ -116,9 +116,9 @@ export const ActionSuite: TestSuite = { }, { name: `Create Bound RPG Program (from member, custom action)`, test: async () => { - const config = instance.getConfig(); - const content = instance.getContent(); - const connection = instance.getConnection(); + const connection = instance.getConnection()!; + const config = connection.getConfig(); + const content = connection.getContent(); const tempLib = config!.tempLibrary; await connection!.runCommand({ command: `ADDPFM FILE(${tempLib}/QRPGLESRC) MBR(HELLO) SRCTYPE(RPGLE)` }); @@ -140,9 +140,9 @@ export const ActionSuite: TestSuite = { { name: `Create Bound RPG Program failure (from member, custom action)`, test: async () => { - const config = instance.getConfig(); - const content = instance.getContent(); - const connection = instance.getConnection(); + const connection = instance.getConnection()!; + const config = connection.getConfig(); + const content = connection.getContent(); const tempLib = config!.tempLibrary; await connection!.runCommand({ command: `ADDPFM FILE(${tempLib}/QRPGLESRC) MBR(THEBADONE) SRCTYPE(RPGLE)` }); @@ -173,7 +173,7 @@ async function testHelloWorldProgram(uri: vscode.Uri, action: Action, library: s const toJSON = (obj: Object) => JSON.stringify(obj, (key, value) => { if (keysToCompare.includes(key)) { return value } }); - const content = instance.getContent(); + const content = instance.getConnection()?.getContent(); const helloWorldProgram = (await content?.getObjectList({ library: library, object: 'HELLO', types: ['*PGM'] }))![0]; assert.deepStrictEqual(toJSON(helloWorldProgram), toJSON({ library: library, diff --git a/src/testing/content.ts b/src/testing/content.ts index c79e96608..c43d37b63 100644 --- a/src/testing/content.ts +++ b/src/testing/content.ts @@ -11,7 +11,7 @@ export const ContentSuite: TestSuite = { tests: [ { name: `Test downloadMemberContent`, test: async () => { - const content = instance.getContent(); + const content = instance.getConnection()?.getContent(); const tmpFile = await util.promisify(tmp.file)(); const memberContent = await content?.downloadMemberContent('QSYSINC', 'H', 'MATH', tmpFile); @@ -30,8 +30,8 @@ export const ContentSuite: TestSuite = { `}` ].join(`\n`); - const connection = instance.getConnection(); - const config = instance.getConfig()!; + const connection = instance.getConnection()!; + const config = connection.getConfig(); assert.ok(config.enableSourceDates, `Source dates must be enabled for this test.`); diff --git a/src/testing/deployTools.ts b/src/testing/deployTools.ts index 11307f57e..1db4f262e 100644 --- a/src/testing/deployTools.ts +++ b/src/testing/deployTools.ts @@ -90,7 +90,7 @@ export const DeployToolsSuite: TestSuite = { assert.ok(features?.md5sum, "md5sum is required to run deploy tools test suite"); const workspaceFolder = vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0] : undefined; - const tempDir = instance.getConfig()?.tempDir; + const tempDir = instance.getConnection()?.getConfig().tempDir; assert.ok(workspaceFolder, "No workspace folder to work with"); assert.ok(tempDir, "Cannot run deploy tools tests: no remote temp directory defined"); @@ -209,7 +209,7 @@ export const DeployToolsSuite: TestSuite = { await vscode.workspace.fs.delete(fakeProject.localPath, { recursive: true, useTrash: false }); } - if (fakeProject.remotePath && await instance.getContent()?.isDirectory(fakeProject.remotePath)) { + if (fakeProject.remotePath && await instance.getConnection()?.getContent().isDirectory(fakeProject.remotePath)) { await instance.getConnection()?.sendCommand({ command: `rm -rf ${fakeProject.remotePath}` }) } }, diff --git a/src/testing/encoding.ts b/src/testing/encoding.ts index d6786aede..9860993c5 100644 --- a/src/testing/encoding.ts +++ b/src/testing/encoding.ts @@ -23,13 +23,13 @@ const rtlEncodings = [`420`]; async function runCommandsWithCCSID(connection: IBMi, commands: string[], ccsid: number) { const testPgmSrcFile = `TESTING`; - const config = connection.config!; + const config = connection.getConfig(); const tempLib = config.tempLibrary; const testPgmName = `T${commands.length}${ccsid}`; const sourceFileCreated = await connection!.runCommand({ command: `CRTSRCPF FILE(${tempLib}/${testPgmSrcFile}) RCDLEN(112) CCSID(${ccsid})`, noLibList: true }); - await connection.content.uploadMemberContent(tempLib, testPgmSrcFile, testPgmName, commands.join(`\n`)); + await connection.getContent().uploadMemberContent(tempLib, testPgmSrcFile, testPgmName, commands.join(`\n`)); const compileCommand = `CRTBNDCL PGM(${tempLib}/${testPgmName}) SRCFILE(${tempLib}/${testPgmSrcFile}) SRCMBR(${testPgmName}) REPLACE(*YES)`; const compileResult = await connection.runCommand({ command: compileCommand, noLibList: true }); @@ -47,7 +47,7 @@ async function runCommandsWithCCSID(connection: IBMi, commands: string[], ccsid: export const EncodingSuite: TestSuite = { name: `Encoding tests`, before: async () => { - const config = instance.getConfig(); + const config = instance.getConnection()?.getConfig(); if (config) { assert.ok(config.enableSourceDates, `Source dates must be enabled for this test.`); } @@ -65,13 +65,13 @@ export const EncodingSuite: TestSuite = { const nameWithSpace = path.posix.join(dirWithSpace, fileName); await connection.sendCommand({command: `mkdir -p "${dirWithSpace}"`}); - await connection.content.createStreamFile(nameWithSpace); + await connection.getContent().createStreamFile(nameWithSpace); // Resolve and get attributes - const resolved = await connection.content.streamfileResolve([fileName], [tempDir, dirWithSpace]); + const resolved = await connection.getContent().streamfileResolve([fileName], [tempDir, dirWithSpace]); assert.strictEqual(resolved, nameWithSpace); - const attributes = await connection.content.getAttributes(resolved, `CCSID`); + const attributes = await connection.getContent().getAttributes(resolved, `CCSID`); assert.ok(attributes); // Write and read the files @@ -82,11 +82,11 @@ export const EncodingSuite: TestSuite = { assert.ok(streamfileContents.toString().includes(`Hello world`)); // List files - const files = await connection.content.getFileList(tempDir); + const files = await connection.getContent().getFileList(tempDir); assert.strictEqual(files.length, 1); assert.ok(files.some(f => f.name === dirName && f.path === dirWithSpace)); - const files2 = await connection.content.getFileList(dirWithSpace); + const files2 = await connection.getContent().getFileList(dirWithSpace); assert.strictEqual(files2.length, 1); assert.ok(files2.some(f => f.name === fileName && f.path === nameWithSpace)); }); @@ -101,12 +101,12 @@ export const EncodingSuite: TestSuite = { await connection.withTempDirectory(async tempDir => { for (const name of nameCombos) { const tempFile = path.posix.join(tempDir, `${name}.txt`); - await connection.content.createStreamFile(tempFile); + await connection.getContent().createStreamFile(tempFile); - const resolved = await connection.content.streamfileResolve([tempFile], [`/`]); + const resolved = await connection.getContent().streamfileResolve([tempFile], [`/`]); assert.strictEqual(resolved, tempFile); - const attributes = await connection.content.getAttributes(resolved, `CCSID`); + const attributes = await connection.getContent().getAttributes(resolved, `CCSID`); assert.ok(attributes); const uri = Uri.from({scheme: `streamfile`, path: tempFile}); @@ -121,9 +121,9 @@ export const EncodingSuite: TestSuite = { })), ...SHELL_CHARS.map(char => ({ name: `Test members with shell character ${char}`, test: async () => { - const content = instance.getContent(); - const config = instance.getConfig(); const connection = instance.getConnection()!; + const content = connection.getContent(); + const config = connection.getConfig(); if (!connection.variantChars.local.includes(char)) { // This test will fail if $ is not a variant character, @@ -174,7 +174,7 @@ export const EncodingSuite: TestSuite = { name: `Variant character in source names and commands`, test: async () => { // CHGUSRPRF X CCSID(284) CNTRYID(ES) LANGID(ESP) const connection = instance.getConnection()!; - const config = instance.getConfig()!; + const config = connection.getConfig()!; const ccsidData = connection.getCcsids()!; @@ -193,7 +193,7 @@ export const EncodingSuite: TestSuite = { const addPf = await connection.runCommand({ command: `ADDPFM FILE(${tempLib}/${testFile}) MBR(${testMember}) SRCTYPE(TXT)`, noLibList: true }); assert.strictEqual(addPf.code, 0); - const attributes = await connection.content.getAttributes({ library: tempLib, name: testFile, member: testMember }, `CCSID`); + const attributes = await connection.getContent().getAttributes({ library: tempLib, name: testFile, member: testMember }, `CCSID`); assert.ok(attributes); assert.strictEqual(attributes[`CCSID`], String(ccsidData.userDefaultCCSID)); @@ -202,29 +202,29 @@ export const EncodingSuite: TestSuite = { const addPfB = await connection.runCommand({ command: `ADDPFM FILE(${tempLib}/${testFile}) MBR(${variantMember}) SRCTYPE(TXT)`, noLibList: true }); assert.strictEqual(addPfB.code, 0); - const attributesB = await connection.content.getAttributes({ library: tempLib, name: testFile, member: variantMember }, `CCSID`); + const attributesB = await connection.getContent().getAttributes({ library: tempLib, name: testFile, member: variantMember }, `CCSID`); assert.ok(attributesB); assert.strictEqual(attributesB[`CCSID`], String(ccsidData.userDefaultCCSID)); /// ----- - const objects = await connection.content.getObjectList({ library: tempLib, types: [`*SRCPF`] }); + const objects = await connection.getContent().getObjectList({ library: tempLib, types: [`*SRCPF`] }); assert.ok(objects.length); assert.ok(objects.some(obj => obj.name === testFile)); - const members = await connection.content.getMemberList({ library: tempLib, sourceFile: testFile }); + const members = await connection.getContent().getMemberList({ library: tempLib, sourceFile: testFile }); assert.ok(members.length); assert.ok(members.some(m => m.name === testMember)); assert.ok(members.some(m => m.file === testFile)); - const smallFilter = await connection.content.getMemberList({ library: tempLib, sourceFile: testFile, members: `${varChar}*` }); + const smallFilter = await connection.getContent().getMemberList({ library: tempLib, sourceFile: testFile, members: `${varChar}*` }); assert.ok(smallFilter.length); - const files = await connection.content.getFileList(`/QSYS.LIB/${tempLib}.LIB/${connection.sysNameInAmerican(testFile)}.FILE`); + const files = await connection.getContent().getFileList(`/QSYS.LIB/${tempLib}.LIB/${connection.sysNameInAmerican(testFile)}.FILE`); assert.ok(files.length); assert.strictEqual(files[0].name, connection.sysNameInAmerican(testMember) + `.MBR`); - await connection.content.uploadMemberContent(tempLib, testFile, testMember, [`**free`, `dsply 'Hello world';`, ` `, ` `, `return;`].join(`\n`)); + await connection.getContent().uploadMemberContent(tempLib, testFile, testMember, [`**free`, `dsply 'Hello world';`, ` `, ` `, `return;`].join(`\n`)); const compileResult = await connection.runCommand({ command: `CRTBNDRPG PGM(${tempLib}/${testMember}) SRCFILE(${tempLib}/${testFile}) SRCMBR(${testMember})`, noLibList: true }); assert.strictEqual(compileResult.code, 0); @@ -248,8 +248,8 @@ export const EncodingSuite: TestSuite = { ...Object.keys(contents).map(ccsid => ({ name: `Encoding ${ccsid}`, test: async () => { - const connection = instance.getConnection(); - const config = instance.getConfig()!; + const connection = instance.getConnection()!; + const config = connection.getConfig(); const oldLines = contents[ccsid as keyof typeof contents]; const lines = oldLines.join(`\n`); diff --git a/src/testing/index.ts b/src/testing/index.ts index 97a9438ff..bf949ba33 100644 --- a/src/testing/index.ts +++ b/src/testing/index.ts @@ -125,7 +125,7 @@ async function setupUserFixture(connectionName: string, fixture: ConnectionFixtu const user = connection.currentUser; fixture.user.USRPRF = user.toUpperCase(); - const changeUserCommand = connection.content.toCl(`CHGUSRPRF`, fixture.user); + const changeUserCommand = connection.getContent().toCl(`CHGUSRPRF`, fixture.user); const changeResult = await connection.runCommand({ command: changeUserCommand }); if (changeResult.code > 0) { diff --git a/src/ui/Terminal.ts b/src/ui/Terminal.ts index 6f1f235b2..93e5defc2 100644 --- a/src/ui/Terminal.ts +++ b/src/ui/Terminal.ts @@ -55,7 +55,7 @@ export namespace Terminal { }), vscode.commands.registerCommand(`code-for-ibmi.openTerminalHere`, async (ifsNode) => { - const content = instance.getContent(); + const content = instance.getConnection()?.getContent(); if (content) { const ifsPath = (await content.isDirectory(ifsNode.path)) ? ifsNode.path : path.dirname(ifsNode.path); await selectAndOpen(context, { openType: TerminalType.PASE, currentDirectory: ifsPath }); @@ -74,8 +74,8 @@ export namespace Terminal { async function selectAndOpen(context: vscode.ExtensionContext, options?: { openType?: TerminalType, currentDirectory?: string }) { const connection = instance.getConnection(); - const configuration = instance.getConfig(); - if (connection && configuration) { + if (connection) { + const configuration = connection.getConfig(); const type = options?.openType || (await vscode.window.showQuickPick(typeItems, { placeHolder: `Select a terminal type` }))?.type; @@ -137,7 +137,7 @@ export namespace Terminal { let emulatorTerminal: vscode.Terminal | undefined; await new Promise((resolve) => { emulatorTerminal = vscode.window.createTerminal({ - name: `IBM i ${terminalSettings.type}: ${connection.config?.name}`, + name: `IBM i ${terminalSettings.type}: ${connection.getConfig().name}`, location: terminalSettings.location, pty: { onDidWrite: writeEmitter.event, diff --git a/src/ui/connection.ts b/src/ui/connection.ts index b80cf0e70..54360ce5b 100644 --- a/src/ui/connection.ts +++ b/src/ui/connection.ts @@ -142,32 +142,30 @@ export async function handleConnectionResults(connection: IBMi, error: Connectio } else { try { - const content = connection.content; - if (content) { - const bashrcContent = (await content.downloadStreamfile(bashrcFile)).split("\n"); - let replaced = false; - bashrcContent.forEach((line, index) => { - if (!replaced) { - const pathRegex = /^((?:export )?PATH=)(.*)(?:)$/.exec(line); - if (pathRegex) { - bashrcContent[index] = `${pathRegex[1]}/QOpenSys/pkgs/bin:${pathRegex[2] - .replace("/QOpenSys/pkgs/bin", "") //Removes /QOpenSys/pkgs/bin wherever it is - .replace("::", ":")}:/QOpenSys/usr/bin:/usr/bin`; //Removes double : in case /QOpenSys/pkgs/bin wasn't at the end - replaced = true; - } - } - }); - + const content = connection.getContent(); + const bashrcContent = (await content.downloadStreamfileRaw(bashrcFile)).toString().split("\n"); + let replaced = false; + bashrcContent.forEach((line, index) => { if (!replaced) { - bashrcContent.push( - "", - "# Generated by Code for IBM i", - "export PATH=/QOpenSys/pkgs/bin:$PATH:/QOpenSys/usr/bin:/usr/bin" - ); + const pathRegex = /^((?:export )?PATH=)(.*)(?:)$/.exec(line); + if (pathRegex) { + bashrcContent[index] = `${pathRegex[1]}/QOpenSys/pkgs/bin:${pathRegex[2] + .replace("/QOpenSys/pkgs/bin", "") //Removes /QOpenSys/pkgs/bin wherever it is + .replace("::", ":")}:/QOpenSys/usr/bin:/usr/bin`; //Removes double : in case /QOpenSys/pkgs/bin wasn't at the end + replaced = true; + } } + }); - await content.writeStreamfile(bashrcFile, bashrcContent.join("\n")); + if (!replaced) { + bashrcContent.push( + "", + "# Generated by Code for IBM i", + "export PATH=/QOpenSys/pkgs/bin:$PATH:/QOpenSys/usr/bin:/usr/bin" + ); } + + await content.writeStreamfileRaw(bashrcFile, bashrcContent.join("\n"), `utf8`); } catch (error) { window.showWarningMessage(`Error modifying PATH in ${bashrcFile}):\n${error}.\n\n Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: true }); diff --git a/src/ui/diagnostics.ts b/src/ui/diagnostics.ts index aa6b3e6e1..2a04a6b81 100644 --- a/src/ui/diagnostics.ts +++ b/src/ui/diagnostics.ts @@ -58,9 +58,10 @@ export function clearDiagnostic(uri: vscode.Uri, changeRange: vscode.Range) { } export async function refreshDiagnosticsFromServer(instance: Instance, evfeventInfo: EvfEventInfo) { - const content = instance.getContent(); + const connection = instance.getConnection(); - if (content) { + if (connection) { + const content = connection.getContent(); const tableData = await content.getTable(evfeventInfo.library, `EVFEVENT`, evfeventInfo.object); const lines = tableData.map(row => String(row.EVFEVENT)); @@ -101,8 +102,8 @@ export async function refreshDiagnosticsFromLocal(instance: Instance, evfeventIn } export function handleEvfeventLines(lines: string[], instance: Instance, evfeventInfo: EvfEventInfo) { - const connection = instance.getConnection(); - const config = instance.getConfig(); + const connection = instance.getConnection()!; + const config = connection.getConfig(); const asp = evfeventInfo.asp ? `${evfeventInfo.asp}/` : ``; const errorsByFiles = parseErrors(lines); diff --git a/src/ui/views/LibraryListView.ts b/src/ui/views/LibraryListView.ts index f37b582c5..56ac80a95 100644 --- a/src/ui/views/LibraryListView.ts +++ b/src/ui/views/LibraryListView.ts @@ -20,9 +20,9 @@ export class LibraryListProvider implements vscode.TreeDataProvider { const connection = instance.getConnection(); - const config = instance.getConfig(); const storage = instance.getStorage(); - if (connection && storage && config) { + if (connection && storage) { + const config = connection.getConfig(); const currentLibrary = connection.upperCaseName(config.currentLibrary); let prevCurLibs = storage.getPreviousCurLibs(); let list = [...prevCurLibs]; @@ -77,9 +77,9 @@ export class LibraryListProvider implements vscode.TreeDataProvider { const connection = instance.getConnection(); - const content = instance.getContent(); - const config = instance.getConfig(); - if (connection && content && config) { + if (connection) { + const content = connection.getContent(); + const config = connection.getConfig(); const libraryList = config.libraryList; const newLibraryListStr = await vscode.window.showInputBox({ @@ -118,10 +118,10 @@ export class LibraryListProvider implements vscode.TreeDataProvider { - const content = instance.getContent(); - const config = instance.getConfig(); const connection = instance.getConnection(); - if (content && config && connection) { + if (connection) { + const content = connection.getContent(); + const config = connection.getConfig(); const addingLib = connection.upperCaseName(newLibrary.library); if (addingLib.length > 10) { @@ -162,8 +162,8 @@ export class LibraryListProvider implements vscode.TreeDataProvider connection.upperCaseName(library) === node.library) @@ -182,9 +182,9 @@ export class LibraryListProvider implements vscode.TreeDataProvider { if (node) { //Running from right click - const config = instance.getConfig(); const connection = instance.getConnection(); - if (connection && config) { + if (connection) { + const config = connection.getConfig(); const libraryList = config.libraryList; const index = libraryList.findIndex(library => connection.upperCaseName(library) === node.library); @@ -203,9 +203,9 @@ export class LibraryListProvider implements vscode.TreeDataProvider { if (node) { //Running from right click - const config = instance.getConfig(); const connection = instance.getConnection(); - if (connection && config) { + if (connection) { + const config = connection.getConfig(); const libraryList = config.libraryList; const index = libraryList.findIndex(library => connection.upperCaseName(library) === node.library); if (index >= 0 && (index + 1) >= 0) { @@ -221,9 +221,10 @@ export class LibraryListProvider implements vscode.TreeDataProvider { - const content = instance.getContent(); - const config = instance.getConfig(); - if (config && content) { + const connection = instance.getConnection(); + if (connection) { + const content = connection.getContent(); + const config = connection.getConfig(); let libraryList = [...config.libraryList]; const badLibs = await content.validateLibraryList(libraryList); @@ -241,11 +242,11 @@ export class LibraryListProvider implements vscode.TreeDataProvider { const library = node.library; if (library) { - const connection = instance.getConnection(); - const content = instance.getContent(); - const config = instance.getConfig(); + const connection = instance.getConnection() const storage = instance.getStorage(); - if (connection && config && content && storage) { + + if (connection && storage) { + const content = connection.getContent(); if (await content.checkObject({ library: "QSYS", name: library, type: "*LIB" })) { await changeCurrentLibrary(library); this.refresh(); @@ -275,18 +276,15 @@ export class LibraryListProvider implements vscode.TreeDataProvider { - return new LibraryListNode(connection.upperCaseName(lib.name), lib, (index === 0 ? `currentLibrary` : `library`), config.showDescInLibList); - })); - } + const content = connection.getContent(); + const config = connection.getConfig(); + const currentLibrary = connection.upperCaseName(config.currentLibrary); + + const libraries = await content.getLibraryList([currentLibrary, ...config.libraryList]); + + items.push(...libraries.map((lib, index) => { + return new LibraryListNode(connection.upperCaseName(lib.name), lib, (index === 0 ? `currentLibrary` : `library`), config.showDescInLibList); + })); } return items; } @@ -307,9 +305,9 @@ class LibraryListNode extends vscode.TreeItem implements WithLibrary { async function changeCurrentLibrary(library: string) { const connection = instance.getConnection(); - const config = instance.getConfig(); const storage = instance.getStorage(); - if (connection && config && storage) { + if (connection && storage) { + const config = connection.getConfig(); const commandResult = await connection.runCommand({ command: `CHGCURLIB ${library}`, noLibList: true }); if (commandResult.code === 0) { const currentLibrary = connection.upperCaseName(config.currentLibrary); diff --git a/src/ui/views/ProfilesView.ts b/src/ui/views/ProfilesView.ts index 9df61bc31..da721961d 100644 --- a/src/ui/views/ProfilesView.ts +++ b/src/ui/views/ProfilesView.ts @@ -22,9 +22,10 @@ export class ProfilesView { }), vscode.commands.registerCommand(`code-for-ibmi.saveConnectionProfile`, async (profileNode?: Profile) => { - const config = instance.getConfig(); + const connection = instance.getConnection(); const storage = instance.getStorage(); - if (config && storage) { + if (connection && storage) { + const config = connection.getConfig(); const currentProfile = storage.getLastProfile() || ''; let currentProfiles = config.connectionProfiles; @@ -54,8 +55,9 @@ export class ProfilesView { }), vscode.commands.registerCommand(`code-for-ibmi.deleteConnectionProfile`, async (profileNode?: Profile) => { - const config = instance.getConfig(); - if (config) { + const connection = instance.getConnection(); + if (connection) { + const config = connection.getConfig(); const currentProfiles = config.connectionProfiles; const chosenProfile = await getOrPickAvailableProfile(currentProfiles, profileNode); if (chosenProfile) { @@ -73,9 +75,10 @@ export class ProfilesView { }), vscode.commands.registerCommand(`code-for-ibmi.loadConnectionProfile`, async (profileNode?: Profile) => { - const config = instance.getConfig(); + const connection = instance.getConnection(); const storage = instance.getStorage(); - if (config && storage) { + if (connection && storage) { + const config = connection.getConfig(); const chosenProfile = await getOrPickAvailableProfile(config.connectionProfiles, profileNode); if (chosenProfile) { assignProfile(chosenProfile, config); @@ -99,8 +102,9 @@ export class ProfilesView { }), vscode.commands.registerCommand(`code-for-ibmi.deleteCommandProfile`, async (commandProfile?: CommandProfileItem) => { - const config = instance.getConfig(); - if (config && commandProfile) { + const connection = instance.getConnection(); + if (connection && commandProfile) { + const config = connection.getConfig(); const storedProfile = config.commandProfiles.findIndex(profile => profile.name === commandProfile.profile); if (storedProfile !== undefined) { config.commandProfiles.splice(storedProfile, 1); @@ -113,9 +117,9 @@ export class ProfilesView { vscode.commands.registerCommand(`code-for-ibmi.loadCommandProfile`, async (commandProfile?: CommandProfileItem) => { const connection = instance.getConnection(); - const config = instance.getConfig(); const storage = instance.getStorage(); - if (commandProfile && connection && config && storage) { + if (commandProfile && connection && storage) { + const config = connection.getConfig(); const storedProfile = config.commandProfiles.find(profile => profile.name === commandProfile.profile); if (storedProfile) { @@ -148,10 +152,10 @@ export class ProfilesView { vscode.commands.registerCommand(`code-for-ibmi.setToDefault`, () => { const connection = instance.getConnection(); - const config = instance.getConfig(); const storage = instance.getStorage(); - if (config && storage) { + if (connection && storage) { + const config = connection.getConfig(); window.showInformationMessage(l10n.t(`Reset to default`), { detail: l10n.t(`This will reset the User Library List, working directory and Custom Variables back to the defaults.`), modal: true @@ -186,7 +190,7 @@ export class ProfilesView { } refresh() { - const config = instance.getConfig(); + const config = instance.getConnection()?.getConfig(); if (config) { vscode.commands.executeCommand(`setContext`, `code-for-ibmi:hasProfiles`, config.connectionProfiles.length > 0 || config.commandProfiles.length > 0); this._onDidChangeTreeData.fire(null); @@ -201,7 +205,7 @@ export class ProfilesView { const connection = instance.getConnection(); if (connection) { - const config = instance.getConfig(); + const config = connection.getConfig(); const storage = instance.getStorage(); if (config && storage) { const currentProfile = storage.getLastProfile(); diff --git a/src/ui/views/helpView.ts b/src/ui/views/helpView.ts index 24239bcac..595047fea 100644 --- a/src/ui/views/helpView.ts +++ b/src/ui/views/helpView.ts @@ -245,9 +245,9 @@ function getExtensions(active: boolean) { async function getRemoteSection() { const connection = instance.getConnection(); - const config = instance.getConfig(); - const content = instance.getContent(); - if (connection && config && content) { + if (connection) { + const config = connection.getConfig(); + return await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: `Gathering issue details...`, @@ -257,7 +257,7 @@ async function getRemoteSection() { TR: "n/a" }; try { - const [osVersionRow] = await content.runSQL( + const [osVersionRow] = await connection.runSQL( `SELECT PTF_GROUP_TARGET_RELEASE as OS, PTF_GROUP_LEVEL AS TR ` + `FROM QSYS2.GROUP_PTF_INFO ` + `WHERE PTF_GROUP_DESCRIPTION = 'TECHNOLOGY REFRESH' AND PTF_GROUP_STATUS = 'INSTALLED' ` + @@ -269,7 +269,7 @@ async function getRemoteSection() { catch (error) { console.log(`Couldn't run QSYS2.GROUP_PTF_INFO: ${error}`); try { - const [osVersionRow] = await content.runSQL(`Select Substring(DATA_AREA_VALUE, 0, 7) as OS ` + + const [osVersionRow] = await connection.runSQL(`Select Substring(DATA_AREA_VALUE, 0, 7) as OS ` + `From TABLE(QSYS2.DATA_AREA_INFO(` + `DATA_AREA_NAME => 'QSS1MRI',` + `DATA_AREA_LIBRARY => 'QUSRSYS'))` + diff --git a/src/ui/views/ifsBrowser.ts b/src/ui/views/ifsBrowser.ts index c79661564..c38b520f2 100644 --- a/src/ui/views/ifsBrowser.ts +++ b/src/ui/views/ifsBrowser.ts @@ -21,7 +21,7 @@ type DragNDropBehavior = DragNDropAction | "ask"; const getDragDropBehavior = () => IBMi.connectionManager.get(`IfsBrowser.DragAndDropDefaultBehavior`) || "ask"; function isProtected(path: string) { - return PROTECTED_DIRS.test(path) || instance.getContent()?.isProtectedPath(path); + return PROTECTED_DIRS.test(path) || instance.getConnection()?.getContent().isProtectedPath(path); } function alwaysShow(name: string) { @@ -45,7 +45,7 @@ class IFSBrowser implements vscode.TreeDataProvider { } getShortCuts() { - return instance.getConfig()?.ifsShortcuts.map(directory => new IFSShortcutItem(directory)) || []; + return instance.getConnection()?.getConfig().ifsShortcuts.map(directory => new IFSShortcutItem(directory)) || []; } getParent(item: BrowserItem) { @@ -53,8 +53,9 @@ class IFSBrowser implements vscode.TreeDataProvider { } async moveShortcut(shortcut: IFSShortcutItem, direction: "top" | "up" | "down" | "bottom") { - const config = instance.getConfig(); - if (config) { + const connection = instance.getConnection(); + if (connection) { + const config = connection.getConfig(); const shortcuts = config.ifsShortcuts; const moveDir = shortcut?.path?.trim(); @@ -156,10 +157,12 @@ class IFSDirectoryItem extends IFSItem { } async getChildren(): Promise { - const content = instance.getContent(); - if (content) { + const connection = instance.getConnection(); + if (connection) {; + const content = connection.getContent(); + const config = connection.getConfig(); try { - const showHidden = instance.getConfig()?.showHiddenFiles; + const showHidden = config.showHiddenFiles; const filterIFSFile = (file: IFSFile, type: "directory" | "streamfile") => file.type === type && (showHidden || !file.name.startsWith(`.`) || alwaysShow(file.name)); const objects = await content.getFileList(this.path, this.sort, handleFileListErrors); const directories = objects.filter(f => filterIFSFile(f, "directory")); @@ -322,8 +325,9 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { vscode.commands.registerCommand(`code-for-ibmi.sortIFSFilesByDate`, (item: IFSItem) => item.sortBy({ order: "date" })), vscode.commands.registerCommand(`code-for-ibmi.changeWorkingDirectory`, async (node?: IFSDirectoryItem) => { - const config = instance.getConfig(); - if (config) { + const connection = instance.getConnection(); + if (connection) { + const config = connection.getConfig(); const homeDirectory = config.homeDirectory; const newDirectory = node?.path || await vscode.window.showInputBox({ @@ -344,9 +348,10 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { }), vscode.commands.registerCommand(`code-for-ibmi.addIFSShortcut`, async (node?: IFSDirectoryItem) => { - const config = instance.getConfig(); - const content = instance.getContent(); - if (config && content) { + const connection = instance.getConnection(); + if (connection) { + const config = connection.getConfig(); + const content = connection.getContent(); const newDirectory = (await vscode.window.showInputBox({ prompt: l10n.t(`Path to IFS directory`), value: node ? node.path : undefined @@ -376,8 +381,9 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { }), vscode.commands.registerCommand(`code-for-ibmi.removeIFSShortcut`, async (node: IFSShortcutItem) => { - const config = instance.getConfig(); - if (config) { + const connection = instance.getConnection(); + if (connection) { + const config = connection.getConfig(); const shortcuts = config.ifsShortcuts; const removeDir = (node.path || (await vscode.window.showQuickPick(shortcuts, { placeHolder: l10n.t(`Select IFS shortcut to remove`), @@ -402,7 +408,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { }), vscode.commands.registerCommand(`code-for-ibmi.sortIFSShortcuts`, async () => { - const config = instance.getConfig(); + const config = instance.getConnection()?.getConfig(); if (config) { try { @@ -424,8 +430,8 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { vscode.commands.registerCommand(`code-for-ibmi.createDirectory`, async (node?: IFSDirectoryItem) => { const connection = instance.getConnection(); - const config = instance.getConfig(); - if (connection && config) { + if (connection) { + const config = connection.getConfig(); const value = `${node?.path || config.homeDirectory}/`; const selectStart = value.length + 1; const fullName = await vscode.window.showInputBox({ @@ -450,9 +456,10 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { }), vscode.commands.registerCommand(`code-for-ibmi.createStreamfile`, async (node?: IFSDirectoryItem) => { - const config = instance.getConfig(); - const content = instance.getContent(); - if (config && content) { + const connection = instance.getConnection(); + if (connection) { + const config = connection.getConfig(); + const content = connection.getContent(); const value = `${node?.path || config.homeDirectory}/`; const selectStart = value.length + 1; const fullName = await vscode.window.showInputBox({ @@ -481,9 +488,9 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { vscode.commands.registerCommand(`code-for-ibmi.uploadStreamfile`, async (node: IFSDirectoryItem, files?: vscode.Uri[]) => { const connection = instance.getConnection(); - const config = instance.getConfig(); - if (config && connection) { + if (connection) { + const config = connection.getConfig(); const root = node?.path || config.homeDirectory; const chosenFiles = files || await showOpenDialog(); @@ -541,8 +548,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { vscode.commands.registerCommand(`code-for-ibmi.deleteIFS`, async (singleItem: IFSItem, items?: IFSItem[]) => { const connection = instance.getConnection(); - const config = instance.getConfig(); - if (connection && config) { + if (connection) { if (items || singleItem) { items = (items || [singleItem]).filter(reduceIFSPath); } @@ -636,8 +642,8 @@ Please type "{0}" to confirm deletion.`, dirName); } } const connection = instance.getConnection(); - const config = instance.getConfig(); - if (config && connection) { + if (connection) { + const config = connection.getConfig(); const homeDirectory = config.homeDirectory; const target = await vscode.window.showInputBox({ prompt: l10n.t(`Name of new path`), @@ -684,10 +690,10 @@ Please type "{0}" to confirm deletion.`, dirName); } }), vscode.commands.registerCommand(`code-for-ibmi.copyIFS`, async (node: IFSItem) => { - const config = instance.getConfig(); const connection = instance.getConnection(); - if (config && connection) { + if (connection) { + const config = connection.getConfig(); const homeDirectory = config.homeDirectory; const target = await vscode.window.showInputBox({ prompt: l10n.t(`Name of new path`), @@ -714,9 +720,9 @@ Please type "{0}" to confirm deletion.`, dirName); vscode.commands.registerCommand(`code-for-ibmi.searchIFS`, async (node?: IFSItem) => { const connection = instance.getConnection(); - const config = instance.getConfig(); - if (connection?.remoteFeatures.grep && config) { + if (connection && connection.remoteFeatures.grep) { + const config = connection.getConfig(); const searchPath = node?.path || await vscode.window.showInputBox({ value: config.homeDirectory, prompt: l10n.t(`Enter IFS directory to search`), @@ -774,9 +780,9 @@ Please type "{0}" to confirm deletion.`, dirName); vscode.commands.registerCommand(`code-for-ibmi.ifs.find`, async (node?: IFSItem) => { const connection = instance.getConnection(); - const config = instance.getConfig(); - if (connection?.remoteFeatures.find && config) { + if (connection && connection.remoteFeatures.find) { + const config = connection.getConfig(); const findPath = node?.path || await vscode.window.showInputBox({ value: config.homeDirectory, prompt: l10n.t(`Enter IFS directory to find files in`), @@ -914,7 +920,7 @@ Do you want to replace it?`, target))) { } vscode.commands.registerCommand(`code-for-ibmi.ifs.toggleShowHiddenFiles`, async function () { - const config = instance.getConfig(); + const config = instance.getConnection()?.getConfig(); if (config) { config.showHiddenFiles = !config.showHiddenFiles; await IBMi.connectionManager.update(config); diff --git a/src/ui/views/objectBrowser.ts b/src/ui/views/objectBrowser.ts index 45c9dd79d..2012e9029 100644 --- a/src/ui/views/objectBrowser.ts +++ b/src/ui/views/objectBrowser.ts @@ -1330,7 +1330,7 @@ Do you want to replace it?`, item.name), { modal: true }, skipAllLabel, overwrit } function getConfig() { - const config = instance.getConfig(); + const config = instance.getConnection()?.getConfig(); if (config) { return config; } @@ -1350,7 +1350,7 @@ function getConnection() { } function getContent() { - const content = instance.getContent(); + const content = instance.getConnection()?.getContent(); if (content) { return content; }