You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

229 lines
7.9 KiB

  1. using System;
  2. using System.Globalization;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using Semver;
  6. using UnityEngine;
  7. using UnityEditor.PackageManager.Requests;
  8. namespace UnityEditor.PackageManager.UI
  9. {
  10. internal abstract class UpmBaseOperation : IBaseOperation
  11. {
  12. public static string GroupName(PackageSource origin)
  13. {
  14. var group = PackageGroupOrigins.Packages.ToString();
  15. if (origin == PackageSource.BuiltIn)
  16. group = PackageGroupOrigins.BuiltInPackages.ToString();
  17. return group;
  18. }
  19. protected static IEnumerable<PackageInfo> FromUpmPackageInfo(PackageManager.PackageInfo info, bool isCurrent=true)
  20. {
  21. var packages = new List<PackageInfo>();
  22. var displayName = info.displayName;
  23. if (string.IsNullOrEmpty(displayName))
  24. {
  25. displayName = info.name.Replace("com.unity.modules.", "");
  26. displayName = displayName.Replace("com.unity.", "");
  27. displayName = new CultureInfo("en-US").TextInfo.ToTitleCase(displayName);
  28. }
  29. string author = info.author.name;
  30. if (string.IsNullOrEmpty(info.author.name) && info.name.StartsWith("com.unity."))
  31. author = "Unity Technologies Inc.";
  32. var lastCompatible = info.versions.latestCompatible;
  33. var versions = new List<string>();
  34. versions.AddRange(info.versions.compatible);
  35. if (versions.FindIndex(version => version == info.version) == -1)
  36. {
  37. versions.Add(info.version);
  38. versions.Sort((left, right) =>
  39. {
  40. if (left == null || right == null) return 0;
  41. SemVersion leftVersion = left;
  42. SemVersion righVersion = right;
  43. return leftVersion.CompareByPrecedence(righVersion);
  44. });
  45. SemVersion packageVersion = info.version;
  46. if (!string.IsNullOrEmpty(lastCompatible))
  47. {
  48. SemVersion lastCompatibleVersion =
  49. string.IsNullOrEmpty(lastCompatible) ? (SemVersion) null : lastCompatible;
  50. if (packageVersion != null && string.IsNullOrEmpty(packageVersion.Prerelease) &&
  51. packageVersion.CompareByPrecedence(lastCompatibleVersion) > 0)
  52. lastCompatible = info.version;
  53. }
  54. else
  55. {
  56. if (packageVersion != null && string.IsNullOrEmpty(packageVersion.Prerelease))
  57. lastCompatible = info.version;
  58. }
  59. }
  60. foreach(var version in versions)
  61. {
  62. var isVersionCurrent = version == info.version && isCurrent;
  63. var isBuiltIn = info.source == PackageSource.BuiltIn;
  64. var isVerified = string.IsNullOrEmpty(SemVersion.Parse(version).Prerelease) && version == info.versions.recommended;
  65. var state = (isBuiltIn || info.version == lastCompatible || !isCurrent ) ? PackageState.UpToDate : PackageState.Outdated;
  66. // Happens mostly when using a package that hasn't been in production yet.
  67. if (info.versions.all.Length <= 0)
  68. state = PackageState.UpToDate;
  69. if (info.errors.Length > 0)
  70. state = PackageState.Error;
  71. var packageInfo = new PackageInfo
  72. {
  73. Name = info.name,
  74. DisplayName = displayName,
  75. PackageId = version == info.version ? info.packageId : null,
  76. Version = version,
  77. Description = info.description,
  78. Category = info.category,
  79. IsCurrent = isVersionCurrent,
  80. IsLatest = version == lastCompatible,
  81. IsVerified = isVerified,
  82. Errors = info.errors.ToList(),
  83. Group = GroupName(info.source),
  84. State = state,
  85. Origin = isBuiltIn || isVersionCurrent ? info.source : PackageSource.Registry,
  86. Author = author,
  87. Info = info
  88. };
  89. packages.Add(packageInfo);
  90. }
  91. return packages;
  92. }
  93. public static event Action<UpmBaseOperation> OnOperationStart = delegate { };
  94. public event Action<Error> OnOperationError = delegate { };
  95. public event Action OnOperationFinalized = delegate { };
  96. public Error ForceError { get; set; } // Allow external component to force an error on the requests (eg: testing)
  97. public Error Error { get; protected set; } // Keep last error
  98. public bool IsCompleted { get; private set; }
  99. protected abstract Request CreateRequest();
  100. [SerializeField]
  101. protected Request CurrentRequest;
  102. public readonly ThreadedDelay Delay = new ThreadedDelay();
  103. protected abstract void ProcessData();
  104. protected void Start()
  105. {
  106. Error = null;
  107. OnOperationStart(this);
  108. Delay.Start();
  109. if (TryForcedError())
  110. return;
  111. EditorApplication.update += Progress;
  112. }
  113. // Common progress code for all classes
  114. private void Progress()
  115. {
  116. if (!Delay.IsDone)
  117. return;
  118. // Create the request after the delay
  119. if (CurrentRequest == null)
  120. {
  121. CurrentRequest = CreateRequest();
  122. }
  123. // Since CurrentRequest's error property is private, we need to simulate
  124. // an error instead of just setting it.
  125. if (TryForcedError())
  126. return;
  127. if (CurrentRequest.IsCompleted)
  128. {
  129. if (CurrentRequest.Status == StatusCode.Success)
  130. OnDone();
  131. else if (CurrentRequest.Status >= StatusCode.Failure)
  132. OnError(CurrentRequest.Error);
  133. else
  134. Debug.LogError("Unsupported progress state " + CurrentRequest.Status);
  135. }
  136. }
  137. private void OnError(Error error)
  138. {
  139. try
  140. {
  141. Error = error;
  142. var message = "Cannot perform upm operation.";
  143. if (error != null)
  144. message = "Cannot perform upm operation: " + Error.message + " [" + Error.errorCode + "]";
  145. Debug.LogError(message);
  146. OnOperationError(Error);
  147. }
  148. catch (Exception exception)
  149. {
  150. Debug.LogError("Package Manager Window had an error while reporting an error in an operation: " + exception);
  151. }
  152. FinalizeOperation();
  153. }
  154. private void OnDone()
  155. {
  156. try
  157. {
  158. ProcessData();
  159. }
  160. catch (Exception error)
  161. {
  162. Debug.LogError("Package Manager Window had an error while completing an operation: " + error);
  163. }
  164. FinalizeOperation();
  165. }
  166. private void FinalizeOperation()
  167. {
  168. EditorApplication.update -= Progress;
  169. OnOperationFinalized();
  170. IsCompleted = true;
  171. }
  172. public void Cancel()
  173. {
  174. EditorApplication.update -= Progress;
  175. OnOperationError = delegate { };
  176. OnOperationFinalized = delegate { };
  177. IsCompleted = true;
  178. }
  179. private bool TryForcedError()
  180. {
  181. if (ForceError != null)
  182. {
  183. OnError(ForceError);
  184. return true;
  185. }
  186. return false;
  187. }
  188. }
  189. }