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