-
-
Notifications
You must be signed in to change notification settings - Fork 934
/
Program.cs
149 lines (139 loc) · 8 KB
/
Program.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
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Win32;
using Xenko.Core.VisualStudio;
namespace Xenko.PackageInstall
{
class Program
{
private static readonly string[] NecessaryVS2017Workloads = new[] { "Microsoft.VisualStudio.Workload.ManagedDesktop", "Microsoft.NetCore.ComponentGroup.DevelopmentTools.2.1" };
private static readonly string[] NecessaryBuildTools2017Workloads = new[] { "Microsoft.VisualStudio.Workload.MSBuildTools", "Microsoft.VisualStudio.Workload.NetCoreBuildTools", "Microsoft.Net.Component.4.6.1.TargetingPack" };
private const bool AllowVisualStudioOnly = true; // Somehow this doesn't work well yet, so disabled for now
static int Main(string[] args)
{
try
{
if (args.Length == 0)
{
throw new Exception("Expecting a parameter such as /install, /repair or /uninstall");
}
switch (args[0])
{
case "/install":
case "/repair":
{
// Run prerequisites installer (if it exists)
var prerequisitesInstallerPath = @"install-prerequisites.exe";
if (File.Exists(prerequisitesInstallerPath))
{
RunProgramAndAskUntilSuccess("prerequisites", prerequisitesInstallerPath, string.Empty);
}
// Make sure we have the proper VS2017/BuildTools prerequisites
CheckVisualStudioAndBuildTools();
break;
}
}
return 0;
}
catch (Exception e)
{
Console.Error.WriteLine($"Error: {e}");
return 1;
}
}
private static int RunProgramAndAskUntilSuccess(string programName, string fileName, string arguments)
{
TryAgain:
try
{
var prerequisitesInstallerProcess = Process.Start(fileName, arguments);
if (prerequisitesInstallerProcess == null)
{
MessageBox.Show($"The installation of {programName} failed (file not found).", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return -1;
}
prerequisitesInstallerProcess.WaitForExit();
if (prerequisitesInstallerProcess.ExitCode != 0)
{
// We'll enter this if UAC has been declined, but also if it timed out (which is a frequent case)
// if you don't stay in front of your computer during the installation.
var result = MessageBox.Show($"The installation of {programName} returned with code {prerequisitesInstallerProcess.ExitCode}.\r\nDo you want to try it again?", "Error", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result != DialogResult.Yes)
return prerequisitesInstallerProcess.ExitCode;
goto TryAgain;
}
return 0;
}
catch (Win32Exception e) when (e.NativeErrorCode == 1223)
{
// We'll enter this if UAC has been declined, but also if it timed out (which is a frequent case)
// if you don't stay in front of your computer during the installation.
var result = MessageBox.Show($"The installation of {programName} failed to run (UAC denied).\r\nDo you want to try it again?", "Error", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result != DialogResult.Yes)
return -1;
goto TryAgain;
}
catch (Exception e)
{
MessageBox.Show($"The installation of {programName} failed unexpectedly:\r\n\r\n{e}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return -1;
}
}
private static void CheckVisualStudioAndBuildTools()
{
// Check if there is any VS2017 installed with necessary workloads
var matchingVisualStudioInstallation = VisualStudioVersions.AvailableVisualStudioInstances.FirstOrDefault(x => NecessaryVS2017Workloads.All(workload => x.PackageVersions.ContainsKey(workload)));
if (AllowVisualStudioOnly && matchingVisualStudioInstallation != null)
{
if (!matchingVisualStudioInstallation.Complete)
MessageBox.Show("We detected Visual Studio 2017 was already installed but is not in a complete state.\r\nYou probably have to reboot, otherwise Xenko projects won't properly compile.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
// Check if there is actually a VS2017+ installed
var existingVisualStudio2017Install = VisualStudioVersions.AvailableVisualStudioInstances.FirstOrDefault(x => x.PackageVersions.ContainsKey("Microsoft.VisualStudio.Component.CoreEditor"));
var vsInstallerPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Microsoft Visual Studio\Installer\vs_installer.exe");
if (AllowVisualStudioOnly && existingVisualStudio2017Install != null && File.Exists(vsInstallerPath))
{
var vsInstallerExitCode = RunProgramAndAskUntilSuccess("Visual Studio", vsInstallerPath, $"modify --passive --norestart --installPath \"{existingVisualStudio2017Install.InstallationPath}\" {string.Join(" ", NecessaryVS2017Workloads.Select(x => $"--add {x}"))}");
if (vsInstallerExitCode == 0)
MessageBox.Show("Visual Studio 2017 was missing the .NET desktop develpment workload.\r\nWe highly recommend a reboot after the installation is finished, otherwise Xenko projects won't compile.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
// Otherwise, fallback to vs_buildtools standalone detection and install
var buildTools = VisualStudioVersions.AvailableBuildTools.Where(x => x.PackageVersions.ContainsKey("Microsoft.VisualStudio.Workload.MSBuildTools")).ToList();
var matchingBuildTool = buildTools.FirstOrDefault(x => NecessaryBuildTools2017Workloads.All(workload => x.PackageVersions.ContainsKey(workload)));
string buildToolsCommandLine = null;
if (matchingBuildTool == null)
{
if (buildTools.Count > 0)
{
// Incomplete installation
buildToolsCommandLine = $"modify --wait --passive --norestart --installPath \"{buildTools.First().InstallationPath}\" {string.Join(" ", NecessaryBuildTools2017Workloads.Select(x => $"--add {x}"))}";
}
else
{
// Not installed yet
buildToolsCommandLine = $"--wait --passive --norestart {string.Join(" ", NecessaryBuildTools2017Workloads.Select(x => $"--add {x}"))}";
}
}
if (buildToolsCommandLine != null)
{
// Run vs_buildtools again
RunProgramAndAskUntilSuccess("Build Tools", "vs_buildtools.exe", buildToolsCommandLine);
}
}
}
}
}
}