#if UNITY_EDITOR #nullable enable using System; using System.IO; using System.Linq; using System.Text; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using UnityEngine; namespace ShrinkSDK.Installer { internal static class ShrinkSdkManifestStore { internal static string ManifestPath => Path.Combine( Path.GetFullPath(Path.Combine(Application.dataPath, "..")), "Packages", "manifest.json"); internal static bool HasShrinkSdkRegistry() { var manifest = ReadManifest(); return GetShrinkSdkRegistry(manifest) != null; } internal static void EnsureShrinkSdkRegistry() { var manifest = ReadManifest(); var registries = manifest["scopedRegistries"] as JArray; if (registries == null) { registries = new JArray(); manifest["scopedRegistries"] = registries; } var conflictingRegistry = registries .OfType() .FirstOrDefault(registry => !UrlEquals((string?)registry["url"], ShrinkSdkPackageCatalog.RegistryUrl) && (registry["scopes"] as JArray)?.Values().Any(scope => string.Equals(scope, ShrinkSdkPackageCatalog.RegistryScope, StringComparison.Ordinal)) == true); if (conflictingRegistry != null) { throw new InvalidOperationException( "Packages/manifest.json already maps com.cneicy to another scoped registry. Resolve that registry explicitly before installing ShrinkSDK."); } var registry = GetShrinkSdkRegistry(manifest); if (registry == null) { registry = new JObject { ["name"] = ShrinkSdkPackageCatalog.RegistryName, ["url"] = ShrinkSdkPackageCatalog.RegistryUrl, ["scopes"] = new JArray(ShrinkSdkPackageCatalog.RegistryScope) }; registries.Add(registry); } else { registry["name"] = ShrinkSdkPackageCatalog.RegistryName; registry["url"] = ShrinkSdkPackageCatalog.RegistryUrl; var scopes = registry["scopes"] as JArray ?? new JArray(); if (!scopes.Values().Any(scope => string.Equals(scope, ShrinkSdkPackageCatalog.RegistryScope, StringComparison.Ordinal))) { scopes.Add(ShrinkSdkPackageCatalog.RegistryScope); } registry["scopes"] = scopes; } AtomicWrite(manifest.ToString(Formatting.Indented) + Environment.NewLine); } private static JObject ReadManifest() { if (!File.Exists(ManifestPath)) { throw new FileNotFoundException("Unity package manifest was not found.", ManifestPath); } return JObject.Parse(File.ReadAllText(ManifestPath, Encoding.UTF8)); } private static JObject? GetShrinkSdkRegistry(JObject manifest) { return (manifest["scopedRegistries"] as JArray)? .OfType() .FirstOrDefault(registry => UrlEquals((string?)registry["url"], ShrinkSdkPackageCatalog.RegistryUrl)); } private static bool UrlEquals(string? left, string right) { return string.Equals(NormalizeUrl(left), NormalizeUrl(right), StringComparison.OrdinalIgnoreCase); } private static string NormalizeUrl(string? url) { return (url ?? string.Empty).Trim().TrimEnd('/') + "/"; } private static void AtomicWrite(string content) { var directory = Path.GetDirectoryName(ManifestPath); if (string.IsNullOrWhiteSpace(directory)) { throw new InvalidOperationException("Unity package manifest directory could not be resolved."); } var temporaryPath = Path.Combine(directory, ".manifest.shrinksdk.tmp"); File.WriteAllText(temporaryPath, content, new UTF8Encoding(false)); try { File.Replace(temporaryPath, ManifestPath, null); } catch { if (File.Exists(temporaryPath)) { File.Delete(temporaryPath); } throw; } } } } #endif