11
11
# See the License for the specific language governing permissions and
12
12
# limitations under the License.
13
13
14
- from datetime import datetime
15
14
from pathlib import Path
16
15
from typing import Optional , List
17
16
18
- import click
17
+ from click import Command , Context , Parameter , ParamType , Option as ClickOption
19
18
20
19
from lean .constants import DEFAULT_LEAN_CONFIG_FILE_NAME
21
20
from lean .container import container
22
21
from lean .models .errors import MoreInfoError
23
22
from lean .models .logger import Option
24
23
25
-
26
- class LeanCommand (click .Command ):
24
+ class LeanCommand (Command ):
27
25
"""A click.Command wrapper with some Lean CLI customization."""
28
26
29
27
def __init__ (self ,
@@ -54,17 +52,21 @@ def __init__(self,
54
52
self .context_settings ["ignore_unknown_options" ] = allow_unknown_options
55
53
self .context_settings ["allow_extra_args" ] = allow_unknown_options
56
54
57
- def invoke (self , ctx : click . Context ):
55
+ def invoke (self , ctx : Context ):
58
56
if self ._requires_lean_config :
59
- lean_config_manager = container .lean_config_manager ()
57
+
58
+ from time import time
59
+ start = time ()
60
+
61
+ lean_config_manager = container .lean_config_manager
60
62
try :
61
63
# This method will raise an error if the directory cannot be found
62
64
lean_config_manager .get_cli_root_directory ()
63
65
except Exception :
64
66
# Use one of the cached Lean config locations to avoid having to abort the command
65
67
lean_config_paths = lean_config_manager .get_known_lean_config_paths ()
66
68
if len (lean_config_paths ) > 0 :
67
- lean_config_path = container .logger () .prompt_list ("Select the Lean configuration file to use" , [
69
+ lean_config_path = container .logger .prompt_list ("Select the Lean configuration file to use" , [
68
70
Option (id = p , label = str (p )) for p in lean_config_paths
69
71
])
70
72
lean_config_manager .set_default_lean_config_path (lean_config_path )
@@ -75,37 +77,36 @@ def invoke(self, ctx: click.Context):
75
77
"https://www.lean.io/docs/v2/lean-cli/key-concepts/troubleshooting#02-Common-Errors"
76
78
)
77
79
78
- import sys
79
- if self ._requires_docker and "pytest" not in sys .modules :
80
- import os
81
- is_system_linux = container .platform_manager ().is_system_linux ()
82
-
83
- # The CLI uses temporary directories in /tmp because sometimes it may leave behind files owned by root
84
- # These files cannot be deleted by the CLI itself, so we rely on the OS to empty /tmp on reboot
85
- # The Snap version of Docker does not provide access to files outside $HOME, so we can't support it
86
- if is_system_linux :
87
- import shutil
88
- docker_path = shutil .which ("docker" )
80
+ if self ._requires_docker :
81
+ from sys import modules , executable , argv
82
+ if "pytest" not in modules and container .platform_manager .is_system_linux ():
83
+ from shutil import which
84
+ from os import getuid , execlp
85
+ # The CLI uses temporary directories in /tmp because sometimes it may leave behind files owned by root
86
+ # These files cannot be deleted by the CLI itself, so we rely on the OS to empty /tmp on reboot
87
+ # The Snap version of Docker does not provide access to files outside $HOME, so we can't support it
88
+
89
+ docker_path = which ("docker" )
89
90
if docker_path is not None and docker_path .startswith ("/snap" ):
90
91
raise MoreInfoError (
91
92
"The Lean CLI does not work with the Snap version of Docker, please re-install Docker via the official installation instructions" ,
92
93
"https://docs.docker.com/engine/install/" )
93
94
94
- # A usual Docker installation on Linux requires the user to use sudo to run Docker
95
- # If we detect that this is the case and the CLI was started without sudo we elevate automatically
96
- if is_system_linux and os . getuid () != 0 and container .docker_manager () .is_missing_permission ():
97
- container .logger () .info (
98
- "This command requires access to Docker, you may be asked to enter your password" )
95
+ # A usual Docker installation on Linux requires the user to use sudo to run Docker
96
+ # If we detect that this is the case and the CLI was started without sudo we elevate automatically
97
+ if getuid () != 0 and container .docker_manager .is_missing_permission ():
98
+ container .logger .info (
99
+ "This command requires access to Docker, you may be asked to enter your password" )
99
100
100
- args = ["sudo" , "--preserve-env=HOME" , sys . executable , * sys . argv ]
101
- os . execlp (args [0 ], * args )
101
+ args = ["sudo" , "--preserve-env=HOME" , executable , * argv ]
102
+ execlp (args [0 ], * args )
102
103
103
104
if self ._allow_unknown_options :
104
- import itertools
105
+ from itertools import chain
105
106
# Unknown options are passed to ctx.args and need to be parsed manually
106
107
# We parse them to ctx.params so they're available like normal options
107
108
# Because of this all commands with allow_unknown_options=True must have a **kwargs argument
108
- arguments = list (itertools . chain (* [arg .split ("=" ) for arg in ctx .args ]))
109
+ arguments = list (chain (* [arg .split ("=" ) for arg in ctx .args ]))
109
110
110
111
skip_next = False
111
112
for index in range (len (arguments ) - 1 ):
@@ -119,7 +120,7 @@ def invoke(self, ctx: click.Context):
119
120
ctx .params [option ] = value
120
121
skip_next = True
121
122
122
- update_manager = container .update_manager ()
123
+ update_manager = container .update_manager
123
124
update_manager .show_announcements ()
124
125
125
126
result = super ().invoke (ctx )
@@ -128,20 +129,20 @@ def invoke(self, ctx: click.Context):
128
129
129
130
return result
130
131
131
- def get_params (self , ctx : click . Context ):
132
+ def get_params (self , ctx : Context ):
132
133
params = super ().get_params (ctx )
133
134
134
135
# Add --lean-config option if the command requires a Lean config
135
136
if self ._requires_lean_config :
136
- params .insert (len (params ) - 1 , click . Option (["--lean-config" ],
137
+ params .insert (len (params ) - 1 , ClickOption (["--lean-config" ],
137
138
type = PathParameter (exists = True , file_okay = True , dir_okay = False ),
138
139
help = f"The Lean configuration file that should be used (defaults to the nearest { DEFAULT_LEAN_CONFIG_FILE_NAME } )" ,
139
140
expose_value = False ,
140
141
is_eager = True ,
141
142
callback = self ._parse_config_option ))
142
143
143
144
# Add --verbose option
144
- params .insert (len (params ) - 1 , click . Option (["--verbose" ],
145
+ params .insert (len (params ) - 1 , ClickOption (["--verbose" ],
145
146
help = "Enable debug logging" ,
146
147
is_flag = True ,
147
148
default = False ,
@@ -151,20 +152,20 @@ def get_params(self, ctx: click.Context):
151
152
152
153
return params
153
154
154
- def _parse_config_option (self , ctx : click . Context , param : click . Parameter , value : Optional [Path ]) -> None :
155
+ def _parse_config_option (self , ctx : Context , param : Parameter , value : Optional [Path ]) -> None :
155
156
"""Parses the --config option."""
156
157
if value is not None :
157
- lean_config_manager = container .lean_config_manager ()
158
+ lean_config_manager = container .lean_config_manager
158
159
lean_config_manager .set_default_lean_config_path (value )
159
160
160
- def _parse_verbose_option (self , ctx : click . Context , param : click . Parameter , value : Optional [bool ]) -> None :
161
+ def _parse_verbose_option (self , ctx : Context , param : Parameter , value : Optional [bool ]) -> None :
161
162
"""Parses the --verbose option."""
162
163
if value :
163
- logger = container .logger ()
164
+ logger = container .logger
164
165
logger .debug_logging_enabled = True
165
166
166
167
167
- class PathParameter (click . ParamType ):
168
+ class PathParameter (ParamType ):
168
169
"""A limited version of click.Path which uses pathlib.Path."""
169
170
170
171
def __init__ (self , exists : bool = False , file_okay : bool = True , dir_okay : bool = True ):
@@ -188,10 +189,10 @@ def __init__(self, exists: bool = False, file_okay: bool = True, dir_okay: bool
188
189
self .name = "path"
189
190
self ._path_type = "Path"
190
191
191
- def convert (self , value : str , param : click . Parameter , ctx : click . Context ) -> Path :
192
+ def convert (self , value : str , param : Parameter , ctx : Context ) -> Path :
192
193
path = Path (value ).expanduser ().resolve ()
193
194
194
- if not container .path_manager () .is_path_valid (path ):
195
+ if not container .path_manager .is_path_valid (path ):
195
196
self .fail (f"{ self ._path_type } '{ value } ' is not a valid path." , param , ctx )
196
197
197
198
if self ._exists and not path .exists ():
@@ -206,15 +207,16 @@ def convert(self, value: str, param: click.Parameter, ctx: click.Context) -> Pat
206
207
return path
207
208
208
209
209
- class DateParameter (click . ParamType ):
210
+ class DateParameter (ParamType ):
210
211
"""A click parameter which returns datetime.datetime objects and requires yyyyMMdd input."""
211
212
212
213
name = "date"
213
214
214
- def get_metavar (self , param : click . Parameter ) -> str :
215
+ def get_metavar (self , param : Parameter ) -> str :
215
216
return "[yyyyMMdd]"
216
217
217
- def convert (self , value : str , param : click .Parameter , ctx : click .Context ) -> datetime :
218
+ def convert (self , value : str , param : Parameter , ctx : Context ):
219
+ from datetime import datetime
218
220
for date_format in ["%Y%m%d" , "%Y-%m-%d" ]:
219
221
try :
220
222
return datetime .strptime (value , date_format )
@@ -229,7 +231,9 @@ def ensure_options(options: List[str]) -> None:
229
231
230
232
:param options: the Python names of the options that must have values
231
233
"""
232
- ctx = click .get_current_context ()
234
+ from click import get_current_context
235
+
236
+ ctx = get_current_context ()
233
237
234
238
missing_options = []
235
239
for key , value in ctx .params .items ():
@@ -251,7 +255,9 @@ def ensure_options(options: List[str]) -> None:
251
255
option = next (param for param in ctx .command .params if param .name == name )
252
256
help_records .append (option .get_help_record (ctx ))
253
257
254
- help_formatter = click .HelpFormatter (max_width = 120 )
258
+ from click import HelpFormatter
259
+
260
+ help_formatter = HelpFormatter (max_width = 120 )
255
261
help_formatter .write_dl (help_records )
256
262
257
263
raise RuntimeError (f"""
0 commit comments