-
Notifications
You must be signed in to change notification settings - Fork 1k
/
VSSettings.cs
155 lines (129 loc) · 5.01 KB
/
VSSettings.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using Microsoft.DotNet.NativeWrapper;
#if NETFRAMEWORK
using Microsoft.VisualStudio.Setup.Configuration;
#endif
#nullable disable
namespace Microsoft.DotNet.DotNetSdkResolver
{
public sealed class VSSettings
{
private readonly object _lock = new object();
private readonly string _settingsFilePath;
private readonly bool _disallowPrereleaseByDefault;
private FileInfo _settingsFile;
private bool _disallowPrerelease;
// In the product, this singleton is used. It must be safe to use in parallel on multiple threads.
// In tests, mock instances can be created with the test constructor below.
public static readonly VSSettings Ambient = new VSSettings();
private VSSettings()
{
#if NETFRAMEWORK
if (!Interop.RunningOnWindows)
{
return;
}
string instanceId;
string installationVersion;
bool isPrerelease;
try
{
var configuration = new SetupConfiguration();
var instance = configuration.GetInstanceForCurrentProcess();
instanceId = instance.GetInstanceId();
installationVersion = instance.GetInstallationVersion();
isPrerelease = ((ISetupInstanceCatalog)instance).IsPrerelease();
}
catch (COMException)
{
return;
}
var version = Version.Parse(installationVersion);
_settingsFilePath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Microsoft",
"VisualStudio",
version.Major + ".0_" + instanceId,
"sdk.txt");
_disallowPrereleaseByDefault = !isPrerelease;
_disallowPrerelease = _disallowPrereleaseByDefault;
#endif
}
// Test constructor
public VSSettings(string settingsFilePath, bool disallowPrereleaseByDefault)
{
_settingsFilePath = settingsFilePath;
_disallowPrereleaseByDefault = disallowPrereleaseByDefault;
_disallowPrerelease = _disallowPrereleaseByDefault;
}
public bool DisallowPrerelease()
{
if (_settingsFilePath != null)
{
Refresh();
}
return _disallowPrerelease;
}
private void Refresh()
{
Debug.Assert(_settingsFilePath != null);
var file = new FileInfo(_settingsFilePath);
// NB: All calls to Exists and LastWriteTimeUtc below will not hit the disk
// They will return data obtained during Refresh() here.
file.Refresh();
lock (_lock)
{
// File does not exist -> use default.
if (!file.Exists)
{
_disallowPrerelease = _disallowPrereleaseByDefault;
_settingsFile = file;
return;
}
// File has not changed -> reuse prior read.
if (_settingsFile?.Exists == true && file.LastWriteTimeUtc <= _settingsFile.LastWriteTimeUtc)
{
return;
}
// File has changed -> read from disk
// If we encounter an I/O exception, assume writer is in the process of updating file,
// ignore the exception, and use stale settings until the next resolution.
try
{
ReadFromDisk();
_settingsFile = file;
return;
}
catch (IOException) { }
catch (UnauthorizedAccessException) { }
}
}
private void ReadFromDisk()
{
using (var reader = new StreamReader(_settingsFilePath))
{
string line;
while ((line = reader.ReadLine()) != null)
{
int indexOfEquals = line.IndexOf('=');
if (indexOfEquals < 0 || indexOfEquals == (line.Length - 1))
{
continue;
}
string key = line.Substring(0, indexOfEquals).Trim();
string value = line.Substring(indexOfEquals + 1).Trim();
if (key.Equals("UsePreviews", StringComparison.OrdinalIgnoreCase)
&& bool.TryParse(value, out bool usePreviews))
{
_disallowPrerelease = !usePreviews;
return;
}
}
}
// File does not have UsePreviews entry -> use default
_disallowPrerelease = _disallowPrereleaseByDefault;
}
}
}