8b97a77413294c159b92b5cbc12b0074a154b88b
Marco Ricci Update copyright notices to...

Marco Ricci authored 2 days ago

1) # SPDX-FileCopyrightText: 2025 Marco Ricci <software@the13thletter.info>
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2) #
Marco Ricci Update copyright notices to...

Marco Ricci authored 2 days ago

3) # SPDX-License-Identifier: Zlib
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

4) 
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

5) # ruff: noqa: TRY400
6) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

7) """Command-line interface for derivepassphrase."""
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

8) 
9) from __future__ import annotations
10) 
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

11) import base64
12) import collections
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

13) import copy
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

14) import enum
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

15) import functools
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

16) import importlib
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

17) import inspect
18) import json
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

19) import logging
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

20) import os
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

21) import shlex
Marco Ricci Introduce a central user co...

Marco Ricci authored 3 weeks ago

22) import sys
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

23) import unicodedata
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

24) import warnings
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

25) from typing import (
26)     TYPE_CHECKING,
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

27)     Callable,
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

28)     Literal,
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

29)     NoReturn,
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

30)     TextIO,
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

31)     TypeVar,
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

32)     cast,
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

33) )
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

34) 
35) import click
Marco Ricci Consolidate shell completio...

Marco Ricci authored 2 days ago

36) import click.shell_completion
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

37) from typing_extensions import (
38)     Any,
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

39)     ParamSpec,
40)     Self,
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

41)     assert_never,
Marco Ricci Consolidate shell completio...

Marco Ricci authored 2 days ago

42)     override,
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

43) )
44) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

45) import derivepassphrase as dpp
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

46) from derivepassphrase import _cli_msg as _msg
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

47) from derivepassphrase import _types, exporter, ssh_agent, vault
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

48) 
Marco Ricci Introduce a central user co...

Marco Ricci authored 3 weeks ago

49) if sys.version_info >= (3, 11):
50)     import tomllib
51) else:
52)     import tomli as tomllib
53) 
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

54) if TYPE_CHECKING:
55)     import pathlib
Marco Ricci Support one-off SSH agent c...

Marco Ricci authored 1 month ago

56)     import socket
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

57)     import types
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

58)     from collections.abc import (
59)         Iterator,
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

60)         MutableSequence,
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

61)         Sequence,
62)     )
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

63) 
64) __author__ = dpp.__author__
65) __version__ = dpp.__version__
66) 
67) __all__ = ('derivepassphrase',)
68) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

69) PROG_NAME = _msg.PROG_NAME
Marco Ricci Make suitable SSH key listi...

Marco Ricci authored 1 month ago

70) KEY_DISPLAY_LENGTH = 50
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

71) 
72) # Error messages
73) _INVALID_VAULT_CONFIG = 'Invalid vault config'
74) _AGENT_COMMUNICATION_ERROR = 'Error communicating with the SSH agent'
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

75) _NO_SUITABLE_KEYS = 'No suitable SSH keys were found'
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

76) _EMPTY_SELECTION = 'Empty selection'
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

77) _NOT_AN_INTEGER = 'not an integer'
78) _NOT_A_NONNEGATIVE_INTEGER = 'not a non-negative integer'
79) _NOT_A_POSITIVE_INTEGER = 'not a positive integer'
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

80) 
81) 
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

82) # Logging
83) # =======
84) 
85) 
86) class ClickEchoStderrHandler(logging.Handler):
87)     """A [`logging.Handler`][] for `click` applications.
88) 
89)     Outputs log messages to [`sys.stderr`][] via [`click.echo`][].
90) 
91)     """
92) 
93)     def emit(self, record: logging.LogRecord) -> None:
94)         """Emit a log record.
95) 
96)         Format the log record, then emit it via [`click.echo`][] to
97)         [`sys.stderr`][].
98) 
99)         """
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

100)         click.echo(
101)             self.format(record),
102)             err=True,
103)             color=getattr(record, 'color', None),
104)         )
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

105) 
106) 
107) class CLIofPackageFormatter(logging.Formatter):
108)     """A [`logging.LogRecord`][] formatter for the CLI of a Python package.
109) 
110)     Assuming a package `PKG` and loggers within the same hierarchy
111)     `PKG`, format all log records from that hierarchy for proper user
112)     feedback on the console.  Intended for use with [`click`][CLICK] and
113)     when `PKG` provides a command-line tool `PKG` and when logs from
114)     that package should show up as output of the command-line tool.
115) 
116)     Essentially, this prepends certain short strings to the log message
117)     lines to make them readable as standard error output.
118) 
119)     Because this log output is intended to be displayed on standard
120)     error as high-level diagnostic output, you are strongly discouraged
121)     from changing the output format to include more tokens besides the
122)     log message.  Use a dedicated log file handler instead, without this
123)     formatter.
124) 
125)     [CLICK]: https://pypi.org/projects/click/
126) 
127)     """
128) 
129)     def __init__(
130)         self,
131)         *,
132)         prog_name: str = PROG_NAME,
133)         package_name: str | None = None,
134)     ) -> None:
135)         self.prog_name = prog_name
136)         self.package_name = (
137)             package_name
138)             if package_name is not None
139)             else prog_name.lower().replace(' ', '_').replace('-', '_')
140)         )
141) 
142)     def format(self, record: logging.LogRecord) -> str:
143)         """Format a log record suitably for standard error console output.
144) 
145)         Prepend the formatted string `"PROG_NAME: LABEL"` to each line
146)         of the message, where `PROG_NAME` is the program name, and
147)         `LABEL` depends on the record's level and on the logger name as
148)         follows:
149) 
150)           * For records at level [`logging.DEBUG`][], `LABEL` is
151)             `"Debug: "`.
152)           * For records at level [`logging.INFO`][], `LABEL` is the
153)             empty string.
154)           * For records at level [`logging.WARNING`][], `LABEL` is
155)             `"Deprecation warning: "` if the logger is named
156)             `PKG.deprecation` (where `PKG` is the package name), else
157)             `"Warning: "`.
158)           * For records at level [`logging.ERROR`][] and
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

159)             [`logging.CRITICAL`][] `"Error: "`, `LABEL` is the empty
160)             string.
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

161) 
162)         The level indication strings at level `WARNING` or above are
163)         highlighted.  Use [`click.echo`][] to output them and remove
164)         color output if necessary.
165) 
166)         Args:
167)             record: A log record.
168) 
169)         Returns:
170)             A formatted log record.
171) 
172)         Raises:
173)             AssertionError:
174)                 The log level is not supported.
175) 
176)         """
177)         preliminary_result = record.getMessage()
178)         prefix = f'{self.prog_name}: '
179)         if record.levelname == 'DEBUG':  # pragma: no cover
180)             level_indicator = 'Debug: '
181)         elif record.levelname == 'INFO':
182)             level_indicator = ''
183)         elif record.levelname == 'WARNING':
184)             level_indicator = (
185)                 f'{click.style("Deprecation warning", bold=True)}: '
186)                 if record.name.endswith('.deprecation')
187)                 else f'{click.style("Warning", bold=True)}: '
188)             )
189)         elif record.levelname in {'ERROR', 'CRITICAL'}:
190)             level_indicator = ''
191)         else:  # pragma: no cover
192)             msg = f'Unsupported logging level: {record.levelname}'
193)             raise AssertionError(msg)
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

194)         parts = [
195)             ''.join(
196)                 prefix + level_indicator + line
197)                 for line in preliminary_result.splitlines(True)  # noqa: FBT003
198)             )
199)         ]
200)         if record.exc_info:
201)             parts.append(self.formatException(record.exc_info) + '\n')
202)         return ''.join(parts)
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

203) 
204) 
205) class StandardCLILogging:
206)     """Set up CLI logging handlers upon instantiation."""
207) 
208)     prog_name = PROG_NAME
209)     package_name = PROG_NAME.lower().replace(' ', '_').replace('-', '_')
210)     cli_formatter = CLIofPackageFormatter(
211)         prog_name=prog_name, package_name=package_name
212)     )
213)     cli_handler = ClickEchoStderrHandler()
214)     cli_handler.addFilter(logging.Filter(name=package_name))
215)     cli_handler.setFormatter(cli_formatter)
216)     cli_handler.setLevel(logging.WARNING)
217)     warnings_handler = ClickEchoStderrHandler()
218)     warnings_handler.addFilter(logging.Filter(name='py.warnings'))
219)     warnings_handler.setFormatter(cli_formatter)
220)     warnings_handler.setLevel(logging.WARNING)
221) 
222)     @classmethod
223)     def ensure_standard_logging(cls) -> StandardLoggingContextManager:
224)         """Return a context manager to ensure standard logging is set up."""
225)         return StandardLoggingContextManager(
226)             handler=cls.cli_handler,
227)             root_logger=cls.package_name,
228)         )
229) 
230)     @classmethod
231)     def ensure_standard_warnings_logging(
232)         cls,
233)     ) -> StandardWarningsLoggingContextManager:
234)         """Return a context manager to ensure warnings logging is set up."""
235)         return StandardWarningsLoggingContextManager(
236)             handler=cls.warnings_handler,
237)         )
238) 
239) 
240) class StandardLoggingContextManager:
241)     """A reentrant context manager setting up standard CLI logging.
242) 
243)     Ensures that the given handler (defaulting to the CLI logging
244)     handler) is added to the named logger (defaulting to the root
245)     logger), and if it had to be added, then that it will be removed
246)     upon exiting the context.
247) 
248)     Reentrant, but not thread safe, because it temporarily modifies
249)     global state.
250) 
251)     """
252) 
253)     def __init__(
254)         self,
255)         handler: logging.Handler,
256)         root_logger: str | None = None,
257)     ) -> None:
258)         self.handler = handler
259)         self.root_logger_name = root_logger
260)         self.base_logger = logging.getLogger(self.root_logger_name)
261)         self.action_required: MutableSequence[bool] = collections.deque()
262) 
263)     def __enter__(self) -> Self:
264)         self.action_required.append(
265)             self.handler not in self.base_logger.handlers
266)         )
267)         if self.action_required[-1]:
268)             self.base_logger.addHandler(self.handler)
269)         return self
270) 
271)     def __exit__(
272)         self,
273)         exc_type: type[BaseException] | None,
274)         exc_value: BaseException | None,
275)         exc_tb: types.TracebackType | None,
276)     ) -> Literal[False]:
277)         if self.action_required[-1]:
278)             self.base_logger.removeHandler(self.handler)
279)         self.action_required.pop()
280)         return False
281) 
282) 
283) class StandardWarningsLoggingContextManager(StandardLoggingContextManager):
284)     """A reentrant context manager setting up standard warnings logging.
285) 
286)     Ensures that warnings are being diverted to the logging system, and
287)     that the given handler (defaulting to the CLI logging handler) is
288)     added to the warnings logger. If the handler had to be added, then
289)     it will be removed upon exiting the context.
290) 
291)     Reentrant, but not thread safe, because it temporarily modifies
292)     global state.
293) 
294)     """
295) 
296)     def __init__(
297)         self,
298)         handler: logging.Handler,
299)     ) -> None:
300)         super().__init__(handler=handler, root_logger='py.warnings')
301)         self.stack: MutableSequence[
302)             tuple[
303)                 Callable[
304)                     [
305)                         type[BaseException] | None,
306)                         BaseException | None,
307)                         types.TracebackType | None,
308)                     ],
309)                     None,
310)                 ],
311)                 Callable[
312)                     [
313)                         str | Warning,
314)                         type[Warning],
315)                         str,
316)                         int,
317)                         TextIO | None,
318)                         str | None,
319)                     ],
320)                     None,
321)                 ],
322)             ]
323)         ] = collections.deque()
324) 
325)     def __enter__(self) -> Self:
326)         def showwarning(  # noqa: PLR0913,PLR0917
327)             message: str | Warning,
328)             category: type[Warning],
329)             filename: str,
330)             lineno: int,
331)             file: TextIO | None = None,
332)             line: str | None = None,
333)         ) -> None:
334)             if file is not None:  # pragma: no cover
335)                 self.stack[0][1](
336)                     message, category, filename, lineno, file, line
337)                 )
338)             else:
339)                 logging.getLogger('py.warnings').warning(
340)                     str(
341)                         warnings.formatwarning(
342)                             message, category, filename, lineno, line
343)                         )
344)                     )
345)                 )
346) 
347)         ctx = warnings.catch_warnings()
348)         exit_func = ctx.__exit__
349)         ctx.__enter__()
350)         self.stack.append((exit_func, warnings.showwarning))
351)         warnings.showwarning = showwarning
352)         return super().__enter__()
353) 
354)     def __exit__(
355)         self,
356)         exc_type: type[BaseException] | None,
357)         exc_value: BaseException | None,
358)         exc_tb: types.TracebackType | None,
359)     ) -> Literal[False]:
360)         ret = super().__exit__(exc_type, exc_value, exc_tb)
361)         val = self.stack.pop()[0](exc_type, exc_value, exc_tb)
362)         assert not val
363)         return ret
364) 
365) 
366) P = ParamSpec('P')
367) R = TypeVar('R')
368) 
369) 
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

370) def adjust_logging_level(
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

371)     ctx: click.Context,
372)     /,
373)     param: click.Parameter | None = None,
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

374)     value: int | None = None,
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

375) ) -> None:
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

376)     """Change the logs that are emitted to standard error.
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

377) 
378)     This modifies the [`StandardCLILogging`][] settings such that log
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

379)     records at the respective level are emitted, based on the `param`
380)     and the `value`.
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

381) 
382)     """
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

383)     # Note: If multiple options use this callback, then we will be
384)     # called multiple times.  Ensure the runs are idempotent.
385)     if param is None or value is None or ctx.resilient_parsing:
386)         return
387)     StandardCLILogging.cli_handler.setLevel(value)
388)     logging.getLogger(StandardCLILogging.package_name).setLevel(value)
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

389) 
390) 
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

391) # Option parsing and grouping
392) # ===========================
393) 
394) 
395) class OptionGroupOption(click.Option):
396)     """A [`click.Option`][] with an associated group name and group epilog.
397) 
398)     Used by [`CommandWithHelpGroups`][] to print help sections.  Each
399)     subclass contains its own group name and epilog.
400) 
401)     Attributes:
402)         option_group_name:
403)             The name of the option group.  Used as a heading on the help
404)             text for options in this section.
405)         epilog:
406)             An epilog to print after listing the options in this
407)             section.
408) 
409)     """
410) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

411)     option_group_name: object = ''
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

412)     """"""
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

413)     epilog: object = ''
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

414)     """"""
415) 
416)     def __init__(self, *args: Any, **kwargs: Any) -> None:  # noqa: ANN401
417)         if self.__class__ == __class__:  # type: ignore[name-defined]
418)             raise NotImplementedError
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

419)         # Though click 8.1 mostly defers help text processing until the
420)         # `BaseCommand.format_*` methods are called, the Option
421)         # constructor still preprocesses the help text, and asserts that
422)         # the help text is a string.  Work around this by removing the
423)         # help text from the constructor arguments and re-adding it,
424)         # unprocessed, after constructor finishes.
425)         unset = object()
426)         help = kwargs.pop('help', unset)  # noqa: A001
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

427)         super().__init__(*args, **kwargs)
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

428)         if help is not unset:  # pragma: no branch
429)             self.help = help
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

430) 
431) 
Marco Ricci Reimplement `--help` and `-...

Marco Ricci authored 1 week ago

432) class StandardOption(OptionGroupOption):
433)     pass
434) 
435) 
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

436) class CommandWithHelpGroups(click.Command):
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

437)     """A [`click.Command`][] with support for some help text customizations.
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

438) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

439)     Supports help/option groups, group epilogs, and help text objects
440)     (objects that stringify to help texts).  The latter is primarily
441)     used to implement translations.
442) 
443)     Inspired by [a comment on `pallets/click#373`][CLICK_ISSUE] for
444)     help/option group support, and further modified to include group
445)     epilogs and help text objects.
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

446) 
447)     [CLICK_ISSUE]: https://github.com/pallets/click/issues/373#issuecomment-515293746
448) 
449)     """
450) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

451)     @staticmethod
452)     def _text(text: object, /) -> str:
453)         if isinstance(text, (list, tuple)):
454)             return '\n\n'.join(str(x) for x in text)
455)         return str(text)
456) 
457)     def collect_usage_pieces(self, ctx: click.Context) -> list[str]:
458)         """Return the pieces for the usage string.
459) 
460)         Based on code from click 8.1.  Subject to the following license
461)         (3-clause BSD license):
462) 
463)             Copyright 2024 Pallets
464) 
465)             Redistribution and use in source and binary forms, with or
466)             without modification, are permitted provided that the
467)             following conditions are met:
468) 
469)              1. Redistributions of source code must retain the above
470)                 copyright notice, this list of conditions and the
471)                 following disclaimer.
472) 
473)              2. Redistributions in binary form must reproduce the above
474)                 copyright notice, this list of conditions and the
475)                 following disclaimer in the documentation and/or other
476)                 materials provided with the distribution.
477) 
478)              3. Neither the name of the copyright holder nor the names
479)                 of its contributors may be used to endorse or promote
480)                 products derived from this software without specific
481)                 prior written permission.
482) 
483)             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
484)             CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
485)             INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
486)             MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
487)             DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
488)             CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
489)             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
490)             NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
491)             LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
492)             HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
493)             CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
494)             OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
495)             SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
496) 
497)         Modifications are marked with respective comments.  They too are
498)         released under the same license above.  The original code did
499)         not contain any "noqa" or "pragma" comments.
500) 
501)         Args:
502)             ctx:
503)                 The click context.
504) 
505)         """
506)         rv = [str(self.options_metavar)] if self.options_metavar else []
507)         for param in self.get_params(ctx):
508)             rv.extend(str(x) for x in param.get_usage_pieces(ctx))
509)         return rv
510) 
Marco Ricci Reimplement `--help` and `-...

Marco Ricci authored 1 week ago

511)     def get_help_option(
512)         self,
513)         ctx: click.Context,
514)     ) -> click.Option | None:
515)         """Return a standard help option object.
516) 
517)         Based on code from click 8.1.  Subject to the following license
518)         (3-clause BSD license):
519) 
520)             Copyright 2024 Pallets
521) 
522)             Redistribution and use in source and binary forms, with or
523)             without modification, are permitted provided that the
524)             following conditions are met:
525) 
526)              1. Redistributions of source code must retain the above
527)                 copyright notice, this list of conditions and the
528)                 following disclaimer.
529) 
530)              2. Redistributions in binary form must reproduce the above
531)                 copyright notice, this list of conditions and the
532)                 following disclaimer in the documentation and/or other
533)                 materials provided with the distribution.
534) 
535)              3. Neither the name of the copyright holder nor the names
536)                 of its contributors may be used to endorse or promote
537)                 products derived from this software without specific
538)                 prior written permission.
539) 
540)             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
541)             CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
542)             INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
543)             MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
544)             DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
545)             CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
546)             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
547)             NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
548)             LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
549)             HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
550)             CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
551)             OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
552)             SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
553) 
554)         Modifications are marked with respective comments.  They too are
555)         released under the same license above.  The original code did
556)         not contain any "noqa" or "pragma" comments.
557) 
558)         Args:
559)             ctx:
560)                 The click context.
561) 
562)         """
563)         help_options = self.get_help_option_names(ctx)
564) 
565)         if not help_options or not self.add_help_option:  # pragma: no cover
566)             return None
567) 
568)         def show_help(
569)             ctx: click.Context,
570)             param: click.Parameter,  # noqa: ARG001
571)             value: str,
572)         ) -> None:
573)             if value and not ctx.resilient_parsing:
574)                 click.echo(ctx.get_help(), color=ctx.color)
575)                 ctx.exit()
576) 
577)         # Modified from click 8.1: We use StandardOption and a non-str
578)         # object as the help string.
579)         return StandardOption(
580)             help_options,
581)             is_flag=True,
582)             is_eager=True,
583)             expose_value=False,
584)             callback=show_help,
585)             help=_msg.TranslatedString(_msg.Label.HELP_OPTION_HELP_TEXT),
586)         )
587) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

588)     def get_short_help_str(
589)         self,
590)         limit: int = 45,
591)     ) -> str:
592)         """Return the short help string for a command.
593) 
594)         If only a long help string is given, shorten it.
595) 
596)         Based on code from click 8.1.  Subject to the following license
597)         (3-clause BSD license):
598) 
599)             Copyright 2024 Pallets
600) 
601)             Redistribution and use in source and binary forms, with or
602)             without modification, are permitted provided that the
603)             following conditions are met:
604) 
605)              1. Redistributions of source code must retain the above
606)                 copyright notice, this list of conditions and the
607)                 following disclaimer.
608) 
609)              2. Redistributions in binary form must reproduce the above
610)                 copyright notice, this list of conditions and the
611)                 following disclaimer in the documentation and/or other
612)                 materials provided with the distribution.
613) 
614)              3. Neither the name of the copyright holder nor the names
615)                 of its contributors may be used to endorse or promote
616)                 products derived from this software without specific
617)                 prior written permission.
618) 
619)             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
620)             CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
621)             INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
622)             MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
623)             DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
624)             CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
625)             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
626)             NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
627)             LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
628)             HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
629)             CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
630)             OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
631)             SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
632) 
633)         Modifications are marked with respective comments.  They too are
634)         released under the same license above.  The original code did
635)         not contain any "noqa" or "pragma" comments.
636) 
637)         Args:
638)             limit:
639)                 The maximum width of the short help string.
640) 
641)         """
642)         # Modification against click 8.1: Call `_text()` on `self.help`
643)         # to allow help texts to be general objects, not just strings.
644)         # Used to implement translatable strings, as objects that
645)         # stringify to the translation.
646)         if self.short_help:  # pragma: no cover
647)             text = inspect.cleandoc(self._text(self.short_help))
648)         elif self.help:
649)             text = click.utils.make_default_short_help(
650)                 self._text(self.help), limit
651)             )
652)         else:  # pragma: no cover
653)             text = ''
654)         if self.deprecated:  # pragma: no cover
655)             # Modification against click 8.1: The translated string is
656)             # looked up in the derivepassphrase message domain, not the
657)             # gettext default domain.
658)             text = str(
659)                 _msg.TranslatedString(_msg.Label.DEPRECATED_COMMAND_LABEL)
660)             ).format(text=text)
661)         return text.strip()
662) 
663)     def format_help_text(
664)         self,
665)         ctx: click.Context,
666)         formatter: click.HelpFormatter,
667)     ) -> None:
668)         """Format the help text prologue, if any.
669) 
670)         Based on code from click 8.1.  Subject to the following license
671)         (3-clause BSD license):
672) 
673)             Copyright 2024 Pallets
674) 
675)             Redistribution and use in source and binary forms, with or
676)             without modification, are permitted provided that the
677)             following conditions are met:
678) 
679)              1. Redistributions of source code must retain the above
680)                 copyright notice, this list of conditions and the
681)                 following disclaimer.
682) 
683)              2. Redistributions in binary form must reproduce the above
684)                 copyright notice, this list of conditions and the
685)                 following disclaimer in the documentation and/or other
686)                 materials provided with the distribution.
687) 
688)              3. Neither the name of the copyright holder nor the names
689)                 of its contributors may be used to endorse or promote
690)                 products derived from this software without specific
691)                 prior written permission.
692) 
693)             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
694)             CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
695)             INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
696)             MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
697)             DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
698)             CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
699)             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
700)             NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
701)             LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
702)             HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
703)             CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
704)             OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
705)             SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
706) 
707)         Modifications are marked with respective comments.  They too are
708)         released under the same license above.  The original code did
709)         not contain any "noqa" or "pragma" comments.
710) 
711)         Args:
712)             ctx:
713)                 The click context.
714)             formatter:
715)                 The formatter for the `--help` listing.
716) 
717)         """
718)         del ctx
719)         # Modification against click 8.1: Call `_text()` on `self.help`
720)         # to allow help texts to be general objects, not just strings.
721)         # Used to implement translatable strings, as objects that
722)         # stringify to the translation.
723)         text = (
724)             inspect.cleandoc(self._text(self.help).partition('\f')[0])
725)             if self.help is not None
726)             else ''
727)         )
728)         if self.deprecated:  # pragma: no cover
729)             # Modification against click 8.1: The translated string is
730)             # looked up in the derivepassphrase message domain, not the
731)             # gettext default domain.
732)             text = str(
733)                 _msg.TranslatedString(_msg.Label.DEPRECATED_COMMAND_LABEL)
734)             ).format(text=text)
735)         if text:  # pragma: no branch
736)             formatter.write_paragraph()
737)             with formatter.indentation():
738)                 formatter.write_text(text)
739) 
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

740)     def format_options(
741)         self,
742)         ctx: click.Context,
743)         formatter: click.HelpFormatter,
744)     ) -> None:
745)         r"""Format options on the help listing, grouped into sections.
746) 
747)         This is a callback for [`click.Command.get_help`][] that
748)         implements the `--help` listing, by calling appropriate methods
749)         of the `formatter`.  We list all options (like the base
750)         implementation), but grouped into sections according to the
751)         concrete [`click.Option`][] subclass being used.  If the option
752)         is an instance of some subclass of [`OptionGroupOption`][], then
753)         the section heading and the epilog are taken from the
754)         [`option_group_name`] [OptionGroupOption.option_group_name] and
755)         [`epilog`] [OptionGroupOption.epilog] attributes; otherwise, the
756)         section heading is "Options" (or "Other options" if there are
757)         other option groups) and the epilog is empty.
758) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

759)         We unconditionally call [`format_commands`][], and rely on it to
760)         act as a no-op if we aren't actually a [`click.MultiCommand`][].
761) 
762)         Based on code from click 8.1.  Subject to the following license
763)         (3-clause BSD license):
764) 
765)             Copyright 2024 Pallets
766) 
767)             Redistribution and use in source and binary forms, with or
768)             without modification, are permitted provided that the
769)             following conditions are met:
770) 
771)              1. Redistributions of source code must retain the above
772)                 copyright notice, this list of conditions and the
773)                 following disclaimer.
774) 
775)              2. Redistributions in binary form must reproduce the above
776)                 copyright notice, this list of conditions and the
777)                 following disclaimer in the documentation and/or other
778)                 materials provided with the distribution.
779) 
780)              3. Neither the name of the copyright holder nor the names
781)                 of its contributors may be used to endorse or promote
782)                 products derived from this software without specific
783)                 prior written permission.
784) 
785)             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
786)             CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
787)             INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
788)             MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
789)             DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
790)             CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
791)             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
792)             NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
793)             LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
794)             HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
795)             CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
796)             OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
797)             SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
798) 
799)         Modifications are released under the same license above.
800) 
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

801)         Args:
802)             ctx:
803)                 The click context.
804)             formatter:
805)                 The formatter for the `--help` listing.
806) 
807)         """
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

808)         default_group_name = ''
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

809)         help_records: dict[str, list[tuple[str, str]]] = {}
810)         epilogs: dict[str, str] = {}
811)         params = self.params[:]
812)         if (  # pragma: no branch
813)             (help_opt := self.get_help_option(ctx)) is not None
814)             and help_opt not in params
815)         ):
816)             params.append(help_opt)
817)         for param in params:
818)             rec = param.get_help_record(ctx)
819)             if rec is not None:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

820)                 rec = (rec[0], self._text(rec[1]))
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

821)                 if isinstance(param, OptionGroupOption):
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

822)                     group_name = self._text(param.option_group_name)
823)                     epilogs.setdefault(group_name, self._text(param.epilog))
Marco Ricci Fix coverage

Marco Ricci authored 1 week ago

824)                 else:  # pragma: no cover
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

825)                     group_name = default_group_name
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

826)                 help_records.setdefault(group_name, []).append(rec)
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

827)         if default_group_name in help_records:  # pragma: no branch
828)             default_group = help_records.pop(default_group_name)
829)             default_group_label = (
830)                 _msg.Label.OTHER_OPTIONS_LABEL
831)                 if len(default_group) > 1
832)                 else _msg.Label.OPTIONS_LABEL
833)             )
834)             default_group_name = self._text(
835)                 _msg.TranslatedString(default_group_label)
836)             )
837)             help_records[default_group_name] = default_group
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

838)         for group_name, records in help_records.items():
839)             with formatter.section(group_name):
840)                 formatter.write_dl(records)
841)             epilog = inspect.cleandoc(epilogs.get(group_name, ''))
842)             if epilog:
843)                 formatter.write_paragraph()
844)                 with formatter.indentation():
845)                     formatter.write_text(epilog)
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

846)         self.format_commands(ctx, formatter)
847) 
848)     def format_commands(
849)         self,
850)         ctx: click.Context,
851)         formatter: click.HelpFormatter,
852)     ) -> None:
853)         """Format the subcommands, if any.
854) 
855)         If called on a command object that isn't derived from
856)         [`click.MultiCommand`][], then do nothing.
857) 
858)         Based on code from click 8.1.  Subject to the following license
859)         (3-clause BSD license):
860) 
861)             Copyright 2024 Pallets
862) 
863)             Redistribution and use in source and binary forms, with or
864)             without modification, are permitted provided that the
865)             following conditions are met:
866) 
867)              1. Redistributions of source code must retain the above
868)                 copyright notice, this list of conditions and the
869)                 following disclaimer.
870) 
871)              2. Redistributions in binary form must reproduce the above
872)                 copyright notice, this list of conditions and the
873)                 following disclaimer in the documentation and/or other
874)                 materials provided with the distribution.
875) 
876)              3. Neither the name of the copyright holder nor the names
877)                 of its contributors may be used to endorse or promote
878)                 products derived from this software without specific
879)                 prior written permission.
880) 
881)             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
882)             CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
883)             INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
884)             MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
885)             DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
886)             CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
887)             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
888)             NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
889)             LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
890)             HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
891)             CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
892)             OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
893)             SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
894) 
895)         Modifications are marked with respective comments.  They too are
896)         released under the same license above.  The original code did
897)         not contain any "noqa" or "pragma" comments.
898) 
899)         Args:
900)             ctx:
901)                 The click context.
902)             formatter:
903)                 The formatter for the `--help` listing.
904) 
905)         """
906)         if not isinstance(self, click.MultiCommand):
907)             return
908)         commands: list[tuple[str, click.Command]] = []
909)         for subcommand in self.list_commands(ctx):
910)             cmd = self.get_command(ctx, subcommand)
911)             if cmd is None or cmd.hidden:  # pragma: no cover
912)                 continue
913)             commands.append((subcommand, cmd))
914)         if commands:  # pragma: no branch
915)             longest_command = max((cmd[0] for cmd in commands), key=len)
916)             limit = formatter.width - 6 - len(longest_command)
917)             rows: list[tuple[str, str]] = []
918)             for subcommand, cmd in commands:
919)                 help_str = self._text(cmd.get_short_help_str(limit) or '')
920)                 rows.append((subcommand, help_str))
921)             if rows:  # pragma: no branch
922)                 commands_label = self._text(
923)                     _msg.TranslatedString(_msg.Label.COMMANDS_LABEL)
924)                 )
925)                 with formatter.section(commands_label):
926)                     formatter.write_dl(rows)
927) 
928)     def format_epilog(
929)         self,
930)         ctx: click.Context,
931)         formatter: click.HelpFormatter,
932)     ) -> None:
933)         """Format the epilog, if any.
934) 
935)         Based on code from click 8.1.  Subject to the following license
936)         (3-clause BSD license):
937) 
938)             Copyright 2024 Pallets
939) 
940)             Redistribution and use in source and binary forms, with or
941)             without modification, are permitted provided that the
942)             following conditions are met:
943) 
944)              1. Redistributions of source code must retain the above
945)                 copyright notice, this list of conditions and the
946)                 following disclaimer.
947) 
948)              2. Redistributions in binary form must reproduce the above
949)                 copyright notice, this list of conditions and the
950)                 following disclaimer in the documentation and/or other
951)                 materials provided with the distribution.
952) 
953)              3. Neither the name of the copyright holder nor the names
954)                 of its contributors may be used to endorse or promote
955)                 products derived from this software without specific
956)                 prior written permission.
957) 
958)             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
959)             CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
960)             INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
961)             MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
962)             DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
963)             CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
964)             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
965)             NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
966)             LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
967)             HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
968)             CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
969)             OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
970)             SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
971) 
972)         Modifications are marked with respective comments.  They too are
973)         released under the same license above.
974) 
975)         Args:
976)             ctx:
977)                 The click context.
978)             formatter:
979)                 The formatter for the `--help` listing.
980) 
981)         """
982)         del ctx
983)         if self.epilog:  # pragma: no branch
984)             # Modification against click 8.1: Call `str()` on
985)             # `self.epilog` to allow help texts to be general objects,
986)             # not just strings.  Used to implement translatable strings,
987)             # as objects that stringify to the translation.
988)             epilog = inspect.cleandoc(self._text(self.epilog))
989)             formatter.write_paragraph()
990)             with formatter.indentation():
991)                 formatter.write_text(epilog)
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

992) 
993) 
Marco Ricci Reimplement `--help` and `-...

Marco Ricci authored 1 week ago

994) def version_option_callback(
995)     ctx: click.Context,
996)     param: click.Parameter,
997)     value: bool,  # noqa: FBT001
Marco Ricci Add tests for help and vers...

Marco Ricci authored 1 week ago

998) ) -> None:
Marco Ricci Reimplement `--help` and `-...

Marco Ricci authored 1 week ago

999)     del param
1000)     if value and not ctx.resilient_parsing:
1001)         click.echo(
1002)             str(
1003)                 _msg.TranslatedString(
1004)                     _msg.Label.VERSION_INFO_TEXT,
1005)                     PROG_NAME=PROG_NAME,
1006)                     __version__=__version__,
1007)                 )
1008)             ),
1009)         )
1010)         ctx.exit()
1011) 
1012) 
1013) def version_option(f: Callable[P, R]) -> Callable[P, R]:
1014)     return click.option(
1015)         '--version',
1016)         is_flag=True,
1017)         is_eager=True,
1018)         expose_value=False,
1019)         callback=version_option_callback,
1020)         cls=StandardOption,
1021)         help=_msg.TranslatedString(_msg.Label.VERSION_OPTION_HELP_TEXT),
1022)     )(f)
1023) 
1024) 
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1025) def color_forcing_callback(
1026)     ctx: click.Context,
1027)     param: click.Parameter,
1028)     value: Any,  # noqa: ANN401
1029) ) -> None:
1030)     """Force the `click` context to honor `NO_COLOR` and `FORCE_COLOR`."""
1031)     del param, value
Marco Ricci Add tests for help and vers...

Marco Ricci authored 1 week ago

1032)     if os.environ.get('NO_COLOR'):
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1033)         ctx.color = False
Marco Ricci Add tests for help and vers...

Marco Ricci authored 1 week ago

1034)     if os.environ.get('FORCE_COLOR'):
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1035)         ctx.color = True
1036) 
1037) 
1038) color_forcing_pseudo_option = click.option(
1039)     '--_pseudo-option-color-forcing',
1040)     '_color_forcing',
1041)     is_flag=True,
1042)     is_eager=True,
1043)     expose_value=False,
1044)     hidden=True,
1045)     callback=color_forcing_callback,
1046)     help='(pseudo-option)',
1047) )
1048) 
1049) 
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1050) class LoggingOption(OptionGroupOption):
1051)     """Logging options for the CLI."""
1052) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1053)     option_group_name = _msg.TranslatedString(_msg.Label.LOGGING_LABEL)
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1054)     epilog = ''
1055) 
1056) 
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

1057) debug_option = click.option(
1058)     '--debug',
1059)     'logging_level',
1060)     is_flag=True,
1061)     flag_value=logging.DEBUG,
1062)     expose_value=False,
1063)     callback=adjust_logging_level,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1064)     help=_msg.TranslatedString(_msg.Label.DEBUG_OPTION_HELP_TEXT),
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

1065)     cls=LoggingOption,
1066) )
1067) verbose_option = click.option(
1068)     '-v',
1069)     '--verbose',
1070)     'logging_level',
1071)     is_flag=True,
1072)     flag_value=logging.INFO,
1073)     expose_value=False,
1074)     callback=adjust_logging_level,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1075)     help=_msg.TranslatedString(_msg.Label.VERBOSE_OPTION_HELP_TEXT),
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

1076)     cls=LoggingOption,
1077) )
1078) quiet_option = click.option(
1079)     '-q',
1080)     '--quiet',
1081)     'logging_level',
1082)     is_flag=True,
1083)     flag_value=logging.ERROR,
1084)     expose_value=False,
1085)     callback=adjust_logging_level,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1086)     help=_msg.TranslatedString(_msg.Label.QUIET_OPTION_HELP_TEXT),
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

1087)     cls=LoggingOption,
1088) )
1089) 
1090) 
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1091) def standard_logging_options(f: Callable[P, R]) -> Callable[P, R]:
1092)     """Decorate the function with standard logging click options.
1093) 
1094)     Adds the three click options `-v`/`--verbose`, `-q`/`--quiet` and
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

1095)     `--debug`, which calls back into the [`adjust_logging_level`][]
1096)     function (with different argument values).
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1097) 
1098)     Args:
1099)         f: A callable to decorate.
1100) 
1101)     Returns:
1102)         The decorated callable.
1103) 
1104)     """
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

1105)     return debug_option(verbose_option(quiet_option(f)))
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1106) 
Marco Ricci Consolidate shell completio...

Marco Ricci authored 2 days ago

1107) # Shell completion
1108) # ================
1109) 
1110) # Use naive filename completion for the `path` argument of
1111) # `derivepassphrase vault`'s `--import` and `--export` options, as well
1112) # as the `path` argument of `derivepassphrase export vault`.  The latter
1113) # treats the pseudo-filename `VAULT_PATH` specially, but this is awkward
1114) # to combine with standard filename completion, particularly in bash, so
1115) # we would probably have to implement *all* completion (`VAULT_PATH` and
1116) # filename completion) ourselves, lacking some niceties of bash's
1117) # built-in completion (e.g., adding spaces or slashes depending on
1118) # whether the completion is a directory or a complete filename).
1119) 
1120) 
1121) def _shell_complete_path(
1122)     ctx: click.Context,
1123)     parameter: click.Parameter,
1124)     value: str,
1125) ) -> list[str | click.shell_completion.CompletionItem]:
1126)     """Request standard path completion for the `path` argument."""
1127)     del ctx, parameter, value
1128)     return [click.shell_completion.CompletionItem('', type='file')]  # noqa: DOC201
1129) 
1130) 
1131) # The standard `click` shell completion scripts serialize the completion
1132) # items as newline-separated one-line entries, which get silently
1133) # corrupted if the value contains newlines.  Each shell imposes
1134) # additional restrictions: Fish uses newlines in all internal completion
1135) # helper scripts, so it is difficult, if not impossible, to register
1136) # completion entries containing newlines if completion comes from within
1137) # a Fish completion function (instead of a Fish builtin).  Zsh's
1138) # completion system supports descriptions for each completion item, and
1139) # the completion helper functions parse every entry as a colon-separated
1140) # 2-tuple of item and description, meaning any colon in the item value
1141) # must be escaped.  Finally, Bash requires the result array to be
1142) # populated at the completion function's top-level scope, but for/while
1143) # loops within pipelines do not run at top-level scope, and Bash *also*
1144) # strips NUL characters from command substitution output, making it
1145) # difficult to read in external data into an array in a cross-platform
1146) # manner from entirely within Bash.
1147) #
1148) # We capitulate in front of these problems---most egregiously because of
1149) # Fish---and ensure that completion items (in this case: service names)
1150) # never contain ASCII control characters by refusing to offer such
1151) # items as valid completions.  On the other side, `derivepassphrase`
1152) # will warn the user when configuring or importing a service with such
1153) # a name that it will not be available for shell completion.
1154) 
1155) 
1156) def _is_completable_item(obj: object) -> bool:
1157)     """Return whether the item is completable on the command-line.
1158) 
1159)     The item is completable if and only if it contains no ASCII control
1160)     characters (U+0000 through U+001F, and U+007F).
1161) 
1162)     """
1163)     obj = str(obj)
1164)     forbidden = frozenset(chr(i) for i in range(32)) | {'\x7F'}
1165)     return not any(f in obj for f in forbidden)
1166) 
1167) 
1168) def _shell_complete_service(
1169)     ctx: click.Context,
1170)     parameter: click.Parameter,
1171)     value: str,
1172) ) -> list[str | click.shell_completion.CompletionItem]:
1173)     """Return known vault service names as completion items.
1174) 
1175)     Service names are looked up in the vault configuration file.  All
1176)     errors will be suppressed.  Additionally, any service names deemed
1177)     not completable as per [`_is_completable_item`][] will be silently
1178)     skipped.
1179) 
1180)     """
1181)     del ctx, parameter
1182)     try:
1183)         config = _load_config()
1184)         return sorted(
1185)             sv
1186)             for sv in config['services']
1187)             if sv.startswith(value) and _is_completable_item(sv)
1188)         )
1189)     except FileNotFoundError:
1190)         try:
1191)             config, _exc = _migrate_and_load_old_config()
1192)             return sorted(
1193)                 sv
1194)                 for sv in config['services']
1195)                 if sv.startswith(value) and _is_completable_item(sv)
1196)             )
1197)         except FileNotFoundError:
1198)             return []
1199)     except Exception:  # noqa: BLE001
1200)         return []
1201) 
1202) 
1203) class ZshComplete(click.shell_completion.ZshComplete):
1204)     """Zsh completion class that supports colons.
1205) 
1206)     `click`'s Zsh completion class (at least v8.1.7 and v8.1.8) uses
1207)     completion helper functions (provided by Zsh) that parse each
1208)     completion item into value-description pairs, separated by a colon.
1209)     Correspondingly, any internal colons in the completion item's value
1210)     need to be escaped.  `click` doesn't do this.  So, this subclass
1211)     overrides those parts, and adds the missing escaping.
1212) 
1213)     """
1214) 
1215)     @override
1216)     def format_completion(
1217)         self,
1218)         item: click.shell_completion.CompletionItem,
1219)     ) -> str:
1220)         """Return a suitable serialization of the CompletionItem.
1221) 
1222)         This serialization ensures colons in the item value are properly
1223)         escaped.
1224) 
1225)         """
1226)         type, value, help = (  # noqa: A001
1227)             item.type,
1228)             item.value.replace(':', '\\:'),
1229)             item.help or '_',
1230)         )
1231)         return f'{type}\n{value}\n{help}'
1232) 
1233) 
1234) click.shell_completion.add_completion_class(ZshComplete)
1235) 
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1236) 
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1237) # Top-level
1238) # =========
1239) 
1240) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1241) class _DefaultToVaultGroup(CommandWithHelpGroups, click.Group):
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1242)     """A helper class to implement the default-to-"vault"-subcommand behavior.
1243) 
1244)     Modifies internal [`click.MultiCommand`][] methods, and thus is both
1245)     an implementation detail and a kludge.
1246) 
1247)     """
1248) 
1249)     def resolve_command(
1250)         self, ctx: click.Context, args: list[str]
1251)     ) -> tuple[str | None, click.Command | None, list[str]]:
1252)         """Resolve a command, but default to "vault" instead of erroring out.
1253) 
1254)         Based on code from click 8.1, which appears to be essentially
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1255)         untouched since at least click 3.2.  Subject to the following
1256)         license (3-clause BSD license):
1257) 
1258)             Copyright 2024 Pallets
1259) 
1260)             Redistribution and use in source and binary forms, with or
1261)             without modification, are permitted provided that the following
1262)             conditions are met:
1263) 
1264)              1. Redistributions of source code must retain the above
1265)                 copyright notice, this list of conditions and the following
1266)                 disclaimer.
1267) 
1268)              2. Redistributions in binary form must reproduce the above
1269)                 copyright notice, this list of conditions and the following
1270)                 disclaimer in the documentation and/or other materials
1271)                 provided with the distribution.
1272) 
1273)              3. Neither the name of the copyright holder nor the names of
1274)                 its contributors may be used to endorse or promote products
1275)                 derived from this software without specific prior written
1276)                 permission.
1277) 
1278)             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
1279)             CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
1280)             INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1281)             MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1282)             DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
1283)             CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1284)             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1285)             LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
1286)             USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
1287)             AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1288)             LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
1289)             IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
1290)             THE POSSIBILITY OF SUCH DAMAGE.
1291) 
1292)         Modifications to this routine are marked with "modifications for
1293)         derivepassphrase".  Furthermore, all "pragma" and "noqa" comments
1294)         are also modifications for derivepassphrase.
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1295) 
1296)         """
1297)         cmd_name = click.utils.make_str(args[0])
1298) 
1299)         # Get the command
1300)         cmd = self.get_command(ctx, cmd_name)
1301) 
1302)         # If we can't find the command but there is a normalization
1303)         # function available, we try with that one.
1304)         if (  # pragma: no cover
1305)             cmd is None and ctx.token_normalize_func is not None
1306)         ):
1307)             cmd_name = ctx.token_normalize_func(cmd_name)
1308)             cmd = self.get_command(ctx, cmd_name)
1309) 
1310)         # If we don't find the command we want to show an error message
1311)         # to the user that it was not provided.  However, there is
1312)         # something else we should do: if the first argument looks like
1313)         # an option we want to kick off parsing again for arguments to
1314)         # resolve things like --help which now should go to the main
1315)         # place.
1316)         if cmd is None and not ctx.resilient_parsing:
1317)             if click.parser.split_opt(cmd_name)[0]:
1318)                 self.parse_args(ctx, ctx.args)
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1319)             ####
1320)             # BEGIN modifications for derivepassphrase
1321)             #
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1322)             # Instead of calling ctx.fail here, default to "vault", and
1323)             # issue a deprecation warning.
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1324)             deprecation = logging.getLogger(f'{PROG_NAME}.deprecation')
1325)             deprecation.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1326)                 _msg.TranslatedString(
1327)                     _msg.WarnMsgTemplate.V10_SUBCOMMAND_REQUIRED
1328)                 )
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1329)             )
1330)             cmd_name = 'vault'
1331)             cmd = self.get_command(ctx, cmd_name)
1332)             assert cmd is not None, 'Mandatory subcommand "vault" missing!'
1333)             args = [cmd_name, *args]
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1334)             #
1335)             # END modifications for derivepassphrase
1336)             ####
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1337)         return cmd_name if cmd else None, cmd, args[1:]  # noqa: DOC201
1338) 
1339) 
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1340) class _TopLevelCLIEntryPoint(_DefaultToVaultGroup):
1341)     """A minor variation of _DefaultToVaultGroup for the top-level command.
1342) 
1343)     When called as a function, this sets up the environment properly
1344)     before invoking the actual callbacks.  Currently, this means setting
1345)     up the logging subsystem and the delegation of Python warnings to
1346)     the logging subsystem.
1347) 
1348)     The environment setup can be bypassed by calling the `.main` method
1349)     directly.
1350) 
1351)     """
1352) 
1353)     def __call__(  # pragma: no cover
1354)         self,
1355)         *args: Any,  # noqa: ANN401
1356)         **kwargs: Any,  # noqa: ANN401
1357)     ) -> Any:  # noqa: ANN401
1358)         """"""  # noqa: D419
1359)         # Coverage testing is done with the `click.testing` module,
1360)         # which does not use the `__call__` shortcut.  So it is normal
1361)         # that this function is never called, and thus should be
1362)         # excluded from coverage.
1363)         with (
1364)             StandardCLILogging.ensure_standard_logging(),
1365)             StandardCLILogging.ensure_standard_warnings_logging(),
1366)         ):
1367)             return self.main(*args, **kwargs)
1368) 
1369) 
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1370) @click.group(
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1371)     context_settings={
1372)         'help_option_names': ['-h', '--help'],
1373)         'ignore_unknown_options': True,
1374)         'allow_interspersed_args': False,
1375)     },
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1376)     epilog=_msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EPILOG_01),
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1377)     invoke_without_command=True,
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1378)     cls=_TopLevelCLIEntryPoint,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1379)     help=(
1380)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_01),
1381)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_02),
1382)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_03),
1383)     ),
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1384) )
Marco Ricci Reimplement `--help` and `-...

Marco Ricci authored 1 week ago

1385) @version_option
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1386) @color_forcing_pseudo_option
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1387) @standard_logging_options
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1388) @click.pass_context
1389) def derivepassphrase(ctx: click.Context, /) -> None:
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1390)     """Derive a strong passphrase, deterministically, from a master secret.
1391) 
1392)     This is a [`click`][CLICK]-powered command-line interface function,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1393)     and not intended for programmatic use.  See the derivepassphrase(1)
1394)     manpage for full documentation of the interface.  (See also
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1395)     [`click.testing.CliRunner`][] for controlled, programmatic
1396)     invocation.)
1397) 
Marco Ricci Update all URLs to stable a...

Marco Ricci authored 3 months ago

1398)     [CLICK]: https://pypi.org/package/click/
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1399) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1400)     """
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1401)     deprecation = logging.getLogger(f'{PROG_NAME}.deprecation')
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1402)     if ctx.invoked_subcommand is None:
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1403)         deprecation.warning(
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1404)             _msg.TranslatedString(
1405)                 _msg.WarnMsgTemplate.V10_SUBCOMMAND_REQUIRED
1406)             ),
1407)             extra={'color': ctx.color},
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1408)         )
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1409)         # See definition of click.Group.invoke, non-chained case.
1410)         with ctx:
1411)             sub_ctx = derivepassphrase_vault.make_context(
1412)                 'vault', ctx.args, parent=ctx
1413)             )
1414)             with sub_ctx:
1415)                 return derivepassphrase_vault.invoke(sub_ctx)
1416)     return None
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1417) 
1418) 
1419) # Exporter
1420) # ========
1421) 
1422) 
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1423) @derivepassphrase.group(
1424)     'export',
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1425)     context_settings={
1426)         'help_option_names': ['-h', '--help'],
1427)         'ignore_unknown_options': True,
1428)         'allow_interspersed_args': False,
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1429)     },
1430)     invoke_without_command=True,
1431)     cls=_DefaultToVaultGroup,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1432)     help=(
1433)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EXPORT_01),
1434)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EXPORT_02),
1435)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EXPORT_03),
1436)     ),
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1437) )
Marco Ricci Reimplement `--help` and `-...

Marco Ricci authored 1 week ago

1438) @version_option
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1439) @color_forcing_pseudo_option
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1440) @standard_logging_options
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1441) @click.pass_context
1442) def derivepassphrase_export(ctx: click.Context, /) -> None:
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1443)     """Export a foreign configuration to standard output.
1444) 
1445)     This is a [`click`][CLICK]-powered command-line interface function,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1446)     and not intended for programmatic use.  See the
1447)     derivepassphrase-export(1) manpage for full documentation of the
1448)     interface.  (See also [`click.testing.CliRunner`][] for controlled,
1449)     programmatic invocation.)
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1450) 
Marco Ricci Update all URLs to stable a...

Marco Ricci authored 3 months ago

1451)     [CLICK]: https://pypi.org/package/click/
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1452) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1453)     """
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1454)     deprecation = logging.getLogger(f'{PROG_NAME}.deprecation')
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1455)     if ctx.invoked_subcommand is None:
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1456)         deprecation.warning(
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1457)             _msg.TranslatedString(
1458)                 _msg.WarnMsgTemplate.V10_SUBCOMMAND_REQUIRED
1459)             ),
1460)             extra={'color': ctx.color},
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1461)         )
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1462)         # See definition of click.Group.invoke, non-chained case.
1463)         with ctx:
1464)             sub_ctx = derivepassphrase_export_vault.make_context(
1465)                 'vault', ctx.args, parent=ctx
1466)             )
1467)             # Constructing the subcontext above will usually already
1468)             # lead to a click.UsageError, so this block typically won't
1469)             # actually be called.
1470)             with sub_ctx:  # pragma: no cover
1471)                 return derivepassphrase_export_vault.invoke(sub_ctx)
1472)     return None
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1473) 
1474) 
1475) def _load_data(
1476)     fmt: Literal['v0.2', 'v0.3', 'storeroom'],
1477)     path: str | bytes | os.PathLike[str],
1478)     key: bytes,
1479) ) -> Any:  # noqa: ANN401
1480)     contents: bytes
1481)     module: types.ModuleType
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

1482)     # Use match/case here once Python 3.9 becomes unsupported.
1483)     if fmt == 'v0.2':
1484)         module = importlib.import_module(
1485)             'derivepassphrase.exporter.vault_native'
1486)         )
1487)         if module.STUBBED:
1488)             raise ModuleNotFoundError
1489)         with open(path, 'rb') as infile:
1490)             contents = base64.standard_b64decode(infile.read())
1491)         return module.export_vault_native_data(
1492)             contents, key, try_formats=['v0.2']
1493)         )
1494)     elif fmt == 'v0.3':  # noqa: RET505
1495)         module = importlib.import_module(
1496)             'derivepassphrase.exporter.vault_native'
1497)         )
1498)         if module.STUBBED:
1499)             raise ModuleNotFoundError
1500)         with open(path, 'rb') as infile:
1501)             contents = base64.standard_b64decode(infile.read())
1502)         return module.export_vault_native_data(
1503)             contents, key, try_formats=['v0.3']
1504)         )
1505)     elif fmt == 'storeroom':
1506)         module = importlib.import_module('derivepassphrase.exporter.storeroom')
1507)         if module.STUBBED:
1508)             raise ModuleNotFoundError
1509)         return module.export_storeroom_data(path, key)
1510)     else:  # pragma: no cover
1511)         assert_never(fmt)
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1512) 
1513) 
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1514) @derivepassphrase_export.command(
1515)     'vault',
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1516)     context_settings={'help_option_names': ['-h', '--help']},
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1517)     cls=CommandWithHelpGroups,
1518)     help=(
1519)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EXPORT_VAULT_01),
1520)         _msg.TranslatedString(
1521)             _msg.Label.DERIVEPASSPHRASE_EXPORT_VAULT_02,
1522)             path_metavar=_msg.TranslatedString(
1523)                 _msg.Label.EXPORT_VAULT_METAVAR_PATH,
1524)             ),
1525)         ),
1526)         _msg.TranslatedString(
1527)             _msg.Label.DERIVEPASSPHRASE_EXPORT_VAULT_03,
1528)             path_metavar=_msg.TranslatedString(
1529)                 _msg.Label.EXPORT_VAULT_METAVAR_PATH,
1530)             ),
1531)         ),
1532)     ),
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1533) )
1534) @click.option(
1535)     '-f',
1536)     '--format',
1537)     'formats',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1538)     metavar=_msg.TranslatedString(_msg.Label.EXPORT_VAULT_FORMAT_METAVAR_FMT),
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1539)     multiple=True,
1540)     default=('v0.3', 'v0.2', 'storeroom'),
1541)     type=click.Choice(['v0.2', 'v0.3', 'storeroom']),
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1542)     help=_msg.TranslatedString(
1543)         _msg.Label.EXPORT_VAULT_FORMAT_HELP_TEXT,
1544)         defaults_hint=_msg.TranslatedString(
1545)             _msg.Label.EXPORT_VAULT_FORMAT_DEFAULTS_HELP_TEXT,
1546)         ),
1547)         metavar=_msg.TranslatedString(
1548)             _msg.Label.EXPORT_VAULT_FORMAT_METAVAR_FMT,
1549)         ),
1550)     ),
1551)     cls=StandardOption,
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1552) )
1553) @click.option(
1554)     '-k',
1555)     '--key',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1556)     metavar=_msg.TranslatedString(_msg.Label.EXPORT_VAULT_KEY_METAVAR_K),
1557)     help=_msg.TranslatedString(
1558)         _msg.Label.EXPORT_VAULT_KEY_HELP_TEXT,
1559)         metavar=_msg.TranslatedString(_msg.Label.EXPORT_VAULT_KEY_METAVAR_K),
1560)         defaults_hint=_msg.TranslatedString(
1561)             _msg.Label.EXPORT_VAULT_KEY_DEFAULTS_HELP_TEXT,
1562)         ),
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1563)     ),
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1564)     cls=StandardOption,
1565) )
Marco Ricci Reimplement `--help` and `-...

Marco Ricci authored 1 week ago

1566) @version_option
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1567) @color_forcing_pseudo_option
Marco Ricci Reimplement `--help` and `-...

Marco Ricci authored 1 week ago

1568) @standard_logging_options
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1569) @click.argument(
1570)     'path',
1571)     metavar=_msg.TranslatedString(_msg.Label.EXPORT_VAULT_METAVAR_PATH),
1572)     required=True,
Marco Ricci Consolidate shell completio...

Marco Ricci authored 2 days ago

1573)     shell_complete=_shell_complete_path,
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1574) )
1575) @click.pass_context
1576) def derivepassphrase_export_vault(
1577)     ctx: click.Context,
1578)     /,
1579)     *,
1580)     path: str | bytes | os.PathLike[str],
1581)     formats: Sequence[Literal['v0.2', 'v0.3', 'storeroom']] = (),
1582)     key: str | bytes | None = None,
1583) ) -> None:
1584)     """Export a vault-native configuration to standard output.
1585) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1586)     This is a [`click`][CLICK]-powered command-line interface function,
1587)     and not intended for programmatic use.  See the
1588)     derivepassphrase-export-vault(1) manpage for full documentation of
1589)     the interface.  (See also [`click.testing.CliRunner`][] for
1590)     controlled, programmatic invocation.)
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1591) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1592)     [CLICK]: https://pypi.org/package/click/
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1593) 
1594)     """
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1595)     logger = logging.getLogger(PROG_NAME)
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1596)     if path in {'VAULT_PATH', b'VAULT_PATH'}:
1597)         path = exporter.get_vault_path()
1598)     if key is None:
1599)         key = exporter.get_vault_key()
1600)     elif isinstance(key, str):  # pragma: no branch
1601)         key = key.encode('utf-8')
1602)     for fmt in formats:
1603)         try:
1604)             config = _load_data(fmt, path, key)
1605)         except (
1606)             IsADirectoryError,
1607)             NotADirectoryError,
1608)             ValueError,
1609)             RuntimeError,
1610)         ):
Marco Ricci Replace strings in `derivep...

Marco Ricci authored 1 week ago

1611)             logger.info(
1612)                 _msg.TranslatedString(
1613)                     _msg.InfoMsgTemplate.CANNOT_LOAD_AS_VAULT_CONFIG,
1614)                     path=path,
1615)                     fmt=fmt,
1616)                 ),
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1617)                 extra={'color': ctx.color},
Marco Ricci Replace strings in `derivep...

Marco Ricci authored 1 week ago

1618)             )
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1619)             continue
1620)         except OSError as exc:
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1621)             logger.error(
Marco Ricci Replace strings in `derivep...

Marco Ricci authored 1 week ago

1622)                 _msg.TranslatedString(
1623)                     _msg.ErrMsgTemplate.CANNOT_PARSE_AS_VAULT_CONFIG_OSERROR,
1624)                     path=path,
1625)                     error=exc.strerror,
1626)                     filename=exc.filename,
1627)                 ).maybe_without_filename(),
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1628)                 extra={'color': ctx.color},
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1629)             )
1630)             ctx.exit(1)
1631)         except ModuleNotFoundError:
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1632)             logger.error(
Marco Ricci Replace strings in `derivep...

Marco Ricci authored 1 week ago

1633)                 _msg.TranslatedString(
1634)                     _msg.ErrMsgTemplate.MISSING_MODULE,
1635)                     module='cryptography',
1636)                 ),
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1637)                 extra={'color': ctx.color},
Marco Ricci Replace strings in `derivep...

Marco Ricci authored 1 week ago

1638)             )
1639)             logger.info(
1640)                 _msg.TranslatedString(
1641)                     _msg.InfoMsgTemplate.PIP_INSTALL_EXTRA,
1642)                     extra_name='export',
1643)                 ),
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1644)                 extra={'color': ctx.color},
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1645)             )
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1646)             ctx.exit(1)
1647)         else:
1648)             if not _types.is_vault_config(config):
Marco Ricci Replace strings in `derivep...

Marco Ricci authored 1 week ago

1649)                 logger.error(
1650)                     _msg.TranslatedString(
1651)                         _msg.ErrMsgTemplate.INVALID_VAULT_CONFIG,
1652)                         config=config,
1653)                     ),
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1654)                     extra={'color': ctx.color},
Marco Ricci Replace strings in `derivep...

Marco Ricci authored 1 week ago

1655)                 )
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1656)                 ctx.exit(1)
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1657)             click.echo(
1658)                 json.dumps(config, indent=2, sort_keys=True),
1659)                 color=ctx.color,
1660)             )
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1661)             break
1662)     else:
Marco Ricci Replace strings in `derivep...

Marco Ricci authored 1 week ago

1663)         logger.error(
1664)             _msg.TranslatedString(
1665)                 _msg.ErrMsgTemplate.CANNOT_PARSE_AS_VAULT_CONFIG,
1666)                 path=path,
1667)             ).maybe_without_filename(),
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1668)             extra={'color': ctx.color},
Marco Ricci Replace strings in `derivep...

Marco Ricci authored 1 week ago

1669)         )
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1670)         ctx.exit(1)
1671) 
1672) 
1673) # Vault
1674) # =====
1675) 
1676) 
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1677) def _config_filename(
Marco Ricci Make obtaining the compatib...

Marco Ricci authored 3 weeks ago

1678)     subsystem: str | None = 'old settings.json',
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1679) ) -> str | bytes | pathlib.Path:
1680)     """Return the filename of the configuration file for the subsystem.
1681) 
1682)     The (implicit default) file is currently named `settings.json`,
1683)     located within the configuration directory as determined by the
1684)     `DERIVEPASSPHRASE_PATH` environment variable, or by
1685)     [`click.get_app_dir`][] in POSIX mode.  Depending on the requested
1686)     subsystem, this will usually be a different file within that
1687)     directory.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1688) 
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1689)     Args:
1690)         subsystem:
1691)             Name of the configuration subsystem whose configuration
1692)             filename to return.  If not given, return the old filename
1693)             from before the subcommand migration.  If `None`, return the
1694)             configuration directory instead.
1695) 
1696)     Raises:
1697)         AssertionError:
1698)             An unknown subsystem was passed.
1699) 
1700)     Deprecated:
1701)         Since v0.2.0: The implicit default subsystem and the old
1702)         configuration filename are deprecated, and will be removed in v1.0.
1703)         The subsystem will be mandatory to specify.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1704) 
1705)     """
1706)     path: str | bytes | pathlib.Path
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1707)     path = os.getenv(PROG_NAME.upper() + '_PATH') or click.get_app_dir(
1708)         PROG_NAME, force_posix=True
1709)     )
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

1710)     # Use match/case here once Python 3.9 becomes unsupported.
1711)     if subsystem is None:
1712)         return path
Marco Ricci Make obtaining the compatib...

Marco Ricci authored 3 weeks ago

1713)     elif subsystem == 'vault':  # noqa: RET505
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

1714)         filename = f'{subsystem}.json'
Marco Ricci Introduce a central user co...

Marco Ricci authored 3 weeks ago

1715)     elif subsystem == 'user configuration':
1716)         filename = 'config.toml'
Marco Ricci Make obtaining the compatib...

Marco Ricci authored 3 weeks ago

1717)     elif subsystem == 'old settings.json':
1718)         filename = 'settings.json'
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

1719)     else:  # pragma: no cover
1720)         msg = f'Unknown configuration subsystem: {subsystem!r}'
1721)         raise AssertionError(msg)
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1722)     return os.path.join(path, filename)
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1723) 
1724) 
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

1725) def _load_config() -> _types.VaultConfig:
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1726)     """Load a vault(1)-compatible config from the application directory.
1727) 
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

1728)     The filename is obtained via [`_config_filename`][].  This must be
1729)     an unencrypted JSON file.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1730) 
1731)     Returns:
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

1732)         The vault settings.  See [`_types.VaultConfig`][] for details.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1733) 
1734)     Raises:
1735)         OSError:
1736)             There was an OS error accessing the file.
1737)         ValueError:
1738)             The data loaded from the file is not a vault(1)-compatible
1739)             config.
1740) 
1741)     """
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1742)     filename = _config_filename(subsystem='vault')
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1743)     with open(filename, 'rb') as fileobj:
1744)         data = json.load(fileobj)
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

1745)     if not _types.is_vault_config(data):
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

1746)         raise ValueError(_INVALID_VAULT_CONFIG)
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1747)     return data
1748) 
1749) 
Marco Ricci Permit one flaky test and f...

Marco Ricci authored 2 months ago

1750) def _migrate_and_load_old_config() -> tuple[
1751)     _types.VaultConfig, OSError | None
1752) ]:
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1753)     """Load and migrate a vault(1)-compatible config.
1754) 
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

1755)     The (old) filename is obtained via [`_config_filename`][].  This
1756)     must be an unencrypted JSON file.  After loading, the file is
1757)     migrated to the new standard filename.
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1758) 
1759)     Returns:
1760)         The vault settings, and an optional exception encountered during
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

1761)         migration.  See [`_types.VaultConfig`][] for details on the
1762)         former.
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1763) 
1764)     Raises:
1765)         OSError:
1766)             There was an OS error accessing the old file.
1767)         ValueError:
1768)             The data loaded from the file is not a vault(1)-compatible
1769)             config.
1770) 
1771)     """
1772)     new_filename = _config_filename(subsystem='vault')
Marco Ricci Make obtaining the compatib...

Marco Ricci authored 3 weeks ago

1773)     old_filename = _config_filename(subsystem='old settings.json')
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1774)     with open(old_filename, 'rb') as fileobj:
1775)         data = json.load(fileobj)
1776)     if not _types.is_vault_config(data):
1777)         raise ValueError(_INVALID_VAULT_CONFIG)
1778)     try:
1779)         os.replace(old_filename, new_filename)
1780)     except OSError as exc:
1781)         return data, exc
1782)     else:
1783)         return data, None
1784) 
1785) 
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

1786) def _save_config(config: _types.VaultConfig, /) -> None:
Marco Ricci Create the configuration di...

Marco Ricci authored 5 months ago

1787)     """Save a vault(1)-compatible config to the application directory.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1788) 
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

1789)     The filename is obtained via [`_config_filename`][].  The config
1790)     will be stored as an unencrypted JSON file.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1791) 
1792)     Args:
1793)         config:
1794)             vault configuration to save.
1795) 
1796)     Raises:
1797)         OSError:
1798)             There was an OS error accessing or writing the file.
1799)         ValueError:
1800)             The data cannot be stored as a vault(1)-compatible config.
1801) 
1802)     """
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

1803)     if not _types.is_vault_config(config):
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

1804)         raise ValueError(_INVALID_VAULT_CONFIG)
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1805)     filename = _config_filename(subsystem='vault')
Marco Ricci Create the configuration di...

Marco Ricci authored 5 months ago

1806)     filedir = os.path.dirname(os.path.abspath(filename))
1807)     try:
1808)         os.makedirs(filedir, exist_ok=False)
1809)     except FileExistsError:
1810)         if not os.path.isdir(filedir):
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

1811)             raise  # noqa: DOC501
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

1812)     with open(filename, 'w', encoding='UTF-8') as fileobj:
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1813)         json.dump(config, fileobj)
1814) 
1815) 
Marco Ricci Introduce a central user co...

Marco Ricci authored 3 weeks ago

1816) def _load_user_config() -> dict[str, Any]:
1817)     """Load the user config from the application directory.
1818) 
1819)     The filename is obtained via [`_config_filename`][].
1820) 
1821)     Returns:
1822)         The user configuration, as a nested `dict`.
1823) 
1824)     Raises:
1825)         OSError:
1826)             There was an OS error accessing the file.
1827)         ValueError:
1828)             The data loaded from the file is not a valid configuration
1829)             file.
1830) 
1831)     """
1832)     filename = _config_filename(subsystem='user configuration')
1833)     with open(filename, 'rb') as fileobj:
1834)         return tomllib.load(fileobj)
1835) 
1836) 
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1837) def _get_suitable_ssh_keys(
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 5 months ago

1838)     conn: ssh_agent.SSHAgentClient | socket.socket | None = None, /
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

1839) ) -> Iterator[_types.KeyCommentPair]:
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1840)     """Yield all SSH keys suitable for passphrase derivation.
1841) 
1842)     Suitable SSH keys are queried from the running SSH agent (see
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

1843)     [`ssh_agent.SSHAgentClient.list_keys`][]).
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1844) 
1845)     Args:
1846)         conn:
Marco Ricci Support one-off SSH agent c...

Marco Ricci authored 1 month ago

1847)             An optional connection hint to the SSH agent.  See
1848)             [`ssh_agent.SSHAgentClient.ensure_agent_subcontext`][].
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1849) 
1850)     Yields:
Marco Ricci Convert old syntax for Yiel...

Marco Ricci authored 3 months ago

1851)         Every SSH key from the SSH agent that is suitable for passphrase
1852)         derivation.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1853) 
1854)     Raises:
Marco Ricci Document and handle other e...

Marco Ricci authored 4 months ago

1855)         KeyError:
1856)             `conn` was `None`, and the `SSH_AUTH_SOCK` environment
1857)             variable was not found.
Marco Ricci Fail gracefully if UNIX dom...

Marco Ricci authored 3 months ago

1858)         NotImplementedError:
1859)             `conn` was `None`, and this Python does not support
1860)             [`socket.AF_UNIX`][], so the SSH agent client cannot be
1861)             automatically set up.
Marco Ricci Document and handle other e...

Marco Ricci authored 4 months ago

1862)         OSError:
1863)             `conn` was a socket or `None`, and there was an error
1864)             setting up a socket connection to the agent.
Marco Ricci Distinguish between a key l...

Marco Ricci authored 6 months ago

1865)         LookupError:
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1866)             No keys usable for passphrase derivation are loaded into the
1867)             SSH agent.
Marco Ricci Distinguish between a key l...

Marco Ricci authored 6 months ago

1868)         RuntimeError:
1869)             There was an error communicating with the SSH agent.
Marco Ricci Fix miscellaneous small doc...

Marco Ricci authored 3 months ago

1870)         ssh_agent.SSHAgentFailedError:
Marco Ricci Add a specific error class...

Marco Ricci authored 4 months ago

1871)             The agent failed to supply a list of loaded keys.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1872) 
1873)     """
Marco Ricci Support one-off SSH agent c...

Marco Ricci authored 1 month ago

1874)     with ssh_agent.SSHAgentClient.ensure_agent_subcontext(conn) as client:
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1875)         try:
1876)             all_key_comment_pairs = list(client.list_keys())
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

1877)         except EOFError as exc:  # pragma: no cover
1878)             raise RuntimeError(_AGENT_COMMUNICATION_ERROR) from exc
Marco Ricci Publish polished `is_suitab...

Marco Ricci authored 1 month ago

1879)         suitable_keys = copy.copy(all_key_comment_pairs)
1880)         for pair in all_key_comment_pairs:
1881)             key, _comment = pair
1882)             if vault.Vault.is_suitable_ssh_key(key, client=client):
1883)                 yield pair
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1884)     if not suitable_keys:  # pragma: no cover
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1885)         raise LookupError(_NO_SUITABLE_KEYS)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1886) 
1887) 
1888) def _prompt_for_selection(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1889)     items: Sequence[str | bytes],
1890)     heading: str = 'Possible choices:',
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1891)     single_choice_prompt: str = 'Confirm this choice?',
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1892)     ctx: click.Context | None = None,
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1893) ) -> int:
1894)     """Prompt user for a choice among the given items.
1895) 
1896)     Print the heading, if any, then present the items to the user.  If
1897)     there are multiple items, prompt the user for a selection, validate
1898)     the choice, then return the list index of the selected item.  If
1899)     there is only a single item, request confirmation for that item
1900)     instead, and return the correct index.
1901) 
1902)     Args:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

1903)         items:
1904)             The list of items to choose from.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1905)         heading:
1906)             A heading for the list of items, to print immediately
1907)             before.  Defaults to a reasonable standard heading.  If
1908)             explicitly empty, print no heading.
1909)         single_choice_prompt:
1910)             The confirmation prompt if there is only a single possible
1911)             choice.  Defaults to a reasonable standard prompt.
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1912)         ctx:
1913)             An optional `click` context, from which output device
1914)             properties and color preferences will be queried.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1915) 
1916)     Returns:
1917)         An index into the items sequence, indicating the user's
1918)         selection.
1919) 
1920)     Raises:
1921)         IndexError:
1922)             The user made an invalid or empty selection, or requested an
1923)             abort.
1924) 
1925)     """
1926)     n = len(items)
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1927)     color = ctx.color if ctx is not None else None
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1928)     if heading:
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1929)         click.echo(click.style(heading, bold=True), color=color)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1930)     for i, x in enumerate(items, start=1):
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1931)         click.echo(click.style(f'[{i}]', bold=True), nl=False, color=color)
1932)         click.echo(' ', nl=False, color=color)
1933)         click.echo(x, color=color)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1934)     if n > 1:
1935)         choices = click.Choice([''] + [str(i) for i in range(1, n + 1)])
1936)         choice = click.prompt(
1937)             f'Your selection? (1-{n}, leave empty to abort)',
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1938)             err=True,
1939)             type=choices,
1940)             show_choices=False,
1941)             show_default=False,
1942)             default='',
1943)         )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1944)         if not choice:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

1945)             raise IndexError(_EMPTY_SELECTION)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1946)         return int(choice) - 1
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1947)     prompt_suffix = (
1948)         ' ' if single_choice_prompt.endswith(tuple('?.!')) else ': '
1949)     )
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

1950)     try:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1951)         click.confirm(
1952)             single_choice_prompt,
1953)             prompt_suffix=prompt_suffix,
1954)             err=True,
1955)             abort=True,
1956)             default=False,
1957)             show_default=False,
1958)         )
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

1959)     except click.Abort:
1960)         raise IndexError(_EMPTY_SELECTION) from None
1961)     return 0
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1962) 
1963) 
1964) def _select_ssh_key(
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1965)     conn: ssh_agent.SSHAgentClient | socket.socket | None = None,
1966)     /,
1967)     *,
1968)     ctx: click.Context | None = None,
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1969) ) -> bytes | bytearray:
1970)     """Interactively select an SSH key for passphrase derivation.
1971) 
1972)     Suitable SSH keys are queried from the running SSH agent (see
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

1973)     [`ssh_agent.SSHAgentClient.list_keys`][]), then the user is prompted
1974)     interactively (see [`click.prompt`][]) for a selection.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1975) 
1976)     Args:
1977)         conn:
Marco Ricci Support one-off SSH agent c...

Marco Ricci authored 1 month ago

1978)             An optional connection hint to the SSH agent.  See
1979)             [`ssh_agent.SSHAgentClient.ensure_agent_subcontext`][].
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

1980)         ctx:
1981)             An `click` context, queried for output device properties and
1982)             color preferences when issuing the prompt.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1983) 
1984)     Returns:
1985)         The selected SSH key.
1986) 
1987)     Raises:
Marco Ricci Document and handle other e...

Marco Ricci authored 4 months ago

1988)         KeyError:
1989)             `conn` was `None`, and the `SSH_AUTH_SOCK` environment
1990)             variable was not found.
Marco Ricci Fail gracefully if UNIX dom...

Marco Ricci authored 3 months ago

1991)         NotImplementedError:
1992)             `conn` was `None`, and this Python does not support
1993)             [`socket.AF_UNIX`][], so the SSH agent client cannot be
1994)             automatically set up.
Marco Ricci Document and handle other e...

Marco Ricci authored 4 months ago

1995)         OSError:
1996)             `conn` was a socket or `None`, and there was an error
1997)             setting up a socket connection to the agent.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1998)         IndexError:
1999)             The user made an invalid or empty selection, or requested an
2000)             abort.
Marco Ricci Distinguish between a key l...

Marco Ricci authored 6 months ago

2001)         LookupError:
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2002)             No keys usable for passphrase derivation are loaded into the
2003)             SSH agent.
Marco Ricci Distinguish between a key l...

Marco Ricci authored 6 months ago

2004)         RuntimeError:
2005)             There was an error communicating with the SSH agent.
Marco Ricci Add a specific error class...

Marco Ricci authored 4 months ago

2006)         SSHAgentFailedError:
2007)             The agent failed to supply a list of loaded keys.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2008)     """
2009)     suitable_keys = list(_get_suitable_ssh_keys(conn))
2010)     key_listing: list[str] = []
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 5 months ago

2011)     unstring_prefix = ssh_agent.SSHAgentClient.unstring_prefix
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2012)     for key, comment in suitable_keys:
2013)         keytype = unstring_prefix(key)[0].decode('ASCII')
2014)         key_str = base64.standard_b64encode(key).decode('ASCII')
Marco Ricci Make suitable SSH key listi...

Marco Ricci authored 1 month ago

2015)         remaining_key_display_length = KEY_DISPLAY_LENGTH - 1 - len(keytype)
2016)         key_extract = min(
2017)             key_str,
2018)             '...' + key_str[-remaining_key_display_length:],
2019)             key=len,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2020)         )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2021)         comment_str = comment.decode('UTF-8', errors='replace')
Marco Ricci Make suitable SSH key listi...

Marco Ricci authored 1 month ago

2022)         key_listing.append(f'{keytype} {key_extract}  {comment_str}')
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2023)     choice = _prompt_for_selection(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2024)         key_listing,
2025)         heading='Suitable SSH keys:',
2026)         single_choice_prompt='Use this key?',
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

2027)         ctx=ctx,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2028)     )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2029)     return suitable_keys[choice].key
2030) 
2031) 
2032) def _prompt_for_passphrase() -> str:
2033)     """Interactively prompt for the passphrase.
2034) 
2035)     Calls [`click.prompt`][] internally.  Moved into a separate function
2036)     mainly for testing/mocking purposes.
2037) 
2038)     Returns:
2039)         The user input.
2040) 
2041)     """
Marco Ricci Fix typing issues in mypy s...

Marco Ricci authored 5 months ago

2042)     return cast(
2043)         str,
2044)         click.prompt(
2045)             'Passphrase',
2046)             default='',
2047)             hide_input=True,
2048)             show_default=False,
2049)             err=True,
2050)         ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2051)     )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2052) 
2053) 
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

2054) def _toml_key(*parts: str) -> str:
2055)     """Return a formatted TOML key, given its parts."""
Marco Ricci Fix formatting, some covera...

Marco Ricci authored 2 weeks ago

2056) 
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

2057)     def escape(string: str) -> str:
2058)         translated = string.translate({
2059)             0: r'\u0000',
2060)             1: r'\u0001',
2061)             2: r'\u0002',
2062)             3: r'\u0003',
2063)             4: r'\u0004',
2064)             5: r'\u0005',
2065)             6: r'\u0006',
2066)             7: r'\u0007',
2067)             8: r'\b',
2068)             9: r'\t',
2069)             10: r'\n',
2070)             11: r'\u000B',
2071)             12: r'\f',
2072)             13: r'\r',
2073)             14: r'\u000E',
2074)             15: r'\u000F',
2075)             ord('"'): r'\"',
2076)             ord('\\'): r'\\',
2077)             127: r'\u007F',
2078)         })
2079)         return f'"{translated}"' if translated != string else string
Marco Ricci Fix formatting, some covera...

Marco Ricci authored 2 weeks ago

2080) 
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

2081)     return '.'.join(map(escape, parts))
2082) 
2083) 
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

2084) class _ORIGIN(enum.Enum):
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

2085)     INTERACTIVE: str = 'interactive input'
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

2086) 
2087) 
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

2088) def _check_for_misleading_passphrase(
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

2089)     key: tuple[str, ...] | _ORIGIN,
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

2090)     value: dict[str, Any],
2091)     *,
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

2092)     main_config: dict[str, Any],
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

2093)     ctx: click.Context | None = None,
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

2094) ) -> None:
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

2095)     form_key = 'unicode-normalization-form'
2096)     default_form: str = main_config.get('vault', {}).get(
2097)         f'default-{form_key}', 'NFC'
2098)     )
2099)     form_dict: dict[str, dict] = main_config.get('vault', {}).get(form_key, {})
2100)     form: Any = (
2101)         default_form
2102)         if isinstance(key, _ORIGIN) or key == ('global',)
2103)         else form_dict.get(key[1], default_form)
2104)     )
2105)     config_key = (
2106)         _toml_key('vault', key[1], form_key)
2107)         if isinstance(key, tuple) and len(key) > 1 and key[1] in form_dict
2108)         else f'vault.default-{form_key}'
2109)     )
2110)     if form not in {'NFC', 'NFD', 'NFKC', 'NFKD'}:
2111)         msg = f'Invalid value {form!r} for config key {config_key}'
2112)         raise AssertionError(msg)
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2113)     logger = logging.getLogger(PROG_NAME)
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

2114)     formatted_key = (
2115)         key.value if isinstance(key, _ORIGIN) else _types.json_path(key)
2116)     )
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

2117)     if 'phrase' in value:
2118)         phrase = value['phrase']
2119)         if not unicodedata.is_normalized(form, phrase):
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2120)             logger.warning(
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

2121)                 (
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2122)                     'The %s passphrase is not %s-normalized.  Its '
2123)                     'serialization as a byte string may not be what you '
2124)                     'expect it to be, even if it *displays* correctly.  '
2125)                     'Please make sure to double-check any derived '
2126)                     'passphrases for unexpected results.'
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

2127)                 ),
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2128)                 formatted_key,
2129)                 form,
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

2130)                 stacklevel=2,
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

2131)                 extra={'color': ctx.color if ctx is not None else None},
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

2132)             )
2133) 
2134) 
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

2135) def _key_to_phrase(
2136)     key_: str | bytes | bytearray,
2137)     /,
2138)     *,
2139)     error_callback: Callable[..., NoReturn] = sys.exit,
2140) ) -> bytes | bytearray:
2141)     key = base64.standard_b64decode(key_)
2142)     try:
2143)         with ssh_agent.SSHAgentClient.ensure_agent_subcontext() as client:
2144)             try:
2145)                 return vault.Vault.phrase_from_key(key, conn=client)
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2146)             except ssh_agent.SSHAgentFailedError as exc:
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

2147)                 try:
2148)                     keylist = client.list_keys()
2149)                 except ssh_agent.SSHAgentFailedError:
2150)                     pass
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2151)                 except Exception as exc2:  # noqa: BLE001
2152)                     exc.__context__ = exc2
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

2153)                 else:
2154)                     if not any(  # pragma: no branch
2155)                         k == key for k, _ in keylist
2156)                     ):
2157)                         error_callback(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2158)                             _msg.TranslatedString(
2159)                                 _msg.ErrMsgTemplate.SSH_KEY_NOT_LOADED
2160)                             )
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

2161)                         )
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2162)                 error_callback(
2163)                     _msg.TranslatedString(
2164)                         _msg.ErrMsgTemplate.AGENT_REFUSED_SIGNATURE
2165)                     ),
2166)                     exc_info=exc,
2167)                 )
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

2168)     except KeyError:
2169)         error_callback(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2170)             _msg.TranslatedString(_msg.ErrMsgTemplate.NO_SSH_AGENT_FOUND)
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

2171)         )
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2172)     except NotImplementedError:
2173)         error_callback(_msg.TranslatedString(_msg.ErrMsgTemplate.NO_AF_UNIX))
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2174)     except OSError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2175)         error_callback(
2176)             _msg.TranslatedString(
2177)                 _msg.ErrMsgTemplate.CANNOT_CONNECT_TO_AGENT,
2178)                 error=exc.strerror,
2179)                 filename=exc.filename,
2180)             ).maybe_without_filename()
2181)         )
2182)     except RuntimeError as exc:
2183)         error_callback(
2184)             _msg.TranslatedString(_msg.ErrMsgTemplate.CANNOT_UNDERSTAND_AGENT),
2185)             exc_info=exc,
2186)         )
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

2187) 
2188) 
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

2189) def _print_config_as_sh_script(
2190)     config: _types.VaultConfig,
2191)     /,
2192)     *,
2193)     outfile: TextIO,
2194)     prog_name_list: Sequence[str],
2195) ) -> None:
2196)     service_keys = (
2197)         'length',
2198)         'repeat',
2199)         'lower',
2200)         'upper',
2201)         'number',
2202)         'space',
2203)         'dash',
2204)         'symbol',
2205)     )
2206)     print('#!/bin/sh -e', file=outfile)
2207)     print(file=outfile)
2208)     print(shlex.join([*prog_name_list, '--clear']), file=outfile)
2209)     sv_obj_pairs: list[
2210)         tuple[
2211)             str | None,
2212)             _types.VaultConfigGlobalSettings
2213)             | _types.VaultConfigServicesSettings,
2214)         ],
2215)     ] = list(config['services'].items())
2216)     if config.get('global', {}):
2217)         sv_obj_pairs.insert(0, (None, config['global']))
2218)     for sv, sv_obj in sv_obj_pairs:
2219)         this_service_keys = tuple(k for k in service_keys if k in sv_obj)
2220)         this_other_keys = tuple(k for k in sv_obj if k not in service_keys)
2221)         if this_other_keys:
2222)             other_sv_obj = {k: sv_obj[k] for k in this_other_keys}  # type: ignore[literal-required]
2223)             dumped_config = json.dumps(
2224)                 (
2225)                     {'services': {sv: other_sv_obj}}
2226)                     if sv is not None
2227)                     else {'global': other_sv_obj, 'services': {}}
2228)                 ),
2229)                 ensure_ascii=False,
2230)                 indent=None,
2231)             )
2232)             print(
2233)                 shlex.join([*prog_name_list, '--import', '-']) + " <<'HERE'",
2234)                 dumped_config,
2235)                 'HERE',
2236)                 sep='\n',
2237)                 file=outfile,
2238)             )
2239)         if not this_service_keys and not this_other_keys and sv:
2240)             dumped_config = json.dumps(
2241)                 {'services': {sv: {}}},
2242)                 ensure_ascii=False,
2243)                 indent=None,
2244)             )
2245)             print(
2246)                 shlex.join([*prog_name_list, '--import', '-']) + " <<'HERE'",
2247)                 dumped_config,
2248)                 'HERE',
2249)                 sep='\n',
2250)                 file=outfile,
2251)             )
2252)         elif this_service_keys:
2253)             tokens = [*prog_name_list, '--config']
2254)             for key in this_service_keys:
2255)                 tokens.extend([f'--{key}', str(sv_obj[key])])  # type: ignore[literal-required]
2256)             if sv is not None:
2257)                 tokens.extend(['--', sv])
2258)             print(shlex.join(tokens), file=outfile)
2259) 
2260) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2261) # Concrete option groups used by this command-line interface.
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2262) class PassphraseGenerationOption(OptionGroupOption):
2263)     """Passphrase generation options for the CLI."""
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2264) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2265)     option_group_name = _msg.TranslatedString(
2266)         _msg.Label.PASSPHRASE_GENERATION_LABEL
2267)     )
2268)     epilog = _msg.TranslatedString(
2269)         _msg.Label.PASSPHRASE_GENERATION_EPILOG,
2270)         metavar=_msg.TranslatedString(
2271)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2272)         ),
2273)     )
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2274) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2275) 
2276) class ConfigurationOption(OptionGroupOption):
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2277)     """Configuration options for the CLI."""
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2278) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2279)     option_group_name = _msg.TranslatedString(_msg.Label.CONFIGURATION_LABEL)
2280)     epilog = _msg.TranslatedString(_msg.Label.CONFIGURATION_EPILOG)
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2281) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2282) 
2283) class StorageManagementOption(OptionGroupOption):
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2284)     """Storage management options for the CLI."""
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2285) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2286)     option_group_name = _msg.TranslatedString(
2287)         _msg.Label.STORAGE_MANAGEMENT_LABEL
2288)     )
2289)     epilog = _msg.TranslatedString(
2290)         _msg.Label.STORAGE_MANAGEMENT_EPILOG,
2291)         metavar=_msg.TranslatedString(
2292)             _msg.Label.STORAGE_MANAGEMENT_METAVAR_PATH
2293)         ),
2294)     )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2295) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2296) 
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2297) class CompatibilityOption(OptionGroupOption):
2298)     """Compatibility and incompatibility options for the CLI."""
2299) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2300)     option_group_name = _msg.TranslatedString(
2301)         _msg.Label.COMPATIBILITY_OPTION_LABEL
2302)     )
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2303) 
2304) 
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2305) def _validate_occurrence_constraint(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2306)     ctx: click.Context,
2307)     param: click.Parameter,
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

2308)     value: Any,  # noqa: ANN401
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2309) ) -> int | None:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

2310)     """Check that the occurrence constraint is valid (int, 0 or larger).
2311) 
2312)     Args:
2313)         ctx: The `click` context.
2314)         param: The current command-line parameter.
2315)         value: The parameter value to be checked.
2316) 
2317)     Returns:
2318)         The parsed parameter value.
2319) 
2320)     Raises:
2321)         click.BadParameter: The parameter value is invalid.
2322) 
2323)     """
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2324)     del ctx  # Unused.
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

2325)     del param  # Unused.
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2326)     if value is None:
2327)         return value
2328)     if isinstance(value, int):
2329)         int_value = value
2330)     else:
2331)         try:
2332)             int_value = int(value, 10)
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2333)         except ValueError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2334)             raise click.BadParameter(_NOT_AN_INTEGER) from exc
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2335)     if int_value < 0:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2336)         raise click.BadParameter(_NOT_A_NONNEGATIVE_INTEGER)
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2337)     return int_value
2338) 
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2339) 
2340) def _validate_length(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2341)     ctx: click.Context,
2342)     param: click.Parameter,
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

2343)     value: Any,  # noqa: ANN401
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2344) ) -> int | None:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

2345)     """Check that the length is valid (int, 1 or larger).
2346) 
2347)     Args:
2348)         ctx: The `click` context.
2349)         param: The current command-line parameter.
2350)         value: The parameter value to be checked.
2351) 
2352)     Returns:
2353)         The parsed parameter value.
2354) 
2355)     Raises:
2356)         click.BadParameter: The parameter value is invalid.
2357) 
2358)     """
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2359)     del ctx  # Unused.
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

2360)     del param  # Unused.
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2361)     if value is None:
2362)         return value
2363)     if isinstance(value, int):
2364)         int_value = value
2365)     else:
2366)         try:
2367)             int_value = int(value, 10)
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2368)         except ValueError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2369)             raise click.BadParameter(_NOT_AN_INTEGER) from exc
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2370)     if int_value < 1:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2371)         raise click.BadParameter(_NOT_A_POSITIVE_INTEGER)
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2372)     return int_value
2373) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2374) 
2375) DEFAULT_NOTES_TEMPLATE = """\
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2376) # Enter notes below the line with the cut mark (ASCII scissors and
2377) # dashes).  Lines above the cut mark (such as this one) will be ignored.
2378) #
2379) # If you wish to clear the notes, leave everything beyond the cut mark
2380) # blank.  However, if you leave the *entire* file blank, also removing
2381) # the cut mark, then the edit is aborted, and the old notes contents are
2382) # retained.
2383) #
2384) # - - - - - >8 - - - - - >8 - - - - - >8 - - - - - >8 - - - - -
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2385) """
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2386) DEFAULT_NOTES_MARKER = '# - - - - - >8 - - - - -'
2387) 
2388) 
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

2389) @derivepassphrase.command(
2390)     'vault',
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2391)     context_settings={'help_option_names': ['-h', '--help']},
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2392)     cls=CommandWithHelpGroups,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2393)     help=(
2394)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_VAULT_01),
2395)         _msg.TranslatedString(
2396)             _msg.Label.DERIVEPASSPHRASE_VAULT_02,
2397)             service_metavar=_msg.TranslatedString(
2398)                 _msg.Label.VAULT_METAVAR_SERVICE
2399)             ),
2400)         ),
2401)     ),
2402)     epilog=(
2403)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_VAULT_EPILOG_01),
2404)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_VAULT_EPILOG_02),
2405)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2406) )
2407) @click.option(
2408)     '-p',
2409)     '--phrase',
2410)     'use_phrase',
2411)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2412)     help=_msg.TranslatedString(
2413)         _msg.Label.DERIVEPASSPHRASE_VAULT_PHRASE_HELP_TEXT
2414)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2415)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2416) )
2417) @click.option(
2418)     '-k',
2419)     '--key',
2420)     'use_key',
2421)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2422)     help=_msg.TranslatedString(
2423)         _msg.Label.DERIVEPASSPHRASE_VAULT_KEY_HELP_TEXT
2424)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2425)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2426) )
2427) @click.option(
2428)     '-l',
2429)     '--length',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2430)     metavar=_msg.TranslatedString(
2431)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2432)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2433)     callback=_validate_length,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2434)     help=_msg.TranslatedString(
2435)         _msg.Label.DERIVEPASSPHRASE_VAULT_LENGTH_HELP_TEXT,
2436)         metavar=_msg.TranslatedString(
2437)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2438)         ),
2439)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2440)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2441) )
2442) @click.option(
2443)     '-r',
2444)     '--repeat',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2445)     metavar=_msg.TranslatedString(
2446)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2447)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2448)     callback=_validate_occurrence_constraint,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2449)     help=_msg.TranslatedString(
2450)         _msg.Label.DERIVEPASSPHRASE_VAULT_REPEAT_HELP_TEXT,
2451)         metavar=_msg.TranslatedString(
2452)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2453)         ),
2454)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2455)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2456) )
2457) @click.option(
2458)     '--lower',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2459)     metavar=_msg.TranslatedString(
2460)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2461)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2462)     callback=_validate_occurrence_constraint,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2463)     help=_msg.TranslatedString(
2464)         _msg.Label.DERIVEPASSPHRASE_VAULT_LOWER_HELP_TEXT,
2465)         metavar=_msg.TranslatedString(
2466)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2467)         ),
2468)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2469)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2470) )
2471) @click.option(
2472)     '--upper',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2473)     metavar=_msg.TranslatedString(
2474)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2475)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2476)     callback=_validate_occurrence_constraint,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2477)     help=_msg.TranslatedString(
2478)         _msg.Label.DERIVEPASSPHRASE_VAULT_UPPER_HELP_TEXT,
2479)         metavar=_msg.TranslatedString(
2480)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2481)         ),
2482)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2483)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2484) )
2485) @click.option(
2486)     '--number',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2487)     metavar=_msg.TranslatedString(
2488)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2489)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2490)     callback=_validate_occurrence_constraint,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2491)     help=_msg.TranslatedString(
2492)         _msg.Label.DERIVEPASSPHRASE_VAULT_NUMBER_HELP_TEXT,
2493)         metavar=_msg.TranslatedString(
2494)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2495)         ),
2496)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2497)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2498) )
2499) @click.option(
2500)     '--space',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2501)     metavar=_msg.TranslatedString(
2502)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2503)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2504)     callback=_validate_occurrence_constraint,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2505)     help=_msg.TranslatedString(
2506)         _msg.Label.DERIVEPASSPHRASE_VAULT_SPACE_HELP_TEXT,
2507)         metavar=_msg.TranslatedString(
2508)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2509)         ),
2510)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2511)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2512) )
2513) @click.option(
2514)     '--dash',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2515)     metavar=_msg.TranslatedString(
2516)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2517)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2518)     callback=_validate_occurrence_constraint,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2519)     help=_msg.TranslatedString(
2520)         _msg.Label.DERIVEPASSPHRASE_VAULT_DASH_HELP_TEXT,
2521)         metavar=_msg.TranslatedString(
2522)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2523)         ),
2524)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2525)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2526) )
2527) @click.option(
2528)     '--symbol',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2529)     metavar=_msg.TranslatedString(
2530)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2531)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2532)     callback=_validate_occurrence_constraint,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2533)     help=_msg.TranslatedString(
2534)         _msg.Label.DERIVEPASSPHRASE_VAULT_SYMBOL_HELP_TEXT,
2535)         metavar=_msg.TranslatedString(
2536)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2537)         ),
2538)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2539)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2540) )
2541) @click.option(
2542)     '-n',
2543)     '--notes',
2544)     'edit_notes',
2545)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2546)     help=_msg.TranslatedString(
2547)         _msg.Label.DERIVEPASSPHRASE_VAULT_NOTES_HELP_TEXT,
2548)         service_metavar=_msg.TranslatedString(
2549)             _msg.Label.VAULT_METAVAR_SERVICE
2550)         ),
2551)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2552)     cls=ConfigurationOption,
2553) )
2554) @click.option(
2555)     '-c',
2556)     '--config',
2557)     'store_config_only',
2558)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2559)     help=_msg.TranslatedString(
2560)         _msg.Label.DERIVEPASSPHRASE_VAULT_CONFIG_HELP_TEXT,
2561)         service_metavar=_msg.TranslatedString(
2562)             _msg.Label.VAULT_METAVAR_SERVICE
2563)         ),
2564)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2565)     cls=ConfigurationOption,
2566) )
2567) @click.option(
2568)     '-x',
2569)     '--delete',
2570)     'delete_service_settings',
2571)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2572)     help=_msg.TranslatedString(
2573)         _msg.Label.DERIVEPASSPHRASE_VAULT_DELETE_HELP_TEXT,
2574)         service_metavar=_msg.TranslatedString(
2575)             _msg.Label.VAULT_METAVAR_SERVICE
2576)         ),
2577)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2578)     cls=ConfigurationOption,
2579) )
2580) @click.option(
2581)     '--delete-globals',
2582)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2583)     help=_msg.TranslatedString(
2584)         _msg.Label.DERIVEPASSPHRASE_VAULT_DELETE_GLOBALS_HELP_TEXT,
2585)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2586)     cls=ConfigurationOption,
2587) )
2588) @click.option(
2589)     '-X',
2590)     '--clear',
2591)     'clear_all_settings',
2592)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2593)     help=_msg.TranslatedString(
2594)         _msg.Label.DERIVEPASSPHRASE_VAULT_DELETE_ALL_HELP_TEXT,
2595)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2596)     cls=ConfigurationOption,
2597) )
2598) @click.option(
2599)     '-e',
2600)     '--export',
2601)     'export_settings',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2602)     metavar=_msg.TranslatedString(
2603)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2604)     ),
2605)     help=_msg.TranslatedString(
2606)         _msg.Label.DERIVEPASSPHRASE_VAULT_EXPORT_HELP_TEXT,
2607)         metavar=_msg.TranslatedString(
2608)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2609)         ),
2610)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2611)     cls=StorageManagementOption,
Marco Ricci Add shell completion suppor...

Marco Ricci authored 1 week ago

2612)     shell_complete=_shell_complete_path,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2613) )
2614) @click.option(
2615)     '-i',
2616)     '--import',
2617)     'import_settings',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2618)     metavar=_msg.TranslatedString(
2619)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2620)     ),
2621)     help=_msg.TranslatedString(
2622)         _msg.Label.DERIVEPASSPHRASE_VAULT_IMPORT_HELP_TEXT,
2623)         metavar=_msg.TranslatedString(
2624)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2625)         ),
2626)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2627)     cls=StorageManagementOption,
Marco Ricci Add shell completion suppor...

Marco Ricci authored 1 week ago

2628)     shell_complete=_shell_complete_path,
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2629) )
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2630) @click.option(
2631)     '--overwrite-existing/--merge-existing',
2632)     'overwrite_config',
2633)     default=False,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2634)     help=_msg.TranslatedString(
2635)         _msg.Label.DERIVEPASSPHRASE_VAULT_OVERWRITE_HELP_TEXT
2636)     ),
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2637)     cls=CompatibilityOption,
2638) )
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

2639) @click.option(
2640)     '--unset',
2641)     'unset_settings',
2642)     multiple=True,
2643)     type=click.Choice([
2644)         'phrase',
2645)         'key',
2646)         'length',
2647)         'repeat',
2648)         'lower',
2649)         'upper',
2650)         'number',
2651)         'space',
2652)         'dash',
2653)         'symbol',
2654)     ]),
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2655)     help=_msg.TranslatedString(
2656)         _msg.Label.DERIVEPASSPHRASE_VAULT_UNSET_HELP_TEXT
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

2657)     ),
2658)     cls=CompatibilityOption,
2659) )
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

2660) @click.option(
2661)     '--export-as',
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2662)     type=click.Choice(['json', 'sh']),
2663)     default='json',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2664)     help=_msg.TranslatedString(
2665)         _msg.Label.DERIVEPASSPHRASE_VAULT_EXPORT_AS_HELP_TEXT
2666)     ),
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

2667)     cls=CompatibilityOption,
2668) )
Marco Ricci Reimplement `--help` and `-...

Marco Ricci authored 1 week ago

2669) @version_option
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

2670) @color_forcing_pseudo_option
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2671) @standard_logging_options
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2672) @click.argument(
2673)     'service',
2674)     metavar=_msg.TranslatedString(_msg.Label.VAULT_METAVAR_SERVICE),
2675)     required=False,
2676)     default=None,
Marco Ricci Add shell completion suppor...

Marco Ricci authored 1 week ago

2677)     shell_complete=_shell_complete_service,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2678) )
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2679) @click.pass_context
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

2680) def derivepassphrase_vault(  # noqa: C901,PLR0912,PLR0913,PLR0914,PLR0915
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2681)     ctx: click.Context,
2682)     /,
2683)     *,
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2684)     service: str | None = None,
2685)     use_phrase: bool = False,
2686)     use_key: bool = False,
2687)     length: int | None = None,
2688)     repeat: int | None = None,
2689)     lower: int | None = None,
2690)     upper: int | None = None,
2691)     number: int | None = None,
2692)     space: int | None = None,
2693)     dash: int | None = None,
2694)     symbol: int | None = None,
2695)     edit_notes: bool = False,
2696)     store_config_only: bool = False,
2697)     delete_service_settings: bool = False,
2698)     delete_globals: bool = False,
2699)     clear_all_settings: bool = False,
2700)     export_settings: TextIO | pathlib.Path | os.PathLike[str] | None = None,
2701)     import_settings: TextIO | pathlib.Path | os.PathLike[str] | None = None,
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2702)     overwrite_config: bool = False,
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

2703)     unset_settings: Sequence[str] = (),
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

2704)     export_as: Literal['json', 'sh'] = 'json',
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2705) ) -> None:
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

2706)     """Derive a passphrase using the vault(1) derivation scheme.
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2707) 
2708)     This is a [`click`][CLICK]-powered command-line interface function,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2709)     and not intended for programmatic use.  See the
2710)     derivepassphrase-vault(1) manpage for full documentation of the
2711)     interface.  (See also [`click.testing.CliRunner`][] for controlled,
2712)     programmatic invocation.)
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2713) 
Marco Ricci Update all URLs to stable a...

Marco Ricci authored 3 months ago

2714)     [CLICK]: https://pypi.org/package/click/
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2715) 
2716)     Parameters:
2717)         ctx (click.Context):
2718)             The `click` context.
2719) 
2720)     Other Parameters:
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2721)         service:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2722)             A service name.  Required, unless operating on global
2723)             settings or importing/exporting settings.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2724)         use_phrase:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2725)             Command-line argument `-p`/`--phrase`.  If given, query the
2726)             user for a passphrase instead of an SSH key.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2727)         use_key:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2728)             Command-line argument `-k`/`--key`.  If given, query the
2729)             user for an SSH key instead of a passphrase.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2730)         length:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2731)             Command-line argument `-l`/`--length`.  Override the default
2732)             length of the generated passphrase.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2733)         repeat:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2734)             Command-line argument `-r`/`--repeat`.  Override the default
2735)             repetition limit if positive, or disable the repetition
2736)             limit if 0.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2737)         lower:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2738)             Command-line argument `--lower`.  Require a given amount of
2739)             ASCII lowercase characters if positive, else forbid ASCII
2740)             lowercase characters if 0.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2741)         upper:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2742)             Command-line argument `--upper`.  Same as `lower`, but for
2743)             ASCII uppercase characters.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2744)         number:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2745)             Command-line argument `--number`.  Same as `lower`, but for
2746)             ASCII digits.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2747)         space:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

2748)             Command-line argument `--space`.  Same as `lower`, but for
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2749)             the space character.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2750)         dash:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

2751)             Command-line argument `--dash`.  Same as `lower`, but for
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2752)             the hyphen-minus and underscore characters.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2753)         symbol:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

2754)             Command-line argument `--symbol`.  Same as `lower`, but for
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2755)             all other ASCII printable characters (except backquote).
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2756)         edit_notes:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2757)             Command-line argument `-n`/`--notes`.  If given, spawn an
2758)             editor to edit notes for `service`.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2759)         store_config_only:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2760)             Command-line argument `-c`/`--config`.  If given, saves the
2761)             other given settings (`--key`, ..., `--symbol`) to the
2762)             configuration file, either specifically for `service` or as
2763)             global settings.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2764)         delete_service_settings:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2765)             Command-line argument `-x`/`--delete`.  If given, removes
2766)             the settings for `service` from the configuration file.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2767)         delete_globals:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2768)             Command-line argument `--delete-globals`.  If given, removes
2769)             the global settings from the configuration file.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2770)         clear_all_settings:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2771)             Command-line argument `-X`/`--clear`.  If given, removes all
2772)             settings from the configuration file.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2773)         export_settings:
2774)             Command-line argument `-e`/`--export`.  If a file object,
2775)             then it must be open for writing and accept `str` inputs.
2776)             Otherwise, a filename to open for writing.  Using `-` for
2777)             standard output is supported.
2778)         import_settings:
2779)             Command-line argument `-i`/`--import`.  If a file object, it
2780)             must be open for reading and yield `str` values.  Otherwise,
2781)             a filename to open for reading.  Using `-` for standard
2782)             input is supported.
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2783)         overwrite_config:
2784)             Command-line arguments `--overwrite-existing` (True) and
2785)             `--merge-existing` (False).  Controls whether config saving
2786)             and config importing overwrite existing configurations, or
2787)             merge them section-wise instead.
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

2788)         unset_settings:
2789)             Command-line argument `--unset`.  If given together with
2790)             `--config`, unsets the specified settings (in addition to
2791)             any other changes requested).
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

2792)         export_as:
2793)             Command-line argument `--export-as`.  If given together with
2794)             `--export`, selects the format to export the current
2795)             configuration as: JSON ("json", default) or POSIX sh ("sh").
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2796) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2797)     """
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2798)     logger = logging.getLogger(PROG_NAME)
2799)     deprecation = logging.getLogger(PROG_NAME + '.deprecation')
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2800)     service_metavar = _msg.TranslatedString(_msg.Label.VAULT_METAVAR_SERVICE)
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2801)     options_in_group: dict[type[click.Option], list[click.Option]] = {}
2802)     params_by_str: dict[str, click.Parameter] = {}
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2803)     for param in ctx.command.params:
2804)         if isinstance(param, click.Option):
2805)             group: type[click.Option]
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

2806)             # Use match/case here once Python 3.9 becomes unsupported.
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2807)             if isinstance(param, PassphraseGenerationOption):
2808)                 group = PassphraseGenerationOption
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

2809)             elif isinstance(param, ConfigurationOption):
2810)                 group = ConfigurationOption
2811)             elif isinstance(param, StorageManagementOption):
2812)                 group = StorageManagementOption
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2813)             elif isinstance(param, LoggingOption):
2814)                 group = LoggingOption
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2815)             elif isinstance(param, CompatibilityOption):
2816)                 group = CompatibilityOption
Marco Ricci Add tests for help and vers...

Marco Ricci authored 1 week ago

2817)             elif isinstance(param, StandardOption):
Marco Ricci Reimplement `--help` and `-...

Marco Ricci authored 1 week ago

2818)                 group = StandardOption
Marco Ricci Fix coverage

Marco Ricci authored 1 week ago

2819)             elif isinstance(param, OptionGroupOption):  # pragma: no cover
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

2820)                 raise AssertionError(  # noqa: DOC501,TRY003,TRY004
2821)                     f'Unknown option group for {param!r}'  # noqa: EM102
2822)                 )
Marco Ricci Add tests for help and vers...

Marco Ricci authored 1 week ago

2823)             else:
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

2824)                 group = click.Option
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2825)             options_in_group.setdefault(group, []).append(param)
2826)         params_by_str[param.human_readable_name] = param
2827)         for name in param.opts + param.secondary_opts:
2828)             params_by_str[name] = param
2829) 
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2830)     @functools.cache
Marco Ricci Fix typing issues in mypy s...

Marco Ricci authored 5 months ago

2831)     def is_param_set(param: click.Parameter) -> bool:
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2832)         return bool(ctx.params.get(param.human_readable_name))
2833) 
Marco Ricci Make the mutually exclusive...

Marco Ricci authored 2 weeks ago

2834)     def option_name(param: click.Parameter | str) -> str:
2835)         # Annoyingly, `param.human_readable_name` contains the *function*
2836)         # parameter name, not the list of option names.  *Those* are
2837)         # stashed in the `.opts` and `.secondary_opts` attributes, which
2838)         # are visible in the `.to_info_dict()` output, but not otherwise
2839)         # documented.
2840)         param = params_by_str[param] if isinstance(param, str) else param
2841)         names = [param.human_readable_name, *param.opts, *param.secondary_opts]
2842)         option_names = [n for n in names if n.startswith('--')]
2843)         return min(option_names, key=len)
2844) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2845)     def check_incompatible_options(
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2846)         param1: click.Parameter | str,
2847)         param2: click.Parameter | str,
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2848)     ) -> None:
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2849)         param1 = params_by_str[param1] if isinstance(param1, str) else param1
2850)         param2 = params_by_str[param2] if isinstance(param2, str) else param2
2851)         if param1 == param2:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2852)             return
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2853)         if not is_param_set(param1):
2854)             return
2855)         if is_param_set(param2):
Marco Ricci Make the mutually exclusive...

Marco Ricci authored 2 weeks ago

2856)             param1_str = option_name(param1)
2857)             param2_str = option_name(param2)
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2858)             raise click.BadOptionUsage(
Marco Ricci Make the mutually exclusive...

Marco Ricci authored 2 weeks ago

2859)                 param1_str,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2860)                 str(
2861)                     _msg.TranslatedString(
2862)                         _msg.ErrMsgTemplate.PARAMS_MUTUALLY_EXCLUSIVE,
2863)                         param1=param1_str,
2864)                         param2=param2_str,
2865)                     )
2866)                 ),
Marco Ricci Make the mutually exclusive...

Marco Ricci authored 2 weeks ago

2867)                 ctx=ctx,
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2868)             )
2869)         return
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2870) 
Marco Ricci Force logging calls in erro...

Marco Ricci authored 1 week ago

2871)     def err(msg: Any, /, **kwargs: Any) -> NoReturn:  # noqa: ANN401
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2872)         stacklevel = kwargs.pop('stacklevel', 1)
2873)         stacklevel += 1
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

2874)         extra = kwargs.pop('extra', {})
2875)         extra.setdefault('color', ctx.color)
2876)         logger.error(msg, stacklevel=stacklevel, extra=extra, **kwargs)
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

2877)         ctx.exit(1)
2878) 
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

2879)     def get_config() -> _types.VaultConfig:
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2880)         try:
2881)             return _load_config()
2882)         except FileNotFoundError:
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

2883)             try:
2884)                 backup_config, exc = _migrate_and_load_old_config()
2885)             except FileNotFoundError:
2886)                 return {'services': {}}
Marco Ricci Make obtaining the compatib...

Marco Ricci authored 3 weeks ago

2887)             old_name = os.path.basename(
2888)                 _config_filename(subsystem='old settings.json')
2889)             )
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

2890)             new_name = os.path.basename(_config_filename(subsystem='vault'))
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2891)             deprecation.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2892)                 _msg.TranslatedString(
2893)                     _msg.WarnMsgTemplate.V01_STYLE_CONFIG,
2894)                     old=old_name,
2895)                     new=new_name,
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

2896)                 ),
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

2897)                 extra={'color': ctx.color},
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

2898)             )
2899)             if isinstance(exc, OSError):
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2900)                 logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2901)                     _msg.TranslatedString(
2902)                         _msg.WarnMsgTemplate.FAILED_TO_MIGRATE_CONFIG,
2903)                         path=new_name,
2904)                         error=exc.strerror,
2905)                         filename=exc.filename,
2906)                     ).maybe_without_filename(),
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

2907)                     extra={'color': ctx.color},
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

2908)                 )
2909)             else:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2910)                 deprecation.info(
2911)                     _msg.TranslatedString(
2912)                         _msg.InfoMsgTemplate.SUCCESSFULLY_MIGRATED,
2913)                         path=new_name,
2914)                     ),
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

2915)                     extra={'color': ctx.color},
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2916)                 )
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

2917)             return backup_config
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2918)         except OSError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2919)             err(
2920)                 _msg.TranslatedString(
2921)                     _msg.ErrMsgTemplate.CANNOT_LOAD_VAULT_SETTINGS,
2922)                     error=exc.strerror,
2923)                     filename=exc.filename,
2924)                 ).maybe_without_filename(),
2925)             )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2926)         except Exception as exc:  # noqa: BLE001
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2927)             err(
2928)                 _msg.TranslatedString(
2929)                     _msg.ErrMsgTemplate.CANNOT_LOAD_VAULT_SETTINGS,
2930)                     error=str(exc),
2931)                     filename=None,
2932)                 ).maybe_without_filename(),
2933)                 exc_info=exc,
2934)             )
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

2935) 
2936)     def put_config(config: _types.VaultConfig, /) -> None:
2937)         try:
2938)             _save_config(config)
Marco Ricci Document and handle other e...

Marco Ricci authored 4 months ago

2939)         except OSError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2940)             err(
2941)                 _msg.TranslatedString(
2942)                     _msg.ErrMsgTemplate.CANNOT_STORE_VAULT_SETTINGS,
2943)                     error=exc.strerror,
2944)                     filename=exc.filename,
2945)                 ).maybe_without_filename(),
2946)             )
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

2947)         except Exception as exc:  # noqa: BLE001
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2948)             err(
2949)                 _msg.TranslatedString(
2950)                     _msg.ErrMsgTemplate.CANNOT_STORE_VAULT_SETTINGS,
2951)                     error=str(exc),
2952)                     filename=None,
2953)                 ).maybe_without_filename(),
2954)                 exc_info=exc,
2955)             )
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2956) 
Marco Ricci Introduce a central user co...

Marco Ricci authored 3 weeks ago

2957)     def get_user_config() -> dict[str, Any]:
2958)         try:
2959)             return _load_user_config()
2960)         except FileNotFoundError:
2961)             return {}
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2962)         except OSError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2963)             err(
2964)                 _msg.TranslatedString(
2965)                     _msg.ErrMsgTemplate.CANNOT_LOAD_USER_CONFIG,
2966)                     error=exc.strerror,
2967)                     filename=exc.filename,
2968)                 ).maybe_without_filename(),
2969)             )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2970)         except Exception as exc:  # noqa: BLE001
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2971)             err(
2972)                 _msg.TranslatedString(
2973)                     _msg.ErrMsgTemplate.CANNOT_LOAD_USER_CONFIG,
2974)                     error=str(exc),
2975)                     filename=None,
2976)                 ).maybe_without_filename(),
2977)                 exc_info=exc,
2978)             )
Marco Ricci Introduce a central user co...

Marco Ricci authored 3 weeks ago

2979) 
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

2980)     configuration: _types.VaultConfig
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2981) 
2982)     check_incompatible_options('--phrase', '--key')
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2983)     for group in (ConfigurationOption, StorageManagementOption):
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2984)         for opt in options_in_group[group]:
2985)             if opt != params_by_str['--config']:
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2986)                 for other_opt in options_in_group[PassphraseGenerationOption]:
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2987)                     check_incompatible_options(opt, other_opt)
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2988) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2989)     for group in (ConfigurationOption, StorageManagementOption):
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2990)         for opt in options_in_group[group]:
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2991)             for other_opt in options_in_group[ConfigurationOption]:
2992)                 check_incompatible_options(opt, other_opt)
2993)             for other_opt in options_in_group[StorageManagementOption]:
2994)                 check_incompatible_options(opt, other_opt)
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2995)     sv_or_global_options = options_in_group[PassphraseGenerationOption]
Marco Ricci Correctly model vault globa...

Marco Ricci authored 2 months ago

2996)     for param in sv_or_global_options:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2997)         if is_param_set(param) and not (
Marco Ricci Fix check of empty service...

Marco Ricci authored 1 week ago

2998)             service is not None or is_param_set(params_by_str['--config'])
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2999)         ):
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3000)             err_msg = _msg.TranslatedString(
3001)                 _msg.ErrMsgTemplate.PARAMS_NEEDS_SERVICE_OR_CONFIG,
3002)                 param=param.opts[0],
3003)                 service_metavar=service_metavar,
3004)             )
3005)             raise click.UsageError(str(err_msg))  # noqa: DOC501
Marco Ricci Correctly model vault globa...

Marco Ricci authored 2 months ago

3006)     sv_options = [params_by_str['--notes'], params_by_str['--delete']]
3007)     for param in sv_options:
Marco Ricci Fix check of empty service...

Marco Ricci authored 1 week ago

3008)         if is_param_set(param) and not service is not None:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3009)             err_msg = _msg.TranslatedString(
3010)                 _msg.ErrMsgTemplate.PARAMS_NEEDS_SERVICE,
3011)                 param=param.opts[0],
3012)                 service_metavar=service_metavar,
3013)             )
3014)             raise click.UsageError(str(err_msg))
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3015)     no_sv_options = [
3016)         params_by_str['--delete-globals'],
3017)         params_by_str['--clear'],
3018)         *options_in_group[StorageManagementOption],
3019)     ]
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

3020)     for param in no_sv_options:
Marco Ricci Fix check of empty service...

Marco Ricci authored 1 week ago

3021)         if is_param_set(param) and service is not None:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3022)             err_msg = _msg.TranslatedString(
3023)                 _msg.ErrMsgTemplate.PARAMS_NO_SERVICE,
3024)                 param=param.opts[0],
3025)                 service_metavar=service_metavar,
3026)             )
3027)             raise click.UsageError(str(err_msg))
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3028) 
Marco Ricci Introduce a central user co...

Marco Ricci authored 3 weeks ago

3029)     user_config = get_user_config()
3030) 
Marco Ricci Warn the user upon supplyin...

Marco Ricci authored 2 months ago

3031)     if service == '':  # noqa: PLC1901
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

3032)         logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3033)             _msg.TranslatedString(
3034)                 _msg.WarnMsgTemplate.EMPTY_SERVICE_NOT_SUPPORTED,
3035)                 service_metavar=service_metavar,
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

3036)             ),
3037)             extra={'color': ctx.color},
Marco Ricci Warn the user upon supplyin...

Marco Ricci authored 2 months ago

3038)         )
3039) 
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3040)     if edit_notes:
3041)         assert service is not None
3042)         configuration = get_config()
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3043)         text = DEFAULT_NOTES_TEMPLATE + configuration['services'].get(
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

3044)             service, cast(_types.VaultConfigServicesSettings, {})
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3045)         ).get('notes', '')
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3046)         notes_value = click.edit(text=text)
3047)         if notes_value is not None:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

3048)             notes_lines = collections.deque(notes_value.splitlines(True))  # noqa: FBT003
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3049)             while notes_lines:
3050)                 line = notes_lines.popleft()
3051)                 if line.startswith(DEFAULT_NOTES_MARKER):
3052)                     notes_value = ''.join(notes_lines)
3053)                     break
3054)             else:
3055)                 if not notes_value.strip():
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3056)                     err(
3057)                         _msg.TranslatedString(
3058)                             _msg.ErrMsgTemplate.USER_ABORTED_EDIT
3059)                         )
3060)                     )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3061)             configuration['services'].setdefault(service, {})['notes'] = (
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3062)                 notes_value.strip('\n')
3063)             )
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

3064)             put_config(configuration)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3065)     elif delete_service_settings:
3066)         assert service is not None
3067)         configuration = get_config()
3068)         if service in configuration['services']:
3069)             del configuration['services'][service]
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

3070)             put_config(configuration)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3071)     elif delete_globals:
3072)         configuration = get_config()
3073)         if 'global' in configuration:
3074)             del configuration['global']
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

3075)             put_config(configuration)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3076)     elif clear_all_settings:
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

3077)         put_config({'services': {}})
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3078)     elif import_settings:
3079)         try:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

3080)             # TODO(the-13th-letter): keep track of auto-close; try
3081)             # os.dup if feasible
Marco Ricci Document handling of file o...

Marco Ricci authored 3 weeks ago

3082)             infile = cast(
3083)                 TextIO,
3084)                 (
3085)                     import_settings
3086)                     if hasattr(import_settings, 'close')
3087)                     else click.open_file(os.fspath(import_settings), 'rt')
3088)                 ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3089)             )
Marco Ricci Document handling of file o...

Marco Ricci authored 3 weeks ago

3090)             # Don't specifically catch TypeError or ValueError here if
3091)             # the passed-in fileobj is not a readable text stream.  This
3092)             # will never happen on the command-line (thanks to `click`),
3093)             # and for programmatic use, our caller may want accurate
3094)             # error information.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3095)             with infile:
3096)                 maybe_config = json.load(infile)
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

3097)         except json.JSONDecodeError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3098)             err(
3099)                 _msg.TranslatedString(
3100)                     _msg.ErrMsgTemplate.CANNOT_DECODEIMPORT_VAULT_SETTINGS,
3101)                     error=exc,
3102)                 )
3103)             )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

3104)         except OSError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3105)             err(
3106)                 _msg.TranslatedString(
3107)                     _msg.ErrMsgTemplate.CANNOT_IMPORT_VAULT_SETTINGS,
3108)                     error=exc.strerror,
3109)                     filename=exc.filename,
3110)                 ).maybe_without_filename()
3111)             )
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

3112)         cleaned = _types.clean_up_falsy_vault_config_values(maybe_config)
3113)         if not _types.is_vault_config(maybe_config):
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3114)             err(
3115)                 _msg.TranslatedString(
3116)                     _msg.ErrMsgTemplate.CANNOT_IMPORT_VAULT_SETTINGS,
3117)                     error=_msg.TranslatedString(
3118)                         _msg.ErrMsgTemplate.INVALID_VAULT_CONFIG,
3119)                         config=maybe_config,
3120)                     ),
3121)                     filename=None,
3122)                 ).maybe_without_filename()
3123)             )
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

3124)         assert cleaned is not None
3125)         for step in cleaned:
3126)             # These are never fatal errors, because the semantics of
3127)             # vault upon encountering these settings are ill-specified,
3128)             # but not ill-defined.
3129)             if step.action == 'replace':
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

3130)                 logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3131)                     _msg.TranslatedString(
3132)                         _msg.WarnMsgTemplate.STEP_REPLACE_INVALID_VALUE,
3133)                         old=json.dumps(step.old_value),
3134)                         path=_types.json_path(step.path),
3135)                         new=json.dumps(step.new_value),
3136)                     ),
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

3137)                     extra={'color': ctx.color},
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

3138)                 )
3139)             else:
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

3140)                 logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3141)                     _msg.TranslatedString(
3142)                         _msg.WarnMsgTemplate.STEP_REMOVE_INEFFECTIVE_VALUE,
3143)                         path=_types.json_path(step.path),
3144)                         old=json.dumps(step.old_value),
3145)                     ),
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

3146)                     extra={'color': ctx.color},
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

3147)                 )
Marco Ricci Warn the user upon supplyin...

Marco Ricci authored 2 months ago

3148)         if '' in maybe_config['services']:
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

3149)             logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3150)                 _msg.TranslatedString(
3151)                     _msg.WarnMsgTemplate.EMPTY_SERVICE_SETTINGS_INACCESSIBLE,
3152)                     service_metavar=service_metavar,
3153)                     PROG_NAME=PROG_NAME,
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

3154)                 ),
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

3155)                 extra={'color': ctx.color},
Marco Ricci Warn the user upon supplyin...

Marco Ricci authored 2 months ago

3156)             )
Marco Ricci Consolidate shell completio...

Marco Ricci authored 2 days ago

3157)         for service_name in sorted(maybe_config['services'].keys()):
3158)             if not _is_completable_item(service_name):
3159)                 logger.warning(
3160)                     _msg.TranslatedString(
3161)                         _msg.WarnMsgTemplate.SERVICE_NAME_INCOMPLETABLE,
3162)                         service=service_name,
3163)                     ),
3164)                     extra={'color': ctx.color},
3165)                 )
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

3166)         try:
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

3167)             _check_for_misleading_passphrase(
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

3168)                 ('global',),
3169)                 cast(dict[str, Any], maybe_config.get('global', {})),
3170)                 main_config=user_config,
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

3171)                 ctx=ctx,
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

3172)             )
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

3173)             for key, value in maybe_config['services'].items():
3174)                 _check_for_misleading_passphrase(
3175)                     ('services', key),
3176)                     cast(dict[str, Any], value),
3177)                     main_config=user_config,
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

3178)                     ctx=ctx,
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

3179)                 )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

3180)         except AssertionError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3181)             err(
3182)                 _msg.TranslatedString(
3183)                     _msg.ErrMsgTemplate.INVALID_USER_CONFIG,
3184)                     error=exc,
3185)                     filename=None,
3186)                 ).maybe_without_filename(),
3187)             )
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 2 weeks ago

3188)         global_obj = maybe_config.get('global', {})
3189)         has_key = _types.js_truthiness(global_obj.get('key'))
3190)         has_phrase = _types.js_truthiness(global_obj.get('phrase'))
3191)         if has_key and has_phrase:
3192)             logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3193)                 _msg.TranslatedString(
3194)                     _msg.WarnMsgTemplate.GLOBAL_PASSPHRASE_INEFFECTIVE,
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

3195)                 ),
3196)                 extra={'color': ctx.color},
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 2 weeks ago

3197)             )
3198)         for service_name, service_obj in maybe_config['services'].items():
3199)             has_key = _types.js_truthiness(
3200)                 service_obj.get('key')
3201)             ) or _types.js_truthiness(global_obj.get('key'))
3202)             has_phrase = _types.js_truthiness(
3203)                 service_obj.get('phrase')
3204)             ) or _types.js_truthiness(global_obj.get('phrase'))
3205)             if has_key and has_phrase:
3206)                 logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3207)                     _msg.TranslatedString(
3208)                         _msg.WarnMsgTemplate.SERVICE_PASSPHRASE_INEFFECTIVE,
3209)                         service=json.dumps(service_name),
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 2 weeks ago

3210)                     ),
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

3211)                     extra={'color': ctx.color},
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 2 weeks ago

3212)                 )
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

3213)         if overwrite_config:
3214)             put_config(maybe_config)
3215)         else:
3216)             configuration = get_config()
3217)             merged_config: collections.ChainMap[str, Any] = (
3218)                 collections.ChainMap(
3219)                     {
3220)                         'services': collections.ChainMap(
3221)                             maybe_config['services'],
3222)                             configuration['services'],
3223)                         ),
3224)                     },
3225)                     {'global': maybe_config['global']}
3226)                     if 'global' in maybe_config
3227)                     else {},
3228)                     {'global': configuration['global']}
3229)                     if 'global' in configuration
3230)                     else {},
3231)                 )
3232)             )
3233)             new_config: Any = {
3234)                 k: dict(v) if isinstance(v, collections.ChainMap) else v
3235)                 for k, v in sorted(merged_config.items())
3236)             }
3237)             assert _types.is_vault_config(new_config)
3238)             put_config(new_config)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3239)     elif export_settings:
3240)         configuration = get_config()
3241)         try:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

3242)             # TODO(the-13th-letter): keep track of auto-close; try
3243)             # os.dup if feasible
Marco Ricci Document handling of file o...

Marco Ricci authored 3 weeks ago

3244)             outfile = cast(
3245)                 TextIO,
3246)                 (
3247)                     export_settings
3248)                     if hasattr(export_settings, 'close')
3249)                     else click.open_file(os.fspath(export_settings), 'wt')
3250)                 ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3251)             )
Marco Ricci Document handling of file o...

Marco Ricci authored 3 weeks ago

3252)             # Don't specifically catch TypeError or ValueError here if
3253)             # the passed-in fileobj is not a writable text stream.  This
3254)             # will never happen on the command-line (thanks to `click`),
3255)             # and for programmatic use, our caller may want accurate
3256)             # error information.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3257)             with outfile:
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

3258)                 if export_as == 'sh':
3259)                     this_ctx = ctx
3260)                     prog_name_pieces = collections.deque([
3261)                         this_ctx.info_name or 'vault',
3262)                     ])
3263)                     while (
3264)                         this_ctx.parent is not None
3265)                         and this_ctx.parent.info_name is not None
3266)                     ):
3267)                         prog_name_pieces.appendleft(this_ctx.parent.info_name)
3268)                         this_ctx = this_ctx.parent
3269)                     _print_config_as_sh_script(
3270)                         configuration,
3271)                         outfile=outfile,
3272)                         prog_name_list=prog_name_pieces,
3273)                     )
3274)                 else:
3275)                     json.dump(configuration, outfile)
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

3276)         except OSError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3277)             err(
3278)                 _msg.TranslatedString(
3279)                     _msg.ErrMsgTemplate.CANNOT_EXPORT_VAULT_SETTINGS,
3280)                     error=exc.strerror,
3281)                     filename=exc.filename,
3282)                 ).maybe_without_filename(),
3283)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3284)     else:
3285)         configuration = get_config()
3286)         # This block could be type checked more stringently, but this
3287)         # would probably involve a lot of code repetition.  Since we
3288)         # have a type guarding function anyway, assert that we didn't
3289)         # make any mistakes at the end instead.
3290)         global_keys = {'key', 'phrase'}
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3291)         service_keys = {
3292)             'key',
3293)             'phrase',
3294)             'length',
3295)             'repeat',
3296)             'lower',
3297)             'upper',
3298)             'number',
3299)             'space',
3300)             'dash',
3301)             'symbol',
3302)         }
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3303)         settings: collections.ChainMap[str, Any] = collections.ChainMap(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3304)             {
3305)                 k: v
3306)                 for k, v in locals().items()
3307)                 if k in service_keys and v is not None
3308)             },
3309)             cast(
3310)                 dict[str, Any],
Marco Ricci Fix check of empty service...

Marco Ricci authored 1 week ago

3311)                 configuration['services'].get(service, {}) if service else {},
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3312)             ),
3313)             cast(dict[str, Any], configuration.get('global', {})),
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3314)         )
Marco Ricci Fix check of empty service...

Marco Ricci authored 1 week ago

3315)         if not store_config_only and not service:
3316)             err_msg = _msg.TranslatedString(
3317)                 _msg.ErrMsgTemplate.SERVICE_REQUIRED,
3318)                 service_metavar=_msg.TranslatedString(
3319)                     _msg.Label.VAULT_METAVAR_SERVICE
3320)                 ),
3321)             )
3322)             raise click.UsageError(str(err_msg))
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3323)         if use_key:
3324)             try:
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

3325)                 key = base64.standard_b64encode(
3326)                     _select_ssh_key(ctx=ctx)
3327)                 ).decode('ASCII')
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3328)             except IndexError:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3329)                 err(
3330)                     _msg.TranslatedString(
3331)                         _msg.ErrMsgTemplate.USER_ABORTED_SSH_KEY_SELECTION
3332)                     ),
3333)                 )
Marco Ricci Document and handle other e...

Marco Ricci authored 4 months ago

3334)             except KeyError:
Marco Ricci Fail gracefully if UNIX dom...

Marco Ricci authored 3 months ago

3335)                 err(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3336)                     _msg.TranslatedString(
3337)                         _msg.ErrMsgTemplate.NO_SSH_AGENT_FOUND
3338)                     ),
3339)                 )
3340)             except LookupError:
3341)                 err(
3342)                     _msg.TranslatedString(
3343)                         _msg.ErrMsgTemplate.NO_SUITABLE_SSH_KEYS,
3344)                         PROG_NAME=PROG_NAME,
3345)                     )
Marco Ricci Fail gracefully if UNIX dom...

Marco Ricci authored 3 months ago

3346)                 )
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3347)             except NotImplementedError:
3348)                 err(_msg.TranslatedString(_msg.ErrMsgTemplate.NO_AF_UNIX))
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

3349)             except OSError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3350)                 err(
3351)                     _msg.TranslatedString(
3352)                         _msg.ErrMsgTemplate.CANNOT_CONNECT_TO_AGENT,
3353)                         error=exc.strerror,
3354)                         filename=exc.filename,
3355)                     ).maybe_without_filename(),
3356)                 )
3357)             except ssh_agent.SSHAgentFailedError as exc:
3358)                 err(
3359)                     _msg.TranslatedString(
3360)                         _msg.ErrMsgTemplate.AGENT_REFUSED_LIST_KEYS
3361)                     ),
3362)                     exc_info=exc,
3363)                 )
3364)             except RuntimeError as exc:
3365)                 err(
3366)                     _msg.TranslatedString(
3367)                         _msg.ErrMsgTemplate.CANNOT_UNDERSTAND_AGENT
3368)                     ),
3369)                     exc_info=exc,
3370)                 )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3371)         elif use_phrase:
3372)             maybe_phrase = _prompt_for_passphrase()
3373)             if not maybe_phrase:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3374)                 err(
3375)                     _msg.TranslatedString(
3376)                         _msg.ErrMsgTemplate.USER_ABORTED_PASSPHRASE
3377)                     )
3378)                 )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3379)             else:
3380)                 phrase = maybe_phrase
3381)         if store_config_only:
3382)             view: collections.ChainMap[str, Any]
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3383)             view = (
3384)                 collections.ChainMap(*settings.maps[:2])
3385)                 if service
Marco Ricci Fix missing consideration o...

Marco Ricci authored 2 months ago

3386)                 else collections.ChainMap(settings.maps[0], settings.maps[2])
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3387)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3388)             if use_key:
3389)                 view['key'] = key
3390)             elif use_phrase:
Marco Ricci Fix missing consideration o...

Marco Ricci authored 2 months ago

3391)                 view['phrase'] = phrase
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

3392)                 try:
3393)                     _check_for_misleading_passphrase(
3394)                         ('services', service) if service else ('global',),
3395)                         {'phrase': phrase},
3396)                         main_config=user_config,
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

3397)                         ctx=ctx,
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

3398)                     )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

3399)                 except AssertionError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3400)                     err(
3401)                         _msg.TranslatedString(
3402)                             _msg.ErrMsgTemplate.INVALID_USER_CONFIG,
3403)                             error=exc,
3404)                             filename=None,
3405)                         ).maybe_without_filename(),
3406)                     )
Marco Ricci Fix missing consideration o...

Marco Ricci authored 2 months ago

3407)                 if 'key' in settings:
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 2 weeks ago

3408)                     if service:
Marco Ricci Consolidate and slightly si...

Marco Ricci authored 2 days ago

3409)                         w_msg = _msg.TranslatedString(
3410)                             _msg.WarnMsgTemplate.SERVICE_PASSPHRASE_INEFFECTIVE,
3411)                             service=json.dumps(service),
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 2 weeks ago

3412)                         )
3413)                     else:
Marco Ricci Consolidate and slightly si...

Marco Ricci authored 2 days ago

3414)                         w_msg = _msg.TranslatedString(
3415)                             _msg.WarnMsgTemplate.GLOBAL_PASSPHRASE_INEFFECTIVE
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 2 weeks ago

3416)                         )
Marco Ricci Consolidate and slightly si...

Marco Ricci authored 2 days ago

3417)                     logger.warning(w_msg, extra={'color': ctx.color})
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

3418)             if not view.maps[0] and not unset_settings:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

3419)                 settings_type = 'service' if service else 'global'
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3420)                 err_msg = _msg.TranslatedString(
3421)                     _msg.ErrMsgTemplate.CANNOT_UPDATE_SETTINGS_NO_SETTINGS,
3422)                     settings_type=settings_type,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3423)                 )
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3424)                 raise click.UsageError(str(err_msg))
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

3425)             for setting in unset_settings:
3426)                 if setting in view.maps[0]:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3427)                     err_msg = _msg.TranslatedString(
3428)                         _msg.ErrMsgTemplate.SET_AND_UNSET_SAME_SETTING,
3429)                         setting=setting,
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

3430)                     )
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3431)                     raise click.UsageError(str(err_msg))
Marco Ricci Consolidate shell completio...

Marco Ricci authored 2 days ago

3432)             if not _is_completable_item(service):
3433)                 logger.warning(
3434)                     _msg.TranslatedString(
3435)                         _msg.WarnMsgTemplate.SERVICE_NAME_INCOMPLETABLE,
3436)                         service=service,
3437)                     ),
3438)                     extra={'color': ctx.color},
3439)                 )
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

3440)             subtree: dict[str, Any] = (
3441)                 configuration['services'].setdefault(service, {})  # type: ignore[assignment]
3442)                 if service
3443)                 else configuration.setdefault('global', {})
3444)             )
3445)             if overwrite_config:
3446)                 subtree.clear()
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

3447)             else:
3448)                 for setting in unset_settings:
3449)                     subtree.pop(setting, None)
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

3450)             subtree.update(view)
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

3451)             assert _types.is_vault_config(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3452)                 configuration
Marco Ricci Fix error message capitaliz...

Marco Ricci authored 4 months ago

3453)             ), f'Invalid vault configuration: {configuration!r}'
Marco Ricci Fix error bubbling in outda...

Marco Ricci authored 4 months ago

3454)             put_config(configuration)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3455)         else:
Marco Ricci Fix check of empty service...

Marco Ricci authored 1 week ago

3456)             assert service is not None
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3457)             kwargs: dict[str, Any] = {
3458)                 k: v
3459)                 for k, v in settings.items()
3460)                 if k in service_keys and v is not None
3461)             }
3462) 
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

3463)             if use_phrase:
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

3464)                 try:
3465)                     _check_for_misleading_passphrase(
3466)                         _ORIGIN.INTERACTIVE,
3467)                         {'phrase': phrase},
3468)                         main_config=user_config,
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

3469)                         ctx=ctx,
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

3470)                     )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

3471)                 except AssertionError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3472)                     err(
3473)                         _msg.TranslatedString(
3474)                             _msg.ErrMsgTemplate.INVALID_USER_CONFIG,
3475)                             error=exc,
3476)                             filename=None,
3477)                         ).maybe_without_filename(),
3478)                     )
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

3479) 
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3480)             # If either --key or --phrase are given, use that setting.
3481)             # Otherwise, if both key and phrase are set in the config,
Marco Ricci Align behavior with vault c...

Marco Ricci authored 3 months ago

3482)             # use the key.  Otherwise, if only one of key and phrase is
3483)             # set in the config, use that one.  In all these above
3484)             # cases, set the phrase via vault.Vault.phrase_from_key if
3485)             # a key is given.  Finally, if nothing is set, error out.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3486)             if use_key or use_phrase:
Marco Ricci Fix formatting, some covera...

Marco Ricci authored 2 weeks ago

3487)                 kwargs['phrase'] = (
3488)                     _key_to_phrase(key, error_callback=err)
3489)                     if use_key
3490)                     else phrase
3491)                 )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3492)             elif kwargs.get('key'):
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

3493)                 kwargs['phrase'] = _key_to_phrase(
3494)                     kwargs['key'], error_callback=err
3495)                 )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3496)             elif kwargs.get('phrase'):
3497)                 pass
3498)             else:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3499)                 err_msg = _msg.TranslatedString(
3500)                     _msg.ErrMsgTemplate.NO_KEY_OR_PHRASE
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3501)                 )
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3502)                 raise click.UsageError(str(err_msg))
Marco Ricci Avoid crashing when overrid...

Marco Ricci authored 5 months ago

3503)             kwargs.pop('key', '')
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 5 months ago

3504)             result = vault.Vault(**kwargs).generate(service)
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

3505)             click.echo(result.decode('ASCII'), color=ctx.color)