public bool TryGet(GitConfigurationLevel level, GitConfigurationType type, string name, out string value)
        {
            value = null;

            // Proceed in order from least to most specific level and read the entry value
            foreach (var(_, dict) in GetDictionaries(level))
            {
                if (dict.TryGetValue(name, out var values))
                {
                    if (values.Count > 1)
                    {
                        throw new Exception("Configuration entry is a multivar");
                    }

                    if (values.Count == 1)
                    {
                        value = values[0];

                        if (type == GitConfigurationType.Path)
                        {
                            // Create "fake" canonical path
                            value = value.Replace("~", CanonicalPathPrefix);
                        }
                    }
                }
            }

            return(value != null);
        }
 private string GetCanonicalizeTypeArg(GitConfigurationType type)
 {
     if (_git.Version >= TypeConfigMinVersion)
     {
         return(type switch
         {
             GitConfigurationType.Bool => "--type=bool",
             GitConfigurationType.Path => "--type=path",
             _ => null
         });
 public IEnumerable <string> GetAll(GitConfigurationLevel level, GitConfigurationType type, string name)
 {
     foreach (var(_, dict) in GetDictionaries(level))
     {
         if (dict.TryGetValue(name, out IList <string> values))
         {
             foreach (string value in values)
             {
                 yield return(value);
             }
         }
     }
 }
 public IEnumerable <string> GetRegex(GitConfigurationLevel level, GitConfigurationType type, string nameRegex, string valueRegex)
 {
     foreach (var(_, dict) in GetDictionaries(level))
     {
         foreach (string key in dict.Keys)
         {
             if (Regex.IsMatch(key, nameRegex))
             {
                 var values = dict[key].Where(x => Regex.IsMatch(x, valueRegex));
                 foreach (string value in values)
                 {
                     yield return(value);
                 }
             }
         }
     }
 }
        public IEnumerable <string> GetRegex(GitConfigurationLevel level, GitConfigurationType type, string nameRegex, string valueRegex)
        {
            string levelArg = GetLevelFilterArg(level);
            string typeArg  = GetCanonicalizeTypeArg(type);

            var gitArgs = $"config --null {levelArg} {typeArg} --get-regex {QuoteCmdArg(nameRegex)}";

            if (valueRegex != null)
            {
                gitArgs += $" {QuoteCmdArg(valueRegex)}";
            }

            using (Process git = _git.CreateProcess(gitArgs))
            {
                git.Start();
                // To avoid deadlocks, always read the output stream first and then wait
                // TODO: don't read in all the data at once; stream it
                string data = git.StandardOutput.ReadToEnd();
                git.WaitForExit();

                switch (git.ExitCode)
                {
                case 0:     // OK
                case 1:     // No results
                    break;

                default:
                    _trace.WriteLine($"Failed to get all multivar regex '{nameRegex}' and value regex '{valueRegex}' (exit={git.ExitCode}, level={level})");
                    throw GitProcess.CreateGitException(git, $"Failed to get Git configuration multi-valued entries with name regex '{nameRegex}'");
                }

                string[] entries = data.Split('\0');
                foreach (string entry in entries)
                {
                    string[] kvp = entry.Split(new[] { '\n' }, count: 2);

                    if (kvp.Length == 2)
                    {
                        yield return(kvp[1]);
                    }
                }
            }
        }
        public IEnumerable <string> GetAll(GitConfigurationLevel level, GitConfigurationType type, string name)
        {
            string levelArg = GetLevelFilterArg(level);
            string typeArg  = GetCanonicalizeTypeArg(type);

            var gitArgs = $"config --null {levelArg} {typeArg} --get-all {QuoteCmdArg(name)}";

            using (Process git = _git.CreateProcess(gitArgs))
            {
                git.Start();

                // TODO: don't read in all the data at once; stream it
                string data = git.StandardOutput.ReadToEnd();
                git.WaitForExit();

                switch (git.ExitCode)
                {
                case 0:     // OK
                    string[] entries = data.Split('\0');

                    // Because each line terminates with the \0 character, splitting leaves us with one
                    // bogus blank entry at the end of the array which we should ignore
                    for (var i = 0; i < entries.Length - 1; i++)
                    {
                        yield return(entries[i]);
                    }
                    break;

                case 1:     // No results
                    break;

                default:
                    _trace.WriteLine($"Failed to get all config entries '{name}' (exit={git.ExitCode}, level={level})");
                    throw GitProcess.CreateGitException(git, $"Failed to get all Git configuration entries '{name}'");
                }
            }
        }
        public bool TryGet(GitConfigurationLevel level, GitConfigurationType type, string name, out string value)
        {
            string levelArg = GetLevelFilterArg(level);
            string typeArg  = GetCanonicalizeTypeArg(type);

            using (Process git = _git.CreateProcess($"config --null {levelArg} {typeArg} {QuoteCmdArg(name)}"))
            {
                git.Start();
                git.WaitForExit();

                switch (git.ExitCode)
                {
                case 0:     // OK
                    break;

                case 1:     // Not found
                    value = null;
                    return(false);

                default:     // Error
                    _trace.WriteLine($"Failed to read Git configuration entry '{name}'. (exit={git.ExitCode}, level={level})");
                    value = null;
                    return(false);
                }

                string   data    = git.StandardOutput.ReadToEnd();
                string[] entries = data.Split('\0');
                if (entries.Length > 0)
                {
                    value = entries[0];
                    return(true);
                }

                value = null;
                return(false);
            }
        }