55import pathlib
66import sys
77import textwrap
8- from typing import Any , Dict , Optional , List
8+ from typing import Any , Dict , Optional , List , Type
99from urllib .parse import urlsplit , urlunsplit , SplitResult
1010
1111import validators # pylint: disable=import-error
@@ -49,7 +49,6 @@ def __init__(self: "FerryCLI", config_path: Optional[pathlib.Path]) -> None:
4949 self .authorizer : Optional ["Auth" ] = None
5050 self .ferry_api : Optional ["FerryAPI" ] = None
5151 self .parser : Optional ["FerryParser" ] = None
52-
5352 if config_path is None :
5453 print (
5554 'A configuration file is required to run the Ferry CLI. Please run "ferry-cli" to generate one interactively if one does not already exist.'
@@ -66,10 +65,9 @@ def get_arg_parser(self: "FerryCLI") -> FerryParser:
6665 description = "CLI for Ferry API endpoints" , parents = [get_auth_parser ()]
6766 )
6867 parser .add_argument (
69- "--dryrun" ,
70- action = "store_true" ,
71- default = False ,
72- help = "Populate the API call(s) but don't actually run them" ,
68+ "--output" ,
69+ default = None ,
70+ help = "(string) Specifies the path to a file where the output will be stored in JSON format. If a file already exists in the specified path, it will be overritten." ,
7371 )
7472 parser .add_argument (
7573 "--filter" ,
@@ -290,7 +288,9 @@ def parse_description(
290288 endpoint_description += f"{ '' :<50} | { line } \n "
291289 return endpoint_description
292290
293- def run (self : "FerryCLI" , debug : bool , quiet : bool , extra_args : Any ) -> None :
291+ def run (
292+ self : "FerryCLI" , debug : bool , quiet : bool , dryrun : bool , extra_args : Any
293+ ) -> None :
294294 self .parser = self .get_arg_parser ()
295295 args , endpoint_args = self .parser .parse_known_args (extra_args )
296296
@@ -300,7 +300,7 @@ def run(self: "FerryCLI", debug: bool, quiet: bool, extra_args: Any) -> None:
300300
301301 if not self .ferry_api :
302302 self .ferry_api = FerryAPI (
303- base_url = self .base_url , authorizer = self .authorizer , quiet = quiet , dryrun = args . dryrun # type: ignore
303+ base_url = self .base_url , authorizer = self .authorizer , quiet = quiet , dryrun = dryrun # type: ignore
304304 )
305305
306306 if args .endpoint :
@@ -310,8 +310,10 @@ def run(self: "FerryCLI", debug: bool, quiet: bool, extra_args: Any) -> None:
310310 json_result = self .execute_endpoint (args .endpoint , endpoint_args )
311311 except Exception as e :
312312 raise Exception (f"{ e } " )
313- if (not quiet ) and (not args .dryrun ):
314- self .handle_output (json .dumps (json_result , indent = 4 ))
313+ if not dryrun :
314+ self .handle_output (
315+ json .dumps (json_result , indent = 4 ), args .output , quiet
316+ )
315317
316318 elif args .workflow :
317319 try :
@@ -320,25 +322,59 @@ def run(self: "FerryCLI", debug: bool, quiet: bool, extra_args: Any) -> None:
320322 workflow .init_parser ()
321323 workflow_params , _ = workflow .parser .parse_known_args (endpoint_args )
322324 json_result = workflow .run (self .ferry_api , vars (workflow_params )) # type: ignore
323- if (not quiet ) and (not args .dryrun ):
324- self .handle_output (json .dumps (json_result , indent = 4 ))
325+ if not dryrun :
326+ self .handle_output (
327+ json .dumps (json_result , indent = 4 ), args .output , quiet
328+ )
325329 except KeyError :
326330 raise KeyError (f"Error: '{ args .workflow } ' is not a supported workflow." )
327331
328332 else :
329333 self .parser .print_help ()
330334
331- # TBD if we will use this at all
332- def handle_output (self : "FerryCLI" , output : str ) -> None :
333- # Don't print excessively long responses - just store them in the result.json file and point to it.
334- if len (output ) < 1000 :
335- print (f"Response: { output } " )
336- else :
337- with open ("result.json" , "w" ) as file :
335+ def handle_output (
336+ self : "FerryCLI" , output : str , output_file : str = "" , quiet : bool = False
337+ ) -> None :
338+ def error_raised (
339+ exception_type : Type [BaseException ],
340+ message : str ,
341+ ) -> None :
342+ message = f"{ exception_type .__name__ } \n " f"{ message } "
343+ if not quiet :
344+ message += f"\n Printing response instead: { output } "
345+ raise exception_type (message )
346+
347+ if not output_file :
348+ if not quiet :
349+ print (f"Response: { output } " )
350+ return
351+
352+ directory = os .path .dirname (output_file )
353+ if directory :
354+ try :
355+ os .makedirs (directory , exist_ok = True )
356+ except PermissionError :
357+ error_raised (
358+ PermissionError ,
359+ f"Permission denied: Unable to create directory: { directory } " ,
360+ )
361+ except OSError as e :
362+ error_raised (OSError , f"Error creating directory: { e } " )
363+ try :
364+ with open (output_file , "w" ) as file :
338365 file .write (output )
339- print (
340- f"\n Response in file: { os .path .abspath (os .environ .get ('PWD' , '' ))} /result.json"
366+ if not quiet :
367+ print (f"Output file: { output_file } " )
368+ return
369+ except PermissionError :
370+ error_raised (
371+ PermissionError ,
372+ f"Permission denied: Unable to write to file: { output_file } " ,
341373 )
374+ except IOError as e :
375+ error_raised (IOError , f"Error writing to file: { e } " )
376+ except Exception as e : # pylint: disable=broad-except
377+ error_raised (Exception , f"Error: { e } " )
342378
343379 @staticmethod
344380 def _sanitize_base_url (raw_base_url : str ) -> str :
@@ -529,19 +565,21 @@ def main() -> None:
529565 sys .exit (0 )
530566 ferry_cli .authorizer = set_auth_from_args (auth_args )
531567 if auth_args .update or not os .path .exists (f"{ CONFIG_DIR } /swagger.json" ):
532- print ("Fetching latest swagger file..." )
568+ if not auth_args .quiet :
569+ print ("Fetching latest swagger file..." )
533570 ferry_cli .ferry_api = FerryAPI (
534571 ferry_cli .base_url , ferry_cli .authorizer , auth_args .quiet
535572 )
536573 ferry_cli .ferry_api .get_latest_swagger_file ()
537- print ("Successfully stored latest swagger file.\n " )
574+ if not auth_args .quiet :
575+ print ("Successfully stored latest swagger file.\n " )
538576
539577 ferry_cli .endpoints = ferry_cli .generate_endpoints ()
540- ferry_cli .run (auth_args .debug , auth_args .quiet , other_args )
578+ ferry_cli .run (auth_args .debug , auth_args .quiet , auth_args . dryrun , other_args )
541579 except (
542580 Exception # pylint: disable=broad-except
543581 ) as e : # TODO Eventually we want to handle a certain set of exceptions, but this will do for now # pylint: disable=fixme
544- print (f"There was an error querying the FERRY API : { e } " )
582+ print (f"An error occurred while using the FERRY CLI : { e } " )
545583 sys .exit (1 )
546584
547585
0 commit comments