Skip to content

Commit

Permalink
feat: support nuget package drawer
Browse files Browse the repository at this point in the history
  • Loading branch information
mob-sakai committed Nov 15, 2020
1 parent e6770d5 commit 34d1a28
Show file tree
Hide file tree
Showing 3 changed files with 283 additions and 6 deletions.
205 changes: 205 additions & 0 deletions Editor/NugetPackageDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;

namespace Coffee.CSharpCompilerSettings
{
[CustomPropertyDrawer(typeof(NugetPackage))]
internal class NugetPackageDrawer : PropertyDrawer
{
public static readonly float Height = 2 * (EditorGUIUtility.singleLineHeight + 2);

public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return Height;
}

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
var p = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);

var indentLevel = EditorGUI.indentLevel;
var labelWidth = EditorGUIUtility.labelWidth;
EditorGUI.indentLevel = 0;
EditorGUIUtility.labelWidth = 50;
{
var spName = property.FindPropertyRelative("m_Name");
var spVersion = property.FindPropertyRelative("m_Version");

DrawPackageNameField(new Rect(p.x, p.y, p.width, 16), spName, spVersion);
DrawPackageVersionField(new Rect(p.x, p.y + 18, p.width, 16), spName, spVersion);
}
EditorGUI.indentLevel = indentLevel;
EditorGUIUtility.labelWidth = labelWidth;

EditorGUI.EndProperty();
}

private void DrawPackageNameField(Rect rect, SerializedProperty spName, SerializedProperty spVersion)
{
// Text field.
var r = new Rect(rect.x, rect.y, rect.width - 18, 16);
EditorGUI.BeginChangeCheck();
EditorGUI.PropertyField(r, spName);
if (EditorGUI.EndChangeCheck())
spVersion.stringValue = "";

// Draw button.
r = new Rect(rect.x + rect.width - 14, rect.y + 4, 14, 12);
if (!GUI.Button(r, EditorGUIUtility.IconContent("icon dropdown"), EditorStyles.label)) return;

GUI.FocusControl("");

// Create menu.
var menu = new GenericMenu();
foreach (var pkgName in NugetPackageCatalog.GetPackageNames())
menu.AddItem(new GUIContent(pkgName), spName.stringValue == pkgName, () =>
{
spName.stringValue = pkgName;
spVersion.stringValue = "";
});

menu.ShowAsContext();
}

private static void DrawPackageVersionField(Rect rect, SerializedProperty spName, SerializedProperty spVersion)
{
// Draw button.
var selectedVersion = string.IsNullOrEmpty(spVersion.stringValue) ? "-" : spVersion.stringValue;
var buttonRect = EditorGUI.PrefixLabel(rect, new GUIContent(spVersion.displayName, spVersion.tooltip));
if (!GUI.Button(buttonRect, selectedVersion, EditorStyles.popup)) return;

// Refresh package versions.
var pkgName = spName.stringValue;
NugetPackageCatalog.RefreshAvailableVersions(pkgName);

// Create menu.
var menu = new GenericMenu();
foreach (var pkgVersion in NugetPackageCatalog.GetPackagePreReleaseVersions(pkgName))
menu.AddItem(new GUIContent("Pre Releases/" + pkgVersion), selectedVersion == pkgVersion, () => spVersion.stringValue = pkgVersion);
if (0 < menu.GetItemCount())
menu.AddSeparator("");
foreach (var pkgVersion in NugetPackageCatalog.GetPackageVersions(pkgName))
menu.AddItem(new GUIContent(pkgVersion), selectedVersion == pkgVersion, () => spVersion.stringValue = pkgVersion);

if (menu.GetItemCount() == 0)
menu.AddDisabledItem(new GUIContent("No available versions"));
menu.ShowAsContext();
}
}

internal class NugetPackageCatalog : ScriptableSingleton<NugetPackageCatalog>
{
#pragma warning disable 649
[Serializable]
private class CatalogRoot
{
public CatalogPage[] items;

[Serializable]
internal class CatalogPage
{
public Package[] items;

[Serializable]
internal class Package
{
public PackageDetails catalogEntry;

[Serializable]
internal class PackageDetails
{
public string id;
public string version;
}
}
}
}
#pragma warning restore 649


public static NugetPackage.CategoryType CurrentCategory = NugetPackage.CategoryType.Compiler;

public List<NugetPackage> m_Packages = new List<NugetPackage>()
{
new NugetPackage("Microsoft.Net.Compilers.Toolset", "3.5.0", NugetPackage.CategoryType.Compiler),
new NugetPackage("Microsoft.Net.Compilers", "3.5.0", NugetPackage.CategoryType.Compiler),
new NugetPackage("OpenSesame.Net.Compilers.Toolset", "3.5.0", NugetPackage.CategoryType.Compiler),
new NugetPackage("OpenSesame.Net.Compilers", "3.5.0", NugetPackage.CategoryType.Compiler),
new NugetPackage("Roslynator.Analyzers", "3.0.0", NugetPackage.CategoryType.Analyzer),
new NugetPackage("Roslynator.CodeAnalysis.Analyzers", "1.0.0", NugetPackage.CategoryType.Analyzer),
new NugetPackage("Roslynator.Formatting.Analyzers", "1.0.0", NugetPackage.CategoryType.Analyzer),
new NugetPackage("ErrorProne.NET.CoreAnalyzers", "0.1.2", NugetPackage.CategoryType.Analyzer),
new NugetPackage("StyleCop.Analyzers", "1.0.0", NugetPackage.CategoryType.Analyzer),
};

public static IEnumerable<string> GetPackageNames()
{
return instance.m_Packages
.Where(x => x.Category == CurrentCategory)
.Select(x => x.Name)
.Distinct();
}

public static IEnumerable<string> GetPackageVersions(string packageName)
{
return instance.m_Packages
.Where(x => x.Name == packageName && x.Category == CurrentCategory)
.Select(x => x.Version)
.Where(x => !SemVersion.Parse(x).IsPrerelease);
}

public static IEnumerable<string> GetPackagePreReleaseVersions(string packageName)
{
return instance.m_Packages
.Where(x => x.Name == packageName && x.Category == CurrentCategory)
.Select(x => x.Version)
.Where(x => SemVersion.Parse(x).IsPrerelease);
}

public static void RefreshAvailableVersions(string packageName)
{
var filename = "Temp/DownloadedPackages/" + packageName + ".json/index";
if (!File.Exists(filename))
{
try
{
EditorUtility.DisplayProgressBar("Package Installer", string.Format("Fetch package versions: {0}", packageName), 0.5f);
var file = Utils.DownloadFile("https://api.nuget.org/v3/registration5-gz-semver2/" + packageName.ToLower() + "/index.json");
Utils.ExtractArchive(file, Path.GetDirectoryName(filename));
}
catch
{
var dir = Path.GetDirectoryName(filename);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);

File.WriteAllText(filename, "{}");
Logger.LogException("Package '{0}' is not found.", packageName);
return;
}
finally
{
EditorUtility.ClearProgressBar();
}
}

var json = File.ReadAllText(filename);
var obj = JsonUtility.FromJson<CatalogRoot>(json);
if (obj.items == null || obj.items.Length == 0) return;

instance.m_Packages = instance.m_Packages
.Concat(obj.items
.SelectMany(x => x.items)
.Select(x => new NugetPackage(x.catalogEntry.id, x.catalogEntry.version, CurrentCategory)))
.Distinct()
.OrderBy(x => x.Name)
.ThenByDescending(x => SemVersion.Parse(x.Version))
.ToList();
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

82 changes: 77 additions & 5 deletions Plugins/CSharpCompilerSettings/CscSettingsAsset.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.IO;
using System.Text;
using UnityEditor;
Expand All @@ -14,6 +15,68 @@ internal enum Nullable
Annotations,
}

internal enum CompilerType
{
BuiltIn,
CustomPackage
}

[Serializable]
public struct NugetPackage
{
public enum CategoryType
{
Compiler,
Analyzer,
}

[SerializeField] private string m_Name;
[SerializeField] private string m_Version;
[SerializeField] private CategoryType m_Category;

public string PackageId
{
get { return m_Name + "." + m_Version; }
}

public string Name
{
get { return m_Name; }
}

public string Version
{
get { return m_Version; }
}

public CategoryType Category
{
get { return m_Category; }
}

public NugetPackage(string name, string version, CategoryType category = CategoryType.Compiler)
{
m_Name = name;
m_Version = version;
m_Category = category;
}

public override string ToString()
{
return PackageId;
}
}

public class SplitAttribute : PropertyAttribute
{
public char separater { get; }

public SplitAttribute(char separater)
{
this.separater = separater;
}
}

internal class CscSettingsAsset : ScriptableObject, ISerializationCallbackReceiver
{
public const string k_SettingsPath = "ProjectSettings/CSharpCompilerSettings.asset";
Expand All @@ -27,10 +90,12 @@ internal class CscSettingsAsset : ScriptableObject, ISerializationCallbackReceiv
[SerializeField] private bool m_EnableLogging = false;
[SerializeField] private bool m_EnableNullable = false;
[SerializeField] private Nullable m_Nullable = Nullable.Disable;
[SerializeField] private NugetPackage m_CompilerPackage = new NugetPackage("Microsoft.Net.Compilers", "3.5.0", NugetPackage.CategoryType.Compiler);

[Tooltip(
"When compiling this assembly, add or remove specific symbols separated with semicolons (;) or commas (,).\nSymbols starting with '!' will be removed.\n\ne.g. 'SYMBOL_TO_ADD;!SYMBOL_TO_REMOVE;...'")]
[SerializeField]
[Split(';')]
private string m_ModifySymbols = "";

private static CscSettingsAsset CreateFromProjectSettings()
Expand All @@ -42,11 +107,8 @@ private static CscSettingsAsset CreateFromProjectSettings()
}

private static CscSettingsAsset s_Instance;

public static CscSettingsAsset instance => s_Instance ? s_Instance : s_Instance = CreateFromProjectSettings();

public string PackageId => m_PackageName + "." + m_PackageVersion;

public NugetPackage CompilerPackage => m_CompilerPackage;
public bool UseDefaultCompiler => m_CompilerType == CompilerType.BuiltIn;
public bool ShouldToRecompile => m_CompilerType == CompilerType.CustomPackage || !string.IsNullOrEmpty(m_ModifySymbols);
public Nullable Nullable => m_Nullable;
Expand Down Expand Up @@ -100,7 +162,7 @@ public static CscSettingsAsset GetAtPath(string path)
{
try
{
return !Core.HasPortableDll(path)
return string.IsNullOrEmpty(Core.GetPortableDllPath(path))
? null
: CreateFromJson(AssetImporter.GetAtPath(path).userData);
}
Expand All @@ -120,6 +182,9 @@ public static CscSettingsAsset CreateFromJson(string json = "")
public void OnBeforeSerialize()
{
m_UseDefaultCompiler = m_CompilerType == CompilerType.BuiltIn;
m_EnableNullable = m_Nullable != Nullable.Disable;
m_PackageName = m_CompilerPackage.Name;
m_PackageVersion = m_CompilerPackage.Version;
}

public void OnAfterDeserialize()
Expand All @@ -131,13 +196,20 @@ public void OnAfterDeserialize()
? CompilerType.BuiltIn
: CompilerType.CustomPackage;
}

if (m_Version < 130)
{
m_Version = 130;
m_Nullable = m_EnableNullable
? Nullable.Enable
: Nullable.Disable;
}

if (m_Version < 140)
{
m_Version = 140;
m_CompilerPackage = new NugetPackage(m_PackageName, m_PackageVersion, NugetPackage.CategoryType.Compiler);
}
}
}
}

0 comments on commit 34d1a28

Please sign in to comment.