DependencyResolver.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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\"", waitExit: true);
  28. #else
  29. ProcessHelper.Run("pwsh", $"-NoExit -ExecutionPolicy Bypass -File \"Scripts/MoveToPackages.ps1\"", waitExit: true);
  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. MoveToPackage();
  67. AssetDatabase.Refresh();
  68. // Install the dependencies
  69. InstallDependencies(dependencies);
  70. }
  71. /// <summary>
  72. /// Request a list of git dependencies in the package
  73. /// </summary>
  74. /// <param name="packageInfo">The package to get the git dependencies from</param>
  75. /// <param name="dependencies">The retrieved list of git dependencies </param>
  76. /// <returns>Was the request successful?</returns>
  77. static bool GetDependencies(PackageInfo packageInfo, out PackageGitDependency dependencies)
  78. {
  79. // Read the contents of the package.json file
  80. string packageJsonPath = $"{packageInfo.resolvedPath}/package.json";
  81. string packageJsonContent = File.ReadAllText(packageJsonPath);
  82. PackageGitDependency packageGitDependency = BsonSerializer.Deserialize<PackageGitDependency>(packageJsonContent);
  83. // if no token with the key git-dependecies is found, failed to get git dependencies
  84. if (packageGitDependency.gitDependencies is null || packageGitDependency.gitDependencies.Count == 0)
  85. {
  86. dependencies = null;
  87. return false;
  88. }
  89. // convert the git dependency token to a list of strings...
  90. // maybe we should check for errors in this process? what if git-dependency isn't array of string?
  91. dependencies = packageGitDependency;
  92. return true;
  93. }
  94. /// <summary>
  95. /// Is the given dependency url found in the given collection
  96. /// </summary>
  97. /// <param name="dependency">The url the dependency to check for</param>
  98. /// <param name="collection">The collection to look through</param>
  99. /// <returns></returns>
  100. static bool IsInCollection(string dependency, List<PackageInfo> collection)
  101. {
  102. // when package collection given is null, it's inferred that the dependency is not in the collection
  103. if (collection == null)
  104. {
  105. return false;
  106. }
  107. // check if any of the installed package has the dependency
  108. foreach (var package in collection)
  109. {
  110. // the package id for a package installed with git is `package_name@package_giturl`
  111. // get the repo url by performing some string manipulation on the package id
  112. //string repourl = package.packageId.Substring(package.packageId.IndexOf('@') + 1);
  113. // Found!
  114. if (package.name == dependency)
  115. {
  116. return true;
  117. }
  118. }
  119. // the dependency wasn't found in the package collection
  120. return false;
  121. }
  122. /// <summary>
  123. /// Install all the given dependencies
  124. /// </summary>
  125. static void InstallDependencies(Dictionary<string, string> dependencies)
  126. {
  127. if (dependencies.Count == 0)
  128. {
  129. MoveToPackage();
  130. return;
  131. }
  132. // before installing the packages, make sure that user knows what
  133. // the dependencies to install are... additionally, check if the
  134. // application is being run on batch mode so that we can skip the
  135. // installation dialog
  136. Debug.Log($"The following dependencies are required:\n{string.Join("\n", dependencies.Keys)}");
  137. // the user pressed install, perform the actual installation
  138. // (or the application was in batch mode)
  139. packageInstallationRequest = Client.AddAndRemove(dependencies.Values.ToArray());
  140. // show the progress bar till the installation is complete
  141. EditorUtility.DisplayProgressBar("Dependency Resolver", "Preparing installation of dependencies...", 0);
  142. EditorApplication.update += DisplayProgress;
  143. }
  144. /// <summary>
  145. /// Shows a progress bar till the AddAndRemoveRequest is completed
  146. /// </summary>
  147. static void DisplayProgress()
  148. {
  149. if (!packageInstallationRequest.IsCompleted)
  150. {
  151. return;
  152. }
  153. EditorUtility.ClearProgressBar();
  154. EditorApplication.update -= DisplayProgress;
  155. }
  156. [MenuItem("ET/RepairDependencies")]
  157. static void RepairDependencies()
  158. {
  159. AssetDatabase.Refresh();
  160. MoveToPackage();
  161. AssetDatabase.Refresh();
  162. Dictionary<string, string> dependencies = new();
  163. List<PackageInfo> installedPackages = PackageInfo.GetAllRegisteredPackages().ToList();
  164. foreach (var package in installedPackages)
  165. {
  166. if (!GetDependencies(package, out PackageGitDependency packageDependencies))
  167. {
  168. continue;
  169. }
  170. foreach (var gitDependency in packageDependencies.gitDependencies)
  171. {
  172. if (IsInCollection(gitDependency.Key, installedPackages))
  173. {
  174. continue;
  175. }
  176. Debug.Log($"Dependency not found: {gitDependency.Key}");
  177. dependencies.Add(gitDependency.Key, gitDependency.Value);
  178. }
  179. }
  180. if (dependencies.Count == 0)
  181. {
  182. Debug.Log($"git Dependencies are all installed");
  183. return;
  184. }
  185. InstallDependencies(dependencies);
  186. }
  187. }
  188. }