225 lines
8.3 KiB
C#
225 lines
8.3 KiB
C#
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.IO;
|
||
|
using System.Linq;
|
||
|
using UnityEngine;
|
||
|
|
||
|
namespace UnityEditor.PackageManager.UI
|
||
|
{
|
||
|
// History of a single package
|
||
|
internal class Package : IEquatable<Package>
|
||
|
{
|
||
|
static public bool ShouldProposeLatestVersions
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
// Until we figure out a way to test this properly, alway show standard behavior
|
||
|
// return InternalEditorUtility.IsUnityBeta() && !Unsupported.IsDeveloperMode();
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// There can only be one package add/remove operation.
|
||
|
private static IBaseOperation addRemoveOperationInstance;
|
||
|
|
||
|
public static bool AddRemoveOperationInProgress
|
||
|
{
|
||
|
get { return addRemoveOperationInstance != null && !addRemoveOperationInstance.IsCompleted; }
|
||
|
}
|
||
|
|
||
|
internal const string packageManagerUIName = "com.unity.package-manager-ui";
|
||
|
private readonly string packageName;
|
||
|
private IEnumerable<PackageInfo> source;
|
||
|
|
||
|
internal Package(string packageName, IEnumerable<PackageInfo> infos)
|
||
|
{
|
||
|
if (string.IsNullOrEmpty(packageName))
|
||
|
throw new ArgumentException("Cannot be empty or null", "packageName");
|
||
|
|
||
|
if (!infos.Any())
|
||
|
throw new ArgumentException("Cannot be empty", "infos");
|
||
|
|
||
|
this.packageName = packageName;
|
||
|
UpdateSource(infos);
|
||
|
}
|
||
|
|
||
|
internal void UpdateSource(IEnumerable<PackageInfo> source)
|
||
|
{
|
||
|
this.source = source;
|
||
|
#if UNITY_2018_3_OR_NEWER
|
||
|
if (IsPackageManagerUI)
|
||
|
this.source = this.source.Where(p => p != null && p.Version.Major >= 2);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
public PackageInfo Current { get { return Versions.FirstOrDefault(package => package.IsCurrent); } }
|
||
|
|
||
|
// This is the latest verified or official release (eg: 1.3.2). Not necessarily the latest verified release (eg: 1.2.4) or that latest candidate (eg: 1.4.0-beta)
|
||
|
public PackageInfo LatestUpdate
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
// We want to show the absolute latest when in beta mode
|
||
|
if (ShouldProposeLatestVersions)
|
||
|
return Latest;
|
||
|
|
||
|
// Override with current when it's version locked
|
||
|
var current = Current;
|
||
|
if (current != null && current.IsVersionLocked)
|
||
|
return current;
|
||
|
|
||
|
// Get all the candidates versions (verified, release, preview) that are newer than current
|
||
|
var verified = Verified;
|
||
|
var latestRelease = LatestRelease;
|
||
|
var latestPreview = Versions.LastOrDefault(package => package.IsPreview);
|
||
|
var candidates = new List<PackageInfo>
|
||
|
{
|
||
|
verified,
|
||
|
latestRelease,
|
||
|
latestPreview,
|
||
|
}.Where(package => package != null && (current == null || current == package || current.Version < package.Version)).ToList();
|
||
|
|
||
|
if (candidates.Contains(verified))
|
||
|
return verified;
|
||
|
if ((current == null || !current.IsVerified) && candidates.Contains(latestRelease))
|
||
|
return latestRelease;
|
||
|
if ((current == null || current.IsPreview) && candidates.Contains(latestPreview))
|
||
|
return latestPreview;
|
||
|
|
||
|
// Show current if it exists, otherwise latest user visible, and then otherwise show the absolute latest
|
||
|
return current ?? Latest;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public PackageInfo LatestPatch
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (Current == null)
|
||
|
return null;
|
||
|
|
||
|
// Get all version that have the same Major/Minor
|
||
|
var versions = Versions.Where(package => package.Version.Major == Current.Version.Major && package.Version.Minor == Current.Version.Minor);
|
||
|
|
||
|
return versions.LastOrDefault();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// This is the very latest version, including pre-releases (eg: 1.4.0-beta).
|
||
|
internal PackageInfo Latest { get { return Versions.FirstOrDefault(package => package.IsLatest) ?? Versions.LastOrDefault(); } }
|
||
|
|
||
|
// Returns the current version if it exist, otherwise returns the latest user visible version.
|
||
|
internal PackageInfo VersionToDisplay { get { return Current ?? LatestUpdate; } }
|
||
|
|
||
|
// Every version available for this package
|
||
|
internal IEnumerable<PackageInfo> Versions { get { return source.OrderBy(package => package.Version); } }
|
||
|
|
||
|
// Every version that's not a pre-release (eg: not beta/alpha/preview).
|
||
|
internal IEnumerable<PackageInfo> ReleaseVersions
|
||
|
{
|
||
|
get { return Versions.Where(package => !package.IsPreRelease); }
|
||
|
}
|
||
|
|
||
|
internal PackageInfo LatestRelease { get {return ReleaseVersions.LastOrDefault();}}
|
||
|
internal PackageInfo Verified { get {return Versions.FirstOrDefault(package => package.IsVerified);}}
|
||
|
|
||
|
internal bool IsAfterCurrentVersion(PackageInfo packageInfo) { return Current == null || (packageInfo != null && packageInfo.Version > Current.Version); }
|
||
|
|
||
|
internal bool IsBuiltIn {get { return Versions.Any() && Versions.First().IsBuiltIn; }}
|
||
|
|
||
|
internal bool IsUnityPackage { get { return VersionToDisplay.IsUnityPackage; } }
|
||
|
|
||
|
public string Name { get { return packageName; } }
|
||
|
|
||
|
public bool IsPackageManagerUI
|
||
|
{
|
||
|
get { return Name == packageManagerUIName; }
|
||
|
}
|
||
|
|
||
|
public bool Equals(Package other)
|
||
|
{
|
||
|
if (other == null)
|
||
|
return false;
|
||
|
|
||
|
return packageName == other.packageName;
|
||
|
}
|
||
|
|
||
|
public override int GetHashCode()
|
||
|
{
|
||
|
return packageName.GetHashCode();
|
||
|
}
|
||
|
|
||
|
[SerializeField]
|
||
|
internal readonly OperationSignal<IAddOperation> AddSignal = new OperationSignal<IAddOperation>();
|
||
|
|
||
|
private Action OnAddOperationFinalizedEvent;
|
||
|
|
||
|
internal void Add(PackageInfo packageInfo)
|
||
|
{
|
||
|
if (packageInfo == Current || AddRemoveOperationInProgress)
|
||
|
return;
|
||
|
|
||
|
var operation = OperationFactory.Instance.CreateAddOperation();
|
||
|
addRemoveOperationInstance = operation;
|
||
|
OnAddOperationFinalizedEvent = () =>
|
||
|
{
|
||
|
AddSignal.Operation = null;
|
||
|
operation.OnOperationFinalized -= OnAddOperationFinalizedEvent;
|
||
|
PackageCollection.Instance.FetchListOfflineCache(true);
|
||
|
};
|
||
|
|
||
|
operation.OnOperationFinalized += OnAddOperationFinalizedEvent;
|
||
|
|
||
|
AddSignal.SetOperation(operation);
|
||
|
operation.AddPackageAsync(packageInfo);
|
||
|
}
|
||
|
|
||
|
internal void Update()
|
||
|
{
|
||
|
Add(Latest);
|
||
|
}
|
||
|
|
||
|
internal static void AddFromLocalDisk(string path)
|
||
|
{
|
||
|
if (AddRemoveOperationInProgress)
|
||
|
return;
|
||
|
|
||
|
var packageJson = PackageJsonHelper.Load(path);
|
||
|
if (null == packageJson)
|
||
|
{
|
||
|
Debug.LogError(string.Format("Invalid package path: cannot find \"{0}\".", path));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var operation = OperationFactory.Instance.CreateAddOperation();
|
||
|
addRemoveOperationInstance = operation;
|
||
|
operation.AddPackageAsync(packageJson.PackageInfo);
|
||
|
}
|
||
|
|
||
|
[SerializeField]
|
||
|
internal readonly OperationSignal<IRemoveOperation> RemoveSignal = new OperationSignal<IRemoveOperation>();
|
||
|
|
||
|
private Action OnRemoveOperationFinalizedEvent;
|
||
|
|
||
|
public void Remove()
|
||
|
{
|
||
|
if (Current == null || AddRemoveOperationInProgress)
|
||
|
return;
|
||
|
|
||
|
var operation = OperationFactory.Instance.CreateRemoveOperation();
|
||
|
addRemoveOperationInstance = operation;
|
||
|
OnRemoveOperationFinalizedEvent = () =>
|
||
|
{
|
||
|
RemoveSignal.Operation = null;
|
||
|
operation.OnOperationFinalized -= OnRemoveOperationFinalizedEvent;
|
||
|
PackageCollection.Instance.FetchListOfflineCache(true);
|
||
|
};
|
||
|
|
||
|
operation.OnOperationFinalized += OnRemoveOperationFinalizedEvent;
|
||
|
RemoveSignal.SetOperation(operation);
|
||
|
|
||
|
operation.RemovePackageAsync(Current);
|
||
|
}
|
||
|
}
|
||
|
}
|