1from contextlib import contextmanager
2
3from typing import Any
4from typing import List
5from typing import Optional
6
7from clikit.api.args.args_parser import ArgsParser
8from clikit.api.args.format.args_format import ArgsFormat
9from clikit.api.args.format.args_format_builder import ArgsFormatBuilder
10from clikit.api.args.format.command_name import CommandName
11from clikit.api.command.exceptions import NoSuchCommandException
12
13from .config import Config
14
15
16class CommandConfig(Config):
17    """
18    The configuration of a console command.
19    """
20
21    def __init__(self, name=None):  # type: (Optional[str]) -> None
22        super(CommandConfig, self).__init__()
23
24        self._name = name
25        self._aliases = []
26        self._description = ""
27        self._help = None
28        self._enabled = True
29        self._hidden = False
30        self._process_title = None
31        self._default = None
32        self._anonymous = None
33        self._sub_command_configs = []  # type: List[CommandConfig]
34
35        self._parent_config = None  # type: Optional[CommandConfig]
36
37    @property
38    def name(self):  # type: () -> Optional[str]
39        return self._name
40
41    def set_name(self, name):  # type: (Optional[str]) -> CommandConfig
42        self._name = name
43
44        return self
45
46    @property
47    def aliases(self):  # type: () -> List[str]
48        return self._aliases
49
50    def add_alias(self, alias):  # type: (str) -> CommandConfig
51        self._aliases.append(alias)
52
53        return self
54
55    def add_aliases(self, aliases):  # type: (List[str]) -> CommandConfig
56        for alias in aliases:
57            self.add_alias(alias)
58
59        return self
60
61    def set_aliases(self, aliases):  # type: (List[str]) -> CommandConfig
62        self._aliases = []
63
64        return self.add_aliases(aliases)
65
66    @property
67    def description(self):  # type: () -> str
68        return self._description
69
70    def set_description(self, description):  # type: (str) -> CommandConfig
71        self._description = description
72
73        return self
74
75    @property
76    def help(self):  # type: () -> Optional[str]
77        return self._help
78
79    def set_help(self, help):  # type: (Optional[str]) -> CommandConfig
80        self._help = help
81
82        return self
83
84    def is_enabled(self):  # type: () -> bool
85        return self._enabled
86
87    def enable(self):  # type: () -> CommandConfig
88        self._enabled = True
89
90        return self
91
92    def disable(self):  # type: () -> CommandConfig
93        self._enabled = False
94
95        return self
96
97    def is_hidden(self):  # type: () -> bool
98        return self._hidden
99
100    def hide(self, hidden=True):  # type: (bool) -> CommandConfig
101        self._hidden = hidden
102
103        return self
104
105    @property
106    def process_title(self):  # type: () -> Optional[str]
107        return self._process_title
108
109    def set_process_title(
110        self, process_title
111    ):  # type: (Optional[str]) -> CommandConfig
112        self._process_title = process_title
113
114        return self
115
116    def default(self, default=True):  # type: (bool) -> CommandConfig
117        """
118        Marks the command as the default command.
119        """
120        self._default = default
121        self._anonymous = False
122
123        return self
124
125    def anonymous(self):  # type: () -> CommandConfig
126        self._default = True
127        self._anonymous = True
128
129        return self
130
131    def is_default(self):  # type: () -> bool
132        return self._default
133
134    def is_anonymous(self):  # type: () -> bool
135        return self._anonymous
136
137    @property
138    def parent_config(self):  # type: () -> Optional[CommandConfig]
139        return self._parent_config
140
141    def set_parent_config(
142        self, parent_config
143    ):  # type: (Optional[CommandConfig]) -> CommandConfig
144        self._parent_config = parent_config
145
146        return self
147
148    def is_sub_command_config(self):  # type: () -> bool
149        return self._parent_config is not None
150
151    def build_args_format(
152        self, base_format=None
153    ):  # type: (Optional[ArgsFormat]) -> ArgsFormat
154        builder = ArgsFormatBuilder(base_format)
155
156        if not self._anonymous:
157            builder.add_command_name(CommandName(self.name, self.aliases))
158
159        builder.add_options(*self.options.values())
160        builder.add_arguments(*self.arguments.values())
161
162        return builder.format
163
164    @contextmanager
165    def sub_command(self, name):  # type: (str) -> CommandConfig
166        sub_command_config = CommandConfig(name)
167        self.add_sub_command_config(sub_command_config)
168
169        yield sub_command_config
170
171    def create_sub_command(self, name):  # type: (str) -> CommandConfig
172        sub_command_config = CommandConfig(name)
173        self.add_sub_command_config(sub_command_config)
174
175        return sub_command_config
176
177    @contextmanager
178    def edit_sub_command(self, name):  # type: (str) -> CommandConfig
179        sub_command_config = self.get_sub_command_config(name)
180
181        yield sub_command_config
182
183    def add_sub_command_config(
184        self, sub_command_config
185    ):  # type: (CommandConfig) -> CommandConfig
186        self._sub_command_configs.append(sub_command_config)
187
188        return self
189
190    def add_sub_command_configs(
191        self, sub_command_configs
192    ):  # type: (List[CommandConfig]) -> CommandConfig
193        for sub_command_config in sub_command_configs:
194            self.add_sub_command_config(sub_command_config)
195
196        return self
197
198    def get_sub_command_config(self, name):  # type: (str) -> CommandConfig
199        for sub_command_config in self._sub_command_configs:
200            if sub_command_config.name == name:
201                return sub_command_config
202
203        raise NoSuchCommandException(name)
204
205    @property
206    def sub_command_configs(self):  # type: () -> List[CommandConfig]
207        return self._sub_command_configs
208
209    def has_sub_command_config(self, name):  # type: (str) -> bool
210        for sub_command_config in self._sub_command_configs:
211            if sub_command_config.name == name:
212                return True
213
214        return False
215
216    def has_sub_command_configs(self):  # type: () -> bool
217        return len(self._sub_command_configs) > 0
218
219    @property
220    def default_helper_set(self):  # type: () -> HelperSet
221        if self._parent_config:
222            return self._parent_config.default_helper_set
223
224        return super(CommandConfig, self).default_helper_set
225
226    @property
227    def default_args_parser(self):  # type: () -> ArgsParser
228        if self._parent_config:
229            return self._parent_config.default_args_parser
230
231        return super(CommandConfig, self).default_args_parser
232
233    @property
234    def default_lenient_args_parsing(self):  # type: () -> bool
235        if self._parent_config:
236            return self._parent_config.default_lenient_args_parsing
237
238        return super(CommandConfig, self).default_lenient_args_parsing
239
240    @property
241    def default_handler(self):  # type: () -> Any
242        if self._parent_config:
243            return self._parent_config.default_handler
244
245        return super(CommandConfig, self).default_handler
246
247    @property
248    def default_handler_method(self):  # type: () -> str
249        if self._parent_config:
250            return self._parent_config.default_handler_method
251
252        return super(CommandConfig, self).default_handler_method
253