From 8849ef7d723b6611303b799f0527f7a7604560c0 Mon Sep 17 00:00:00 2001 From: gjsjohnmurray Date: Thu, 6 Feb 2025 15:59:26 +0000 Subject: [PATCH 1/5] Support definitions that reference `intersystems.servers` entries --- connection.schema.json | 15 ++++- package-lock.json | 41 +++++++++----- package.json | 7 ++- src/extension.ts | 123 ++++++++++++++++++++++++++++++++++------- src/ls/driver.ts | 24 ++++---- 5 files changed, 158 insertions(+), 52 deletions(-) diff --git a/connection.schema.json b/connection.schema.json index 6b474d6..e1582c8 100644 --- a/connection.schema.json +++ b/connection.schema.json @@ -30,7 +30,7 @@ "title": "Connect using", "type": "string", "minLength": 1, - "enum": ["Server and Port"], + "enum": ["Server and Port", "Server Definition"], "default": "Server and Port" }, "showSystem": { @@ -83,6 +83,19 @@ "askForPassword": { "$ref": "#/definitions/askForPassword" } }, "required": ["server", "port", "username"] + }, + { + "properties": { + "connectionMethod": { + "enum": ["Server Definition"] + }, + "serverName": { + "title": "Server name", + "type": "string", + "minLength": 1 + } + }, + "required": ["serverName"] } ] }, diff --git a/package-lock.json b/package-lock.json index aac73d7..cc2e74b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "sqltools-intersystems-driver", - "version": "0.1.8-SNAPSHOT", + "version": "0.2.0-SNAPSHOT", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sqltools-intersystems-driver", - "version": "0.1.8-SNAPSHOT", + "version": "0.2.0-SNAPSHOT", "license": "MIT", "dependencies": { "@babel/core": "^7.14.3", @@ -20,8 +20,9 @@ }, "devDependencies": { "@babel/preset-env": "^7.14.2", + "@intersystems-community/intersystems-servermanager": "^3.8.0", "@types/node": "^14.17.0", - "@types/vscode": "^1.66.0", + "@types/vscode": "^1.93.0", "@vscode/vsce": "^2.19.0", "rimraf": "^3.0.2", "ts-loader": "^9.2.1", @@ -30,7 +31,7 @@ "webpack-cli": "^4.7.0" }, "engines": { - "vscode": "^1.66.0" + "vscode": "^1.93.0" } }, "node_modules/@ampproject/remapping": { @@ -1701,6 +1702,13 @@ "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.1.0.tgz", "integrity": "sha512-i1BpaNDVLJdRBEKeJWkVO6tYX6DMFBuwMhSuWqLsY4ufeTKGVuV5rBsUhxPayXqnnWHgXUAmWK16H/ykO5Wj4Q==" }, + "node_modules/@intersystems-community/intersystems-servermanager": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@intersystems-community/intersystems-servermanager/-/intersystems-servermanager-3.8.0.tgz", + "integrity": "sha512-D3/LoQXOsApLo07BLHipuibUYIQLz5MK57GWLtmtYIiNa2gJ0Igaz0Fv5SuZ+gdPL3tlN1g88iQ4vJ7E+arRiQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", @@ -1838,10 +1846,11 @@ "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==" }, "node_modules/@types/vscode": { - "version": "1.66.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.66.0.tgz", - "integrity": "sha512-ZfJck4M7nrGasfs4A4YbUoxis3Vu24cETw3DERsNYtDZmYSYtk6ljKexKFKhImO/ZmY6ZMsmegu2FPkXoUFImA==", - "dev": true + "version": "1.96.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.96.0.tgz", + "integrity": "sha512-qvZbSZo+K4ZYmmDuaodMbAa67Pl6VDQzLKFka6rq+3WUTY4Kro7Bwoi0CuZLO/wema0ygcmpwow7zZfPJTs5jg==", + "dev": true, + "license": "MIT" }, "node_modules/@vscode/vsce": { "version": "2.19.0", @@ -2604,10 +2613,11 @@ "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3653,12 +3663,13 @@ "dev": true }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { diff --git a/package.json b/package.json index 2ebb5b0..ab6629b 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,9 @@ "name": "sqltools-intersystems-driver", "displayName": "SQLTools InterSystems IRIS", "description": "SQLTools Driver for InterSystems IRIS", - "version": "0.1.8-SNAPSHOT", + "version": "0.2.0-SNAPSHOT", "engines": { - "vscode": "^1.66.0" + "vscode": "^1.93.0" }, "publisher": "intersystems-community", "license": "MIT", @@ -67,8 +67,9 @@ }, "devDependencies": { "@babel/preset-env": "^7.14.2", + "@intersystems-community/intersystems-servermanager": "^3.8.0", "@types/node": "^14.17.0", - "@types/vscode": "^1.66.0", + "@types/vscode": "^1.93.0", "@vscode/vsce": "^2.19.0", "rimraf": "^3.0.2", "ts-loader": "^9.2.1", diff --git a/src/extension.ts b/src/extension.ts index 8ed3627..71c54f1 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,6 +6,13 @@ const { publisher, name } = require('../package.json'); // import { workspace } from 'vscode'; // import { Uri } from 'vscode'; // import path from 'path'; +import * as serverManager from "@intersystems-community/intersystems-servermanager"; + +const smExtensionId = "intersystems-community.servermanager"; +let serverManagerApi: serverManager.ServerManagerAPI; + +/** Map of the intersystems.server connection specs we have resolved via the API to that extension */ +const resolvedConnSpecs = new Map(); const driverName = 'InterSystems IRIS Driver'; @@ -45,35 +52,113 @@ export async function activate(extContext: ExtensionContext): Promise { /** - * This hook is called before saving the connecton using the assistant - * so you can do any transformations before saving it to disk.active - * EG: relative file path transformation, string manipulation etc - * Below is the exmaple for SQLite, where we save the DB path relative to workspace - * and later we transform it back to absolute before editing + * This hook is called before saving the connection using the assistant + * so you can do any transformations before saving it */ - // if (path.isAbsolute(connInfo.database)) { - // const databaseUri = Uri.file(connInfo.database); - // const dbWorkspace = workspace.getWorkspaceFolder(databaseUri); - // if (dbWorkspace) { - // connInfo.database = `\$\{workspaceFolder:${dbWorkspace.name}\}/${workspace.asRelativePath(connInfo.database, false)}`; - // } - // } + if (connInfo.connectionMethod === 'Server Definition') { + // Transform to a connectString property + connInfo.connectString = `${connInfo.serverName}:${connInfo.namespace}`; + connInfo.serverName = undefined; + connInfo.namespace = undefined; + // Remove properties carried over from 'Server and Port' type connection + connInfo.server = undefined; + connInfo.port = undefined; + connInfo.pathPrefix = undefined; + connInfo.https = undefined; + connInfo.askForPassword = undefined; + connInfo.username = undefined; + connInfo.password = undefined; + + } return connInfo; }, parseBeforeEditConnection: ({ connInfo }) => { /** - * This hook is called before editing the connecton using the assistant + * This hook is called before editing the connection using the assistant * so you can do any transformations before editing it. * EG: absolute file path transformation, string manipulation etc * Below is the exmaple for SQLite, where we use relative path to save, * but we transform to asolute before editing */ - // if (!path.isAbsolute(connInfo.database) && /\$\{workspaceFolder:(.+)}/g.test(connInfo.database)) { - // const workspaceName = connInfo.database.match(/\$\{workspaceFolder:(.+)}/)[1]; - // const dbWorkspace = workspace.workspaceFolders.find(w => w.name === workspaceName); - // if (dbWorkspace) - // connInfo.database = path.resolve(dbWorkspace.uri.fsPath, connInfo.database.replace(/\$\{workspaceFolder:(.+)}/g, './')); - // } + if (connInfo.connectionMethod === 'Server Definition') { + const connParts = connInfo.connectString.split(':'); + connInfo.serverName = connParts[0]; + connInfo.namespace = connParts[1]; + } + return connInfo; + }, + resolveConnection: async ({ connInfo }) => { + /** + * This hook is called after a connection definition has been fetched + * from settings and is about to be used to connect. + */ + if (connInfo.connectionMethod === 'Server Definition') { + const connParts = connInfo.connectString.split(':'); + const serverName = connParts[0]; + const namespace = connParts[1]; + let connSpec = resolvedConnSpecs.get(serverName) + if (!connSpec) { + + if (!serverManagerApi) { + + // Get api for servermanager extension + const smExt = vscode.extensions.getExtension(smExtensionId); + if (!smExt) { + throw new Error("Server Manager extension not found"); + } + if (!smExt.isActive) await smExt.activate(); + serverManagerApi = smExt.exports; + } + connSpec = await serverManagerApi.getServerSpec(serverName); + if (!connSpec) { + throw new Error(`Failed to fetch definition of server '${serverName}'`) + } + const isUnauthenticated = (username?: string): boolean => { + return username && (username == "" || username.toLowerCase() == "unknownuser"); + } + const resolvePassword = async (serverSpec): Promise => { + if ( + // Connection isn't unauthenticated + (!isUnauthenticated(serverSpec.username)) && + // A password is missing + typeof serverSpec.password == "undefined" + ) { + const scopes = [serverSpec.name, serverSpec.username || ""]; + + // Handle Server Manager extension version < 3.8.0 + const account = serverManagerApi.getAccount ? serverManagerApi.getAccount(serverSpec) : undefined; + + let session = await vscode.authentication.getSession(serverManager.AUTHENTICATION_PROVIDER, scopes, { + silent: true, + account, + }); + if (!session) { + session = await vscode.authentication.getSession(serverManager.AUTHENTICATION_PROVIDER, scopes, { + createIfNone: true, + account, + }); + } + if (session) { + // If original spec lacked username use the one obtained by the authprovider + serverSpec.username = serverSpec.username || session.scopes[1]; + serverSpec.password = session.accessToken; + } + } + } + + await resolvePassword(connSpec); + resolvedConnSpecs.set(serverName, connSpec); + } + connInfo = { ...connInfo, + https: connSpec.webServer.scheme === 'https', + server: connSpec.webServer.host, + port: connSpec.webServer.port, + pathPrefix: connSpec.webServer.pathPrefix || '', + username: connSpec.username, + password: connSpec.password, + namespace, + } + } return connInfo; }, driverAliases: DRIVER_ALIASES, diff --git a/src/ls/driver.ts b/src/ls/driver.ts index bab4859..ba4d8be 100644 --- a/src/ls/driver.ts +++ b/src/ls/driver.ts @@ -25,20 +25,16 @@ export default class IRISDriver extends AbstractDriver im this.showSystem = this.credentials.showSystem || false; this.filter = this.credentials.filter || ""; - if (this.credentials.serverName) { - throw new Error("not supported"); - } else { - let { https, server: host, port, pathPrefix, username, password } = this.credentials; - config = { - https, - host, - port, - pathPrefix, - namespace, - username, - password - }; - } + let { https, server: host, port, pathPrefix, username, password } = this.credentials; + config = { + https, + host, + port, + pathPrefix, + namespace, + username, + password + }; const irisdb = new IRISdb(config); return irisdb.open() From 7ad5d114e32417147b375e02b60b7888254b6756 Mon Sep 17 00:00:00 2001 From: gjsjohnmurray Date: Thu, 6 Feb 2025 16:43:03 +0000 Subject: [PATCH 2/5] Try to fix CI --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3cc8239..3a7b75e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -58,12 +58,12 @@ jobs: if: runner.os == 'Linux' run: | npx vsce package -o ${{ steps.set-version.outputs.name }}.vsix - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 if: runner.os == 'Linux' with: name: ${{ steps.set-version.outputs.name }}.vsix path: ${{ steps.set-version.outputs.name }}.vsix - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 if: runner.os == 'Linux' with: name: meta From 9b2d82f04b033b738ed7e407e2e3c324d729bd80 Mon Sep 17 00:00:00 2001 From: gjsjohnmurray Date: Thu, 6 Feb 2025 17:02:14 +0000 Subject: [PATCH 3/5] Make new connection spec type the default --- connection.schema.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/connection.schema.json b/connection.schema.json index e1582c8..24b0622 100644 --- a/connection.schema.json +++ b/connection.schema.json @@ -30,8 +30,8 @@ "title": "Connect using", "type": "string", "minLength": 1, - "enum": ["Server and Port", "Server Definition"], - "default": "Server and Port" + "enum": ["Server Definition", "Server and Port"], + "default": "Server Definition" }, "showSystem": { "title": "Show system items?", @@ -75,7 +75,7 @@ "default": "" }, "https": { - "title": "Use HTTPS", + "title": "Use HTTPS?", "default": false, "type": "boolean" }, From 1b40457c24f0870baeeb9cb8d5da17660c51178f Mon Sep 17 00:00:00 2001 From: gjsjohnmurray Date: Thu, 6 Feb 2025 17:05:49 +0000 Subject: [PATCH 4/5] Update CHANGELOG and README --- CHANGELOG.md | 4 ++++ README.md | 12 ++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 420e6f2..1d5966e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,5 @@ # Change Log + +## [0.2.0] 05-Feb-2025 +- Enhancements + - Support use of Server Manager connection definitions (#60) diff --git a/README.md b/README.md index 3b92451..1316596 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,14 @@ Try out the [SQL QuickStart](https://gettingstarted.intersystems.com/language-qu - If you have no previous database connections, you will see an "Add new connection" button. Click that. ![Add connection button](https://raw.githubusercontent.com/intersystems-community/sqltools-intersystems-driver/master/docs/assets/img/addconnection.png) - If you already have other connections defined, you won't see the button. Instead, open the command palette (Ctrl/Cmd+Shift+P) and run "SQLTools Management: Add New Connection" ![Add connection from command palette](https://raw.githubusercontent.com/intersystems-community/sqltools-intersystems-driver/master/docs/assets/img/command_palette_add_new.png) -- Click InterSystems IRIS -- Fill out connection information -- Test the connection -- Save the connection +- Click InterSystems IRIS. +- Fill out connection information: + - Namespace to work in. + - Connect using: "Server Definition" or "Server and Port" + - For "Server Definition", provide in "Server name" the name of a server configured using the InterSystems Server Manager extension. These server specs are stored in the `intersystems.servers` settings object. + - For "Server and Port", provide (as applicable) "Webserver address", "Webserver port", "Path prefix (for shared webserver)", "Use HTTPS", "Username", "Ask for password?" and "Password". +- Test the connection. +- Save the connection. ## Use From 2e8cfdbd5fd2677d77b0e950a7b4992352631a3d Mon Sep 17 00:00:00 2001 From: gjsjohnmurray Date: Thu, 6 Feb 2025 17:12:17 +0000 Subject: [PATCH 5/5] Add description to "Server name" prompt --- connection.schema.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/connection.schema.json b/connection.schema.json index 24b0622..288526f 100644 --- a/connection.schema.json +++ b/connection.schema.json @@ -92,7 +92,8 @@ "serverName": { "title": "Server name", "type": "string", - "minLength": 1 + "minLength": 1, + "description": "Name of a server definition configured using InterSystems Server Manager" } }, "required": ["serverName"]