2222class Environment (object ):
2323 """Provides access to the current CLI environment."""
2424 def __init__ (self ):
25- # {'module_name': {'action': plugin_loader}}
26- self .plugins = {}
25+ # {'path:to:command': ModuleLoader()}
26+ # {'vs:list': ModuleLoader()}
27+ self .commands = {}
2728 self .aliases = {
2829 'meta' : 'metadata' ,
2930 'my' : 'metadata' ,
@@ -41,39 +42,57 @@ def __init__(self):
4142 self ._modules_loaded = False
4243 self .config_file = None
4344
44- def command_list (self , module_name ):
45- """Command listing."""
45+ def out (self , output , newline = True ):
46+ """Outputs a string to the console (stdout)."""
47+ click .echo (output , nl = newline )
4648
47- self ._load_modules ()
48- # Filter commands registered as None. These are the bases.
49- return sorted ([m for m in self .plugins [module_name ].keys ()
50- if m is not None ])
49+ def err (self , output , newline = True ):
50+ """Outputs an error string to the console (stderr)."""
51+ click .echo (output , nl = newline , err = True )
5152
52- def module_list (self ):
53- """Returns the list of modules in SoftLayer.CLI.modules."""
54- self ._load_modules ()
55- return sorted (list (self .plugins .keys ()))
53+ def fmt (self , output ):
54+ """Format output based on current the environment format."""
55+ return formatting .format_output (output , fmt = self .format )
5656
57- def get_command (self , module_name , command_name ):
58- """Based on the loaded modules, return a command."""
57+ def input (self , prompt ):
58+ """Provide a command prompt."""
59+ return utils .console_input (prompt )
60+
61+ def getpass (self , prompt ):
62+ """Provide a password prompt."""
63+ return getpass .getpass (prompt )
64+
65+ # Command loading methods
66+ def list_commands (self , * path ):
67+ """Command listing."""
5968 self ._load_modules ()
60- actions = self .plugins . get ( module_name ) or {}
69+ path_str = self .resolve_alias ( ':' . join ( path ))
6170
62- if command_name in actions :
63- return actions [command_name ].load ()
71+ commands = []
72+ for command in self .commands .keys ():
73+ # Filter based on prefix and the segment length
74+ if all ([command .startswith (path_str ),
75+ len (path ) == command .count (":" )]):
76+ offset = len (path_str )+ 1 if path_str else 0
77+ commands .append (command [offset :])
6478
65- raise exceptions . InvalidCommand ( module_name , command_name )
79+ return sorted ( commands )
6680
67- def get_module (self , module_name ):
68- """Returns the module ."""
81+ def get_command (self , * path ):
82+ """Return command at the given path or raise error ."""
6983 self ._load_modules ()
70- return self .get_command ( module_name , None )
84+ path_str = self .resolve_alias ( ':' . join ( path ) )
7185
72- def get_module_name (self , module_name ):
73- """Returns the actual module name. Uses the alias mapping."""
74- if module_name in self .aliases :
75- return self .aliases [module_name ]
76- return module_name
86+ if path_str in self .commands :
87+ return self .commands [path_str ].load ()
88+
89+ raise exceptions .InvalidCommand (path )
90+
91+ def resolve_alias (self , path_str ):
92+ """Returns the actual command name. Uses the alias mapping."""
93+ if path_str in self .aliases :
94+ return self .aliases [path_str ]
95+ return path_str
7796
7897 def _load_modules (self ):
7998 """Loads all modules."""
@@ -88,45 +107,17 @@ def _load_modules(self):
88107 def _load_modules_from_python (self ):
89108 """Load modules from the native python source."""
90109 for name , modpath in routes .ALL_ROUTES :
91- module , subcommand = _parse_name (name )
92- if module not in self .plugins :
93- self .plugins [module ] = {}
94-
95110 if ':' in modpath :
96111 path , attr = modpath .split (':' , 1 )
97112 else :
98113 path , attr = modpath , None
99- self .plugins [ module ][ subcommand ] = ModuleLoader (path , attr = attr )
114+ self .commands [ name ] = ModuleLoader (path , attr = attr )
100115
101116 def _load_modules_from_entry_points (self ):
102117 """Load modules from the entry_points (slower)."""
103118 for obj in pkg_resources .iter_entry_points (group = 'softlayer.cli' ,
104119 name = None ):
105-
106- module , subcommand = _parse_name (obj .name )
107- if module not in self .plugins :
108- self .plugins [module ] = {}
109- self .plugins [module ][subcommand ] = obj
110-
111- def out (self , output , newline = True ):
112- """Outputs a string to the console (stdout)."""
113- click .echo (output , nl = newline )
114-
115- def err (self , output , newline = True ):
116- """Outputs an error string to the console (stderr)."""
117- click .echo (output , nl = newline , err = True )
118-
119- def fmt (self , output ):
120- """Format output based on current the environment format."""
121- return formatting .format_output (output , fmt = self .format )
122-
123- def input (self , prompt ):
124- """Provide a command prompt."""
125- return utils .console_input (prompt )
126-
127- def getpass (self , prompt ):
128- """Provide a password prompt."""
129- return getpass .getpass (prompt )
120+ self .commands [obj .name ] = obj
130121
131122
132123class ModuleLoader (object ):
@@ -144,14 +135,4 @@ def load(self):
144135 return module
145136
146137
147- def _parse_name (name ):
148- """Parse command name and path from the given name."""
149- if ':' in name :
150- module , subcommand = name .split (':' , 1 )
151- else :
152- module , subcommand = name , None
153-
154- return module , subcommand
155-
156-
157138pass_env = click .make_pass_decorator (Environment , ensure = True )
0 commit comments