using System; using System.IO; using Needle.Engine.Utils; using UnityEngine; using UnityEngine.Serialization; #if UNITY_EDITOR using UnityEditor; #endif namespace Needle.Engine { [Serializable] public struct Dependency { public string Name; public string Version; [FormerlySerializedAs("VersionOrPath")] public string Path; // the guid is used to find the new path of a dependency public string Guid; /// /// Add the dependency to the package.json file /// public bool Install(string packageJsonPath) { if (string.IsNullOrEmpty(Name)) return false; if (IsMissingNpmDef()) { Debug.LogWarning("Can not install dependency \"" + Name + "\" because npmdef was not found in project at \"" + Path + "\""); return false; } if (!System.IO.Path.IsPathRooted(packageJsonPath)) { packageJsonPath = System.IO.Path.GetFullPath(packageJsonPath); } if (TryGetEmbeddedPath(out var path) && File.Exists($"{path}/package.json")) { if (PackageUtils.TryReadDependencies(packageJsonPath, out var deps)) { path = System.IO.Path.GetFullPath(path); var isLocalPath = Directory.Exists(path); path = path.RelativeTo(packageJsonPath); if (isLocalPath && !path.StartsWith("file:")) path = "file:" + path; deps[Name] = path; PackageUtils.TryWriteDependencies(packageJsonPath, deps); return true; } } else if(!string.IsNullOrWhiteSpace(Version) && !string.IsNullOrEmpty(Name)) { if (PackageUtils.TryReadDependencies(packageJsonPath, out var deps)) { // If the dependency is already installed with either a filepath OR a version, we don't need to install it again // For example: if we install a remote npm package (and the npmdef is installed by that package) we don't need to update the version // Because then the user can change the version in the web project package.json (e.g. 1.0.0 to 2.0.0) // And the package will be installed from npm and update the npmdef with the right version if (!deps.ContainsKey(Name)) { deps[Name] = Version; PackageUtils.TryWriteDependencies(packageJsonPath, deps); } return true; } } return false; } public bool IsMissingNpmDef() { ResolvePath(); var path = Path; if (string.IsNullOrEmpty(path)) return false; if (path.EndsWith(".npmdef")) { if (!File.Exists(path)) { return true; } } return false; } public bool TryGetEmbeddedPath(out string path, bool ignoreMissing = false) { path = null; ResolvePath(); // we want to install the path to the hidden package dir var versionOrPath = Path; if (string.IsNullOrEmpty(versionOrPath)) return false; if (versionOrPath.EndsWith(".npmdef")) { if (!ignoreMissing && !File.Exists(versionOrPath)) { return false; } versionOrPath = versionOrPath.Substring(0, versionOrPath.Length - ".npmdef".Length) + "~"; } path = versionOrPath; return !string.IsNullOrWhiteSpace(path) && Directory.Exists(path); } public bool TryGetNpmPackageDirectoryPath(out string npmPackageDirectoryPath) { if (TryGetEmbeddedPath(out var path)) { npmPackageDirectoryPath = System.IO.Path.GetFullPath(path); return Directory.Exists(npmPackageDirectoryPath); } npmPackageDirectoryPath = null; return false; } private void ResolvePath() { #if UNITY_EDITOR if (!string.IsNullOrEmpty(Guid)) { var fromGuid = AssetDatabase.GUIDToAssetPath(Guid); if (!string.IsNullOrEmpty(fromGuid)) Path = fromGuid; } #endif } } }