diff --git a/Cake.Issues.Recipe/Content/loader/AddinData.cake b/Cake.Issues.Recipe/Content/loader/AddinData.cake new file mode 100644 index 00000000..91d2e570 --- /dev/null +++ b/Cake.Issues.Recipe/Content/loader/AddinData.cake @@ -0,0 +1,159 @@ +using System.Reflection; +using Cake.Core.Annotations; + +public abstract class AddinData +{ + protected AddinData(ICakeContext context, string packageName, string packageVersion, string assemblyName = null) + { + this.Initialize(context, packageName, packageVersion, assemblyName); + } + + public Assembly AddinAssembly { get; private set; } + public IEnumerable DeclaredEnums { get; private set; } + public IEnumerable DefinedAliases { get; private set; } + public IEnumerable DefinedClasses { get; private set; } + public IEnumerable DefinedMethods { get; private set; } + + protected void Initialize(ICakeContext context, string packageName, string packageVersion, string assemblyName = null) + { + if (string.IsNullOrEmpty(assemblyName)) + { + assemblyName = packageName; + } + + var assembly = LoadAddinAssembly(context, packageName, packageVersion, assemblyName); + + if (assembly is null) + { + return; + } + + AddinAssembly = assembly; + + var declaredEnums = new List(); + var definedClasses = new List(); + + foreach (var ti in assembly.DefinedTypes.Where(ti => ti.IsPublic)) + { + if (ti.IsEnum) + { + declaredEnums.Add(ti.AsType()); + EnumerationFound(context, ti.AsType()); + } + else if(ti.IsClass && (!ti.IsAbstract || ti.IsStatic()) && !ti.IsGenericTypeDefinition) + { + definedClasses.Add(ti); + ClassFound(context, ti); + ParseClass(context, ti); + } + } + + DeclaredEnums = declaredEnums; + DefinedClasses = definedClasses; + } + + protected virtual void AliasFound(ICakeContext context, MethodInfo method) + { + } + + protected virtual void ClassFound(ICakeContext context, TypeInfo classTypeInfo) + { + } + + protected void ParseClass(ICakeContext context, TypeInfo classTypeInfo) + { + var aliases = new List(); + var methods = new List(); + + foreach (var mi in classTypeInfo.DeclaredMethods.Where(i => i.IsPublic)) + { + if (mi.GetCustomAttribute() != null) + { + aliases.Add(mi); + AliasFound(context, mi); + } + else + { + methods.Add(mi); + MethodFound(context, mi); + } + } + + DefinedAliases = aliases; + DefinedMethods = methods; + } + + protected virtual void EnumerationFound(ICakeContext context, Type enumType) + { + } + + protected virtual void MethodFound(ICakeContext context, MethodInfo method) + { + } + + private static Assembly LoadAddinAssembly(ICakeContext context, string packageName, string packageVersion, string assemblyName) + { + var dllPath = GetAssemblyPath(context, packageName, packageVersion, assemblyName); + + if (dllPath is null) + { + var script = $"#tool nuget:?package={packageName}&version={packageVersion}&prerelease"; + var tempFile = Guid.NewGuid() + ".cake"; + + System.IO.File.WriteAllText(tempFile, script); + + try + { + context.CakeExecuteScript(tempFile); + } + finally + { + if (context.FileExists(tempFile)) + { + context.DeleteFile(tempFile); + } + } + } + + dllPath = GetAssemblyPath(context, packageName, packageVersion, assemblyName); + + if (dllPath is null) + { + context.Warning("Unable to find path to the {0} package assembly!", packageName); + return null; + } + + var assembly = Assembly.LoadFrom(dllPath.FullPath); + return assembly; + } + + private static FilePath GetAssemblyPath(ICakeContext context, string packageName, string packageVersion, string assemblyName) + { + FilePath dllPath = null; + const string pathFormat = "{0}.{1}/**/{2}*/{3}.dll"; + + var possibleFrameworks = new List(); + + if (context.Environment.Runtime.IsCoreClr) + { + possibleFrameworks.Add("netcoreapp"); + possibleFrameworks.Add("net4"); // TODO: Remove this after debugging + } + else + { + possibleFrameworks.Add("net4"); + } + possibleFrameworks.Add("netstandard"); + + foreach (var framework in possibleFrameworks) + { + dllPath = context.Tools.Resolve(string.Format(pathFormat, packageName, packageVersion, framework, assemblyName)); + if (dllPath is null) + dllPath = context.Tools.Resolve(string.Format(pathFormat, packageName, "*", framework, assemblyName)); + if (dllPath is object) + break; + } + + return dllPath; + } +} \ No newline at end of file diff --git a/Cake.Issues.Recipe/Content/loader/loader.cake b/Cake.Issues.Recipe/Content/loader/loader.cake new file mode 100644 index 00000000..71fc854d --- /dev/null +++ b/Cake.Issues.Recipe/Content/loader/loader.cake @@ -0,0 +1 @@ +#load ./AddinData.cake \ No newline at end of file