Skip to content

Commit 143d27a

Browse files
author
David Kline
authored
Merge pull request #7216 from davidkline-ms/upgradeMSBU
Configure dialog will prompt if the version of MSBuild for Unity should be upgraded
2 parents ebe6f97 + f0e7bfb commit 143d27a

File tree

2 files changed

+128
-70
lines changed

2 files changed

+128
-70
lines changed

Assets/MixedRealityToolkit/Utilities/Editor/PackageManifest/PackageManifestUpdater.cs

Lines changed: 127 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Collections.Generic;
66
using System.IO;
7+
using UnityEditor.PackageManager;
78
using UnityEngine;
89

910
namespace Microsoft.MixedReality.Toolkit.Utilities.Editor
@@ -17,14 +18,14 @@ internal static class PackageManifestUpdater
1718
private static string MSBuildRegistryName = "MS Build for Unity";
1819
private static string[] MSBuildRegistryScopes = new string[] { "com.microsoft" };
1920

20-
private static string MSBuildPackageName = "com.microsoft.msbuildforunity";
21-
private static string MSBuildPackageVersion = "0.9.1";
21+
internal const string MSBuildPackageName = "com.microsoft.msbuildforunity";
22+
internal const string MSBuildPackageVersion = "0.9.1";
2223

2324
/// <summary>
24-
/// Ensures the required settings exist in the package manager to allow for
25-
/// installing MSBuild for Unity.
25+
/// Finds and returns the fully qualified path to the Unity Package Manager manifest
2626
/// </summary>
27-
internal static void EnsureMSBuildForUnity()
27+
/// <returns>The path to the manifest file, or null.</returns>
28+
private static string GetPackageManifestFilePath()
2829
{
2930
// Locate the full path to the package manifest.
3031
DirectoryInfo projectRoot = new DirectoryInfo(Application.dataPath).Parent;
@@ -35,11 +36,95 @@ internal static void EnsureMSBuildForUnity()
3536
if (!File.Exists(manifestPath))
3637
{
3738
Debug.LogError($"Package manifest file ({manifestPath}) could not be found.");
38-
return;
39+
return null;
40+
}
41+
42+
return manifestPath;
43+
}
44+
45+
/// <summary>
46+
/// Reports whether or not the appropriate version of MSBuild for Unity is specified
47+
/// in the Unity Package Manager manifest.
48+
/// </summary>
49+
/// <returns>
50+
/// True if an appropriate verson of MS Build for Unity is configured in the manifest, otherwise false.
51+
/// </returns>
52+
internal static bool IsMSBuildForUnityEnabled()
53+
{
54+
string manifestPath = GetPackageManifestFilePath();
55+
if (string.IsNullOrWhiteSpace(manifestPath))
56+
{
57+
return false;
58+
}
59+
60+
// Load the manifest file.
61+
string manifestFileContents = File.ReadAllText(manifestPath);
62+
if (string.IsNullOrWhiteSpace(manifestFileContents))
63+
{
64+
return false;
65+
}
66+
67+
// Read the package manifest a line at a time.
68+
bool msBuildFound = false;
69+
bool isAppropriateVersion = false;
70+
Version minVersion = Version.Parse(MSBuildPackageVersion);
71+
using (FileStream manifestStream = new FileStream(manifestPath, FileMode.Open, FileAccess.Read))
72+
{
73+
using (StreamReader reader = new StreamReader(manifestStream))
74+
{
75+
// Read the manifest file a line at a time.
76+
while (!reader.EndOfStream)
77+
{
78+
string line = reader.ReadLine();
79+
if (line.Contains(MSBuildPackageName))
80+
{
81+
msBuildFound = true;
82+
83+
// Next, check the version.
84+
string[] splitLine = line.Split(new char[] { ':' });
85+
if (splitLine.Length == 2)
86+
{
87+
// Ensure correct formatting of the version string, before we attempt to parse it.
88+
string versionString = splitLine[1].Trim(new char[] { ' ', '\"', ',' });
89+
bool replaceOnEquals = false;
90+
if (versionString.Contains("-"))
91+
{
92+
// The string references a preview version. Truncate at the '-'.
93+
versionString = versionString.Substring(0, versionString.IndexOf('-'));
94+
95+
// We want to update preview versions to the final.
96+
replaceOnEquals = true;
97+
}
98+
99+
Version version;
100+
if (Version.TryParse(versionString, out version))
101+
{
102+
isAppropriateVersion = replaceOnEquals ? (version > minVersion) : (version >= minVersion);
103+
}
104+
}
105+
106+
break;
107+
}
108+
}
109+
}
39110
}
40111

112+
return (msBuildFound && isAppropriateVersion);
113+
}
114+
115+
/// <summary>
116+
/// Ensures the required settings exist in the package manager to allow for using MSBuild for Unity.
117+
/// </summary>
118+
internal static void EnsureMSBuildForUnity()
119+
{
41120
PackageManifest manifest = null;
42121

122+
string manifestPath = GetPackageManifestFilePath();
123+
if (string.IsNullOrWhiteSpace(manifestPath))
124+
{
125+
return;
126+
}
127+
43128
// Read the package manifest into a list of strings (for easy finding of entries)
44129
// and then deserialize.
45130
List<string> manifestFileLines = new List<string>();
@@ -102,11 +187,12 @@ internal static void EnsureMSBuildForUnity()
102187
int dependenciesStartIndex = -1;
103188
int scopedRegistriesStartIndex = -1;
104189
int scopedRegistriesEndIndex = -1;
190+
int packageLine = -1;
105191

106192
// Attempt to find the MSBuild for Unity package entry in the dependencies collection
107193
// This loop also identifies the dependecies collection line and the start / end of a
108194
// pre-existing scoped registries collections
109-
bool needToAddPackage = true;
195+
bool addPackage = true;
110196
for (int i = 0; i < manifestFileLines.Count; i++)
111197
{
112198
if (manifestFileLines[i].Contains("\"scopedRegistries\":"))
@@ -123,55 +209,57 @@ internal static void EnsureMSBuildForUnity()
123209
}
124210
if (manifestFileLines[i].Contains(MSBuildPackageName))
125211
{
126-
needToAddPackage = false;
212+
packageLine = i;
213+
addPackage = false;
127214
}
128215
}
129216

130217
// If no package was found add it to the dependencies collection.
131-
if (needToAddPackage)
218+
if (addPackage)
132219
{
133220
// Add the package to the collection (pad the entry with four spaces)
134221
manifestFileLines.Insert(dependenciesStartIndex + 1, $" \"{MSBuildPackageName}\": \"{MSBuildPackageVersion}\",");
135222
}
136-
137-
if (needToAddRegistry || needToAddPackage)
223+
else
138224
{
139-
// If we added a scoped registry or package, rewrite the manifest file.
225+
// Replace the line that currently exists
226+
manifestFileLines[packageLine] = $" \"{MSBuildPackageName}\": \"{MSBuildPackageVersion}\",";
227+
}
140228

141-
// First, serialize the scoped registry collection.
142-
string serializedRegistriesJson = JsonUtility.ToJson(manifest, true);
229+
// Update the manifest file.
230+
// First, serialize the scoped registry collection.
231+
string serializedRegistriesJson = JsonUtility.ToJson(manifest, true);
143232

144-
// Ensure that the file is truncated to ensure it is always valid after writing.
145-
using (FileStream outFile = new FileStream(manifestPath, FileMode.Truncate, FileAccess.Write))
233+
// Ensure that the file is truncated to ensure it is always valid after writing.
234+
using (FileStream outFile = new FileStream(manifestPath, FileMode.Truncate, FileAccess.Write))
235+
{
236+
using (StreamWriter writer = new StreamWriter(outFile))
146237
{
147-
using (StreamWriter writer = new StreamWriter(outFile))
148-
{
149-
bool scopedRegistriesWritten = false;
238+
bool scopedRegistriesWritten = false;
150239

151-
// Write each line of the manifest back to the file.
152-
for (int i = 0; i < manifestFileLines.Count; i++)
240+
// Write each line of the manifest back to the file.
241+
for (int i = 0; i < manifestFileLines.Count; i++)
242+
{
243+
if ((i >= scopedRegistriesStartIndex) && (i <= scopedRegistriesEndIndex))
153244
{
154-
if ((i >= scopedRegistriesStartIndex) && (i <= scopedRegistriesEndIndex))
155-
{
156-
// Skip these lines, they will be replaced.
157-
continue;
158-
}
245+
// Skip these lines, they will be replaced.
246+
continue;
247+
}
159248

160-
if (!scopedRegistriesWritten && (i > 0))
161-
{
162-
// Trim the leading '{' and '\n' from the serialized scoped registries
163-
serializedRegistriesJson = serializedRegistriesJson.Remove(0, 2);
164-
// Trim, the trailing '\n' and '}'
165-
serializedRegistriesJson = serializedRegistriesJson.Remove(serializedRegistriesJson.Length - 2);
166-
// Append a trailing ',' to close the scopedRegistries node
167-
serializedRegistriesJson = serializedRegistriesJson.Insert(serializedRegistriesJson.Length, ",");
168-
writer.WriteLine(serializedRegistriesJson);
169-
170-
scopedRegistriesWritten = true;
171-
}
249+
if (!scopedRegistriesWritten && (i > 0))
250+
{
251+
// Trim the leading '{' and '\n' from the serialized scoped registries
252+
serializedRegistriesJson = serializedRegistriesJson.Remove(0, 2);
253+
// Trim, the trailing '\n' and '}'
254+
serializedRegistriesJson = serializedRegistriesJson.Remove(serializedRegistriesJson.Length - 2);
255+
// Append a trailing ',' to close the scopedRegistries node
256+
serializedRegistriesJson = serializedRegistriesJson.Insert(serializedRegistriesJson.Length, ",");
257+
writer.WriteLine(serializedRegistriesJson);
172258

173-
writer.WriteLine(manifestFileLines[i]);
259+
scopedRegistriesWritten = true;
174260
}
261+
262+
writer.WriteLine(manifestFileLines[i]);
175263
}
176264
}
177265
}

Assets/MixedRealityToolkit/Utilities/Editor/Setup/MixedRealityProjectConfigurator.cs

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public bool IsActiveBuildTargetValid()
102102
{ Configurations.VirtualRealitySupported, new ConfigGetter(() => { return XRSettingsUtilities.LegacyXREnabled; }) },
103103
{ Configurations.SinglePassInstancing, new ConfigGetter(() => { return MixedRealityOptimizeUtils.IsSinglePassInstanced(); }) },
104104
{ Configurations.SpatialAwarenessLayer, new ConfigGetter(() => { return HasSpatialAwarenessLayer(); }) },
105-
{ Configurations.EnableMSBuildForUnity, new ConfigGetter(() => { return IsMSBuildForUnityEnabled(); }, BuildTarget.WSAPlayer) },
105+
{ Configurations.EnableMSBuildForUnity, new ConfigGetter(() => { return PackageManifestUpdater.IsMSBuildForUnityEnabled(); }, BuildTarget.WSAPlayer) },
106106

107107
// UWP Capabilities
108108
{ Configurations.SpatialPerceptionCapability, new ConfigGetter(() => { return GetCapability(PlayerSettings.WSACapability.SpatialPerception); }, BuildTarget.WSAPlayer) },
@@ -265,36 +265,6 @@ public static bool IsForceTextSerialization()
265265
return EditorSettings.serializationMode == SerializationMode.ForceText;
266266
}
267267

268-
/// <summary>
269-
/// Checks package manifest to see if MSBuild for Unity is included in the dependencies.
270-
/// </summary>
271-
public static bool IsMSBuildForUnityEnabled()
272-
{
273-
// Locate the full path to the package manifest.
274-
DirectoryInfo projectRoot = new DirectoryInfo(Application.dataPath).Parent;
275-
string[] paths = { projectRoot.FullName, "Packages", "manifest.json" };
276-
string manifestPath = Path.Combine(paths);
277-
278-
// Verify that the package manifest file exists.
279-
if (!File.Exists(manifestPath))
280-
{
281-
Debug.LogError($"Package manifest file ({manifestPath}) could not be found.");
282-
return false;
283-
}
284-
285-
// Load the manifest file.
286-
string manifestFileContents = File.ReadAllText(manifestPath);
287-
if (string.IsNullOrWhiteSpace(manifestFileContents))
288-
{
289-
Debug.LogError($"Failed to read the package manifest file ({manifestPath})");
290-
return false;
291-
}
292-
293-
// Attempt to find the MSBuild for Unity package name.
294-
const string msBuildPackageName = "com.microsoft.msbuildforunity";
295-
return manifestFileContents.Contains(msBuildPackageName);
296-
}
297-
298268
/// <summary>
299269
/// Configures current Unity project to force text serialization
300270
/// </summary>

0 commit comments

Comments
 (0)