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

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
{
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.", "");
displayName = displayName.Replace("com.unity.", "");
displayName = new CultureInfo("en-US").TextInfo.ToTitleCase(displayName);
}
string author = info.author.name;
if (string.IsNullOrEmpty(info.author.name) && info.name.StartsWith("com.unity."))
author = "Unity Technologies Inc.";
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 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
};
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;
}
}
}