77"""Entry point for the CLI."""
88
99from os import _exit as os_exit
10+ from urllib .parse import urlparse
1011
1112from typing import Optional
1213
2021from ocebuild_cli .logging import _format_url , abort
2122
2223
23- @click .group (context_settings = CONTEXT_SETTINGS )
24+ class PassthroughCommand (click .Group ):
25+ """A custom command group that handles the exec option specially."""
26+
27+ @staticmethod
28+ def is_url (s ):
29+ try :
30+ result = urlparse (s )
31+ return all ([result .scheme , result .netloc ])
32+ except ValueError :
33+ return False
34+
35+ def parse_args (self , ctx , args ):
36+ ctx .obj = CLIEnv ()
37+
38+ # Check if -e or --exec is in args
39+ if '-e' in args or '--exec' in args :
40+ # Find the position of -e or --exec
41+ try :
42+ idx = args .index ('-e' )
43+ except ValueError :
44+ idx = args .index ('--exec' )
45+
46+ # Get the script path (next argument after -e/--exec)
47+ if idx + 1 < len (args ):
48+ script_path = args [idx + 1 ]
49+
50+ # If the script is a URL, we should download it to a tmp dir
51+ if self .is_url (script_path ):
52+ from ocebuild .sources import request
53+ from tempfile import TemporaryDirectory
54+ with request (script_path ) as response :
55+ # Create a temporary dir and store the script with the same name
56+ # as the URL's last part (instead of a random name).
57+ with TemporaryDirectory (delete = False ) as tmpdir :
58+ from os .path import join , basename
59+ ctx .obj .tmpdir = tmpdir
60+ script_path = join (tmpdir , basename (urlparse (script_path ).path ))
61+ with open (script_path , 'wb' ) as f :
62+ f .write (response .read ())
63+
64+ # Remove -e/--exec and script_path from args
65+ new_args = args [:idx ] + args [idx + 2 :]
66+
67+ # Store the script path and remaining args in the context
68+ ctx .params ['exec_file' ] = script_path
69+ ctx .params ['args' ] = new_args
70+
71+ return [] # No more arguments to process
72+
73+ # Default processing for other cases
74+ return super ().parse_args (ctx , args )
75+
76+ @click .group (cls = PassthroughCommand , invoke_without_command = True ,
77+ context_settings = CONTEXT_SETTINGS )
78+ @click .option ('-e' , '--exec' , 'exec_file' ,
79+ type = click .Path (exists = True , dir_okay = False ),
80+ help = 'Run the specified Python file with the CLI environment.' )
81+ @click .argument ('args' , nargs = - 1 , type = click .UNPROCESSED )
2482@click .version_option (message = 'ocebuild-cli %(version)s' , version = __version__ )
2583@click .pass_context
26- def cli (ctx ):
84+ def cli (ctx , exec_file = None , args = None ):
2785 """Main runner for the CLI."""
28- ctx .obj = CLIEnv ()
86+ if exec_file and ctx .invoked_subcommand is None :
87+ try :
88+ # Run python script in a controlled namespace (inherits pyinstaller env)
89+ import runpy , sys
90+
91+ sys .argv = [exec_file ] + list (args ) if args else [exec_file ]
92+ ctx .obj .__dict__ ['argv' ] = list (args ) if args else []
93+
94+ runpy .run_path (exec_file , run_name = "__main__" , init_globals = ctx .obj .__dict__ )
95+ return
96+ # If an error occurs, abort with a message and traceback
97+ except Exception as e :
98+ abort (msg = f"Failed to execute { exec_file } : { e } " , traceback = True )
99+ finally :
100+ tmpdir = ctx .obj .tmpdir
101+ if tmpdir :
102+ # Remove the temporary directory if it was created
103+ import tempfile
104+ from os .path import isdir
105+ from shutil import rmtree
106+ if isdir (tmpdir ) and tmpdir .startswith (tempfile .gettempdir ()):
107+ try :
108+ rmtree (tmpdir )
109+ except OSError as e :
110+ abort (msg = f"Failed to remove temporary directory { tmpdir } : { e } " )
29111
30112def cli_exit (env : Optional [CLIEnv ]= None , status : int = 0 ):
31113 """Cleanup the CLI environment on exit."""
@@ -39,7 +121,7 @@ def cli_exit(env: Optional[CLIEnv]=None, status: int=0):
39121
40122@cli .result_callback (replace = True )
41123@click .make_pass_decorator (CLIEnv )
42- def cli_exit_hook (env , res , status : int = 0 ):
124+ def cli_exit_hook (env , res , status : int = 0 , ** _ ):
43125 """Exit hook for CLI commands."""
44126 cli_exit (env , status )
45127
@@ -52,7 +134,7 @@ def _main():
52134 cli () #pylint: disable=no-value-for-parameter
53135 # Cleanup the CLI environment on exit.
54136 except SystemExit as e :
55- cli_exit (status = e .code or 0 )
137+ cli_exit (status = int ( e .code ) if e . code is not None else 0 )
56138 # Catch any unhandled exceptions.
57139 except Exception : #pylint: disable=broad-exception-caught
58140 issues_url = _format_url ("https://github.com/Qonfused/OCE-Build/issues" )
0 commit comments