1
1
import { getInstance } from "../base" ;
2
2
3
- import { Config } from "../config" ;
4
3
import path from "path" ;
5
4
import { OutputChannel , extensions , window } from "vscode" ;
5
+ import { Config } from "../config" ;
6
6
7
7
import { stat } from "fs/promises" ;
8
8
import { SERVER_VERSION_FILE } from "./SCVersion" ;
9
9
10
+ import IBMi from "@halcyontech/vscode-ibmi-types/api/IBMi" ;
11
+ import Crypto from 'crypto' ;
12
+ import { readFileSync } from "fs" ;
13
+
10
14
const ExecutablePathDir = `$HOME/.vscode/` ;
11
15
12
16
export enum UpdateStatus {
@@ -33,7 +37,7 @@ export class ServerComponent {
33
37
if ( show ) {
34
38
this . outputChannel . show ( ) ;
35
39
}
36
-
40
+
37
41
if ( this . outputChannel ) {
38
42
this . outputChannel . appendLine ( jsonString ) ;
39
43
}
@@ -43,15 +47,15 @@ export class ServerComponent {
43
47
return this . installed ;
44
48
}
45
49
46
- static getInitCommand ( ) : string | undefined {
50
+ static getInitCommand ( ) : string | undefined {
47
51
const path = this . getComponentPath ( ) ;
48
52
49
53
if ( path ) {
50
54
return `/QOpenSys/QIBM/ProdData/JavaVM/jdk80/64bit/bin/java -Dos400.stdio.convert=N -jar ${ path } --single`
51
55
}
52
56
}
53
57
54
- static getComponentPath ( ) : string | undefined {
58
+ static getComponentPath ( ) : string | undefined {
55
59
if ( Config . ready ) {
56
60
const installedVersion = Config . getServerComponentName ( ) ;
57
61
@@ -107,13 +111,13 @@ export class ServerComponent {
107
111
const assetPath = path . join ( extensionPath , `dist` , SERVER_VERSION_FILE ) ;
108
112
const assetExistsLocally = await exists ( assetPath ) ;
109
113
110
- ServerComponent . writeOutput ( JSON . stringify ( { assetPath, assetExists : assetExistsLocally } ) ) ;
114
+ ServerComponent . writeOutput ( JSON . stringify ( { assetPath, assetExists : assetExistsLocally } ) ) ;
111
115
112
116
if ( assetExistsLocally ) {
113
117
const basename = SERVER_VERSION_FILE ;
114
118
const lastInstalledName = Config . getServerComponentName ( ) ;
115
119
116
- ServerComponent . writeOutput ( JSON . stringify ( { basename, lastInstalledName} ) ) ;
120
+ ServerComponent . writeOutput ( JSON . stringify ( { basename, lastInstalledName } ) ) ;
117
121
118
122
await this . initialise ( ) ;
119
123
@@ -132,26 +136,44 @@ export class ServerComponent {
132
136
const stuffInStderr = commandResult . stderr . length > 0 ;
133
137
const remotePath = path . posix . join ( commandResult . stdout , basename ) ;
134
138
135
- ServerComponent . writeOutput ( JSON . stringify ( { remotePath, ExecutablePathDir} ) ) ;
139
+ ServerComponent . writeOutput ( JSON . stringify ( { remotePath, ExecutablePathDir } ) ) ;
140
+
141
+ const remoteExists = await connection . content . testStreamFile ( remotePath , "f" ) ;
142
+ const md5IsEqual = remoteExists && await compareMD5Hash ( connection , assetPath , remotePath ) ;
143
+ if ( ! remoteExists || ! md5IsEqual ) {
144
+ if ( remoteExists ) {
145
+ const allowWrite = await connection . sendCommand ( {
146
+ command : `chmod 600 ${ remotePath } `
147
+ } ) ;
148
+ if ( allowWrite . code !== 0 ) {
149
+ this . writeOutput ( JSON . stringify ( allowWrite ) ) ;
150
+ window . showErrorMessage ( `Remote file ${ remotePath } cannot be written; try to delete it and reconnect.` , 'Show' )
151
+ . then ( show => {
152
+ if ( show ) {
153
+ this . outputChannel . show ( ) ;
154
+ }
155
+ } ) ;
156
+ return UpdateStatus . FAILED ;
157
+ }
158
+ }
159
+ await connection . uploadFiles ( [ { local : assetPath , remote : remotePath } ] ) ;
136
160
137
- await connection . uploadFiles ( [ { local : assetPath , remote : remotePath } ] ) ;
161
+ const scAuth = await connection . sendCommand ( {
162
+ command : `chmod 400 ${ remotePath } `
163
+ } ) ;
138
164
139
- const scAuth = await connection . sendCommand ( {
140
- command : `chmod 400 ${ remotePath } `
141
- } ) ;
165
+ this . writeOutput ( JSON . stringify ( scAuth ) ) ;
142
166
143
- this . writeOutput ( JSON . stringify ( scAuth ) ) ;
167
+ await Config . setServerComponentName ( basename ) ;
144
168
145
- await Config . setServerComponentName ( basename ) ;
169
+ if ( stuffInStderr ) {
170
+ 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.` ) ;
171
+ }
146
172
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.` ) ;
173
+ window . showInformationMessage ( `Db2 for IBM i extension server component has been updated!` ) ;
174
+ this . installed = true ;
175
+ updateResult = UpdateStatus . JUST_UPDATED ;
149
176
}
150
-
151
- window . showInformationMessage ( `Db2 for IBM i extension server component has been updated!` ) ;
152
- this . installed = true ;
153
- updateResult = UpdateStatus . JUST_UPDATED ;
154
-
155
177
} else {
156
178
updateResult = UpdateStatus . FAILED ;
157
179
@@ -196,4 +218,20 @@ async function exists(path: string) {
196
218
} catch ( e ) {
197
219
return false ;
198
220
}
221
+ }
222
+
223
+ async function compareMD5Hash ( connection : IBMi , local : string , remote : string ) {
224
+ const localMD5 = Crypto . createHash ( "md5" )
225
+ . update ( readFileSync ( local ) )
226
+ . digest ( "hex" )
227
+ . toLowerCase ( ) ;
228
+
229
+ const remoteMD5Result = ( await connection . sendCommand ( { command : `${ connection . remoteFeatures . md5sum } ${ remote } ` } ) ) ;
230
+ if ( remoteMD5Result . code === 0 ) {
231
+ return localMD5 === remoteMD5Result . stdout . split ( / \s + / ) . at ( 0 ) ;
232
+ }
233
+ else {
234
+ ServerComponent . writeOutput ( JSON . stringify ( remoteMD5Result ) ) ;
235
+ return false ;
236
+ }
199
237
}
0 commit comments