1
+ using System . Reflection ;
2
+ using Cake . Core . Annotations ;
3
+
4
+ public class AddinData
5
+ {
6
+ private readonly ICakeContext _context ;
7
+
8
+ public AddinData ( ICakeContext context , string packageName , string packageVersion , string assemblyName = null )
9
+ {
10
+ this . _context = context ;
11
+ this . Initialize ( context , packageName , packageVersion , assemblyName ) ;
12
+ }
13
+
14
+ public Assembly AddinAssembly { get ; private set ; }
15
+ public IList < Type > _declaredEnums = new List < Type > ( ) ;
16
+ public IList < TypeInfo > _definedClasses = new List < TypeInfo > ( ) ;
17
+ private IList < MethodInfo > _definedMethods = new List < MethodInfo > ( ) ;
18
+
19
+ public object CreateClass ( string classTypeString , params object [ ] parameters )
20
+ {
21
+ var possibleClass = _definedClasses . FirstOrDefault ( c => string . Compare ( c . Name , classTypeString , StringComparison . OrdinalIgnoreCase ) == 0 ) ;
22
+
23
+ if ( possibleClass is null )
24
+ {
25
+ throw new NullReferenceException ( $ "No loaded class named { classTypeString } was found in this assembly.") ;
26
+ }
27
+
28
+ return CreateClass ( possibleClass , parameters ) ;
29
+ }
30
+
31
+ public object CreateClass ( TypeInfo classType , params object [ ] parameters )
32
+ {
33
+ parameters = parameters ?? new object [ 0 ] ;
34
+ var constructors = classType . DeclaredConstructors . Where ( c => c . IsPublic && ! c . IsStatic && c . GetParameters ( ) . Length == parameters . Length ) ;
35
+ ConstructorInfo constructor = null ;
36
+
37
+ foreach ( var ctx in constructors )
38
+ {
39
+ var ctxParams = ctx . GetParameters ( ) ;
40
+ bool useCtx = true ;
41
+ for ( int i = 0 ; i < ctxParams . Length && useCtx ; i ++ )
42
+ {
43
+ useCtx = ctxParams [ i ] . ParameterType == parameters [ i ] . GetType ( ) ;
44
+ }
45
+
46
+ if ( useCtx )
47
+ {
48
+ constructor = ctx ;
49
+ break ;
50
+ }
51
+ }
52
+
53
+ if ( constructor is null )
54
+ {
55
+ throw new NullReferenceException ( "No valid constructor was found!" ) ;
56
+ }
57
+
58
+ return constructor . Invoke ( parameters ?? new object [ 0 ] ) ;
59
+ }
60
+
61
+ public object CallStaticMethod ( string methodName , params object [ ] parameters )
62
+ {
63
+ parameters = parameters ?? new object [ 0 ] ;
64
+
65
+ for ( int i = 0 ; i < parameters . Length ; i ++ )
66
+ {
67
+ var parameterType = parameters [ i ] . GetType ( ) ;
68
+ int index = parameterType == typeof ( string ) ? parameters [ i ] . ToString ( ) . IndexOf ( '.' ) : - 1 ;
69
+ if ( index >= 0 )
70
+ {
71
+ var enumOrClass = parameters [ i ] . ToString ( ) . Substring ( 0 , index ) ;
72
+ var enumType = _declaredEnums . FirstOrDefault ( e => string . Compare ( e . Name , enumOrClass , StringComparison . OrdinalIgnoreCase ) == 0 ) ;
73
+ if ( enumType is object )
74
+ {
75
+ var value = parameters [ i ] . ToString ( ) . Substring ( index + 1 ) ;
76
+ parameters [ i ] = Enum . Parse ( enumType , value ) ;
77
+ }
78
+ }
79
+ }
80
+
81
+ var methods = this . _definedMethods . Where ( m => m . IsPublic && m . IsStatic && string . Compare ( m . Name , methodName , StringComparison . OrdinalIgnoreCase ) == 0 ) ;
82
+ MethodInfo method = null ;
83
+
84
+ foreach ( var m in methods . Where ( m => m . GetParameters ( ) . Length == parameters . Length ) )
85
+ {
86
+ var methodParams = m . GetParameters ( ) ;
87
+ bool useMethod = true ;
88
+
89
+ for ( int i = 0 ; i < methodParams . Length && useMethod ; i ++ )
90
+ {
91
+ var methodParamType = methodParams [ i ] . ParameterType ;
92
+ var optionParamType = parameters [ i ] . GetType ( ) ;
93
+ if ( methodParamType . IsEnum && optionParamType == typeof ( string ) )
94
+ {
95
+ try
96
+ {
97
+ var parsedValue = Enum . Parse ( methodParamType , parameters [ i ] . ToString ( ) ) ;
98
+ if ( parsedValue is object )
99
+ {
100
+ parameters [ i ] = parsedValue ;
101
+ }
102
+ else
103
+ useMethod = false ;
104
+ }
105
+ catch
106
+ {
107
+ useMethod = false ;
108
+ }
109
+ }
110
+ else if ( methodParamType == typeof ( Enum ) && optionParamType . IsEnum )
111
+ {
112
+ useMethod = true ;
113
+ }
114
+ else
115
+ {
116
+ useMethod = methodParamType == optionParamType || methodParamType . IsAssignableFrom ( optionParamType ) ;
117
+ }
118
+ }
119
+
120
+ if ( useMethod )
121
+ {
122
+ method = m ;
123
+ break ;
124
+ }
125
+ }
126
+
127
+ if ( method is null )
128
+ {
129
+ throw new NullReferenceException ( "No method with the specified name was found!" ) ;
130
+ }
131
+
132
+ return method . Invoke ( null , parameters ) ;
133
+ }
134
+
135
+ protected void Initialize ( ICakeContext context , string packageName , string packageVersion , string assemblyName = null )
136
+ {
137
+ if ( string . IsNullOrEmpty ( assemblyName ) )
138
+ {
139
+ assemblyName = packageName ;
140
+ }
141
+
142
+ var assembly = LoadAddinAssembly ( context , packageName , packageVersion , assemblyName ) ;
143
+
144
+ if ( assembly is null )
145
+ {
146
+ return ;
147
+ }
148
+
149
+ AddinAssembly = assembly ;
150
+
151
+ foreach ( var ti in assembly . DefinedTypes . Where ( ti => ti . IsPublic ) )
152
+ {
153
+ if ( ti . IsEnum )
154
+ {
155
+ _declaredEnums . Add ( ti . AsType ( ) ) ;
156
+ }
157
+ else if ( ti . IsClass && ( ! ti . IsAbstract || ti . IsStatic ( ) ) && ! ti . IsGenericTypeDefinition )
158
+ {
159
+ _definedClasses . Add ( ti ) ;
160
+ ParseClass ( context , ti ) ;
161
+ }
162
+ }
163
+ }
164
+
165
+ protected void ParseClass ( ICakeContext context , TypeInfo classTypeInfo )
166
+ {
167
+ var aliases = new List < MethodInfo > ( ) ;
168
+ var methods = new List < MethodInfo > ( ) ;
169
+
170
+ foreach ( var mi in classTypeInfo . DeclaredMethods . Where ( i => i . IsPublic ) )
171
+ {
172
+ _definedMethods . Add ( mi ) ;
173
+ }
174
+ }
175
+
176
+ private static Assembly LoadAddinAssembly ( ICakeContext context , string packageName , string packageVersion , string assemblyName )
177
+ {
178
+ var dllPath = GetAssemblyPath ( context , packageName , packageVersion , assemblyName ) ;
179
+
180
+ if ( dllPath is null )
181
+ {
182
+ var script = $ "#tool nuget:?package={ packageName } &version={ packageVersion } &prerelease";
183
+ var tempFile = Guid . NewGuid ( ) + ".cake" ;
184
+
185
+ System . IO . File . WriteAllText ( tempFile , script ) ;
186
+
187
+ try
188
+ {
189
+ context . CakeExecuteScript ( tempFile ) ;
190
+ }
191
+ finally
192
+ {
193
+ if ( context . FileExists ( tempFile ) )
194
+ {
195
+ context . DeleteFile ( tempFile ) ;
196
+ }
197
+ }
198
+ }
199
+
200
+ dllPath = GetAssemblyPath ( context , packageName , packageVersion , assemblyName ) ;
201
+
202
+ if ( dllPath is null )
203
+ {
204
+ context . Warning ( "Unable to find path to the {0} package assembly!" , packageName ) ;
205
+ return null ;
206
+ }
207
+
208
+ var assembly = Assembly . LoadFrom ( dllPath . FullPath ) ;
209
+ return assembly ;
210
+ }
211
+
212
+ private static FilePath GetAssemblyPath ( ICakeContext context , string packageName , string packageVersion , string assemblyName )
213
+ {
214
+ FilePath dllPath = null ;
215
+ const string pathFormat = "{0}.{1}/**/{2}*/{3}.dll" ;
216
+
217
+ var possibleFrameworks = new List < String > ( ) ;
218
+
219
+ if ( context . Environment . Runtime . IsCoreClr )
220
+ {
221
+ possibleFrameworks . Add ( "netcoreapp" ) ;
222
+ possibleFrameworks . Add ( "net4" ) ; // TODO: Remove this after debugging
223
+ }
224
+ else
225
+ {
226
+ possibleFrameworks . Add ( "net4" ) ;
227
+ }
228
+ possibleFrameworks . Add ( "netstandard" ) ;
229
+
230
+ foreach ( var framework in possibleFrameworks )
231
+ {
232
+ dllPath = context . Tools . Resolve ( string . Format ( pathFormat , packageName , packageVersion , framework , assemblyName ) ) ;
233
+ if ( dllPath is null )
234
+ dllPath = context . Tools . Resolve ( string . Format ( pathFormat , packageName , "*" , framework , assemblyName ) ) ;
235
+ if ( dllPath is object )
236
+ break ;
237
+ }
238
+
239
+ return dllPath ;
240
+ }
241
+ }
0 commit comments