| 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 |