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 OverloadsSub New
39     '         Function: __directInvoke, DirectInvoke, EntryPointFullName, HelpInformation, (+2 OverloadsInvoke
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 BooleanAs 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 = FalseAs 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 = TrueAs 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 = TrueAs 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 BooleanAs 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 ObjectOptional [Throw] As Boolean = TrueAs 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 ObjectOptional [Throw] As Boolean = TrueAs 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