microsoft-visualbasic-runtime/CommandLine/Reflection/EntryPoints/APIEntryPoint.vb

350 lines
14 KiB
VB.net
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#Region "Microsoft.VisualBasic::91f190c969bd8ce7ba229be04bca2bcc, Microsoft.VisualBasic.Core\CommandLine\Reflection\EntryPoints\APIEntryPoint.vb"
' Author:
'
' asuka (amethyst.asuka@gcmodeller.org)
' xie (genetics@smrucc.org)
' xieguigang (xie.guigang@live.com)
'
' Copyright (c) 2018 GPL3 Licensed
'
'
' GNU GENERAL PUBLIC LICENSE (GPL3)
'
'
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
' GNU General Public License for more details.
'
' You should have received a copy of the GNU General Public License
' along with this program. If not, see <http://www.gnu.org/licenses/>.
' /********************************************************************************/
' Summaries:
' Class APIEntryPoint
'
' Properties: Arguments, EntryPoint, IsInstanceMethod, target
'
' Constructor: (+3 Overloads) Sub New
' Function: DirectInvoke, EntryPointFullName, handleUnexpectedErrorCalls, HelpInformation, (+2 Overloads) Invoke
' InvokeCLI, tryInvoke
'
'
' /********************************************************************************/
#End Region
Imports System.Reflection
Imports System.Runtime.CompilerServices
Imports System.Text
Imports Microsoft.VisualBasic.ApplicationServices.Debugging
Imports Microsoft.VisualBasic.CommandLine.ManView
Imports Microsoft.VisualBasic.ComponentModel
Imports Microsoft.VisualBasic.Linq.Extensions
Namespace CommandLine.Reflection.EntryPoints
''' <summary>
''' The entry point data of the commands in the command line which was original loaded
''' from the source meta data in the compiled target.
''' (命令行命令的执行入口点)
''' </summary>
''' <remarks></remarks>
Public Class APIEntryPoint : Inherits APIDelegate
#Region "ReadOnly Properties"
''' <summary>
''' 当前的这个命令对象的参数帮助信息列表
''' </summary>
''' <returns></returns>
Public ReadOnly Property Arguments As ArgumentCollection
''' <summary>
''' The reflection entry point in the assembly for the target method object.
''' </summary>
''' <returns></returns>
Public ReadOnly Property EntryPoint As MethodInfo
''' <summary>
''' If the target invoked <see cref="EntryPoint">method delegate</see> is a instance method,
''' then this property value should be the target object instance which has the method delegate.
''' (假若目标方法不是共享的方法则必须要使用本对象来进行Invoke的调用)
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property target As Object
''' <summary>
''' The shared method did not requires of the object instance.(这个方法是否为实例方法)
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property IsInstanceMethod As Boolean
Get
Return Not Me.EntryPoint.IsStatic OrElse Not target Is Nothing
End Get
End Property
''' <summary>
''' The full name path of the target invoked method delegate in the namespace library.
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Public Function EntryPointFullName(relativePath As Boolean) As String
Dim path$ = EntryPoint.DeclaringType.Assembly.Location
If relativePath Then
path = PathExtensions.RelativePath(path)
Else
path = path.ToFileURL
End If
Return $"{path}!{EntryPoint.DeclaringType.FullName}::{EntryPoint.ToString}"
End Function
#End Region
#Region "Constructors"
Public Sub New()
End Sub
''' <summary>
''' 这个构造函数只设置目标实例对象,其他的数据从属性进行设置
''' </summary>
''' <param name="invokeOn"></param>
Public Sub New(invokeOn As Object)
Me.target = invokeOn
End Sub
''' <summary>
''' Instance method can be initialize from this constructor.
''' (假若目标方法为实例方法,请使用本方法进行初始化)
''' </summary>
''' <param name="attribute"></param>
''' <param name="Invoke"></param>
''' <remarks></remarks>
Public Sub New(attribute As ExportAPIAttribute, [Invoke] As MethodInfo, Optional [Throw] As Boolean = True)
_metaData = New Binding(Of ExportAPIAttribute, MethodInfo) With {
.Bind = attribute,
.Target = Invoke
}
__funcInvoker = Function(args As Object()) InvokeCLI(parameters:=args, target:=Nothing, [Throw]:=[Throw])
_EntryPoint = Invoke
_Arguments = New ArgumentCollection(methodInfo:=Invoke)
_NumberOfParameters = Invoke.GetParameters.Length
End Sub
#End Region
#Region "Public Methods"
''' <summary>
''' Returns the help information details for this command line entry object.(获取本命令行执行入口点的详细帮助信息)
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Public Overrides Function HelpInformation(Optional md As Boolean = False) As String
Dim sb As New StringBuilder(MyBase.HelpInformation(md))
If Not Arguments.IsNullOrEmpty Then
Call sb.AppendLine(vbCrLf)
Call sb.AppendLine(" #### Arguments")
If Not md Then
Call sb.AppendLine(" ---------------------------------------")
Call sb.AppendLine()
Call sb.AppendLine(" " & Arguments.ToString)
Else
For Each param In Arguments
Call sb.AppendLine("##### " & If(param.Value.Optional, $"[{param.Name}]", param.Name))
Call sb.AppendLine(param.Value.Description)
Call sb.AppendLine("###### Example")
Call sb.AppendLine("```bash")
If param.Value.TokenType = CLITypes.Boolean Then
Call sb.AppendLine(param.Name)
Call sb.AppendLine("#" & ManualBuilder.boolFlag)
Else
Call sb.AppendLine(param.Name & " " & param.Value.ExampleValue)
If param.Value.Pipeline <> PipelineTypes.undefined Then
Call sb.AppendLine("# " & param.Value.Pipeline.Description)
End If
End If
Call sb.AppendLine("```")
Next
End If
End If
Dim note As NoteAttribute = EntryPoint.GetCustomAttribute(Of NoteAttribute)
If Not note Is Nothing Then
Call sb.AppendLine()
Call sb.AppendLine("Author Comment About This Command:")
Call sb.AppendLine(note.noteText)
End If
Return sb.ToString
End Function
''' <summary>
''' Invoke this command line and returns the function value.(函数会补齐可选参数)
''' </summary>
''' <param name="parameters">The function parameter for the target invoked method, the optional value will be filled
''' using the paramter default value if you are not specific the optional paramter value is the element position of
''' this paramter value.</param>
''' <param name="Throw">If throw then if the exception happened from delegate invocation then the program will throw an
''' exception and terminated, if not then the program will save the exception information into a log file and then
''' returns a failure status.</param>
''' <returns></returns>
''' <remarks></remarks>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function Invoke(parameters As Object(), Optional [Throw] As Boolean = True) As Object
Return Invoke(parameters, Me.target, [Throw])
End Function
''' <summary>
''' 不会自动调整补齐参数
''' </summary>
''' <param name="callParameters"></param>
''' <param name="[Throw]"></param>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function DirectInvoke(callParameters As Object(), Optional [Throw] As Boolean = True) As Object
Return tryInvoke(callParameters, Me.target, [Throw])
End Function
''' <summary>
''' 记录错误信息的最上层的堆栈
''' </summary>
''' <param name="callParameters"></param>
''' <param name="target"></param>
''' <param name="[throw]"></param>
''' <returns></returns>
Private Function tryInvoke(callParameters As Object(), target As Object, [throw] As Boolean) As Object
#If DEBUG Then
Return EntryPoint.Invoke(target, callParameters)
#Else
Return handleUnexpectedErrorCalls(callParameters, target, [throw])
#End If
End Function
Private Function handleUnexpectedErrorCalls(callParameters As Object(), target As Object, [throw] As Boolean) As Object
Dim rtvl As Object
Try
rtvl = EntryPoint.Invoke(target, callParameters)
Catch ex As Exception
Dim args$() = callParameters _
.Select(AddressOf Scripting.ToString) _
.ToArray
Dim paramTrace As String = String.Join(vbCrLf, args)
Dim source As Exception = ex
Dim trace$ = MethodBase.GetCurrentMethod.GetFullName
ex = New Exception(paramTrace, ex)
ex = New VisualBasicAppException(ex, EntryPoint.GetFullName(True))
' Enable output the exception details on the console.
VBDebugger.Mute = False
Call App.LogException(ex, trace)
Call DebuggerArgs.SaveErrorLog(VBDebugger.BugsFormatter(ex))
Call VBDebugger.WaitOutput()
If [throw] Then
Throw ex
Else
Call "".EchoLine
Call ExceptionHandler.Print(source, EntryPoint)
Call "".EchoLine
Call $"[Log] {trace.GetFullPath}".__INFO_ECHO
Call VBDebugger.WaitOutput()
rtvl = -100
End If
End Try
Return rtvl
End Function
''' <summary>
''' Invoke this command line and returns the function value.
''' (函数会补齐可选参数)
''' </summary>
''' <param name="parameters">The function parameter for the target invoked method, the optional value will be filled
''' using the paramter default value if you are not specific the optional paramter value is the element position of
''' this paramter value.</param>
''' <param name="target">Target entry pointer of this function method delegate.</param>
''' <param name="Throw">If throw then if the exception happened from delegate invocation then the program will throw an
''' exception and terminated, if not then the program will save the exception information into a log file and then
''' returns a failure status.</param>
''' <returns></returns>
''' <remarks></remarks>
Public Function Invoke(parameters As Object(), target As Object, Optional [Throw] As Boolean = True) As Object
Dim callParameters() As Object
If parameters.Length < _NumberOfParameters Then
callParameters = New Object(_NumberOfParameters - 1) {}
Call parameters.CopyTo(callParameters, 0)
ElseIf parameters.Length > _NumberOfParameters Then
callParameters = New Object(_NumberOfParameters - 1) {}
Call Array.ConstrainedCopy(parameters, 0, callParameters, 0, _NumberOfParameters)
Else
callParameters = parameters
End If
Return tryInvoke(callParameters, target, [Throw])
End Function
''' <summary>
''' Invoke this command line but returns the function execute success, Zero for success and -1 for failure.
''' (函数会补齐可选参数)
''' </summary>
''' <param name="parameters"></param>
''' <param name="target"></param>
''' <param name="Throw"></param>
''' <returns></returns>
''' <remarks></remarks>
Public Function InvokeCLI(parameters As Object(), target As Object, Optional [Throw] As Boolean = True) As Integer
Dim rtvl As Object = Invoke(parameters, target, [Throw])
If EntryPoint.ReturnType Is GetType(Void) Then
' is a sub
' always return zero
Return 0
ElseIf rtvl Is Nothing Then
' function return value is nothing
Return -1
Else
Dim type As Type = rtvl.GetType
If type = GetType(Integer) OrElse
type = GetType(Long) OrElse
type = GetType(Double) OrElse
type = GetType(Short) Then
Return CType(rtvl, Integer)
Else
Return 0
End If
End If
End Function
#End Region
End Class
End Namespace