Skip to content

Commit 267b8e8

Browse files
committed
Merge branch 'main' into dev
Signed-off-by: worksofliam <[email protected]>
2 parents 3ed6969 + ecb20dc commit 267b8e8

File tree

4 files changed

+95
-43
lines changed

4 files changed

+95
-43
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"lint": "eslint .",
3737
"pretest": "npm run lint",
3838
"language:test": "vitest",
39-
"dsc": "mkdir -p dist && npx tsx src/dsc",
39+
"dsc": "npx tsx src/dsc",
4040
"package": "vsce package",
4141
"vscode:prepublish": "rm -rf dist && webpack --mode production && npm run dsc",
4242
"webpack": "webpack --mode development",
@@ -1325,4 +1325,4 @@
13251325
"showdown": "^2.1.0",
13261326
"sql-formatter": "^14.0.0"
13271327
}
1328-
}
1328+
}

src/connection/serverComponent.ts

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import { getInstance } from "../base";
22

3-
import { Config } from "../config";
43
import path from "path";
54
import { OutputChannel, extensions, window } from "vscode";
5+
import { Config } from "../config";
66

77
import { stat } from "fs/promises";
88
import { SERVER_VERSION_FILE } from "./SCVersion";
99

10+
import IBMi from "@halcyontech/vscode-ibmi-types/api/IBMi";
11+
import Crypto from 'crypto';
12+
import { readFileSync } from "fs";
13+
1014
const ExecutablePathDir = `$HOME/.vscode/`;
1115

1216
export enum UpdateStatus {
@@ -33,7 +37,7 @@ export class ServerComponent {
3337
if (show) {
3438
this.outputChannel.show();
3539
}
36-
40+
3741
if (this.outputChannel) {
3842
this.outputChannel.appendLine(jsonString);
3943
}
@@ -43,15 +47,15 @@ export class ServerComponent {
4347
return this.installed;
4448
}
4549

46-
static getInitCommand(): string|undefined {
50+
static getInitCommand(): string | undefined {
4751
const path = this.getComponentPath();
4852

4953
if (path) {
5054
return `/QOpenSys/QIBM/ProdData/JavaVM/jdk80/64bit/bin/java -Dos400.stdio.convert=N -jar ${path} --single`
5155
}
5256
}
5357

54-
static getComponentPath(): string|undefined {
58+
static getComponentPath(): string | undefined {
5559
if (Config.ready) {
5660
const installedVersion = Config.getServerComponentName();
5761

@@ -82,6 +86,10 @@ export class ServerComponent {
8286
return this.installed;
8387
}
8488

89+
static reset(){
90+
this.installed = false;
91+
}
92+
8593
static async isAlreadyInstalled() {
8694
const instance = getInstance();
8795
const connection = instance.getConnection();
@@ -107,13 +115,13 @@ export class ServerComponent {
107115
const assetPath = path.join(extensionPath, `dist`, SERVER_VERSION_FILE);
108116
const assetExistsLocally = await exists(assetPath);
109117

110-
ServerComponent.writeOutput(JSON.stringify({assetPath, assetExists: assetExistsLocally}));
118+
ServerComponent.writeOutput(JSON.stringify({ assetPath, assetExists: assetExistsLocally }));
111119

112120
if (assetExistsLocally) {
113121
const basename = SERVER_VERSION_FILE;
114122
const lastInstalledName = Config.getServerComponentName();
115123

116-
ServerComponent.writeOutput(JSON.stringify({basename, lastInstalledName}));
124+
ServerComponent.writeOutput(JSON.stringify({ basename, lastInstalledName }));
117125

118126
await this.initialise();
119127

@@ -132,26 +140,49 @@ export class ServerComponent {
132140
const stuffInStderr = commandResult.stderr.length > 0;
133141
const remotePath = path.posix.join(commandResult.stdout, basename);
134142

135-
ServerComponent.writeOutput(JSON.stringify({remotePath, ExecutablePathDir}));
143+
ServerComponent.writeOutput(JSON.stringify({ remotePath, ExecutablePathDir }));
144+
145+
const remoteExists = await connection.content.testStreamFile(remotePath, "f");
146+
const md5IsEqual = remoteExists && await compareMD5Hash(connection, assetPath, remotePath);
147+
if (!remoteExists || !md5IsEqual) {
148+
if (remoteExists) {
149+
const allowWrite = await connection.sendCommand({
150+
command: `chmod 600 ${remotePath}`
151+
});
152+
if (allowWrite.code !== 0) {
153+
this.writeOutput(JSON.stringify(allowWrite));
154+
window.showErrorMessage(`Remote file ${remotePath} cannot be written; try to delete it and reconnect.`, 'Show')
155+
.then(show => {
156+
if (show) {
157+
this.outputChannel.show();
158+
}
159+
});
160+
return UpdateStatus.FAILED;
161+
}
162+
}
163+
await connection.uploadFiles([{ local: assetPath, remote: remotePath }]);
136164

137-
await connection.uploadFiles([{local: assetPath, remote: remotePath}]);
165+
const scAuth = await connection.sendCommand({
166+
command: `chmod 400 ${remotePath}`
167+
});
138168

139-
const scAuth = await connection.sendCommand({
140-
command: `chmod 400 ${remotePath}`
141-
});
169+
this.writeOutput(JSON.stringify(scAuth));
142170

143-
this.writeOutput(JSON.stringify(scAuth));
171+
await Config.setServerComponentName(basename);
144172

145-
await Config.setServerComponentName(basename);
173+
if (stuffInStderr) {
174+
ServerComponent.writeOutput(`Server component was uploaded to ${remotePath} but there was something in stderr, which is not right. It might be worth seeing your user profile startup scripts.`);
175+
}
146176

147-
if (stuffInStderr) {
148-
ServerComponent.writeOutput(`Server component was uploaded to ${remotePath} but there was something in stderr, which is not right. It might be worth seeing your user profile startup scripts.`);
177+
window.showInformationMessage(`Db2 for IBM i extension server component has been updated!`);
178+
this.installed = true;
179+
updateResult = UpdateStatus.JUST_UPDATED;
180+
}
181+
else{
182+
await Config.setServerComponentName(basename);
183+
this.installed = true;
184+
updateResult = UpdateStatus.UP_TO_DATE;
149185
}
150-
151-
window.showInformationMessage(`Db2 for IBM i extension server component has been updated!`);
152-
this.installed = true;
153-
updateResult = UpdateStatus.JUST_UPDATED;
154-
155186
} else {
156187
updateResult = UpdateStatus.FAILED;
157188

@@ -196,4 +227,20 @@ async function exists(path: string) {
196227
} catch (e) {
197228
return false;
198229
}
230+
}
231+
232+
async function compareMD5Hash(connection: IBMi, local: string, remote: string) {
233+
const localMD5 = Crypto.createHash("md5")
234+
.update(readFileSync(local))
235+
.digest("hex")
236+
.toLowerCase();
237+
238+
const remoteMD5Result = (await connection.sendCommand({ command: `${connection.remoteFeatures.md5sum} ${remote}` }));
239+
if (remoteMD5Result.code === 0) {
240+
return localMD5 === remoteMD5Result.stdout.split(/\s+/)[0];
241+
}
242+
else {
243+
ServerComponent.writeOutput(JSON.stringify(remoteMD5Result));
244+
return false;
245+
}
199246
}

src/dsc.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import path from "path";
22

3+
import { existsSync, mkdirSync } from "fs";
4+
import { writeFile } from "fs/promises";
35
import fetch from "node-fetch";
46
import { Octokit } from "octokit";
5-
import { writeFile } from "fs/promises";
67
import { SERVER_VERSION_FILE, SERVER_VERSION_TAG } from "./connection/SCVersion";
78

89
async function work() {
@@ -26,12 +27,15 @@ async function work() {
2627
console.log(`Asset found: ${newAsset.name}`);
2728

2829
const url = newAsset.browser_download_url;
30+
const distDirectory = path.join(`.`, `dist`);
31+
if (!existsSync(distDirectory)) {
32+
mkdirSync(distDirectory);
33+
}
2934

30-
const dist = path.join(`.`, `dist`, SERVER_VERSION_FILE);
31-
32-
await downloadFile(url, dist);
35+
const serverFile = path.join(distDirectory, SERVER_VERSION_FILE);
36+
await downloadFile(url, serverFile);
3337

34-
console.log(`Asset downloaded.`);
38+
console.log(`Asset downloaded: ${serverFile}`);
3539

3640
} else {
3741
console.log(`Release found but no asset found.`);
@@ -45,8 +49,8 @@ async function work() {
4549

4650
function downloadFile(url, outputPath) {
4751
return fetch(url)
48-
.then(x => x.arrayBuffer())
49-
.then(x => writeFile(outputPath, Buffer.from(x)));
52+
.then(x => x.arrayBuffer())
53+
.then(x => writeFile(outputPath, Buffer.from(x)));
5054
}
5155

5256
work();

src/extension.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
// The module 'vscode' contains the VS Code extensibility API
22
// Import the module and reference it with the alias vscode in your code below
3-
import vscode from "vscode"
3+
import * as vscode from "vscode";
44
import schemaBrowser from "./views/schemaBrowser";
55

66
import * as JSONServices from "./language/json";
77
import * as resultsProvider from "./views/results";
88

9+
import { JDBCOptions } from "@ibm/mapepire-js/dist/src/types";
910
import { getInstance, loadBase } from "./base";
10-
import { JobManager, onConnectOrServerInstall, initConfig } from "./config";
11-
import { queryHistory } from "./views/queryHistoryView";
12-
import { ExampleBrowser } from "./views/examples/exampleBrowser";
13-
import { languageInit } from "./language/providers";
14-
import { initialiseTestSuite } from "./testing";
15-
import { JobManagerView } from "./views/jobManager/jobManagerView";
16-
import { ServerComponent } from "./connection/serverComponent";
11+
import { JobManager, initConfig, onConnectOrServerInstall } from "./config";
12+
import Configuration from "./configuration";
1713
import { SQLJobManager } from "./connection/manager";
14+
import { ServerComponent } from "./connection/serverComponent";
1815
import { OldSQLJob } from "./connection/sqlJob";
16+
import { languageInit } from "./language/providers";
17+
import { DbCache } from "./language/providers/logic/cache";
1918
import { notebookInit } from "./notebooks/IBMiSerializer";
19+
import { initialiseTestSuite } from "./testing";
20+
import { Db2iUriHandler, getStatementUri } from "./uriHandler";
21+
import { ExampleBrowser } from "./views/examples/exampleBrowser";
22+
import { JobManagerView } from "./views/jobManager/jobManagerView";
2023
import { SelfTreeDecorationProvider, selfCodesResultsView } from "./views/jobManager/selfCodes/selfCodesResultsView";
21-
import Configuration from "./configuration";
24+
import { queryHistory } from "./views/queryHistoryView";
2225
import { activateChat } from "./chat/chat";
23-
import { JDBCOptions } from "@ibm/mapepire-js/dist/src/types";
24-
import { Db2iUriHandler, getStatementUri } from "./uriHandler";
25-
import { DbCache } from "./language/providers/logic/cache";
2626

2727
export interface Db2i {
2828
sqlJobManager: SQLJobManager,
@@ -42,7 +42,7 @@ interface IDB2ChatResult extends vscode.ChatResult {
4242
// your extension is activated the very first time the command is executed
4343

4444
export function activate(context: vscode.ExtensionContext): Db2i {
45-
45+
4646
// Use the console to output diagnostic information (console.log) and errors (console.error)
4747
// This line of code will only be executed once when your extension is activated
4848
console.log(`Congratulations, your extension "vscode-db2i" is now active!`);
@@ -90,7 +90,7 @@ export function activate(context: vscode.ExtensionContext): Db2i {
9090

9191
console.log(`Developer environment: ${process.env.DEV}`);
9292
const devMode = process.env.DEV !== undefined;
93-
let runTests: Function|undefined;
93+
let runTests: Function | undefined;
9494
if (devMode) {
9595
// Run tests if not in production build
9696
runTests = initialiseTestSuite(context);
@@ -159,6 +159,7 @@ export function activate(context: vscode.ExtensionContext): Db2i {
159159

160160

161161

162+
instance.subscribe(context, `disconnected`, `db2i-disconnected`, () => ServerComponent.reset());
162163

163164
return { sqlJobManager: JobManager, sqlJob: (options?: JDBCOptions) => new OldSQLJob(options) };
164165
}

0 commit comments

Comments
 (0)