-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Output MSBuild Tasks assembly from Sdk project - Implement PluginInfoType+manifest generation as MSBuild Tasks - Implement MSBuild Tasks for restoring+resolving ThunderDependency plugins - Update README with documentation on ThunderDependency configuration - Sdk: Don't generate .deps.json file when building a project - Sdk: expand configuration of plugin related props - Sdk: support r2modman (fix #1) - Sdk: improve logging/warnings - Sdk: validate generated manifest.json values - Sdk: support disabling release optimizations - Sdk: rename PluginInfoTypeAccessModifier -> PluginInfoTypeModifiers
- Loading branch information
Showing
22 changed files
with
1,718 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
using Microsoft.Build.Framework; | ||
|
||
namespace LethalCompany.Plugin.Sdk; | ||
|
||
/// <summary> Generates C# code for a type containing constant values of PluginInfo passed in from MSBuild Properties. </summary> | ||
public sealed class GeneratePluginInfoCode : Microsoft.Build.Utilities.Task | ||
{ | ||
/// <summary> The code that was generated. </summary> | ||
[Output] | ||
public string GeneratedText { get; set; } = string.Empty; | ||
|
||
/// <summary> The plugin's identifier to include in the generated code. </summary> | ||
[Required] | ||
public string Identifier { get; init; } = string.Empty; | ||
|
||
/// <summary> The plugin's name to include in the generated code. </summary> | ||
[Required] | ||
public string Name { get; init; } = string.Empty; | ||
|
||
/// <summary> The namespace to generated code in. </summary> | ||
[Required] | ||
public string Namespace { get; init; } = string.Empty; | ||
|
||
/// <summary> The access modifiers to be used when generating the PluginInfo type. </summary> | ||
public string TypeModifiers { get; init; } = "internal static"; | ||
|
||
/// <summary> The name of the PluginInfo type to generate. </summary> | ||
public string TypeName { get; init; } = "GeneratedPluginInfo"; | ||
|
||
/// <summary> The plugin's version to include in the generated code. </summary> | ||
[Required] | ||
public string Version { get; init; } = string.Empty; | ||
|
||
/// <inheritdoc/> | ||
public override bool Execute() | ||
{ | ||
GeneratedText = $@"// <auto-generated /> | ||
namespace {Namespace}; | ||
[System.Runtime.CompilerServices.CompilerGenerated] | ||
{TypeModifiers} class {TypeName} | ||
{{ | ||
public const string Identifier = ""{Identifier}""; | ||
public const string Name = ""{Name}""; | ||
public const string Version = ""{Version}""; | ||
}}"; | ||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using System.Text.Json; | ||
using LethalCompany.Plugin.Sdk.Internal; | ||
using Microsoft.Build.Framework; | ||
|
||
namespace LethalCompany.Plugin.Sdk; | ||
|
||
/// <summary> Generates the JSON text of a Thunderstore manifest. </summary> | ||
public sealed class GeneratePluginManifestJson : Microsoft.Build.Utilities.Task | ||
{ | ||
/// <summary> The <c>@(ThunderDependency)</c> items to write to the generated json. </summary> | ||
[Required] | ||
public ITaskItem[] Dependencies { get; init; } = []; | ||
|
||
/// <summary> The <c>description</c> to write to the generated json. </summary> | ||
[Required] | ||
public string Description { get; init; } = string.Empty; | ||
|
||
/// <summary> The json text that was generated. </summary> | ||
[Output] | ||
public string GeneratedText { get; set; } = string.Empty; | ||
|
||
/// <summary> The <c>name</c> to write to the generated json. </summary> | ||
[Required] | ||
public string Name { get; init; } = string.Empty; | ||
|
||
/// <summary> The <c>version_number</c> to write to the generated json. </summary> | ||
[Required] | ||
public string Version { get; init; } = string.Empty; | ||
|
||
/// <summary> The <c>website_url</c> to write to the generated json. </summary> | ||
public string WebsiteUrl { get; init; } = string.Empty; | ||
|
||
/// <inheritdoc/> | ||
public override bool Execute() | ||
{ | ||
var manifest = new PluginManifest | ||
{ | ||
Dependencies = [.. Dependencies.Select(ThunderDependencyMoniker.From)], | ||
Description = Description, | ||
Name = Name, | ||
Version = SemanticVersion.Parse(Version), | ||
WebsiteUrl = WebsiteUrl, | ||
}; | ||
|
||
if (!manifest.TryValidate(out var errors)) | ||
{ | ||
foreach (var error in errors) | ||
{ | ||
Log.LogWarning($"Thunderstore Manifest Validation: {error.ErrorMessage}"); | ||
} | ||
} | ||
|
||
GeneratedText = JsonSerializer.Serialize(manifest, ThunderstoreJsonContext.Default.PluginManifest); | ||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
namespace LethalCompany.Plugin.Sdk.Internal; | ||
|
||
internal static class EnumerableExtensions | ||
{ | ||
public static IEnumerable<TResult> FullJoin<TOuter, TInner, TKey, TResult>( | ||
this IEnumerable<TOuter> outer, | ||
IEnumerable<TInner> inner, | ||
Func<TOuter, TKey> outerKeySelector, | ||
Func<TInner, TKey> innerKeySelector, | ||
Func<TOuter?, TInner?, TResult> resultSelector) | ||
{ | ||
var outerLookup = outer.ToLookup(outerKeySelector); | ||
var innerLookup = inner.ToLookup(innerKeySelector); | ||
|
||
var keys = new HashSet<TKey>( | ||
outerLookup.Select(group => group.Key) | ||
.Concat( | ||
innerLookup.Select(group => group.Key))); | ||
|
||
foreach (var key in keys) | ||
{ | ||
foreach (var outerItem in outerLookup[key].DefaultIfEmpty()) | ||
{ | ||
foreach (var innerItem in innerLookup[key].DefaultIfEmpty()) | ||
{ | ||
yield return resultSelector(outerItem, innerItem); | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
using System.Collections; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace LethalCompany.Plugin.Sdk.Internal; | ||
|
||
[JsonConverter(typeof(PluginAssetsCollectionJsonConverter))] | ||
internal sealed class PluginAssetsCollection(Dictionary<ThunderDependencyMoniker, string[]>? source = null) : IDictionary<ThunderDependencyMoniker, string[]> | ||
{ | ||
private readonly IDictionary<ThunderDependencyMoniker, string[]> source = source ?? []; | ||
|
||
public string[] this[ThunderDependencyMoniker key] { get => source[key]; set => source[key] = value; } | ||
|
||
public ICollection<ThunderDependencyMoniker> Keys => source.Keys; | ||
public ICollection<string[]> Values => source.Values; | ||
public int Count => source.Count; | ||
public bool IsReadOnly => source.IsReadOnly; | ||
|
||
public void Add(ThunderDependencyMoniker key, string[] value) => source.Add(key, value); | ||
|
||
public void Add(KeyValuePair<ThunderDependencyMoniker, string[]> item) => source.Add(item); | ||
|
||
public void Clear() => source.Clear(); | ||
|
||
public bool Contains(KeyValuePair<ThunderDependencyMoniker, string[]> item) => source.Contains(item); | ||
|
||
public bool ContainsKey(ThunderDependencyMoniker key) => source.ContainsKey(key); | ||
|
||
public void CopyTo(KeyValuePair<ThunderDependencyMoniker, string[]>[] array, int arrayIndex) => source.CopyTo(array, arrayIndex); | ||
|
||
public IEnumerator<KeyValuePair<ThunderDependencyMoniker, string[]>> GetEnumerator() => source.GetEnumerator(); | ||
|
||
public bool Remove(ThunderDependencyMoniker key) => source.Remove(key); | ||
|
||
public bool Remove(KeyValuePair<ThunderDependencyMoniker, string[]> item) => source.Remove(item); | ||
|
||
#pragma warning disable CS8767 | ||
public bool TryGetValue(ThunderDependencyMoniker key, [MaybeNullWhen(false)] out string[] value) => source.TryGetValue(key, out value); | ||
#pragma warning restore CS8767 | ||
|
||
IEnumerator IEnumerable.GetEnumerator() => source.GetEnumerator(); | ||
} | ||
|
||
internal sealed class PluginAssetsCollectionJsonConverter : JsonConverter<PluginAssetsCollection> | ||
{ | ||
public override PluginAssetsCollection? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) | ||
{ | ||
var assets = JsonSerializer.Deserialize<Dictionary<string, string[]>>(ref reader, options); | ||
return new( | ||
assets?.ToDictionary(asset => ThunderDependencyMoniker.Parse(asset.Key), asset => asset.Value)); | ||
} | ||
|
||
public override void Write(Utf8JsonWriter writer, PluginAssetsCollection value, JsonSerializerOptions options) | ||
{ | ||
var assets = value.ToDictionary( | ||
asset => asset.Key.Value, | ||
asset => asset.Value); | ||
|
||
JsonSerializer.Serialize(writer, assets, options); | ||
} | ||
} |
Oops, something went wrong.