DependencyResolver.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using ET;
  6. using MongoDB.Bson.Serialization;
  7. using MongoDB.Bson.Serialization.Attributes;
  8. using UnityEditor;
  9. using UnityEditor.PackageManager;
  10. using UnityEngine;
  11. using PackageInfo = UnityEditor.PackageManager.PackageInfo;
  12. using UnityEditor.PackageManager.Requests;
  13. namespace Hibzz.DependencyResolver
  14. {
  15. [BsonIgnoreExtraElements]
  16. public class PackageGitDependency
  17. {
  18. public Dictionary<string, string> gitDependencies;
  19. }
  20. [InitializeOnLoad]
  21. public class DependencyResolver
  22. {
  23. [MenuItem("ET/MoveToPackages")]
  24. static void MoveToPackage()
  25. {
  26. #if UNITY_EDITOR_WIN
  27. ProcessHelper.Run("powershell.exe", $"-NoExit -ExecutionPolicy Bypass -File \"Scripts/MoveToPackages.ps1\"");
  28. #else
  29. ProcessHelper.Run("pwsh", $"-NoExit -ExecutionPolicy Bypass -File \"Scripts/MoveToPackages.ps1\"");
  30. #endif
  31. }
  32. static AddAndRemoveRequest packageInstallationRequest;
  33. static DependencyResolver()
  34. {
  35. Events.registeredPackages += OnPackagesRegistered;
  36. }
  37. // Invoked when the package manager completes registering new packages
  38. static void OnPackagesRegistered(PackageRegistrationEventArgs packageRegistrationInfo)
  39. {
  40. if (packageRegistrationInfo.added.Count == 0)
  41. {
  42. return;
  43. }
  44. Debug.Log($"Packages Registered: {string.Join(" ", packageRegistrationInfo.added.Select(x=>x.name))}");
  45. // loop through all of the added packages and get their git
  46. // dependencies and add it to the list that contains all the
  47. // dependencies that need to be installed
  48. Dictionary<string, string> dependencies = new();
  49. List<PackageInfo> installedPackages = PackageInfo.GetAllRegisteredPackages().ToList();
  50. foreach (var package in packageRegistrationInfo.added)
  51. {
  52. // get the dependencies of the added package
  53. if (!GetDependencies(package, out PackageGitDependency packageDependencies))
  54. {
  55. continue;
  56. }
  57. foreach (var gitDependency in packageDependencies.gitDependencies)
  58. {
  59. if (IsInCollection(gitDependency.Key, installedPackages))
  60. {
  61. continue;
  62. }
  63. dependencies[gitDependency.Key] = gitDependency.Value;
  64. }
  65. }
  66. Debug.Log($"Packages Dependency: {string.Join(" ", dependencies.Keys)}");
  67. // Install the dependencies
  68. InstallDependencies(dependencies);
  69. }
  70. /// <summary>
  71. /// Request a list of git dependencies in the package
  72. /// </summary>
  73. /// <param name="packageInfo">The package to get the git dependencies from</param>
  74. /// <param name="dependencies">The retrieved list of git dependencies </param>
  75. /// <returns>Was the request successful?</returns>
  76. static bool GetDependencies(PackageInfo packageInfo, out PackageGitDependency dependencies)
  77. {
  78. // Read the contents of the package.json file
  79. string packageJsonPath = $"{packageInfo.resolvedPath}/package.json";
  80. string packageJsonContent = File.ReadAllText(packageJsonPath);
  81. PackageGitDependency packageGitDependency = BsonSerializer.Deserialize<PackageGitDependency>(packageJsonContent);
  82. // if no token with the key git-dependecies is found, failed to get git dependencies
  83. if (packageGitDependency.gitDependencies is null || packageGitDependency.gitDependencies.Count == 0)
  84. {
  85. dependencies = null;
  86. return false;
  87. }
  88. // convert the git dependency token to a list of strings...
  89. // maybe we should check for errors in this process? what if git-dependency isn't array of string?
  90. dependencies = packageGitDependency;
  91. return true;
  92. }
  93. /// <summary>
  94. /// Is the given dependency url found in the given collection
  95. /// </summary>
  96. /// <param name="dependency">The url the dependency to check for</param>
  97. /// <param name="collection">The collection to look through</param>
  98. /// <returns></returns>
  99. static bool IsInCollection(string dependency, List<PackageInfo> collection)
  100. {
  101. // when package collection given is null, it's inferred that the dependency is not in the collection
  102. if (collection == null)
  103. {
  104. return false;
  105. }
  106. // check if any of the installed package has the dependency
  107. foreach (var package in collection)
  108. {
  109. // the package id for a package installed with git is `package_name@package_giturl`
  110. // get the repo url by performing some string manipulation on the package id
  111. //string repourl = package.packageId.Substring(package.packageId.IndexOf('@') + 1);
  112. // Found!
  113. if (package.name == dependency)
  114. {
  115. return true;
  116. }
  117. }
  118. // the dependency wasn't found in the package collection
  119. return false;
  120. }
  121. /// <summary>
  122. /// Install all the given dependencies
  123. /// </summary>
  124. static void InstallDependencies(Dictionary<string, string> dependencies)
  125. {
  126. if (dependencies.Count == 0)
  127. {
  128. MoveToPackage();
  129. return;
  130. }
  131. // before installing the packages, make sure that user knows what
  132. // the dependencies to install are... additionally, check if the
  133. // application is being run on batch mode so that we can skip the
  134. // installation dialog
  135. if (!Application.isBatchMode &&
  136. !EditorUtility.DisplayDialog(
  137. $"Dependency Resolver",
  138. $"The following dependencies are required:\n{string.Join("\n", dependencies.Keys)}",
  139. "Install Dependencies",
  140. "Cancel"))
  141. {
  142. // user decided to cancel the installation of the dependencies...
  143. return;
  144. }
  145. // the user pressed install, perform the actual installation
  146. // (or the application was in batch mode)
  147. packageInstallationRequest = Client.AddAndRemove(dependencies.Values.ToArray());
  148. // show the progress bar till the installation is complete
  149. EditorUtility.DisplayProgressBar("Dependency Resolver", "Preparing installation of dependencies...", 0);
  150. EditorApplication.update += DisplayProgress;
  151. }
  152. /// <summary>
  153. /// Shows a progress bar till the AddAndRemoveRequest is completed
  154. /// </summary>
  155. static void DisplayProgress()
  156. {
  157. if (!packageInstallationRequest.IsCompleted)
  158. {
  159. return;
  160. }
  161. EditorUtility.ClearProgressBar();
  162. EditorApplication.update -= DisplayProgress;
  163. }
  164. [MenuItem("ET/RepairDependencies")]
  165. static void RepairDependencies()
  166. {
  167. Dictionary<string, string> dependencies = new();
  168. List<PackageInfo> installedPackages = PackageInfo.GetAllRegisteredPackages().ToList();
  169. foreach (var package in installedPackages)
  170. {
  171. if (!GetDependencies(package, out PackageGitDependency packageDependencies))
  172. {
  173. continue;
  174. }
  175. foreach (var gitDependency in packageDependencies.gitDependencies)
  176. {
  177. if (IsInCollection(gitDependency.Key, installedPackages))
  178. {
  179. continue;
  180. }
  181. Debug.Log($"Dependency not found: {gitDependency.Key}");
  182. dependencies.Add(gitDependency.Key, gitDependency.Value);
  183. }
  184. }
  185. if (dependencies.Count == 0)
  186. {
  187. Debug.Log($"git Dependencies are all installed");
  188. return;
  189. }
  190. if (!Application.isBatchMode &&
  191. !EditorUtility.DisplayDialog(
  192. $"Dependency Resolver",
  193. $"The following dependencies are required:\n{string.Join("\n", dependencies.Keys)}",
  194. "Install Dependencies",
  195. "Cancel"))
  196. {
  197. // user decided to cancel the installation of the dependencies...
  198. return;
  199. }
  200. InstallDependencies(dependencies);
  201. }
  202. }
  203. }