1 | #Region "Microsoft.VisualBasic::47ba5af8f77b29a450220523e141ab3e, Microsoft.VisualBasic.Core\CommandLine\Reflection\EntryPoints\APIEntryPoint.vb" |
2 | |
3 | ' Author: |
4 | ' |
5 | ' asuka (amethyst.asuka@gcmodeller.org) |
6 | ' xie (genetics@smrucc.org) |
7 | ' xieguigang (xie.guigang@live.com) |
8 | ' |
9 | ' Copyright (c) 2018 GPL3 Licensed |
10 | ' |
11 | ' |
12 | ' GNU GENERAL PUBLIC LICENSE (GPL3) |
13 | ' |
14 | ' |
15 | ' This program is free software: you can redistribute it and/or modify |
16 | ' it under the terms of the GNU General Public License as published by |
17 | ' the Free Software Foundation, either version 3 of the License, or |
18 | ' (at your option) any later version. |
19 | ' |
20 | ' This program is distributed in the hope that it will be useful, |
21 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of |
22 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
23 | ' GNU General Public License for more details. |
24 | ' |
25 | ' You should have received a copy of the GNU General Public License |
26 | ' along with this program. If not, see <http://www.gnu.org/licenses/>. |
27 | |
28 | |
29 | |
30 | ' /********************************************************************************/ |
31 | |
32 | ' Summaries: |
33 | |
34 | ' Class APIEntryPoint |
35 | ' |
36 | ' Properties: Arguments, EntryPoint, IsInstanceMethod, target |
37 | ' |
38 | ' Constructor: (+3 Overloads) Sub New |
39 | ' Function: __directInvoke, DirectInvoke, EntryPointFullName, HelpInformation, (+2 Overloads) Invoke |
40 | ' InvokeCLI |
41 | ' |
42 | ' |
43 | ' /********************************************************************************/ |
44 | |
45 | #End Region |
46 | |
47 | Imports System.Reflection |
48 | Imports System.Runtime.CompilerServices |
49 | Imports System.Text |
50 | Imports Microsoft.VisualBasic.ApplicationServices.Debugging |
51 | Imports Microsoft.VisualBasic.CommandLine.ManView |
52 | Imports Microsoft.VisualBasic.ComponentModel |
53 | Imports Microsoft.VisualBasic.Linq.Extensions |
54 | |
55 | Namespace CommandLine.Reflection.EntryPoints |
56 | |
57 | ''' <summary> |
58 | ''' The entry point data of the commands in the command line which was original loaded |
59 | ''' from the source meta data in the compiled target. |
60 | ''' (命令行命令的执行入口点) |
61 | ''' </summary> |
62 | ''' <remarks></remarks> |
63 | Public Class APIEntryPoint : Inherits APIDelegate |
64 | |
65 | #Region "ReadOnly Properties" |
66 | |
67 | ''' <summary> |
68 | ''' 当前的这个命令对象的参数帮助信息列表 |
69 | ''' </summary> |
70 | ''' <returns></returns> |
71 | Public ReadOnly Property Arguments As ArgumentCollection |
72 | ''' <summary> |
73 | ''' The reflection entry point in the assembly for the target method object. |
74 | ''' </summary> |
75 | ''' <returns></returns> |
76 | Public ReadOnly Property EntryPoint As MethodInfo |
77 | |
78 | ''' <summary> |
79 | ''' If the target invoked <see cref="EntryPoint">method delegate</see> is a instance method, |
80 | ''' then this property value should be the target object instance which has the method delegate. |
81 | ''' (假若目标方法不是共享的方法,则必须要使用本对象来进行Invoke的调用) |
82 | ''' </summary> |
83 | ''' <value></value> |
84 | ''' <returns></returns> |
85 | ''' <remarks></remarks> |
86 | Public Property target As Object |
87 | |
88 | ''' <summary> |
89 | ''' The shared method did not requires of the object instance.(这个方法是否为实例方法) |
90 | ''' </summary> |
91 | ''' <value></value> |
92 | ''' <returns></returns> |
93 | ''' <remarks></remarks> |
94 | Public ReadOnly Property IsInstanceMethod As Boolean |
95 | Get |
96 | Return Not Me.EntryPoint.IsStatic OrElse Not target Is Nothing |
97 | End Get |
98 | End Property |
99 | |
100 | ''' <summary> |
101 | ''' The full name path of the target invoked method delegate in the namespace library. |
102 | ''' </summary> |
103 | ''' <returns></returns> |
104 | ''' <remarks></remarks> |
105 | Public Function EntryPointFullName(relativePath As Boolean) As String |
106 | Dim path$ = EntryPoint.DeclaringType.Assembly.Location |
107 | |
108 | If relativePath Then |
109 | path = PathExtensions.RelativePath(path) |
110 | Else |
111 | path = path.ToFileURL |
112 | End If |
113 | |
114 | Return $"{path}!{EntryPoint.DeclaringType.FullName}::{EntryPoint.ToString}" |
115 | End Function |
116 | #End Region |
117 | |
118 | #Region "Constructors" |
119 | |
120 | Public Sub New() |
121 | End Sub |
122 | |
123 | ''' <summary> |
124 | ''' 这个构造函数只设置目标实例对象,其他的数据从属性进行设置 |
125 | ''' </summary> |
126 | ''' <param name="invokeOn"></param> |
127 | Public Sub New(invokeOn As Object) |
128 | Me.target = invokeOn |
129 | End Sub |
130 | |
131 | ''' <summary> |
132 | ''' Instance method can be initialize from this constructor. |
133 | ''' (假若目标方法为实例方法,请使用本方法进行初始化) |
134 | ''' </summary> |
135 | ''' <param name="attribute"></param> |
136 | ''' <param name="Invoke"></param> |
137 | ''' <remarks></remarks> |
138 | Public Sub New(attribute As ExportAPIAttribute, [Invoke] As MethodInfo, Optional [Throw] As Boolean = True) |
139 | _metaData = New Binding(Of ExportAPIAttribute, MethodInfo) With { |
140 | .Bind = attribute, |
141 | .Target = Invoke |
142 | } |
143 | __funcInvoker = Function(args As Object()) InvokeCLI(parameters:=args, target:=Nothing, [Throw]:=[Throw]) |
144 | _EntryPoint = Invoke |
145 | _Arguments = New ArgumentCollection(methodInfo:=Invoke) |
146 | _NumberOfParameters = Invoke.GetParameters.Length |
147 | End Sub |
148 | #End Region |
149 | |
150 | #Region "Public Methods" |
151 | |
152 | ''' <summary> |
153 | ''' Returns the help information details for this command line entry object.(获取本命令行执行入口点的详细帮助信息) |
154 | ''' </summary> |
155 | ''' <returns></returns> |
156 | ''' <remarks></remarks> |
157 | Public Overrides Function HelpInformation(Optional md As Boolean = False) As String |
158 | Dim sb As New StringBuilder(MyBase.HelpInformation(md)) |
159 | |
160 | If Not Arguments.IsNullOrEmpty Then |
161 | Call sb.AppendLine(vbCrLf) |
162 | Call sb.AppendLine(" #### Arguments") |
163 | |
164 | If Not md Then |
165 | Call sb.AppendLine(" ---------------------------------------") |
166 | Call sb.AppendLine() |
167 | Call sb.AppendLine(" " & Arguments.ToString) |
168 | Else |
169 | For Each param In Arguments |
170 | Call sb.AppendLine("##### " & If(param.Value.Optional, $"[{param.Name}]", param.Name)) |
171 | Call sb.AppendLine(param.Value.Description) |
172 | Call sb.AppendLine("###### Example") |
173 | Call sb.AppendLine("```bash") |
174 | |
175 | If param.Value.TokenType = CLITypes.Boolean Then |
176 | Call sb.AppendLine(param.Name) |
177 | Call sb.AppendLine("#" & ManualBuilder.boolFlag) |
178 | Else |
179 | Call sb.AppendLine(param.Name & " " & param.Value.ExampleValue) |
180 | If param.Value.Pipeline <> PipelineTypes.undefined Then |
181 | Call sb.AppendLine("# " & param.Value.Pipeline.Description) |
182 | End If |
183 | End If |
184 | |
185 | Call sb.AppendLine("```") |
186 | Next |
187 | End If |
188 | End If |
189 | |
190 | Return sb.ToString |
191 | End Function |
192 | |
193 | ''' <summary> |
194 | ''' Invoke this command line and returns the function value.(函数会补齐可选参数) |
195 | ''' </summary> |
196 | ''' <param name="parameters">The function parameter for the target invoked method, the optional value will be filled |
197 | ''' using the paramter default value if you are not specific the optional paramter value is the element position of |
198 | ''' this paramter value.</param> |
199 | ''' <param name="Throw">If throw then if the exception happened from delegate invocation then the program will throw an |
200 | ''' exception and terminated, if not then the program will save the exception information into a log file and then |
201 | ''' returns a failure status.</param> |
202 | ''' <returns></returns> |
203 | ''' <remarks></remarks> |
204 | ''' |
205 | <MethodImpl(MethodImplOptions.AggressiveInlining)> |
206 | Public Function Invoke(parameters As Object(), Optional [Throw] As Boolean = True) As Object |
207 | Return Invoke(parameters, Me.target, [Throw]) |
208 | End Function |
209 | |
210 | ''' <summary> |
211 | ''' 不会自动调整补齐参数 |
212 | ''' </summary> |
213 | ''' <param name="callParameters"></param> |
214 | ''' <param name="[Throw]"></param> |
215 | ''' <returns></returns> |
216 | ''' |
217 | <MethodImpl(MethodImplOptions.AggressiveInlining)> |
218 | Public Function DirectInvoke(callParameters As Object(), Optional [Throw] As Boolean = True) As Object |
219 | Return __directInvoke(callParameters, Me.target, [Throw]) |
220 | End Function |
221 | |
222 | ''' <summary> |
223 | ''' 记录错误信息的最上层的堆栈 |
224 | ''' </summary> |
225 | ''' <param name="callParameters"></param> |
226 | ''' <param name="target"></param> |
227 | ''' <param name="[throw]"></param> |
228 | ''' <returns></returns> |
229 | Private Function __directInvoke(callParameters As Object(), target As Object, [throw] As Boolean) As Object |
230 | Dim rtvl As Object |
231 | |
232 | Try |
233 | rtvl = EntryPoint.Invoke(target, callParameters) |
234 | Catch ex As Exception |
235 | Dim args$() = callParameters _ |
236 | .Select(AddressOf Scripting.ToString) _ |
237 | .ToArray |
238 | Dim paramTrace As String = String.Join(vbCrLf, args) |
239 | Dim source As Exception = ex |
240 | Dim trace$ = MethodBase.GetCurrentMethod.GetFullName |
241 | |
242 | ex = New Exception(paramTrace, ex) |
243 | ex = New VisualBasicAppException(ex, EntryPoint.GetFullName(True)) |
244 | |
245 | VBDebugger.Mute = False ' Enable output the exception details on the console. |
246 | |
247 | Call App.LogException(ex, trace) |
248 | Call DebuggerArgs.SaveErrorLog(App.BugsFormatter(ex)) |
249 | Call VBDebugger.WaitOutput() |
250 | |
251 | If [throw] Then |
252 | Throw ex |
253 | Else |
254 | Call "".EchoLine |
255 | Call ExceptionHandler.Print(source, EntryPoint) |
256 | Call "".EchoLine |
257 | Call $"[Log] {trace.GetFullPath}".__INFO_ECHO |
258 | Call VBDebugger.WaitOutput() |
259 | |
260 | rtvl = -100 |
261 | End If |
262 | End Try |
263 | |
264 | Return rtvl |
265 | End Function |
266 | |
267 | ''' <summary> |
268 | ''' Invoke this command line and returns the function value. |
269 | ''' (函数会补齐可选参数) |
270 | ''' </summary> |
271 | ''' <param name="parameters">The function parameter for the target invoked method, the optional value will be filled |
272 | ''' using the paramter default value if you are not specific the optional paramter value is the element position of |
273 | ''' this paramter value.</param> |
274 | ''' <param name="target">Target entry pointer of this function method delegate.</param> |
275 | ''' <param name="Throw">If throw then if the exception happened from delegate invocation then the program will throw an |
276 | ''' exception and terminated, if not then the program will save the exception information into a log file and then |
277 | ''' returns a failure status.</param> |
278 | ''' <returns></returns> |
279 | ''' <remarks></remarks> |
280 | Public Function Invoke(parameters As Object(), target As Object, Optional [Throw] As Boolean = True) As Object |
281 | Dim callParameters() As Object |
282 | |
283 | If parameters.Length < _NumberOfParameters Then |
284 | callParameters = New Object(_NumberOfParameters - 1) {} |
285 | Call parameters.CopyTo(callParameters, 0) |
286 | |
287 | ElseIf parameters.Length > _NumberOfParameters Then |
288 | callParameters = New Object(_NumberOfParameters - 1) {} |
289 | Call Array.ConstrainedCopy(parameters, 0, callParameters, 0, _NumberOfParameters) |
290 | Else |
291 | callParameters = parameters |
292 | End If |
293 | |
294 | Return __directInvoke(callParameters, target, [Throw]) |
295 | End Function |
296 | |
297 | ''' <summary> |
298 | ''' Invoke this command line but returns the function execute success, Zero for success and -1 for failure. |
299 | ''' (函数会补齐可选参数) |
300 | ''' </summary> |
301 | ''' <param name="parameters"></param> |
302 | ''' <param name="target"></param> |
303 | ''' <param name="Throw"></param> |
304 | ''' <returns></returns> |
305 | ''' <remarks></remarks> |
306 | Public Function InvokeCLI(parameters As Object(), target As Object, Optional [Throw] As Boolean = True) As Integer |
307 | Dim rtvl As Object = Invoke(parameters, target, [Throw]) |
308 | Dim Type As Type = rtvl.GetType |
309 | |
310 | If Type = GetType(Integer) OrElse |
311 | Type = GetType(Long) OrElse |
312 | Type = GetType(Double) OrElse |
313 | Type = GetType(Short) Then |
314 | |
315 | Return CType(rtvl, Integer) |
316 | Else |
317 | Dim value As Integer = If(rtvl Is Nothing, -1, 0) |
318 | Return value |
319 | End If |
320 | End Function |
321 | #End Region |
322 | End Class |
323 | End Namespace |