< Summary

Information
Class: Anichron.Infrastructure.Configuration.AppIniInitializer
Assembly: Anichron.Infrastructure
File(s): /home/runner/work/anichron/anichron/src/Anichron.Infrastructure/Configuration/AppIniInitializer.cs
Tag: 228_36821334185
Line coverage
100%
Covered lines: 48
Uncovered lines: 0
Coverable lines: 48
Total lines: 77
Line coverage: 100%
Branch coverage
100%
Covered branches: 12
Total branches: 12
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
EnsureUpToDate(...)100%44100%
WriteNew(...)100%44100%
AppendMissing(...)100%44100%

File(s)

/home/runner/work/anichron/anichron/src/Anichron.Infrastructure/Configuration/AppIniInitializer.cs

#LineLine coverage
 1using Microsoft.Extensions.Configuration;
 2using System.Globalization;
 3using System.IO.Abstractions;
 4using System.Text;
 5
 6namespace Anichron.Infrastructure.Configuration;
 7
 8public sealed record IniEntry(string Section, string Key, Func<string> DefaultValue);
 9
 1710public sealed class AppIniInitializer(IFileSystem fileSystem)
 11{
 12    public void EnsureUpToDate(string iniPath, IReadOnlyList<IniEntry> expectedEntries)
 1713    {
 1714        fileSystem.Directory.CreateDirectory(fileSystem.Path.GetDirectoryName(iniPath)!);
 15
 1716        if (!fileSystem.File.Exists(iniPath))
 1017        {
 1018            WriteNew(iniPath, expectedEntries);
 919            return;
 20        }
 21
 722        using var stream = new MemoryStream(Encoding.UTF8.GetBytes(fileSystem.File.ReadAllText(iniPath)));
 723        var config = new ConfigurationBuilder().AddIniStream(stream).Build();
 724        var missing = expectedEntries
 725            .Where(e => config[$"{e.Section}:{e.Key}"] is null)
 726            .ToList();
 27
 728        if (missing.Count == 0)
 429            return;
 30
 331        AppendMissing(iniPath, missing);
 1932    }
 33
 34    private void WriteNew(string iniPath, IReadOnlyList<IniEntry> entries)
 1035    {
 1036        var sb = new StringBuilder();
 5837        foreach (var section in entries.GroupBy(e => e.Section))
 1438        {
 1439            sb.AppendLine(CultureInfo.InvariantCulture, $"[{section.Key}]");
 8040            foreach (var entry in section)
 1941                sb.AppendLine(CultureInfo.InvariantCulture, $"{entry.Key} = {entry.DefaultValue()}");
 1442            sb.AppendLine();
 1443        }
 44
 45        try
 1046        {
 47            // FileMode.CreateNew is O_CREAT|O_EXCL — atomic exclusive creation; only one wins if two instances race.
 1048            using var stream = fileSystem.FileStream.New(iniPath, FileMode.CreateNew, FileAccess.Write, FileShare.None);
 849            using var writer = new StreamWriter(stream);
 850            writer.Write(sb.ToString());
 851        }
 152        catch (IOException)
 153        {
 154            return; // Another instance created the file concurrently — proceed with that file.
 55        }
 56
 857        Console.Error.WriteLine(
 858            $"[WARN] Configuration file created at {iniPath}. Review the values and keep this file secure.");
 959    }
 60
 61    private void AppendMissing(string iniPath, IReadOnlyList<IniEntry> missing)
 362    {
 363        var sb = new StringBuilder();
 1964        foreach (var section in missing.GroupBy(e => e.Section))
 565        {
 566            sb.AppendLine();
 567            sb.AppendLine(CultureInfo.InvariantCulture, $"[{section.Key}]");
 2568            foreach (var entry in section)
 569                sb.AppendLine(CultureInfo.InvariantCulture, $"{entry.Key} = {entry.DefaultValue()}");
 570        }
 71
 72        // Not atomic: two processes racing here can both append the same entries.
 73        // The INI provider tolerates duplicate keys (last value wins), so behavior is correct.
 374        fileSystem.File.AppendAllText(iniPath, sb.ToString());
 375        Console.Error.WriteLine($"[INFO] Added missing configuration entries to {iniPath}.");
 376    }
 77}