• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

KSP-CKAN / CKAN / 17904669173

22 Sep 2025 04:34AM UTC coverage: 75.604% (+1.2%) from 74.397%
17904669173

push

github

HebaruSan
Merge #4443 Report number of filtered files in install

5231 of 7236 branches covered (72.29%)

Branch coverage included in aggregate %.

192 of 218 new or added lines in 41 files covered. (88.07%)

35 existing lines in 7 files now uncovered.

11163 of 14448 relevant lines covered (77.26%)

1.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

42.28
/Core/Games/KerbalSpaceProgram/GameVersionProviders/KspBuildMap.cs
1
using System;
2
using System.Linq;
3
using System.Collections.Generic;
4
using System.IO;
5
using System.Reflection;
6

7
using log4net;
8
using Newtonsoft.Json;
9

10
using CKAN.IO;
11
using CKAN.Versioning;
12
using CKAN.Extensions;
13

14
namespace CKAN.Games.KerbalSpaceProgram.GameVersionProviders
15
{
16
    // <summary>
17
    // THIS IS NOT THE BUILD MAP! If you are trying to access the build map,
18
    // you want to use IKspBuildMap.
19
    //
20
    // This class represents the internal JSON structure of the build map,
21
    // and should only be used by implementations of IKspBuildMap and
22
    // IConfiguration.
23
    // </summary>
24
    public sealed class JBuilds
25
    {
26
        [JsonProperty("builds")]
27
        // ReSharper disable once UnusedAutoPropertyAccessor.Local
28
        public Dictionary<string, string>? Builds { get; set; }
29
    }
30

31
    // ReSharper disable once ClassNeverInstantiated.Global
32
    public sealed class KspBuildMap : IKspBuildMap
33
    {
34
        // TODO: Need a way for the client to configure this
35
        private static readonly Uri BuildMapUri =
2✔
36
            new Uri("https://raw.githubusercontent.com/KSP-CKAN/CKAN-meta/master/builds.json");
37
        private static readonly string cachedBuildMapPath =
2✔
38
            Path.Combine(CKANPathUtils.AppDataPath, "builds-ksp.json");
39

40
        private static readonly ILog Log = LogManager.GetLogger(typeof(KspBuildMap));
2✔
41

42
        private readonly object _buildMapLock = new object();
2✔
43
        private JBuilds? _jBuilds;
44

45
        public GameVersion? this[string buildId]
46
        {
47
            get
48
            {
2✔
49
                EnsureBuildMap();
2✔
50

51
                return _jBuilds?.Builds != null && _jBuilds.Builds.TryGetValue(buildId, out string? version)
2!
52
                           ? GameVersion.Parse(version) : null;
53
            }
2✔
54
        }
55

56
        public List<GameVersion> KnownVersions
57
        {
58
            get
59
            {
2✔
60
                EnsureBuildMap();
2✔
61
                return _jBuilds?.Builds?.Select(b => GameVersion.Parse(b.Value))
2!
62
                                        .ToList()
63
                               ?? new List<GameVersion>();
64
            }
2✔
65
        }
66

67
        public KspBuildMap()
2✔
68
        {
2✔
69
        }
2✔
70

71
        private void EnsureBuildMap()
72
        {
2✔
73
            if (_jBuilds is null)
2!
UNCOV
74
            {
×
UNCOV
75
                lock (_buildMapLock)
×
UNCOV
76
                {
×
UNCOV
77
                    if (_jBuilds is null)
×
UNCOV
78
                    {
×
79
                        // Check for a cached copy of the remote build map
UNCOV
80
                        if (TrySetCachedBuildMap())
×
81
                        {
×
82
                            return;
×
83
                        }
84
                        // If that doesn't exist, use the copy from when we were compiled
UNCOV
85
                        if (TrySetEmbeddedBuildMap())
×
UNCOV
86
                        {
×
UNCOV
87
                            return;
×
88
                        }
89

90
                        Log.Warn("Could not load build map from cached or embedded copy");
×
91
                    }
×
92
                }
×
93
            }
×
94
        }
2✔
95

96
        /// <summary>
97
        /// Download the build map from the server to the cache
98
        /// </summary>
99
        public void Refresh(string? userAgent)
100
        {
2✔
101
            Log.Debug("Refreshing build map from server");
2✔
102
            if (TrySetRemoteBuildMap(userAgent))
2!
103
            {
2✔
104
                return;
2✔
105
            }
106

107
            Log.Warn("Could not refresh the build map from remote server");
×
108
        }
2✔
109

110
        private bool TrySetBuildMap(string buildMapJson)
111
        {
2✔
112
            try
113
            {
2✔
114
                _jBuilds = JsonConvert.DeserializeObject<JBuilds>(buildMapJson);
2✔
115
                return _jBuilds != null;
2✔
116
            }
117
            catch (Exception e)
×
118
            {
×
119
                Log.WarnFormat("Could not parse build map");
×
120
                Log.DebugFormat("{0}\n{1}", buildMapJson, e);
×
121
                return false;
×
122
            }
123
        }
2✔
124

125
        private bool TrySetCachedBuildMap()
UNCOV
126
        {
×
127
            try
UNCOV
128
            {
×
UNCOV
129
                Log.Debug("Getting cached build map");
×
UNCOV
130
                return TrySetBuildMap(File.ReadAllText(cachedBuildMapPath));
×
131
            }
UNCOV
132
            catch
×
UNCOV
133
            {
×
UNCOV
134
                return false;
×
135
            }
UNCOV
136
        }
×
137

138
        private bool TrySetRemoteBuildMap(string? userAgent)
139
        {
2✔
140
            try
141
            {
2✔
142
                Log.Debug("Getting remote build map");
2✔
143
                var json = Net.DownloadText(BuildMapUri, userAgent);
2✔
144
                if (json != null && TrySetBuildMap(json))
2!
145
                {
2✔
146
                    // Save to disk if parse succeeds
147
                    new FileInfo(cachedBuildMapPath).Directory?.Create();
2!
148
                    json.WriteThroughTo(cachedBuildMapPath);
2✔
149
                    return true;
2✔
150
                }
151
            }
×
152
            catch (Exception e)
×
153
            {
×
154
                Log.WarnFormat("Could not retrieve latest build map from: {0}", BuildMapUri);
×
155
                Log.Debug(e);
×
156
            }
×
157
            return false;
×
158
        }
2✔
159

160
        private bool TrySetEmbeddedBuildMap()
UNCOV
161
        {
×
162
            try
UNCOV
163
            {
×
UNCOV
164
                Log.Debug("Getting embedded build map");
×
UNCOV
165
                if (Assembly.GetExecutingAssembly()
×
166
                            .GetManifestResourceStream("CKAN.builds-ksp.json")
167
                        is Stream resourceStream)
UNCOV
168
                {
×
UNCOV
169
                    using (var reader = new StreamReader(resourceStream))
×
UNCOV
170
                    {
×
UNCOV
171
                        return TrySetBuildMap(reader.ReadToEnd());
×
172
                    }
173
                }
174
                else
175
                {
×
176
                    return false;
×
177
                }
178
            }
179
            catch (Exception e)
×
180
            {
×
181
                Log.WarnFormat("Could not retrieve build map from embedded resource");
×
182
                Log.Debug(e);
×
183
                return false;
×
184
            }
UNCOV
185
        }
×
186
    }
187
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc