1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . IO ;
4+ using System . Text ;
5+ using Avalonia . Markup . Xaml . MarkupExtensions ;
6+
7+ namespace GitCredentialManager . Interop . Linux ;
8+
9+ public class LinuxSettings : Settings
10+ {
11+ private readonly ITrace _trace ;
12+ private readonly IFileSystem _fs ;
13+
14+ private IDictionary < string , string > _extConfigCache ;
15+
16+ /// <summary>
17+ /// Reads settings from Git configuration, environment variables, and defaults from the
18+ /// /etc/git-credential-manager.d app configuration directory.
19+ /// </summary>
20+ public LinuxSettings ( IEnvironment environment , IGit git , ITrace trace , IFileSystem fs )
21+ : base ( environment , git )
22+ {
23+ EnsureArgument . NotNull ( trace , nameof ( trace ) ) ;
24+ EnsureArgument . NotNull ( fs , nameof ( fs ) ) ;
25+
26+ _trace = trace ;
27+ _fs = fs ;
28+
29+ PlatformUtils . EnsureLinux ( ) ;
30+ }
31+
32+ protected internal override bool TryGetExternalDefault ( string section , string scope , string property , out string value )
33+ {
34+ value = null ;
35+
36+ _extConfigCache ??= ReadExternalConfiguration ( ) ;
37+
38+ string name = string . IsNullOrWhiteSpace ( scope )
39+ ? $ "{ section } .{ property } "
40+ : $ "{ section } .{ scope } .{ property } ";
41+
42+ // Check if the setting exists in the configuration
43+ if ( ! _extConfigCache ? . TryGetValue ( name , out value ) ?? false )
44+ {
45+ // No property exists (or failed to read config)
46+ return false ;
47+ }
48+
49+ _trace . WriteLine ( $ "Default setting found in app configuration directory: { name } ={ value } ") ;
50+ return true ;
51+ }
52+
53+ private IDictionary < string , string > ReadExternalConfiguration ( )
54+ {
55+ try
56+ {
57+ // Check for system-wide config files in /etc/git-credential-manager/config.d and concatenate them together
58+ // in alphabetical order to form a single configuration.
59+ const string configDir = Constants . LinuxAppDefaultsDirectoryPath ;
60+ if ( ! _fs . DirectoryExists ( configDir ) )
61+ {
62+ // No configuration directory exists
63+ return null ;
64+ }
65+
66+ // Get all the files in the configuration directory
67+ IEnumerable < string > files = _fs . EnumerateFiles ( configDir , "*" ) ;
68+
69+ // Read the contents of each file and concatenate them together
70+ var combinedFile = new StringBuilder ( ) ;
71+ foreach ( string file in files )
72+ {
73+ using Stream stream = _fs . OpenFileStream ( file , FileMode . Open , FileAccess . Read , FileShare . Read ) ;
74+ using var reader = new StreamReader ( stream ) ;
75+ string contents = reader . ReadToEnd ( ) ;
76+ combinedFile . Append ( contents ) ;
77+ combinedFile . Append ( '\n ' ) ;
78+ }
79+
80+ var parser = new LinuxConfigParser ( _trace ) ;
81+
82+ return parser . Parse ( combinedFile . ToString ( ) ) ;
83+ }
84+ catch ( Exception ex )
85+ {
86+ // Reading defaults is not critical to the operation of the application
87+ // so we can ignore any errors and just log the failure.
88+ _trace . WriteLine ( "Failed to read default setting from app configuration directory." ) ;
89+ _trace . WriteException ( ex ) ;
90+ return null ;
91+ }
92+ }
93+ }
0 commit comments