Skip to content

Commit fb4bb1a

Browse files
committed
(GH-17) Create assembly loader to support dynamic addins
1 parent fc22d28 commit fb4bb1a

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
using System.Reflection;
2+
using Cake.Core.Annotations;
3+
4+
public abstract class AddinData
5+
{
6+
protected AddinData(ICakeContext context, string packageName, string packageVersion, string assemblyName = null)
7+
{
8+
this.Initialize(context, packageName, packageVersion, assemblyName);
9+
}
10+
11+
public Assembly AddinAssembly { get; private set; }
12+
public IEnumerable<Type> DeclaredEnums { get; private set; }
13+
public IEnumerable<MethodInfo> DefinedAliases { get; private set; }
14+
public IEnumerable<TypeInfo> DefinedClasses { get; private set; }
15+
public IEnumerable<MethodInfo> DefinedMethods { get; private set; }
16+
17+
protected void Initialize(ICakeContext context, string packageName, string packageVersion, string assemblyName = null)
18+
{
19+
if (string.IsNullOrEmpty(assemblyName))
20+
{
21+
assemblyName = packageName;
22+
}
23+
24+
var assembly = LoadAddinAssembly(context, packageName, packageVersion, assemblyName);
25+
26+
if (assembly is null)
27+
{
28+
return;
29+
}
30+
31+
AddinAssembly = assembly;
32+
33+
var declaredEnums = new List<Type>();
34+
var definedClasses = new List<TypeInfo>();
35+
36+
foreach (var ti in assembly.DefinedTypes.Where(ti => ti.IsPublic))
37+
{
38+
if (ti.IsEnum)
39+
{
40+
declaredEnums.Add(ti.AsType());
41+
EnumerationFound(context, ti.AsType());
42+
}
43+
else if(ti.IsClass && (!ti.IsAbstract || ti.IsStatic()) && !ti.IsGenericTypeDefinition)
44+
{
45+
definedClasses.Add(ti);
46+
ClassFound(context, ti);
47+
ParseClass(context, ti);
48+
}
49+
}
50+
51+
DeclaredEnums = declaredEnums;
52+
DefinedClasses = definedClasses;
53+
}
54+
55+
protected virtual void AliasFound(ICakeContext context, MethodInfo method)
56+
{
57+
}
58+
59+
protected virtual void ClassFound(ICakeContext context, TypeInfo classTypeInfo)
60+
{
61+
}
62+
63+
protected void ParseClass(ICakeContext context, TypeInfo classTypeInfo)
64+
{
65+
var aliases = new List<MethodInfo>();
66+
var methods = new List<MethodInfo>();
67+
68+
foreach (var mi in classTypeInfo.DeclaredMethods.Where(i => i.IsPublic))
69+
{
70+
if (mi.GetCustomAttribute<CakeMethodAliasAttribute>() != null)
71+
{
72+
aliases.Add(mi);
73+
AliasFound(context, mi);
74+
}
75+
else
76+
{
77+
methods.Add(mi);
78+
MethodFound(context, mi);
79+
}
80+
}
81+
82+
DefinedAliases = aliases;
83+
DefinedMethods = methods;
84+
}
85+
86+
protected virtual void EnumerationFound(ICakeContext context, Type enumType)
87+
{
88+
}
89+
90+
protected virtual void MethodFound(ICakeContext context, MethodInfo method)
91+
{
92+
}
93+
94+
private static Assembly LoadAddinAssembly(ICakeContext context, string packageName, string packageVersion, string assemblyName)
95+
{
96+
var dllPath = GetAssemblyPath(context, packageName, packageVersion, assemblyName);
97+
98+
if (dllPath is null)
99+
{
100+
var script = $"#tool nuget:?package={packageName}&version={packageVersion}&prerelease";
101+
var tempFile = Guid.NewGuid() + ".cake";
102+
103+
System.IO.File.WriteAllText(tempFile, script);
104+
105+
try
106+
{
107+
context.CakeExecuteScript(tempFile);
108+
}
109+
finally
110+
{
111+
if (context.FileExists(tempFile))
112+
{
113+
context.DeleteFile(tempFile);
114+
}
115+
}
116+
}
117+
118+
dllPath = GetAssemblyPath(context, packageName, packageVersion, assemblyName);
119+
120+
if (dllPath is null)
121+
{
122+
context.Warning("Unable to find path to the {0} package assembly!", packageName);
123+
return null;
124+
}
125+
126+
var assembly = Assembly.LoadFrom(dllPath.FullPath);
127+
return assembly;
128+
}
129+
130+
private static FilePath GetAssemblyPath(ICakeContext context, string packageName, string packageVersion, string assemblyName)
131+
{
132+
FilePath dllPath = null;
133+
const string pathFormat = "{0}.{1}/**/{2}*/{3}.dll";
134+
135+
var possibleFrameworks = new List<String>();
136+
137+
if (context.Environment.Runtime.IsCoreClr)
138+
{
139+
possibleFrameworks.Add("netcoreapp");
140+
possibleFrameworks.Add("net4"); // TODO: Remove this after debugging
141+
}
142+
else
143+
{
144+
possibleFrameworks.Add("net4");
145+
}
146+
possibleFrameworks.Add("netstandard");
147+
148+
foreach (var framework in possibleFrameworks)
149+
{
150+
dllPath = context.Tools.Resolve(string.Format(pathFormat, packageName, packageVersion, framework, assemblyName));
151+
if (dllPath is null)
152+
dllPath = context.Tools.Resolve(string.Format(pathFormat, packageName, "*", framework, assemblyName));
153+
if (dllPath is object)
154+
break;
155+
}
156+
157+
return dllPath;
158+
}
159+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#load ./AddinData.cake

0 commit comments

Comments
 (0)