/// <summary> /// Ensures the required settings exist in the package manager to allow for /// installing MSBuild for Unity. /// </summary> internal static void EnsureMSBuildForUnity() { // Locate the full path to the package manifest. DirectoryInfo projectRoot = new DirectoryInfo(Application.dataPath).Parent; string[] paths = { projectRoot.FullName, "Packages", "manifest.json" }; string manifestPath = Path.Combine(paths); // Verify that the package manifest file exists. if (!File.Exists(manifestPath)) { Debug.LogError($"Package manifest file ({manifestPath}) could not be found."); return; } PackageManifest manifest = null; // Read the package manifest into a list of strings (for easy finding of entries) // and then deserialize. List <string> manifestFileLines = new List <string>(); using (FileStream manifestStream = new FileStream(manifestPath, FileMode.Open, FileAccess.Read)) { using (StreamReader reader = new StreamReader(manifestStream)) { // Read the manifest file a line at a time. while (!reader.EndOfStream) { string line = reader.ReadLine(); manifestFileLines.Add(line); } // Go back to the start of the file. manifestStream.Seek(0, 0); // Deserialize the scoped registries portion of the package manifest. manifest = JsonUtility.FromJson <PackageManifest>(reader.ReadToEnd()); } } if (manifest == null) { Debug.LogError($"Failed to read the package manifest file ({manifestPath})"); return; } // Ensure that pre-exising scoped registries are retained. List <ScopedRegistry> scopedRegistries = new List <ScopedRegistry>(); if ((manifest.scopedRegistries != null) && (manifest.scopedRegistries.Length > 0)) { scopedRegistries.AddRange(manifest.scopedRegistries); } // Attempt to find an entry in the scoped regstries collection for the MSBuild for Unity url bool needToAddRegistry = true; foreach (ScopedRegistry registry in scopedRegistries) { if (registry.url == MSBuildRegistryUrl) { needToAddRegistry = false; } } // If no entry was found, add one. if (needToAddRegistry) { ScopedRegistry registry = new ScopedRegistry(); registry.name = MSBuildRegistryName; registry.url = MSBuildRegistryUrl; registry.scopes = MSBuildRegistryScopes; scopedRegistries.Add(registry); } // Update the manifest's scoped registries, as the collection may have been modified. manifest.scopedRegistries = scopedRegistries.ToArray(); int dependenciesStartIndex = -1; int scopedRegistriesStartIndex = -1; int scopedRegistriesEndIndex = -1; // Attempt to find the MSBuild for Unity package entry in the dependencies collection // This loop also identifies the dependecies collection line and the start / end of a // pre-existing scoped registries collections bool needToAddPackage = true; for (int i = 0; i < manifestFileLines.Count; i++) { if (manifestFileLines[i].Contains("\"scopedRegistries\":")) { scopedRegistriesStartIndex = i; } if (manifestFileLines[i].Contains("],") && (scopedRegistriesStartIndex != -1) && (scopedRegistriesEndIndex == -1)) { scopedRegistriesEndIndex = i; } if (manifestFileLines[i].Contains("\"dependencies\": {")) { dependenciesStartIndex = i; } if (manifestFileLines[i].Contains(MSBuildPackageName)) { needToAddPackage = false; } } // If no package was found add it to the dependencies collection. if (needToAddPackage) { // Add the package to the collection (pad the entry with four spaces) manifestFileLines.Insert(dependenciesStartIndex + 1, $" \"{MSBuildPackageName}\": \"{MSBuildPackageVersion}\","); } if (needToAddRegistry || needToAddPackage) { // If we added a scoped registry or package, rewrite the manifest file. // First, serialize the scoped registry collection. string serializedRegistriesJson = JsonUtility.ToJson(manifest, true); // Ensure that the file is truncated to ensure it is always valid after writing. using (FileStream outFile = new FileStream(manifestPath, FileMode.Truncate, FileAccess.Write)) { using (StreamWriter writer = new StreamWriter(outFile)) { bool scopedRegistriesWritten = false; // Write each line of the manifest back to the file. for (int i = 0; i < manifestFileLines.Count; i++) { if ((i >= scopedRegistriesStartIndex) && (i <= scopedRegistriesEndIndex)) { // Skip these lines, they will be replaced. continue; } if (!scopedRegistriesWritten && (i > 0)) { // Trim the leading '{' and '\n' from the serialized scoped registries serializedRegistriesJson = serializedRegistriesJson.Remove(0, 2); // Trim, the trailing '\n' and '}' serializedRegistriesJson = serializedRegistriesJson.Remove(serializedRegistriesJson.Length - 2); // Append a trailing ',' to close the scopedRegistries node serializedRegistriesJson = serializedRegistriesJson.Insert(serializedRegistriesJson.Length, ","); writer.WriteLine(serializedRegistriesJson); scopedRegistriesWritten = true; } writer.WriteLine(manifestFileLines[i]); } } } } }
/// <summary> /// Ensures the required settings exist in the package manager to allow for using MSBuild for Unity. /// </summary> internal static void EnsureMSBuildForUnity() { PackageManifest manifest = null; string manifestPath = GetPackageManifestFilePath(); if (string.IsNullOrWhiteSpace(manifestPath)) { return; } // Read the package manifest into a list of strings (for easy finding of entries) // and then deserialize. List <string> manifestFileLines = new List <string>(); using (FileStream manifestStream = new FileStream(manifestPath, FileMode.Open, FileAccess.Read)) { using (StreamReader reader = new StreamReader(manifestStream)) { // Read the manifest file a line at a time. while (!reader.EndOfStream) { string line = reader.ReadLine(); manifestFileLines.Add(line); } // Go back to the start of the file. manifestStream.Seek(0, 0); // Deserialize the scoped registries portion of the package manifest. manifest = JsonUtility.FromJson <PackageManifest>(reader.ReadToEnd()); } } if (manifest == null) { Debug.LogError($"Failed to read the package manifest file ({manifestPath})"); return; } // Ensure that pre-existing scoped registries are retained. List <ScopedRegistry> scopedRegistries = new List <ScopedRegistry>(); if ((manifest.scopedRegistries != null) && (manifest.scopedRegistries.Length > 0)) { scopedRegistries.AddRange(manifest.scopedRegistries); } // Attempt to find an entry in the scoped registries collection for the MSBuild for Unity URL bool needToAddRegistry = true; foreach (ScopedRegistry registry in scopedRegistries) { if (registry.url == MSBuildRegistryUrl) { needToAddRegistry = false; } } // If no entry was found, add one. if (needToAddRegistry) { ScopedRegistry registry = new ScopedRegistry(); registry.name = MSBuildRegistryName; registry.url = MSBuildRegistryUrl; registry.scopes = MSBuildRegistryScopes; scopedRegistries.Add(registry); } // Update the manifest's scoped registries, as the collection may have been modified. manifest.scopedRegistries = scopedRegistries.ToArray(); int dependenciesStartIndex = -1; int scopedRegistriesStartIndex = -1; int scopedRegistriesEndIndex = -1; int packageLine = -1; // Presume that we need to add the MSBuild for Unity package. If this value is false, // we will check to see if the currently configured version meets or exceeds the // minimum requirements. bool needToAddPackage = true; // Attempt to find the MSBuild for Unity package entry in the dependencies collection // This loop also identifies the dependencies collection line and the start / end of a // pre-existing scoped registries collections for (int i = 0; i < manifestFileLines.Count; i++) { if (manifestFileLines[i].Contains("\"scopedRegistries\":")) { scopedRegistriesStartIndex = i; } if (manifestFileLines[i].Contains("],") && (scopedRegistriesStartIndex != -1) && (scopedRegistriesEndIndex == -1)) { scopedRegistriesEndIndex = i; } if (manifestFileLines[i].Contains("\"dependencies\": {")) { dependenciesStartIndex = i; } if (manifestFileLines[i].Contains(MSBuildPackageName)) { packageLine = i; needToAddPackage = false; } } // If no package was found add it to the dependencies collection. if (needToAddPackage) { // Add the package to the collection (pad the entry with four spaces) manifestFileLines.Insert(dependenciesStartIndex + 1, $" \"{MSBuildPackageName}\": \"{MSBuildPackageVersion}\","); } else { // Replace the line that currently exists manifestFileLines[packageLine] = $" \"{MSBuildPackageName}\": \"{MSBuildPackageVersion}\","; } // Update the manifest file. // First, serialize the scoped registry collection. string serializedRegistriesJson = JsonUtility.ToJson(manifest, true); // Ensure that the file is truncated to ensure it is always valid after writing. using (FileStream outFile = new FileStream(manifestPath, FileMode.Truncate, FileAccess.Write)) { using (StreamWriter writer = new StreamWriter(outFile)) { bool scopedRegistriesWritten = false; // Write each line of the manifest back to the file. for (int i = 0; i < manifestFileLines.Count; i++) { if ((i >= scopedRegistriesStartIndex) && (i <= scopedRegistriesEndIndex)) { // Skip these lines, they will be replaced. continue; } if (!scopedRegistriesWritten && (i > 0)) { // Trim the leading '{' and '\n' from the serialized scoped registries serializedRegistriesJson = serializedRegistriesJson.Remove(0, 2); // Trim, the trailing '\n' and '}' serializedRegistriesJson = serializedRegistriesJson.Remove(serializedRegistriesJson.Length - 2); // Append a trailing ',' to close the scopedRegistries node serializedRegistriesJson = serializedRegistriesJson.Insert(serializedRegistriesJson.Length, ","); writer.WriteLine(serializedRegistriesJson); scopedRegistriesWritten = true; } writer.WriteLine(manifestFileLines[i]); } } } }
internal static void EnableMSBuildForUnity() { if (!EditorUtility.DisplayDialog( "Use MSBuild for Unity for dependency resolution", "Some versions of Unity have experienced issues with MSBuild for Unity. Do you wish to continue?", "Yes", "No")) { return; } List <string> manifestFileLines; PackageManifest manifest = LoadManifest(out manifestFileLines); if (manifest == null) { Debug.LogError($"Failed to read the package manifest file ({ManifestFilePath})"); return; } // Ensure that pre-existing scoped registries are retained. List <ScopedRegistry> scopedRegistries = new List <ScopedRegistry>(); if ((manifest.scopedRegistries != null) && (manifest.scopedRegistries.Length > 0)) { scopedRegistries.AddRange(manifest.scopedRegistries); } // Attempt to find an entry in the scoped registries collection for the MSBuild for Unity URL bool needToAddRegistry = true; foreach (ScopedRegistry registry in scopedRegistries) { if (registry.url == MSBuildRegistryUrl) { needToAddRegistry = false; break; } } // If no entry was found, add one. if (needToAddRegistry) { ScopedRegistry registry = new ScopedRegistry(); registry.name = MSBuildRegistryName; registry.url = MSBuildRegistryUrl; registry.scopes = MSBuildRegistryScopes; scopedRegistries.Add(registry); } // Update the manifest's scoped registries, as the collection may have been modified. manifest.scopedRegistries = scopedRegistries.ToArray(); // Presume that we need to add the MSBuild for Unity package. If this value is false, // we will check to see if the currently configured version meets or exceeds the // minimum requirements. bool needToAddPackage = true; // Attempt to find the MSBuild for Unity package entry in the dependencies collection // This loop also identifies the line that starts the dependencies and encloses the // scoped registries collection. int dependenciesStartIndex = -1; int registriesStartIndex = -1; int packageLine = -1; for (int i = 0; i < manifestFileLines.Count; i++) { if (manifestFileLines[i].Contains("\"scopedRegistries\":")) { registriesStartIndex = i; } if (manifestFileLines[i].Contains("\"dependencies\": {")) { dependenciesStartIndex = i; } if (manifestFileLines[i].Contains(MSBuildPackageName)) { packageLine = i; needToAddPackage = false; } } // If no package was found add it to the dependencies collection. if (needToAddPackage) { // Add the package to the collection (pad the entry with four spaces) manifestFileLines.Insert(dependenciesStartIndex + 1, $" \"{MSBuildPackageName}\": \"{MSBuildPackageVersion}\","); } else { // Replace the line that currently exists manifestFileLines[packageLine] = $" \"{MSBuildPackageName}\": \"{MSBuildPackageVersion}\","; } // Update the manifest if (!needToAddRegistry && !needToAddPackage) { // No changes required. return; } WriteManifest( manifest, manifestFileLines, registriesStartIndex, dependenciesStartIndex); }