@@ -214,18 +214,52 @@ const resolvedConnSpecs = new Map<string, any>();
214
214
/**
215
215
* If servermanager extension is available, fetch the connection spec unless already cached.
216
216
* Prompt for credentials if necessary.
217
- * @param serverName authority element of an isfs uri, or `objectscript.conn.server` property
217
+ * @param serverName authority element of an isfs uri, or `objectscript.conn.server` property, or the name of a root folder with an `objectscript.conn.docker-compose` property object
218
+ * @param uri if passed, re-check the `objectscript.conn.docker-compose` case in case servermanager API couldn't do that because we're still running our own `activate` method.
218
219
*/
219
- export async function resolveConnectionSpec ( serverName : string ) : Promise < void > {
220
- if ( serverManagerApi && serverManagerApi . getServerSpec ) {
221
- if ( serverName && serverName !== "" && ! resolvedConnSpecs . has ( serverName ) ) {
222
- const connSpec = await serverManagerApi . getServerSpec ( serverName ) ;
223
- if ( connSpec ) {
224
- await resolvePassword ( connSpec ) ;
225
- resolvedConnSpecs . set ( serverName , connSpec ) ;
220
+ export async function resolveConnectionSpec ( serverName : string , uri ?: vscode . Uri ) : Promise < void > {
221
+ if ( ! serverManagerApi || ! serverManagerApi . getServerSpec || serverName === "" ) {
222
+ return ;
223
+ }
224
+ if ( resolvedConnSpecs . has ( serverName ) ) {
225
+ // Already resolved
226
+ return ;
227
+ }
228
+ if ( ! vscode . workspace . getConfiguration ( "intersystems.servers" , null ) . has ( serverName ) ) {
229
+ // When not a defined server see it already resolved as a foldername that matches case-insensitively
230
+ if ( getResolvedConnectionSpec ( serverName , undefined ) ) {
231
+ return ;
232
+ }
233
+ }
234
+
235
+ let connSpec = await serverManagerApi . getServerSpec ( serverName ) ;
236
+
237
+ if ( ! connSpec && uri ) {
238
+ // Caller passed uri as a signal to process any docker-compose settings
239
+ const { configName } = connectionTarget ( uri ) ;
240
+ if ( config ( "conn" , configName ) [ "docker-compose" ] ) {
241
+ const serverForUri = await asyncServerForUri ( uri ) ;
242
+ if ( serverForUri ) {
243
+ connSpec = {
244
+ name : serverForUri . serverName ,
245
+ webServer : {
246
+ scheme : serverForUri . scheme ,
247
+ host : serverForUri . host ,
248
+ port : serverForUri . port ,
249
+ pathPrefix : serverForUri . pathPrefix ,
250
+ } ,
251
+ username : serverForUri . username ,
252
+ password : serverForUri . password ? serverForUri . password : undefined ,
253
+ description : `Server for workspace folder '${ serverName } '` ,
254
+ } ;
226
255
}
227
256
}
228
257
}
258
+
259
+ if ( connSpec ) {
260
+ await resolvePassword ( connSpec ) ;
261
+ resolvedConnSpecs . set ( serverName , connSpec ) ;
262
+ }
229
263
}
230
264
231
265
async function resolvePassword ( serverSpec , ignoreUnauthenticated = false ) : Promise < void > {
@@ -260,7 +294,22 @@ async function resolvePassword(serverSpec, ignoreUnauthenticated = false): Promi
260
294
261
295
/** Accessor for the cache of resolved connection specs */
262
296
export function getResolvedConnectionSpec ( key : string , dflt : any ) : any {
263
- return resolvedConnSpecs . has ( key ) ? resolvedConnSpecs . get ( key ) : dflt ;
297
+ let spec = resolvedConnSpecs . get ( key ) ;
298
+ if ( spec ) {
299
+ return spec ;
300
+ }
301
+
302
+ // Try a case-insensitive match
303
+ key = resolvedConnSpecs . keys ( ) . find ( ( oneKey ) => oneKey . toLowerCase ( ) === key . toLowerCase ( ) ) ;
304
+ if ( key ) {
305
+ spec = resolvedConnSpecs . get ( key ) ;
306
+ if ( spec ) {
307
+ return spec ;
308
+ }
309
+ }
310
+
311
+ // Return the default if not found
312
+ return dflt ;
264
313
}
265
314
266
315
export async function checkConnection (
@@ -731,15 +780,20 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
731
780
vscode . workspace . workspaceFolders ?. map ( ( workspaceFolder ) => {
732
781
const uri = workspaceFolder . uri ;
733
782
const { configName } = connectionTarget ( uri ) ;
734
- const serverName = notIsfs ( uri ) ? config ( "conn" , configName ) . server : configName ;
783
+ const conn = config ( "conn" , configName ) ;
784
+
785
+ // When docker-compose object is defined don't fall back to server name, which may have come from user-level settings
786
+ const serverName = notIsfs ( uri ) && ! conn [ "docker-compose" ] ? conn . server : configName ;
735
787
toCheck . set ( serverName , uri ) ;
736
788
} ) ;
737
789
for await ( const oneToCheck of toCheck ) {
738
790
const serverName = oneToCheck [ 0 ] ;
739
791
const uri = oneToCheck [ 1 ] ;
740
792
try {
741
793
try {
742
- await resolveConnectionSpec ( serverName ) ;
794
+ // Pass the uri to resolveConnectionSpec so it will fall back to docker-compose logic if required.
795
+ // Necessary because we are in our activate method, so its call to the Server Manager API cannot call back to our API to do that.
796
+ await resolveConnectionSpec ( serverName , uri ) ;
743
797
} finally {
744
798
await checkConnection ( true , uri , true ) ;
745
799
}
@@ -1517,46 +1571,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
1517
1571
1518
1572
// The API we export
1519
1573
const extensionApi = {
1520
- serverForUri ( uri : vscode . Uri ) : any {
1521
- const { apiTarget } = connectionTarget ( uri ) ;
1522
- const api = new AtelierAPI ( apiTarget ) ;
1523
-
1524
- // This function intentionally no longer exposes the password for a named server UNLESS it is already exposed as plaintext in settings.
1525
- // API client extensions should use Server Manager 3's authentication provider to request a missing password themselves,
1526
- // which will require explicit user consent to divulge the password to the requesting extension.
1527
-
1528
- const {
1529
- serverName,
1530
- active,
1531
- host = "" ,
1532
- https,
1533
- port,
1534
- pathPrefix,
1535
- username,
1536
- password,
1537
- ns = "" ,
1538
- apiVersion,
1539
- serverVersion,
1540
- } = api . config ;
1541
- return {
1542
- serverName,
1543
- active,
1544
- scheme : https ? "https" : "http" ,
1545
- host,
1546
- port,
1547
- pathPrefix,
1548
- username,
1549
- password :
1550
- serverName === ""
1551
- ? password
1552
- : vscode . workspace
1553
- . getConfiguration ( `intersystems.servers.${ serverName . toLowerCase ( ) } ` , uri )
1554
- . get ( "password" ) ,
1555
- namespace : ns ,
1556
- apiVersion : active ? apiVersion : undefined ,
1557
- serverVersion : active ? serverVersion : undefined ,
1558
- } ;
1559
- } ,
1574
+ serverForUri,
1575
+ asyncServerForUri,
1560
1576
serverDocumentUriForUri ( uri : vscode . Uri ) : vscode . Uri {
1561
1577
const { apiTarget } = connectionTarget ( uri ) ;
1562
1578
if ( typeof apiTarget === "string" ) {
@@ -1588,6 +1604,66 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
1588
1604
return extensionApi ;
1589
1605
}
1590
1606
1607
+ // This function is exported as one of our API functions but is also used internally
1608
+ // for example to implement the async variant capable of resolving docker port number.
1609
+ function serverForUri ( uri : vscode . Uri ) : any {
1610
+ const { apiTarget } = connectionTarget ( uri ) ;
1611
+ const api = new AtelierAPI ( apiTarget ) ;
1612
+
1613
+ // This function intentionally no longer exposes the password for a named server UNLESS it is already exposed as plaintext in settings.
1614
+ // API client extensions should use Server Manager 3's authentication provider to request a missing password themselves,
1615
+ // which will require explicit user consent to divulge the password to the requesting extension.
1616
+ const {
1617
+ serverName,
1618
+ active,
1619
+ host = "" ,
1620
+ https,
1621
+ port,
1622
+ pathPrefix,
1623
+ username,
1624
+ password,
1625
+ ns = "" ,
1626
+ apiVersion,
1627
+ serverVersion,
1628
+ } = api . config ;
1629
+ return {
1630
+ serverName,
1631
+ active,
1632
+ scheme : https ? "https" : "http" ,
1633
+ host,
1634
+ port,
1635
+ pathPrefix,
1636
+ username,
1637
+ password :
1638
+ serverName === ""
1639
+ ? password
1640
+ : vscode . workspace . getConfiguration ( `intersystems.servers.${ serverName . toLowerCase ( ) } ` , uri ) . get ( "password" ) ,
1641
+ namespace : ns ,
1642
+ apiVersion : active ? apiVersion : undefined ,
1643
+ serverVersion : active ? serverVersion : undefined ,
1644
+ } ;
1645
+ }
1646
+
1647
+ // An async variant capable of resolving docker port number.
1648
+ // It is exported as one of our API functions but is also used internally.
1649
+ async function asyncServerForUri ( uri : vscode . Uri ) : Promise < any > {
1650
+ const server = serverForUri ( uri ) ;
1651
+ if ( ! server . port ) {
1652
+ let { apiTarget } = connectionTarget ( uri ) ;
1653
+ if ( apiTarget instanceof vscode . Uri ) {
1654
+ apiTarget = vscode . workspace . getWorkspaceFolder ( apiTarget ) ?. name ;
1655
+ }
1656
+ const { port : dockerPort , docker : withDocker } = await portFromDockerCompose ( apiTarget ) ;
1657
+ if ( withDocker && dockerPort ) {
1658
+ server . port = dockerPort ;
1659
+ server . host = "localhost" ;
1660
+ server . pathPrefix = "" ;
1661
+ server . https = false ;
1662
+ }
1663
+ }
1664
+ return server ;
1665
+ }
1666
+
1591
1667
export function deactivate ( ) : void {
1592
1668
if ( workspaceState ) {
1593
1669
workspaceState . update ( "openedClasses" , openedClasses ) ;
0 commit comments