DependencyResolver.cs 6.9 KB

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