This commit is contained in:
Takashi Yoshinaga
2019-08-20 19:20:22 +09:00
parent 354a84e7d8
commit 7aa14adaf7
2259 changed files with 0 additions and 0 deletions
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1067213df0c64b319bc81e73be809b1a
timeCreated: 1505249387
@@ -0,0 +1,17 @@
using System.Linq;
using UnityEngine;
namespace UnityEditor.PackageManager.UI
{
class ApplicationUtil
{
public static bool IsPreReleaseVersion
{
get
{
var lastToken = Application.unityVersion.Split('.').LastOrDefault();
return lastToken.Contains("a") || lastToken.Contains("b");
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7ed48dcc992234c659018e00590315b7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,30 @@
using System;
namespace UnityEditor.PackageManager.UI
{
[Serializable]
internal class OperationSignal<T> where T: IBaseOperation
{
public event Action<T> OnOperation = delegate { };
public T Operation { get; set; }
public void SetOperation(T operation)
{
Operation = operation;
OnOperation(operation);
}
public void WhenOperation(Action<T> callback)
{
if (Operation != null)
callback(Operation);
OnOperation += callback;
}
internal void ResetEvents()
{
OnOperation = delegate { };
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7da0c11c52b4044de81c175887699282
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,19 @@
using UnityEngine.Experimental.UIElements;
namespace UnityEditor.PackageManager.UI
{
internal static class Resources
{
private static string TemplateRoot { get { return PackageManagerWindow.ResourcesPath + "Templates"; } }
private static string TemplatePath(string filename)
{
return string.Format("{0}/{1}", TemplateRoot, filename);
}
public static VisualElement GetTemplate(string templateFilename)
{
return AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(TemplatePath(templateFilename)).CloneTree(null);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d6a708dbb74414a6dbd60e07d9513c1c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,35 @@
using System.Threading;
namespace UnityEditor.PackageManager.UI
{
internal class ThreadedDelay
{
public int Length { get; set; } // In milliseconds
public bool IsDone { get; private set; }
public ThreadedDelay(int length = 0)
{
Length = length;
IsDone = false;
}
public void Start()
{
if (Length <= 0)
{
IsDone = true;
return;
}
IsDone = false;
Thread newThread = new Thread(() =>
{
Thread.Sleep(Length);
IsDone = true;
});
newThread.Start();
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 490fe93dbc954e3ba3651b7f55eaba70
timeCreated: 1505249395
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3385f7527e5be4c65b3a5294e8995ff8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,13 @@
using System;
namespace UnityEditor.PackageManager.UI
{
internal interface IAddOperation : IBaseOperation
{
event Action<PackageInfo> OnOperationSuccess;
PackageInfo PackageInfo { get; }
void AddPackageAsync(PackageInfo packageInfo, Action<PackageInfo> doneCallbackAction = null, Action<Error> errorCallbackAction = null);
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3dcbbc060dea46168ffc09a580836240
timeCreated: 1504191596
@@ -0,0 +1,14 @@
using System;
namespace UnityEditor.PackageManager.UI
{
internal interface IBaseOperation
{
event Action<Error> OnOperationError;
event Action OnOperationFinalized;
bool IsCompleted { get; }
void Cancel();
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2f1849b9179b464381598f68663790d3
timeCreated: 1507041169
@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
namespace UnityEditor.PackageManager.UI
{
internal interface IListOperation : IBaseOperation
{
bool OfflineMode { get; set; }
void GetPackageListAsync(Action<IEnumerable<PackageInfo>> doneCallbackAction, Action<Error> errorCallbackAction = null);
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: b7e8a8fb69eacee439474914ea54bf9b
timeCreated: 1502913188
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,14 @@
namespace UnityEditor.PackageManager.UI
{
/// <summary>
/// This is the Interface we will use to create the facade we need for testing.
/// In the case of the Fake factory, we can create fake operations with doctored data we use for our tests.
/// </summary>
internal interface IOperationFactory
{
IListOperation CreateListOperation(bool offlineMode = false);
ISearchOperation CreateSearchOperation();
IAddOperation CreateAddOperation();
IRemoveOperation CreateRemoveOperation();
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 0a1161a2ab6569948a0aa7899197218c
timeCreated: 1502915478
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
using System;
namespace UnityEditor.PackageManager.UI
{
internal interface IRemoveOperation : IBaseOperation
{
event Action<PackageInfo> OnOperationSuccess;
void RemovePackageAsync(PackageInfo package, Action<PackageInfo> doneCallbackAction = null, Action<Error> errorCallbackAction = null);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 54e5fc61925bc4ca3b2c1e82dfb35eb5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
namespace UnityEditor.PackageManager.UI
{
internal interface ISearchOperation : IBaseOperation
{
void GetAllPackageAsync(Action<IEnumerable<PackageInfo>> doneCallbackAction = null, Action<Error> errorCallbackAction = null);
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 85dba6b2d7204a7f9a1f976eb0a6b4d2
timeCreated: 1508160206
@@ -0,0 +1,24 @@
namespace UnityEditor.PackageManager.UI
{
internal static class OperationFactory
{
private static IOperationFactory _instance;
public static IOperationFactory Instance
{
get {
if (_instance == null)
_instance = new UpmOperationFactory ();
return _instance;
}
internal set {
_instance = value;
}
}
internal static void Reset()
{
_instance = null;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9ec5dc72125424af38a9bfaca532acc8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e53bc96d2d054b8cbc811f0d73e761eb
timeCreated: 1504191702
@@ -0,0 +1,222 @@
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; }}
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);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f499e12eaeb145bf9022f581c0b7fa5b
timeCreated: 1505740170
@@ -0,0 +1,21 @@
using System.Linq;
namespace UnityEditor.PackageManager.UI
{
internal class PackageAssetPostprocessor : AssetPostprocessor
{
static bool IsPackageJsonAsset(string path)
{
var pathComponents = (path ?? "").Split('/');
return pathComponents.Length == 3 && pathComponents[0] == "Packages" && pathComponents[2] == "package.json";
}
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
if (PackageCollection.Instance != null && (importedAssets.Any(IsPackageJsonAsset) || deletedAssets.Any(IsPackageJsonAsset) || movedAssets.Any(IsPackageJsonAsset)))
{
PackageCollection.Instance.FetchListOfflineCache(true);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 63e8a6023745e4347bb661e87a9be1d9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,284 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace UnityEditor.PackageManager.UI
{
[Serializable]
internal class PackageCollection
{
private static PackageCollection instance = new PackageCollection();
public static PackageCollection Instance { get { return instance; } }
public event Action<IEnumerable<Package>> OnPackagesChanged = delegate { };
public event Action<PackageFilter> OnFilterChanged = delegate { };
private readonly Dictionary<string, Package> packages;
private PackageFilter filter;
private string selectedListPackage;
private string selectedSearchPackage;
internal string lastUpdateTime;
private List<PackageInfo> listPackagesOffline;
private List<PackageInfo> listPackages;
private List<PackageInfo> searchPackages;
private List<PackageError> packageErrors;
private int listPackagesVersion;
private int listPackagesOfflineVersion;
private bool searchOperationOngoing;
private bool listOperationOngoing;
private bool listOperationOfflineOngoing;
private IListOperation listOperationOffline;
private IListOperation listOperation;
private ISearchOperation searchOperation;
public readonly OperationSignal<ISearchOperation> SearchSignal = new OperationSignal<ISearchOperation>();
public readonly OperationSignal<IListOperation> ListSignal = new OperationSignal<IListOperation>();
public static void InitInstance(ref PackageCollection value)
{
if (value == null) // UI window opened
{
value = instance;
Instance.OnPackagesChanged = delegate { };
Instance.OnFilterChanged = delegate { };
Instance.SearchSignal.ResetEvents();
Instance.ListSignal.ResetEvents();
Instance.FetchListOfflineCache(true);
Instance.FetchListCache(true);
Instance.FetchSearchCache(true);
}
else // Domain reload
{
instance = value;
Instance.RebuildPackageDictionary();
// Resume operations interrupted by domain reload
Instance.FetchListOfflineCache(Instance.listOperationOfflineOngoing);
Instance.FetchListCache(Instance.listOperationOngoing);
Instance.FetchSearchCache(Instance.searchOperationOngoing);
}
}
public PackageFilter Filter
{
get { return filter; }
// For public usage, use SetFilter() instead
private set
{
var changed = value != filter;
filter = value;
if (changed)
OnFilterChanged(filter);
}
}
public List<PackageInfo> LatestListPackages
{
get { return listPackagesVersion > listPackagesOfflineVersion? listPackages : listPackagesOffline; }
}
public List<PackageInfo> LatestSearchPackages { get { return searchPackages; } }
public string SelectedPackage
{
get { return PackageFilter.All == Filter ? selectedSearchPackage : selectedListPackage; }
set
{
if (PackageFilter.All == Filter)
selectedSearchPackage = value;
else
selectedListPackage = value;
}
}
private PackageCollection()
{
packages = new Dictionary<string, Package>();
listPackagesOffline = new List<PackageInfo>();
listPackages = new List<PackageInfo>();
searchPackages = new List<PackageInfo>();
packageErrors = new List<PackageError>();
listPackagesVersion = 0;
listPackagesOfflineVersion = 0;
searchOperationOngoing = false;
listOperationOngoing = false;
listOperationOfflineOngoing = false;
Filter = PackageFilter.All;
}
public bool SetFilter(PackageFilter value, bool refresh = true)
{
if (value == Filter)
return false;
Filter = value;
if (refresh)
{
UpdatePackageCollection();
}
return true;
}
public void UpdatePackageCollection(bool rebuildDictionary = false)
{
if (rebuildDictionary)
{
lastUpdateTime = DateTime.Now.ToString("HH:mm");
RebuildPackageDictionary();
}
if (packages.Any())
OnPackagesChanged(OrderedPackages());
}
internal void FetchListOfflineCache(bool forceRefetch = false)
{
if (!forceRefetch && (listOperationOfflineOngoing || listPackagesOffline.Any())) return;
if (listOperationOffline != null)
listOperationOffline.Cancel();
listOperationOfflineOngoing = true;
listOperationOffline = OperationFactory.Instance.CreateListOperation(true);
listOperationOffline.OnOperationFinalized += () =>
{
listOperationOfflineOngoing = false;
UpdatePackageCollection(true);
};
listOperationOffline.GetPackageListAsync(
infos =>
{
var version = listPackagesVersion;
UpdateListPackageInfosOffline(infos, version);
},
error => { Debug.LogError("Error fetching package list (offline mode)."); });
}
internal void FetchListCache(bool forceRefetch = false)
{
if (!forceRefetch && (listOperationOngoing || listPackages.Any())) return;
if (listOperation != null)
listOperation.Cancel();
listOperationOngoing = true;
listOperation = OperationFactory.Instance.CreateListOperation();
listOperation.OnOperationFinalized += () =>
{
listOperationOngoing = false;
UpdatePackageCollection(true);
};
listOperation.GetPackageListAsync(UpdateListPackageInfos,
error => { Debug.LogError("Error fetching package list."); });
ListSignal.SetOperation(listOperation);
}
internal void FetchSearchCache(bool forceRefetch = false)
{
if (!forceRefetch && (searchOperationOngoing || searchPackages.Any())) return;
if (searchOperation != null)
searchOperation.Cancel();
searchOperationOngoing = true;
searchOperation = OperationFactory.Instance.CreateSearchOperation();
searchOperation.OnOperationFinalized += () =>
{
searchOperationOngoing = false;
UpdatePackageCollection(true);
};
searchOperation.GetAllPackageAsync(UpdateSearchPackageInfos,
error => { Debug.LogError("Error searching packages online."); });
SearchSignal.SetOperation(searchOperation);
}
private void UpdateListPackageInfosOffline(IEnumerable<PackageInfo> newInfos, int version)
{
listPackagesOfflineVersion = version;
listPackagesOffline = newInfos.Where(p => p.IsUserVisible).ToList();
}
private void UpdateListPackageInfos(IEnumerable<PackageInfo> newInfos)
{
// Each time we fetch list packages, the cache for offline mode will be updated
// We keep track of the list packages version so that we know which version of cache
// we are getting with the offline fetch operation.
listPackagesVersion++;
listPackages = newInfos.Where(p => p.IsUserVisible).ToList();
listPackagesOffline = listPackages;
}
private void UpdateSearchPackageInfos(IEnumerable<PackageInfo> newInfos)
{
searchPackages = newInfos.Where(p => p.IsUserVisible).ToList();
}
private IEnumerable<Package> OrderedPackages()
{
return packages.Values.OrderBy(pkg => pkg.Versions.LastOrDefault() == null ? pkg.Name : pkg.Versions.Last().DisplayName).AsEnumerable();
}
public Package GetPackageByName(string name)
{
Package package;
packages.TryGetValue(name, out package);
return package;
}
public Error GetPackageError(Package package)
{
if (null == package) return null;
var firstMatchingError = packageErrors.FirstOrDefault(p => p.PackageName == package.Name);
return firstMatchingError != null ? firstMatchingError.Error : null;
}
public void AddPackageError(Package package, Error error)
{
if (null == package || null == error) return;
packageErrors.Add(new PackageError(package.Name, error));
}
public void RemovePackageErrors(Package package)
{
if (null == package) return;
packageErrors.RemoveAll(p => p.PackageName == package.Name);
}
private void RebuildPackageDictionary()
{
// Merge list & search packages
var allPackageInfos = new List<PackageInfo>(LatestListPackages);
var installedPackageIds = new HashSet<string>(allPackageInfos.Select(p => p.PackageId));
allPackageInfos.AddRange(searchPackages.Where(p => !installedPackageIds.Contains(p.PackageId)));
if (!PackageManagerPrefs.ShowPreviewPackages)
{
allPackageInfos = allPackageInfos.Where(p => !p.IsPreRelease || installedPackageIds.Contains(p.PackageId)).ToList();
}
// Rebuild packages dictionary
packages.Clear();
foreach (var p in allPackageInfos)
{
var packageName = p.Name;
if (packages.ContainsKey(packageName))
continue;
var packageQuery = from pkg in allPackageInfos where pkg.Name == packageName select pkg;
var package = new Package(packageName, packageQuery);
packages[packageName] = package;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 61d72cb49da3040d5ade3edfd6eccfc1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,17 @@
using System;
namespace UnityEditor.PackageManager.UI
{
[Serializable]
internal class PackageError
{
public string PackageName;
public Error Error;
public PackageError(string packageName, Error error)
{
PackageName = packageName;
Error = error;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b7c10e584b708734ba6141e7d4797931
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,13 @@
using System;
namespace UnityEditor.PackageManager.UI
{
[Serializable]
internal enum PackageFilter
{
None,
All,
Local,
Modules
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 03ffb9844f8d40e8a2f59dd2aff561eb
timeCreated: 1508251051
@@ -0,0 +1,8 @@
namespace UnityEditor.PackageManager.UI
{
internal enum PackageGroupOrigins
{
Packages,
BuiltInPackages
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0e372f1bbea04aa9bd68055d4105bd84
timeCreated: 1508855779
@@ -0,0 +1,198 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Semver;
namespace UnityEditor.PackageManager.UI
{
[Serializable]
internal class PackageInfo : IEquatable<PackageInfo>
{
// Module package.json files contain a documentation url embedded in the description.
// We parse that to have the "View Documentation" button direct to it, instead of showing
// the link in the description text.
private const string builtinPackageDocsUrlKey = "Scripting API: ";
public string Name;
public string DisplayName;
private string _PackageId;
public SemVersion Version;
public string Description;
public string Category;
public PackageState State;
public bool IsCurrent;
public bool IsLatest;
public string Group;
public PackageSource Origin;
public List<Error> Errors;
public bool IsVerified;
public string Author;
public PackageManager.PackageInfo Info { get; set; }
public string PackageId {
get
{
if (!string.IsNullOrEmpty(_PackageId ))
return _PackageId;
return string.Format("{0}@{1}", Name.ToLower(), Version);
}
set
{
_PackageId = value;
}
}
// This will always be <name>@<version>, even for an embedded package.
public string VersionId { get { return string.Format("{0}@{1}", Name.ToLower(), Version); } }
public string ShortVersionId { get { return string.Format("{0}@{1}", Name.ToLower(), Version.ShortVersion()); } }
public string BuiltInDescription { get {
if (IsBuiltIn)
return string.Format("This built in package controls the presence of the {0} module.", DisplayName);
else
return Description.Split(new[] {builtinPackageDocsUrlKey}, StringSplitOptions.None)[0];
} }
private static Version ParseShortVersion(string shortVersionId)
{
try
{
var versionToken = shortVersionId.Split('@')[1];
return new Version(versionToken);
}
catch (Exception)
{
// Keep default version 0.0 on exception
return new Version();
}
}
// Method content must be matched in package manager UI
public static string GetPackageUrlRedirect(string packageName, string shortVersionId)
{
var redirectUrl = "";
if (packageName == "com.unity.ads")
redirectUrl = "https://docs.unity3d.com/Manual/UnityAds.html";
else if (packageName == "com.unity.analytics")
{
if (ParseShortVersion(shortVersionId) < new Version(3, 2))
redirectUrl = "https://docs.unity3d.com/Manual/UnityAnalytics.html";
}
else if (packageName == "com.unity.purchasing")
redirectUrl = "https://docs.unity3d.com/Manual/UnityIAP.html";
else if (packageName == "com.unity.standardevents")
redirectUrl = "https://docs.unity3d.com/Manual/UnityAnalyticsStandardEvents.html";
else if (packageName == "com.unity.xiaomi")
redirectUrl = "https://unity3d.com/cn/partners/xiaomi/guide";
else if (packageName == "com.unity.shadergraph")
{
if (ParseShortVersion(shortVersionId) < new Version(4, 1))
redirectUrl = "https://github.com/Unity-Technologies/ShaderGraph/wiki";
}
return redirectUrl;
}
public bool RedirectsToManual(PackageInfo packageInfo)
{
return !string.IsNullOrEmpty(GetPackageUrlRedirect(packageInfo.Name, packageInfo.ShortVersionId));
}
public bool HasChangelog(PackageInfo packageInfo)
{
// Packages with no docs have no third party notice
return !RedirectsToManual(packageInfo);
}
public string GetDocumentationUrl()
{
if (IsBuiltIn)
{
if (!string.IsNullOrEmpty(Description))
{
var split = Description.Split(new[] {builtinPackageDocsUrlKey}, StringSplitOptions.None);
if (split.Length > 1)
return split[1];
}
}
return string.Format("http://docs.unity3d.com/Packages/{0}/index.html", ShortVersionId);
}
public string GetChangelogUrl()
{
return string.Format("http://docs.unity3d.com/Packages/{0}/changelog/CHANGELOG.html", ShortVersionId);
}
public string GetLicensesUrl()
{
var url = string.Format("http://docs.unity3d.com/Packages/{0}/license/index.html", ShortVersionId);
if (RedirectsToManual(this))
url = "https://unity3d.com/legal/licenses/Unity_Companion_License";
return url;
}
public bool Equals(PackageInfo other)
{
if (other == null)
return false;
if (other == this)
return true;
return Name == other.Name && Version == other.Version;
}
public override int GetHashCode()
{
return PackageId.GetHashCode();
}
public bool HasVersionTag(string tag)
{
if (string.IsNullOrEmpty(Version.Prerelease))
return false;
return String.Equals(Version.Prerelease.Split('.').First(), tag, StringComparison.CurrentCultureIgnoreCase);
}
public bool HasVersionTag(PackageTag tag)
{
return HasVersionTag(tag.ToString());
}
// Is it a pre-release (alpha/beta/experimental/preview)?
// Current logic is any tag is considered pre-release, except recommended
public bool IsPreRelease
{
get { return !string.IsNullOrEmpty(Version.Prerelease) || Version.Major == 0; }
}
public bool IsPreview
{
get { return HasVersionTag(PackageTag.preview) || Version.Major == 0; }
}
// A version is user visible if it has a supported tag (or no tag at all)
public bool IsUserVisible
{
get { return IsCurrent || string.IsNullOrEmpty(Version.Prerelease) || HasVersionTag(PackageTag.preview) || IsVerified; }
}
public bool IsInDevelopment { get { return Origin == PackageSource.Embedded; } }
public bool IsLocal { get { return Origin == PackageSource.Local; } }
public bool IsBuiltIn { get { return Origin == PackageSource.BuiltIn; } }
public string VersionWithoutTag { get { return Version.VersionOnly(); } }
public bool IsVersionLocked
{
get { return Origin == PackageSource.Embedded || Origin == PackageSource.Git || Origin == PackageSource.BuiltIn; }
}
public bool CanBeRemoved
{
get { return Origin == PackageSource.Registry || Origin == PackageSource.BuiltIn || Origin == PackageSource.Local; }
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: b9f324f08cd904ec986357c98dd9eaa6
timeCreated: 1502224642
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,37 @@
using System.Collections.Generic;
using System.Linq;
namespace UnityEditor.PackageManager.UI
{
internal static class PackageInfoListExtensions
{
public static IEnumerable<PackageInfo> ByName(this IEnumerable<PackageInfo> list, string name)
{
return from package in list where package.Name == name select package;
}
public static void SetCurrent(this IEnumerable<PackageInfo> list, bool current = true)
{
foreach (var package in list)
{
package.IsCurrent = current;
}
}
public static void SetLatest(this IEnumerable<PackageInfo> list, bool latest = true)
{
foreach (var package in list)
{
package.IsLatest = latest;
}
}
public static void SetGroup(this IEnumerable<PackageInfo> list, string group)
{
foreach (var package in list)
{
package.Group = group;
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a7b89acd74e047778b42209a7a733d39
timeCreated: 1505740214
@@ -0,0 +1,34 @@
using System.IO;
using UnityEngine;
namespace UnityEditor.PackageManager.UI
{
internal class PackageJsonHelper
{
[SerializeField]
private string name = string.Empty;
private string path = string.Empty;
public static string GetPackagePath(string jsonPath)
{
return Path.GetDirectoryName(jsonPath).Replace("\\", "/");
}
public static PackageJsonHelper Load(string path)
{
// If the path is a directory, find the `package.json` file path
var jsonPath = Directory.Exists(path) ? Path.Combine(path, "package.json") : path;
if (!File.Exists(jsonPath))
return null;
var packageJson = JsonUtility.FromJson<PackageJsonHelper>(File.ReadAllText(jsonPath));
packageJson.path = GetPackagePath(jsonPath);
return string.IsNullOrEmpty(packageJson.name) ? null : packageJson;
}
public PackageInfo PackageInfo
{
get { return new PackageInfo {PackageId = string.Format("{0}@file:{1}", name, path)}; }
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b9374526debed24449d75f8cc6d0103f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,13 @@
using System.Collections.Generic;
using System.Linq;
namespace UnityEditor.PackageManager.UI
{
internal static class PackageListExtensions
{
public static IEnumerable<Package> Current(this IEnumerable<Package> list)
{
return (from package in list where package.Current != null select package);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7a74094b34f74992a5121c0586ccf6ea
timeCreated: 1506458921
@@ -0,0 +1,9 @@
namespace UnityEditor.PackageManager.UI
{
internal enum PackageOrigin
{
Unknown,
Builtin,
Registry
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a98bc92072da64d49a393088e55ce2a0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,26 @@
using System;
namespace UnityEditor.PackageManager.UI
{
[Serializable]
internal class PackageSearchFilter
{
private static PackageSearchFilter instance = new PackageSearchFilter();
public static PackageSearchFilter Instance { get { return instance; } }
public string SearchText { get; set; }
public static void InitInstance(ref PackageSearchFilter value)
{
if (value == null) // UI window opened
value = instance;
else // Domain reload
instance = value;
}
public void ResetSearch()
{
SearchText = string.Empty;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8d65a43500ec84d9186cb6d9ab681277
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,9 @@
namespace UnityEditor.PackageManager.UI
{
internal enum PackageState {
UpToDate,
Outdated,
InProgress,
Error
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0a822dba3d5c4c85b150866e5442a5ec
timeCreated: 1505740158
@@ -0,0 +1,10 @@
namespace UnityEditor.PackageManager.UI
{
internal enum PackageTag
{
preview,
verified,
inDevelopment,
local
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2a3f4f8c4e2df41108f55825c24ff694
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 669717f3193a457b9bad9665ebcae836
timeCreated: 1504191654
@@ -0,0 +1,34 @@
using System;
using UnityEditor.PackageManager.Requests;
using System.Linq;
namespace UnityEditor.PackageManager.UI
{
internal class UpmAddOperation : UpmBaseOperation, IAddOperation
{
public PackageInfo PackageInfo { get; protected set; }
public event Action<PackageInfo> OnOperationSuccess = delegate { };
public void AddPackageAsync(PackageInfo packageInfo, Action<PackageInfo> doneCallbackAction = null, Action<Error> errorCallbackAction = null)
{
PackageInfo = packageInfo;
OnOperationError += errorCallbackAction;
OnOperationSuccess += doneCallbackAction;
Start();
}
protected override Request CreateRequest()
{
return Client.Add(PackageInfo.PackageId);
}
protected override void ProcessData()
{
var request = CurrentRequest as AddRequest;
var package = FromUpmPackageInfo(request.Result).First();
OnOperationSuccess(package);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9f091dea68a1452cb6c04a6dfa73d5f5
timeCreated: 1504190581
@@ -0,0 +1,229 @@
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;
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 4e830e2dbc3315b4b97cd5311a54e4fe
timeCreated: 1502918867
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.PackageManager.Requests;
namespace UnityEditor.PackageManager.UI
{
internal class UpmListOperation : UpmBaseOperation, IListOperation
{
[SerializeField]
private Action<IEnumerable<PackageInfo>> _doneCallbackAction;
public UpmListOperation(bool offlineMode) : base()
{
OfflineMode = offlineMode;
}
public bool OfflineMode { get; set; }
public void GetPackageListAsync(Action<IEnumerable<PackageInfo>> doneCallbackAction, Action<Error> errorCallbackAction = null)
{
this._doneCallbackAction = doneCallbackAction;
OnOperationError += errorCallbackAction;
Start();
}
protected override Request CreateRequest()
{
return Client.List(OfflineMode);
}
protected override void ProcessData()
{
var request = CurrentRequest as ListRequest;
var packages = new List<PackageInfo>();
foreach (var upmPackage in request.Result)
{
var packageInfos = FromUpmPackageInfo(upmPackage);
packages.AddRange(packageInfos);
}
_doneCallbackAction(packages);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 9a2c874c382e2419184b302497279dd9
timeCreated: 1502224642
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,25 @@
namespace UnityEditor.PackageManager.UI
{
internal class UpmOperationFactory : IOperationFactory
{
public IListOperation CreateListOperation(bool offlineMode = false)
{
return new UpmListOperation(offlineMode);
}
public ISearchOperation CreateSearchOperation()
{
return new UpmSearchOperation();
}
public IAddOperation CreateAddOperation()
{
return new UpmAddOperation();
}
public IRemoveOperation CreateRemoveOperation()
{
return new UpmRemoveOperation();
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: e6925bb38494e6a43ba0921e65e424fe
timeCreated: 1502915478
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,33 @@
using System;
using UnityEngine;
using UnityEditor.PackageManager.Requests;
namespace UnityEditor.PackageManager.UI
{
internal class UpmRemoveOperation : UpmBaseOperation, IRemoveOperation
{
[SerializeField]
private PackageInfo _package;
public event Action<PackageInfo> OnOperationSuccess = delegate { };
public void RemovePackageAsync(PackageInfo package, Action<PackageInfo> doneCallbackAction = null, Action<Error> errorCallbackAction = null)
{
_package = package;
OnOperationError += errorCallbackAction;
OnOperationSuccess += doneCallbackAction;
Start();
}
protected override Request CreateRequest()
{
return Client.Remove(_package.Name);
}
protected override void ProcessData()
{
OnOperationSuccess(_package);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d5a61f8cc87394b28aec6b88b4083217
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.PackageManager.Requests;
namespace UnityEditor.PackageManager.UI
{
internal class UpmSearchOperation : UpmBaseOperation, ISearchOperation
{
[SerializeField]
private Action<IEnumerable<PackageInfo>> _doneCallbackAction;
public void GetAllPackageAsync(Action<IEnumerable<PackageInfo>> doneCallbackAction = null, Action<Error> errorCallbackAction = null)
{
_doneCallbackAction = doneCallbackAction;
OnOperationError += errorCallbackAction;
Start();
}
protected override Request CreateRequest()
{
return Client.SearchAll();
}
protected override void ProcessData()
{
var request = CurrentRequest as SearchRequest;
var packages = new List<PackageInfo>();
foreach (var upmPackage in request.Result)
{
var packageInfos = FromUpmPackageInfo(upmPackage, false);
packages.AddRange(packageInfos);
}
_doneCallbackAction(packages);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ef5a2781610c4f12a79939f717f789cf
timeCreated: 1508160183