@@ -31,10 +31,54 @@ const defaultFileSystem: FileSystem = {
31
31
writeFile,
32
32
}
33
33
34
- export const defaultSSHConfigResponse : SSHConfigResponse = {
35
- ssh_config_options : { } ,
36
- // The prefix is not used by the vscode-extension
37
- hostname_prefix : "coder." ,
34
+ export const defaultSSHConfigResponse : Record < string , string > = { }
35
+
36
+ // mergeSSHConfigValues will take a given ssh config and merge it with the overrides
37
+ // provided. The merge handles key case insensitivity, so casing in the "key" does
38
+ // not matter.
39
+ export function mergeSSHConfigValues (
40
+ config : Record < string , string > ,
41
+ overrides : Record < string , string > ,
42
+ ) : Record < string , string > {
43
+ const merged : Record < string , string > = { }
44
+
45
+ // We need to do a case insensitive match for the overrides as ssh config keys are case insensitive.
46
+ // To get the correct key:value, use:
47
+ // key = caseInsensitiveOverrides[key.toLowerCase()]
48
+ // value = overrides[key]
49
+ const caseInsensitiveOverrides : Record < string , string > = { }
50
+ Object . keys ( overrides ) . forEach ( ( key ) => {
51
+ caseInsensitiveOverrides [ key . toLowerCase ( ) ] = key
52
+ } )
53
+
54
+ Object . keys ( config ) . forEach ( ( key ) => {
55
+ const lower = key . toLowerCase ( )
56
+ // If the key is in overrides, use the override value.
57
+ if ( caseInsensitiveOverrides [ lower ] ) {
58
+ const correctCaseKey = caseInsensitiveOverrides [ lower ]
59
+ const value = overrides [ correctCaseKey ]
60
+ delete caseInsensitiveOverrides [ lower ]
61
+
62
+ // If the value is empty, do not add the key. It is being removed.
63
+ if ( value === "" ) {
64
+ return
65
+ }
66
+ merged [ correctCaseKey ] = value
67
+ return
68
+ }
69
+ // If no override, take the original value.
70
+ if ( config [ key ] !== "" ) {
71
+ merged [ key ] = config [ key ]
72
+ }
73
+ } )
74
+
75
+ // Add remaining overrides.
76
+ Object . keys ( caseInsensitiveOverrides ) . forEach ( ( lower ) => {
77
+ const correctCaseKey = caseInsensitiveOverrides [ lower ]
78
+ merged [ correctCaseKey ] = overrides [ correctCaseKey ]
79
+ } )
80
+
81
+ return merged
38
82
}
39
83
40
84
export class SSHConfig {
@@ -58,15 +102,15 @@ export class SSHConfig {
58
102
}
59
103
}
60
104
61
- async update ( values : SSHValues , overrides : SSHConfigResponse = defaultSSHConfigResponse ) {
105
+ async update ( values : SSHValues , overrides : Record < string , string > = defaultSSHConfigResponse ) {
62
106
// We should remove this in March 2023 because there is not going to have
63
107
// old configs
64
108
this . cleanUpOldConfig ( )
65
109
const block = this . getBlock ( )
66
110
if ( block ) {
67
111
this . eraseBlock ( block )
68
112
}
69
- this . appendBlock ( values , overrides . ssh_config_options )
113
+ this . appendBlock ( values , overrides )
70
114
await this . save ( )
71
115
}
72
116
@@ -122,43 +166,16 @@ export class SSHConfig {
122
166
*/
123
167
private appendBlock ( { Host, ...otherValues } : SSHValues , overrides : Record < string , string > ) {
124
168
const lines = [ this . startBlockComment , `Host ${ Host } ` ]
125
- // We need to do a case insensitive match for the overrides as ssh config keys are case insensitive.
126
- // To get the correct key:value, use:
127
- // key = caseInsensitiveOverrides[key.toLowerCase()]
128
- // value = overrides[key]
129
- const caseInsensitiveOverrides : Record < string , string > = { }
130
- Object . keys ( overrides ) . forEach ( ( key ) => {
131
- caseInsensitiveOverrides [ key . toLowerCase ( ) ] = key
132
- } )
133
169
134
- const keys = Object . keys ( otherValues ) as Array < keyof typeof otherValues >
170
+ // configValues is the merged values of the defaults and the overrides.
171
+ const configValues = mergeSSHConfigValues ( otherValues , overrides )
172
+
173
+ // keys is the sorted keys of the merged values.
174
+ const keys = ( Object . keys ( configValues ) as Array < keyof typeof configValues > ) . sort ( )
135
175
keys . forEach ( ( key ) => {
136
- const lower = key . toLowerCase ( )
137
- if ( caseInsensitiveOverrides [ lower ] ) {
138
- const correctCaseKey = caseInsensitiveOverrides [ lower ]
139
- const value = overrides [ correctCaseKey ]
140
- // Remove the key from the overrides so we don't write it again.
141
- delete caseInsensitiveOverrides [ lower ]
142
- if ( value === "" ) {
143
- // If the value is empty, don't write it. Prevent writing the default
144
- // value as well.
145
- return
146
- }
147
- // If the key is in overrides, use the override value.
148
- // Doing it this way maintains the default order of the keys.
149
- lines . push ( this . withIndentation ( `${ key } ${ value } ` ) )
150
- return
151
- }
152
- lines . push ( this . withIndentation ( `${ key } ${ otherValues [ key ] } ` ) )
153
- } )
154
- // Write remaining overrides that have not been written yet. Sort to maintain deterministic order.
155
- const remainingKeys = ( Object . keys ( caseInsensitiveOverrides ) as Array < keyof typeof caseInsensitiveOverrides > ) . sort ( )
156
- remainingKeys . forEach ( ( key ) => {
157
- const correctKey = caseInsensitiveOverrides [ key ]
158
- const value = overrides [ correctKey ]
159
- // Only write the value if it is not empty.
176
+ const value = configValues [ key ]
160
177
if ( value !== "" ) {
161
- lines . push ( this . withIndentation ( `${ correctKey } ${ value } ` ) )
178
+ lines . push ( this . withIndentation ( `${ key } ${ value } ` ) )
162
179
}
163
180
} )
164
181
0 commit comments