@@ -12,6 +12,7 @@ namespace GitCredentialManager
12
12
{
13
13
/// <summary>
14
14
/// Component that represents settings for Git Credential Manager as found from the environment and Git configuration.
15
+ /// Setting values from Git configuration may be cached for performance reasons.
15
16
/// </summary>
16
17
public interface ISettings : IDisposable
17
18
{
@@ -26,7 +27,6 @@ public interface ISettings : IDisposable
26
27
/// <returns>True if a setting value was found, false otherwise.</returns>
27
28
bool TryGetSetting ( string envarName , string section , string property , out string value ) ;
28
29
29
-
30
30
/// <summary>
31
31
/// Try and get the value of a specified setting as specified in the environment and Git configuration,
32
32
/// with the environment taking precedence over Git. If the value is pulled from the Git configuration,
@@ -291,6 +291,8 @@ public class Settings : ISettings
291
291
private readonly IEnvironment _environment ;
292
292
private readonly IGit _git ;
293
293
294
+ private Dictionary < string , string > _configEntries ;
295
+
294
296
public Settings ( IEnvironment environment , IGit git )
295
297
{
296
298
EnsureArgument . NotNull ( environment , nameof ( environment ) ) ;
@@ -334,6 +336,30 @@ public IEnumerable<string> GetSettingValues(string envarName, string section, st
334
336
{
335
337
IGitConfiguration config = _git . GetConfiguration ( ) ;
336
338
339
+ //
340
+ // Enumerate all configuration entries for all sections and property names and make a
341
+ // local copy of them here to avoid needing to call `TryGetValue` on the IGitConfiguration
342
+ // object multiple times in a loop below.
343
+ //
344
+ // This is a performance optimisation to avoid calling `TryGet` on the IGitConfiguration
345
+ // object multiple times in a loop below, or each time this entire method is called.
346
+ // The assumption is that the configuration entries will not change during a single invocation
347
+ // of Git Credential Manager, which is reasonable given process lifetime is typically less
348
+ // than a few seconds. For some entries (type=path), we still need to ask Git in order to
349
+ // expand the path correctly.
350
+ //
351
+ if ( _configEntries is null )
352
+ {
353
+ _configEntries = new Dictionary < string , string > ( GitConfigurationKeyComparer . Instance ) ;
354
+ config . Enumerate ( entry =>
355
+ {
356
+ _configEntries [ entry . Key ] = entry . Value ;
357
+
358
+ // Continue the enumeration
359
+ return true ;
360
+ } ) ;
361
+ }
362
+
337
363
if ( RemoteUri != null )
338
364
{
339
365
/*
@@ -379,26 +405,14 @@ public IEnumerable<string> GetSettingValues(string envarName, string section, st
379
405
*
380
406
*/
381
407
382
- // Enumerate all configuration entries with the correct section and property name
383
- // and make a local copy of them here to avoid needing to call `TryGetValue` on the
384
- // IGitConfiguration object multiple times in a loop below.
385
- var configEntries = new Dictionary < string , string > ( GitConfigurationKeyComparer . Instance ) ;
386
- config . Enumerate ( section , property , entry =>
387
- {
388
- configEntries [ entry . Key ] = entry . Value ;
389
-
390
- // Continue the enumeration
391
- return true ;
392
- } ) ;
393
-
394
408
foreach ( string scope in RemoteUri . GetGitConfigurationScopes ( ) )
395
409
{
396
410
string queryName = $ "{ section } .{ scope } .{ property } ";
397
411
// Look for a scoped entry that includes the scheme "protocol://example.com" first as
398
412
// this is more specific. If `isPath` is true, then re-get the value from the
399
413
// `GitConfiguration` with `isPath` specified.
400
414
if ( ( isPath && config . TryGet ( queryName , isPath , out value ) ) ||
401
- configEntries . TryGetValue ( queryName , out value ) )
415
+ _configEntries . TryGetValue ( queryName , out value ) )
402
416
{
403
417
yield return value ;
404
418
}
@@ -409,7 +423,7 @@ public IEnumerable<string> GetSettingValues(string envarName, string section, st
409
423
string scopeWithoutScheme = scope . TrimUntilIndexOf ( Uri . SchemeDelimiter ) ;
410
424
string queryWithSchemeName = $ "{ section } .{ scopeWithoutScheme } .{ property } ";
411
425
if ( ( isPath && config . TryGet ( queryWithSchemeName , isPath , out value ) ) ||
412
- configEntries . TryGetValue ( queryWithSchemeName , out value ) )
426
+ _configEntries . TryGetValue ( queryWithSchemeName , out value ) )
413
427
{
414
428
yield return value ;
415
429
}
@@ -431,7 +445,7 @@ public IEnumerable<string> GetSettingValues(string envarName, string section, st
431
445
*/
432
446
string name = $ "{ section } .{ property } ";
433
447
if ( ( isPath && config . TryGet ( name , isPath , out value ) ) ||
434
- configEntries . TryGetValue ( name , out value ) )
448
+ _configEntries . TryGetValue ( name , out value ) )
435
449
{
436
450
yield return value ;
437
451
}
0 commit comments