22// Licensed under the MIT license.
33
44using HTTPie . Abstractions ;
5+ using HTTPie . Implement ;
6+ using HTTPie . Middleware ;
57using HTTPie . Utilities ;
68using Json . Path ;
79using Microsoft . Extensions . DependencyInjection ;
810using Microsoft . Extensions . Logging ;
9- using System . CommandLine . Invocation ;
1011using System . Diagnostics ;
1112using System . Text ;
1213using System . Text . Json . Nodes ;
@@ -17,58 +18,101 @@ namespace HTTPie.Commands;
1718
1819public sealed class ExecuteCommand : Command
1920{
20- private static readonly Argument < string > FilePathArgument = new ( "scriptPath" , "The script to execute" ) ;
21+ private static readonly Argument < string > FilePathArgument = new ( "scriptPath" )
22+ {
23+ Description = "The script to execute" ,
24+ Arity = ArgumentArity . ZeroOrOne
25+ } ;
2126
2227 private static readonly Option < string > EnvironmentTypeOption =
23- new ( [ "--env" ] , "The environment to execute script" ) ;
28+ new ( "--env" )
29+ {
30+ Description = "The environment to execute script"
31+ } ;
2432
2533 private static readonly Option < ExecuteScriptType > ExecuteScriptTypeOption =
26- new ( [ "-t" , "--type" ] , "The script type to execute" ) ;
34+ new ( "-t" , "--type" )
35+ {
36+ Description = "The script type to execute"
37+ } ;
2738
2839 public ExecuteCommand ( ) : base ( "exec" , "execute http request" )
2940 {
30- AddOption ( ExecuteScriptTypeOption ) ;
31- AddOption ( EnvironmentTypeOption ) ;
32- AddArgument ( FilePathArgument ) ;
41+ Options . Add ( ExecuteScriptTypeOption ) ;
42+ Options . Add ( EnvironmentTypeOption ) ;
43+ Options . Add ( DefaultRequestMiddleware . DebugOption ) ;
44+ Options . Add ( OutputFormatter . OfflineOption ) ;
45+ Arguments . Add ( FilePathArgument ) ;
3346 }
3447
35- public async Task InvokeAsync ( InvocationContext invocationContext , IServiceProvider serviceProvider )
48+ public async Task InvokeAsync (
49+ ParseResult parseResult , CancellationToken cancellationToken , IServiceProvider serviceProvider
50+ )
3651 {
37- var filePath = invocationContext . ParseResult . GetValueForArgument ( FilePathArgument ) ;
38- if ( string . IsNullOrEmpty ( filePath ) || ! File . Exists ( filePath ) )
52+ var scriptText = string . Empty ;
53+ var filePath = parseResult . GetValue ( FilePathArgument ) ;
54+ if ( string . IsNullOrEmpty ( filePath ) )
55+ {
56+ // try to read script content from stdin
57+ if ( ConsoleHelper . HasStandardInput ( ) )
58+ {
59+ scriptText = ( await Console . In . ReadToEndAsync ( cancellationToken ) ) . Trim ( ) ;
60+ }
61+
62+ if ( string . IsNullOrEmpty ( scriptText ) )
63+ {
64+ throw new InvalidOperationException ( "Invalid script to execute" ) ;
65+ }
66+ }
67+ else
3968 {
40- throw new InvalidOperationException ( "Invalid filePath" ) ;
69+ if ( ! File . Exists ( filePath ) )
70+ {
71+ throw new InvalidOperationException ( $ "Invalid filePath { filePath } ") ;
72+ }
4173 }
4274
4375 var logger = serviceProvider . GetRequiredService < ILogger > ( ) ;
4476 var requestExecutor = serviceProvider . GetRequiredService < IRawHttpRequestExecutor > ( ) ;
45- var cancellationToken = invocationContext . GetCancellationToken ( ) ;
46- var type = invocationContext . ParseResult . GetValueForOption ( ExecuteScriptTypeOption ) ;
47- var environment = invocationContext . ParseResult . GetValueForOption ( EnvironmentTypeOption ) ;
77+ var type = parseResult . GetValue ( ExecuteScriptTypeOption ) ;
78+ var environment = parseResult . GetValue ( EnvironmentTypeOption ) ;
4879 var parser = type switch
4980 {
5081 ExecuteScriptType . Http => serviceProvider . GetRequiredService < IHttpParser > ( ) ,
5182 ExecuteScriptType . Curl => serviceProvider . GetRequiredService < ICurlParser > ( ) ,
5283 _ => throw new InvalidOperationException ( $ "Not supported request type: { type } ")
5384 } ;
5485 parser . Environment = environment ;
55- logger . LogDebug ( "Executing {ScriptType} http request {ScriptPath} with {ScriptExecutor}" ,
56- type , filePath , parser . GetType ( ) . Name ) ;
57- await InvokeRequest ( parser , requestExecutor , filePath , cancellationToken ) ;
86+ logger . LogDebug (
87+ "Executing {ScriptType} http request with scriptPath: [{ScriptPath}], scriptText: ({ScriptText}), environment: {Environment} via {ScriptExecutor}" ,
88+ type , filePath , scriptText , environment , parser . GetType ( ) . Name
89+ ) ;
90+
91+ var offline = parseResult . GetValue ( OutputFormatter . OfflineOption ) ;
92+ await InvokeRequest ( parser , requestExecutor , scriptText , filePath , offline , cancellationToken ) ;
5893 }
5994
60- private static async Task InvokeRequest ( IHttpParser httpParser , IRawHttpRequestExecutor requestExecutor ,
61- string filePath , CancellationToken cancellationToken )
95+ private static async Task InvokeRequest (
96+ IHttpParser httpParser , IRawHttpRequestExecutor requestExecutor , string scriptText ,
97+ string ? filePath , bool offline , CancellationToken cancellationToken )
6298 {
6399 var responseList = new Dictionary < string , HttpResponseMessage > ( ) ;
100+
64101 try
65102 {
66- await foreach ( var request in httpParser . ParseFileAsync ( filePath , cancellationToken ) )
103+ var getRequests = string . IsNullOrEmpty ( filePath )
104+ ? httpParser . ParseScriptAsync ( scriptText , cancellationToken )
105+ : httpParser . ParseFileAsync ( filePath , cancellationToken )
106+ ;
107+ await foreach ( var request in getRequests . WithCancellation ( cancellationToken ) )
67108 {
68109 await EnsureRequestVariableReferenceReplaced ( request , responseList ) ;
69110 var response = await ExecuteRequest (
70- requestExecutor , request . RequestMessage , cancellationToken , request . Name
111+ requestExecutor , request . RequestMessage , offline , cancellationToken , request . Name
71112 ) ;
113+ if ( response is null )
114+ continue ;
115+
72116 responseList [ request . Name ] = response ;
73117 }
74118 }
@@ -90,9 +134,10 @@ private static async Task InvokeRequest(IHttpParser httpParser, IRawHttpRequestE
90134 }
91135 }
92136
93- private static async Task < HttpResponseMessage > ExecuteRequest (
137+ private static async Task < HttpResponseMessage ? > ExecuteRequest (
94138 IRawHttpRequestExecutor requestExecutor ,
95139 HttpRequestMessage requestMessage ,
140+ bool offline ,
96141 CancellationToken cancellationToken ,
97142 string ? requestName = null )
98143 {
@@ -101,6 +146,9 @@ private static async Task<HttpResponseMessage> ExecuteRequest(
101146
102147 Console . WriteLine ( "Request message:" ) ;
103148 Console . WriteLine ( await requestMessage . ToRawMessageAsync ( cancellationToken ) ) ;
149+ if ( offline )
150+ return null ;
151+
104152 var startTimestamp = Stopwatch . GetTimestamp ( ) ;
105153 var response = await requestExecutor . ExecuteAsync ( requestMessage , cancellationToken ) ;
106154 var requestDuration = ProfilerHelper . GetElapsedTime ( startTimestamp ) ;
0 commit comments