-
Notifications
You must be signed in to change notification settings - Fork 40
/
SelectInstanceCommand.cs
190 lines (164 loc) · 6.55 KB
/
SelectInstanceCommand.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// <copyright file="SelectInstanceCommand.cs" company="Microsoft Corporation">
// Copyright (C) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt in the project root for license information.
// </copyright>
namespace Microsoft.VisualStudio.Setup.PowerShell
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Text.RegularExpressions;
using Configuration;
/// <summary>
/// The Select-VSSetupInstance command.
/// </summary>
[Cmdlet(VerbsCommon.Select, "VSSetupInstance")]
[OutputType(typeof(Instance))]
public class SelectInstanceCommand : Cmdlet
{
/// <summary>
/// A regular expression that matches a version range.
/// </summary>
internal const string VersionRangePattern = @"^((\d+(\.\d+){1,3})|([\[\(]\s*(\d+(\.\d+){1,3})?\s*(,\s*(\d+(\.\d+){1,3})?)?\s*[\]\)]))$";
/// <summary>
/// Regular expression options for the version range.
/// </summary>
internal const RegexOptions VersionRangeOptions = RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture | RegexOptions.Singleline;
private static readonly WildcardPattern AllPattern = new WildcardPattern("*", WildcardOptions.None);
private ISetupHelper helper = null;
private Instance latestInstance = null;
private ulong minVersion = 0;
private ulong maxVersion = 0;
/// <summary>
/// Gets or sets the Instance parameter.
/// </summary>
[Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true)]
public Instance[] Instance { get; set; }
/// <summary>
/// Gets or sets the Product parameter.
/// </summary>
[Parameter]
[ValidateNotNullOrEmpty]
public string[] Product { get; set; } = new[]
{
"Microsoft.VisualStudio.Product.Enterprise",
"Microsoft.VisualStudio.Product.Professional",
"Microsoft.VisualStudio.Product.Community",
};
/// <summary>
/// Gets or sets the Require parameter.
/// </summary>
[Parameter]
[ValidateNotNullOrEmpty]
public string[] Require { get; set; }
/// <summary>
/// Gets or sets the <see cref="RequireAny"/> parameter.
/// </summary>
[Parameter]
public SwitchParameter RequireAny { get; set; }
/// <summary>
/// Gets or sets the Version parameter.
/// </summary>
[Parameter]
[ValidatePattern(VersionRangePattern, Options = VersionRangeOptions)]
public string Version { get; set; }
/// <summary>
/// Gets or sets the Latest parameter.
/// </summary>
[Parameter]
public SwitchParameter Latest { get; set; }
/// <inheritdoc/>
protected override void BeginProcessing()
{
if (!string.IsNullOrEmpty(Version))
{
var query = QueryFactory.Create();
if (query != null)
{
helper = (ISetupHelper)new SetupConfiguration();
helper.ParseVersionRange(Version, out minVersion, out maxVersion);
}
}
}
/// <inheritdoc/>
protected override void ProcessRecord()
{
IEnumerable<Instance> instances = Instance;
if (Product != null && Product.Any())
{
// Select instances with no product or the specified product ID.
var patterns = Product.Select(product => GetPattern(product)).ToArray();
instances = from instance in instances
let instanceProduct = instance?.Product
where instanceProduct == null || patterns.Any(pattern => pattern.IsMatch(instanceProduct.Id))
select instance;
}
if (Require != null && Require.Any())
{
// Select instances that contain the specified package IDs.
bool Contains(IEnumerable<PackageReference> packages, Func<PackageReference, string> selector)
{
if (RequireAny)
{
return packages.ContainsAny(selector, Require, StringComparer.OrdinalIgnoreCase);
}
return packages.ContainsAll(selector, Require, StringComparer.OrdinalIgnoreCase);
}
instances = from instance in instances
let instancePackages = instance?.Packages
where instancePackages != null && Contains(instancePackages, package => package.Id)
select instance;
}
if (helper != null)
{
instances = from instance in instances
let instanceVersion = instance?.InstallationVersion?.ToString()
where !string.IsNullOrEmpty(instanceVersion)
let version = helper.ParseVersion(instanceVersion)
where minVersion <= version && version <= maxVersion
select instance;
}
foreach (var instance in instances)
{
if (Latest)
{
if (latestInstance == null || latestInstance.InstallDate < instance.InstallDate)
{
latestInstance = instance;
}
}
else
{
WriteInstance(instance);
}
}
}
/// <inheritdoc/>
protected override void EndProcessing()
{
if (latestInstance != null)
{
WriteInstance(latestInstance);
}
// Release the COM object and its resources ASAP.
helper = null;
}
private static WildcardPattern GetPattern(string pattern)
{
Validate.NotNullOrEmpty(pattern, nameof(pattern));
if (pattern.Length == 1 && pattern[0] == '*')
{
return AllPattern;
}
return new WildcardPattern(pattern, WildcardOptions.CultureInvariant | WildcardOptions.IgnoreCase);
}
private void WriteInstance(Instance instance)
{
if (instance != null)
{
WriteObject(instance);
}
}
}
}