172 lines
6.1 KiB
C#
172 lines
6.1 KiB
C#
#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();
|
|
EnsureShrinkSdkRegistry(manifest);
|
|
AtomicWrite(manifest.ToString(Formatting.Indented) + Environment.NewLine);
|
|
}
|
|
|
|
internal static void EnsurePackageInstallation(ShrinkSdkPackageEntry package)
|
|
{
|
|
var manifest = ReadManifest();
|
|
EnsureShrinkSdkRegistry(manifest);
|
|
EnsurePinnedDependency(manifest, package.PackageName, package.Version);
|
|
if (package.RequiresUniTask)
|
|
{
|
|
EnsurePinnedDependency(
|
|
manifest,
|
|
ShrinkSdkPackageCatalog.UniTaskPackageName,
|
|
ShrinkSdkPackageCatalog.UniTaskGitUrl);
|
|
}
|
|
|
|
AtomicWrite(manifest.ToString(Formatting.Indented) + Environment.NewLine);
|
|
}
|
|
|
|
private static void EnsureShrinkSdkRegistry(JObject manifest)
|
|
{
|
|
var registries = manifest["scopedRegistries"] as JArray;
|
|
if (registries == null)
|
|
{
|
|
registries = new JArray();
|
|
manifest["scopedRegistries"] = registries;
|
|
}
|
|
|
|
var conflictingRegistry = registries
|
|
.OfType<JObject>()
|
|
.FirstOrDefault(registry =>
|
|
!UrlEquals((string?)registry["url"], ShrinkSdkPackageCatalog.RegistryUrl) &&
|
|
(registry["scopes"] as JArray)?.Values<string>().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<string>().Any(scope =>
|
|
string.Equals(scope, ShrinkSdkPackageCatalog.RegistryScope, StringComparison.Ordinal)))
|
|
{
|
|
scopes.Add(ShrinkSdkPackageCatalog.RegistryScope);
|
|
}
|
|
|
|
registry["scopes"] = scopes;
|
|
}
|
|
}
|
|
|
|
private static void EnsurePinnedDependency(JObject manifest, string packageName, string version)
|
|
{
|
|
var dependencies = manifest["dependencies"] as JObject;
|
|
if (dependencies == null)
|
|
{
|
|
dependencies = new JObject();
|
|
manifest["dependencies"] = dependencies;
|
|
}
|
|
|
|
var existing = dependencies[packageName];
|
|
if (existing != null && !string.Equals(existing.Value<string>(), version, StringComparison.Ordinal))
|
|
{
|
|
throw new InvalidOperationException(
|
|
"Packages/manifest.json already pins " + packageName + " to " + existing.Value<string>() +
|
|
". ShrinkSDK requires the fixed version " + version + ".");
|
|
}
|
|
|
|
dependencies[packageName] = version;
|
|
}
|
|
|
|
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<JObject>()
|
|
.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
|