Skip to content

Commit 3eab036

Browse files
author
davidkline-ms
committed
check version of MS Build and ensure a min version is configured
1 parent ebe6f97 commit 3eab036

File tree

2 files changed

+116
-70
lines changed

2 files changed

+116
-70
lines changed

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

Lines changed: 115 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,83 @@ 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></returns>
50+
internal static bool IsMSBuildForUnityEnabled()
51+
{
52+
string manifestPath = GetPackageManifestFilePath();
53+
if (string.IsNullOrWhiteSpace(manifestPath))
54+
{
55+
return false;
56+
}
57+
58+
// Load the manifest file.
59+
string manifestFileContents = File.ReadAllText(manifestPath);
60+
if (string.IsNullOrWhiteSpace(manifestFileContents))
61+
{
62+
return false;
63+
}
64+
65+
// Read the package manifest a line at a time.
66+
bool msBuildFound = false;
67+
bool isAppropriateVersion = false;
68+
Version minVersion = Version.Parse(MSBuildPackageVersion);
69+
using (FileStream manifestStream = new FileStream(manifestPath, FileMode.Open, FileAccess.Read))
70+
{
71+
using (StreamReader reader = new StreamReader(manifestStream))
72+
{
73+
// Read the manifest file a line at a time.
74+
while (!reader.EndOfStream)
75+
{
76+
string line = reader.ReadLine();
77+
if (line.Contains(MSBuildPackageName))
78+
{
79+
msBuildFound = true;
80+
81+
// Next, check the version.
82+
string[] splitLine = line.Split(new char[] { ':' });
83+
if (splitLine.Length == 2)
84+
{
85+
string versionString = splitLine[1].Trim(new char[] { ' ', '\"', ',' });
86+
87+
Version version;
88+
if (Version.TryParse(versionString, out version))
89+
{
90+
isAppropriateVersion = version >= minVersion;
91+
}
92+
}
93+
94+
break;
95+
}
96+
}
97+
}
3998
}
4099

100+
return (msBuildFound && isAppropriateVersion);
101+
}
102+
103+
/// <summary>
104+
/// Ensures the required settings exist in the package manager to allow for using MSBuild for Unity.
105+
/// </summary>
106+
internal static void EnsureMSBuildForUnity()
107+
{
41108
PackageManifest manifest = null;
42109

110+
string manifestPath = GetPackageManifestFilePath();
111+
if (string.IsNullOrWhiteSpace(manifestPath))
112+
{
113+
return;
114+
}
115+
43116
// Read the package manifest into a list of strings (for easy finding of entries)
44117
// and then deserialize.
45118
List<string> manifestFileLines = new List<string>();
@@ -102,11 +175,12 @@ internal static void EnsureMSBuildForUnity()
102175
int dependenciesStartIndex = -1;
103176
int scopedRegistriesStartIndex = -1;
104177
int scopedRegistriesEndIndex = -1;
178+
int packageLine = -1;
105179

106180
// Attempt to find the MSBuild for Unity package entry in the dependencies collection
107181
// This loop also identifies the dependecies collection line and the start / end of a
108182
// pre-existing scoped registries collections
109-
bool needToAddPackage = true;
183+
bool addPackage = true;
110184
for (int i = 0; i < manifestFileLines.Count; i++)
111185
{
112186
if (manifestFileLines[i].Contains("\"scopedRegistries\":"))
@@ -123,55 +197,57 @@ internal static void EnsureMSBuildForUnity()
123197
}
124198
if (manifestFileLines[i].Contains(MSBuildPackageName))
125199
{
126-
needToAddPackage = false;
200+
packageLine = i;
201+
addPackage = false;
127202
}
128203
}
129204

130205
// If no package was found add it to the dependencies collection.
131-
if (needToAddPackage)
206+
if (addPackage)
132207
{
133208
// Add the package to the collection (pad the entry with four spaces)
134209
manifestFileLines.Insert(dependenciesStartIndex + 1, $" \"{MSBuildPackageName}\": \"{MSBuildPackageVersion}\",");
135210
}
136-
137-
if (needToAddRegistry || needToAddPackage)
211+
else
138212
{
139-
// If we added a scoped registry or package, rewrite the manifest file.
213+
// Replace the line that currently exists
214+
manifestFileLines[packageLine] = $" \"{MSBuildPackageName}\": \"{MSBuildPackageVersion}\",";
215+
}
140216

141-
// First, serialize the scoped registry collection.
142-
string serializedRegistriesJson = JsonUtility.ToJson(manifest, true);
217+
// Update the manifest file.
218+
// First, serialize the scoped registry collection.
219+
string serializedRegistriesJson = JsonUtility.ToJson(manifest, true);
143220

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))
221+
// Ensure that the file is truncated to ensure it is always valid after writing.
222+
using (FileStream outFile = new FileStream(manifestPath, FileMode.Truncate, FileAccess.Write))
223+
{
224+
using (StreamWriter writer = new StreamWriter(outFile))
146225
{
147-
using (StreamWriter writer = new StreamWriter(outFile))
148-
{
149-
bool scopedRegistriesWritten = false;
226+
bool scopedRegistriesWritten = false;
150227

151-
// Write each line of the manifest back to the file.
152-
for (int i = 0; i < manifestFileLines.Count; i++)
228+
// Write each line of the manifest back to the file.
229+
for (int i = 0; i < manifestFileLines.Count; i++)
230+
{
231+
if ((i >= scopedRegistriesStartIndex) && (i <= scopedRegistriesEndIndex))
153232
{
154-
if ((i >= scopedRegistriesStartIndex) && (i <= scopedRegistriesEndIndex))
155-
{
156-
// Skip these lines, they will be replaced.
157-
continue;
158-
}
233+
// Skip these lines, they will be replaced.
234+
continue;
235+
}
159236

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-
}
237+
if (!scopedRegistriesWritten && (i > 0))
238+
{
239+
// Trim the leading '{' and '\n' from the serialized scoped registries
240+
serializedRegistriesJson = serializedRegistriesJson.Remove(0, 2);
241+
// Trim, the trailing '\n' and '}'
242+
serializedRegistriesJson = serializedRegistriesJson.Remove(serializedRegistriesJson.Length - 2);
243+
// Append a trailing ',' to close the scopedRegistries node
244+
serializedRegistriesJson = serializedRegistriesJson.Insert(serializedRegistriesJson.Length, ",");
245+
writer.WriteLine(serializedRegistriesJson);
172246

173-
writer.WriteLine(manifestFileLines[i]);
247+
scopedRegistriesWritten = true;
174248
}
249+
250+
writer.WriteLine(manifestFileLines[i]);
175251
}
176252
}
177253
}

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)