220d71df817f2662308efab15e98f138fd6dde18
Marco Ricci Change the author e-mail ad...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

2) #
3) # SPDX-License-Identifier: MIT
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 Fix style issues with ruff...

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 5 months ago

40)     assert_never,
41) )
42) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 5 months ago

59)         Sequence,
60)     )
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

78) 
79) 
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

188)         parts = [
189)             ''.join(
190)                 prefix + level_indicator + line
191)                 for line in preliminary_result.splitlines(True)  # noqa: FBT003
192)             )
193)         ]
194)         if record.exc_info:
195)             parts.append(self.formatException(record.exc_info) + '\n')
196)         return ''.join(parts)
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 month ago

365)     ctx: click.Context,
366)     /,
367)     param: click.Parameter | None = None,
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 month ago

375) 
376)     """
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

377)     # Note: If multiple options use this callback, then we will be
378)     # called multiple times.  Ensure the runs are idempotent.
379)     if param is None or value is None or ctx.resilient_parsing:
380)         return
381)     StandardCLILogging.cli_handler.setLevel(value)
382)     logging.getLogger(StandardCLILogging.package_name).setLevel(value)
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

383) 
384) 
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

408)     """"""
409) 
410)     def __init__(self, *args: Any, **kwargs: Any) -> None:  # noqa: ANN401
411)         if self.__class__ == __class__:  # type: ignore[name-defined]
412)             raise NotImplementedError
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

424) 
425) 
Marco Ricci Reimplement `--help` and `-...

Marco Ricci authored 1 week ago

426) class StandardOption(OptionGroupOption):
427)     pass
428) 
429) 
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

440) 
441)     [CLICK_ISSUE]: https://github.com/pallets/click/issues/373#issuecomment-515293746
442) 
443)     """
444) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

795)         Args:
796)             ctx:
797)                 The click context.
798)             formatter:
799)                 The formatter for the `--help` listing.
800) 
801)         """
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

821)         if default_group_name in help_records:  # pragma: no branch
822)             default_group = help_records.pop(default_group_name)
823)             default_group_label = (
824)                 _msg.Label.OTHER_OPTIONS_LABEL
825)                 if len(default_group) > 1
826)                 else _msg.Label.OPTIONS_LABEL
827)             )
828)             default_group_name = self._text(
829)                 _msg.TranslatedString(default_group_label)
830)             )
831)             help_records[default_group_name] = default_group
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

832)         for group_name, records in help_records.items():
833)             with formatter.section(group_name):
834)                 formatter.write_dl(records)
835)             epilog = inspect.cleandoc(epilogs.get(group_name, ''))
836)             if epilog:
837)                 formatter.write_paragraph()
838)                 with formatter.indentation():
839)                     formatter.write_text(epilog)
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

986) 
987) 
Marco Ricci Reimplement `--help` and `-...

Marco Ricci authored 1 week ago

988) def version_option_callback(
989)     ctx: click.Context,
990)     param: click.Parameter,
991)     value: bool,  # noqa: FBT001
Marco Ricci Fix coverage

Marco Ricci authored 1 week ago

992) ) -> None:  # pragma: no cover
Marco Ricci Reimplement `--help` and `-...

Marco Ricci authored 1 week ago

993)     del param
994)     if value and not ctx.resilient_parsing:
995)         click.echo(
996)             str(
997)                 _msg.TranslatedString(
998)                     _msg.Label.VERSION_INFO_TEXT,
999)                     PROG_NAME=PROG_NAME,
1000)                     __version__=__version__,
1001)                 )
1002)             ),
1003)         )
1004)         ctx.exit()
1005) 
1006) 
1007) def version_option(f: Callable[P, R]) -> Callable[P, R]:
1008)     return click.option(
1009)         '--version',
1010)         is_flag=True,
1011)         is_eager=True,
1012)         expose_value=False,
1013)         callback=version_option_callback,
1014)         cls=StandardOption,
1015)         help=_msg.TranslatedString(_msg.Label.VERSION_OPTION_HELP_TEXT),
1016)     )(f)
1017) 
1018) 
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1019) class LoggingOption(OptionGroupOption):
1020)     """Logging options for the CLI."""
1021) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

1023)     epilog = ''
1024) 
1025) 
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

1026) debug_option = click.option(
1027)     '--debug',
1028)     'logging_level',
1029)     is_flag=True,
1030)     flag_value=logging.DEBUG,
1031)     expose_value=False,
1032)     callback=adjust_logging_level,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

1034)     cls=LoggingOption,
1035) )
1036) verbose_option = click.option(
1037)     '-v',
1038)     '--verbose',
1039)     'logging_level',
1040)     is_flag=True,
1041)     flag_value=logging.INFO,
1042)     expose_value=False,
1043)     callback=adjust_logging_level,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

1045)     cls=LoggingOption,
1046) )
1047) quiet_option = click.option(
1048)     '-q',
1049)     '--quiet',
1050)     'logging_level',
1051)     is_flag=True,
1052)     flag_value=logging.ERROR,
1053)     expose_value=False,
1054)     callback=adjust_logging_level,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

1056)     cls=LoggingOption,
1057) )
1058) 
1059) 
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 month ago

1066) 
1067)     Args:
1068)         f: A callable to decorate.
1069) 
1070)     Returns:
1071)         The decorated callable.
1072) 
1073)     """
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 month ago

1075) 
1076) 
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1077) # Top-level
1078) # =========
1079) 
1080) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

1082)     """A helper class to implement the default-to-"vault"-subcommand behavior.
1083) 
1084)     Modifies internal [`click.MultiCommand`][] methods, and thus is both
1085)     an implementation detail and a kludge.
1086) 
1087)     """
1088) 
1089)     def resolve_command(
1090)         self, ctx: click.Context, args: list[str]
1091)     ) -> tuple[str | None, click.Command | None, list[str]]:
1092)         """Resolve a command, but default to "vault" instead of erroring out.
1093) 
1094)         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

1095)         untouched since at least click 3.2.  Subject to the following
1096)         license (3-clause BSD license):
1097) 
1098)             Copyright 2024 Pallets
1099) 
1100)             Redistribution and use in source and binary forms, with or
1101)             without modification, are permitted provided that the following
1102)             conditions are met:
1103) 
1104)              1. Redistributions of source code must retain the above
1105)                 copyright notice, this list of conditions and the following
1106)                 disclaimer.
1107) 
1108)              2. Redistributions in binary form must reproduce the above
1109)                 copyright notice, this list of conditions and the following
1110)                 disclaimer in the documentation and/or other materials
1111)                 provided with the distribution.
1112) 
1113)              3. Neither the name of the copyright holder nor the names of
1114)                 its contributors may be used to endorse or promote products
1115)                 derived from this software without specific prior written
1116)                 permission.
1117) 
1118)             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
1119)             CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
1120)             INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1121)             MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1122)             DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
1123)             CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1124)             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1125)             LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
1126)             USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
1127)             AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1128)             LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
1129)             IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
1130)             THE POSSIBILITY OF SUCH DAMAGE.
1131) 
1132)         Modifications to this routine are marked with "modifications for
1133)         derivepassphrase".  Furthermore, all "pragma" and "noqa" comments
1134)         are also modifications for derivepassphrase.
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1135) 
1136)         """
1137)         cmd_name = click.utils.make_str(args[0])
1138) 
1139)         # Get the command
1140)         cmd = self.get_command(ctx, cmd_name)
1141) 
1142)         # If we can't find the command but there is a normalization
1143)         # function available, we try with that one.
1144)         if (  # pragma: no cover
1145)             cmd is None and ctx.token_normalize_func is not None
1146)         ):
1147)             cmd_name = ctx.token_normalize_func(cmd_name)
1148)             cmd = self.get_command(ctx, cmd_name)
1149) 
1150)         # If we don't find the command we want to show an error message
1151)         # to the user that it was not provided.  However, there is
1152)         # something else we should do: if the first argument looks like
1153)         # an option we want to kick off parsing again for arguments to
1154)         # resolve things like --help which now should go to the main
1155)         # place.
1156)         if cmd is None and not ctx.resilient_parsing:
1157)             if click.parser.split_opt(cmd_name)[0]:
1158)                 self.parse_args(ctx, ctx.args)
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1159)             ####
1160)             # BEGIN modifications for derivepassphrase
1161)             #
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

1166)                 _msg.TranslatedString(
1167)                     _msg.WarnMsgTemplate.V10_SUBCOMMAND_REQUIRED
1168)                 )
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1169)             )
1170)             cmd_name = 'vault'
1171)             cmd = self.get_command(ctx, cmd_name)
1172)             assert cmd is not None, 'Mandatory subcommand "vault" missing!'
1173)             args = [cmd_name, *args]
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1174)             #
1175)             # END modifications for derivepassphrase
1176)             ####
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

1180) class _TopLevelCLIEntryPoint(_DefaultToVaultGroup):
1181)     """A minor variation of _DefaultToVaultGroup for the top-level command.
1182) 
1183)     When called as a function, this sets up the environment properly
1184)     before invoking the actual callbacks.  Currently, this means setting
1185)     up the logging subsystem and the delegation of Python warnings to
1186)     the logging subsystem.
1187) 
1188)     The environment setup can be bypassed by calling the `.main` method
1189)     directly.
1190) 
1191)     """
1192) 
1193)     def __call__(  # pragma: no cover
1194)         self,
1195)         *args: Any,  # noqa: ANN401
1196)         **kwargs: Any,  # noqa: ANN401
1197)     ) -> Any:  # noqa: ANN401
1198)         """"""  # noqa: D419
1199)         # Coverage testing is done with the `click.testing` module,
1200)         # which does not use the `__call__` shortcut.  So it is normal
1201)         # that this function is never called, and thus should be
1202)         # excluded from coverage.
1203)         with (
1204)             StandardCLILogging.ensure_standard_logging(),
1205)             StandardCLILogging.ensure_standard_warnings_logging(),
1206)         ):
1207)             return self.main(*args, **kwargs)
1208) 
1209) 
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 months ago

1211)     context_settings={
1212)         'help_option_names': ['-h', '--help'],
1213)         'ignore_unknown_options': True,
1214)         'allow_interspersed_args': False,
1215)     },
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

1219)     help=(
1220)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_01),
1221)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_02),
1222)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_03),
1223)     ),
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

1225) @version_option
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 months ago

1229)     """Derive a strong passphrase, deterministically, from a master secret.
1230) 
1231)     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

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

Marco Ricci authored 3 months ago

1234)     [`click.testing.CliRunner`][] for controlled, programmatic
1235)     invocation.)
1236) 
Marco Ricci Update all URLs to stable a...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

1243)             _msg.TranslatedString(_msg.WarnMsgTemplate.V10_SUBCOMMAND_REQUIRED)
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1244)         )
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1245)         # See definition of click.Group.invoke, non-chained case.
1246)         with ctx:
1247)             sub_ctx = derivepassphrase_vault.make_context(
1248)                 'vault', ctx.args, parent=ctx
1249)             )
1250)             with sub_ctx:
1251)                 return derivepassphrase_vault.invoke(sub_ctx)
1252)     return None
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1253) 
1254) 
1255) # Exporter
1256) # ========
1257) 
1258) 
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1259) @derivepassphrase.group(
1260)     'export',
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1261)     context_settings={
1262)         'help_option_names': ['-h', '--help'],
1263)         'ignore_unknown_options': True,
1264)         'allow_interspersed_args': False,
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1265)     },
1266)     invoke_without_command=True,
1267)     cls=_DefaultToVaultGroup,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1268)     help=(
1269)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EXPORT_01),
1270)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EXPORT_02),
1271)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EXPORT_03),
1272)     ),
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

1274) @version_option
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 months ago

1278)     """Export a foreign configuration to standard output.
1279) 
1280)     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

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

1292)             _msg.TranslatedString(_msg.WarnMsgTemplate.V10_SUBCOMMAND_REQUIRED)
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1293)         )
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1294)         # See definition of click.Group.invoke, non-chained case.
1295)         with ctx:
1296)             sub_ctx = derivepassphrase_export_vault.make_context(
1297)                 'vault', ctx.args, parent=ctx
1298)             )
1299)             # Constructing the subcontext above will usually already
1300)             # lead to a click.UsageError, so this block typically won't
1301)             # actually be called.
1302)             with sub_ctx:  # pragma: no cover
1303)                 return derivepassphrase_export_vault.invoke(sub_ctx)
1304)     return None
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1305) 
1306) 
1307) def _load_data(
1308)     fmt: Literal['v0.2', 'v0.3', 'storeroom'],
1309)     path: str | bytes | os.PathLike[str],
1310)     key: bytes,
1311) ) -> Any:  # noqa: ANN401
1312)     contents: bytes
1313)     module: types.ModuleType
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

1314)     # Use match/case here once Python 3.9 becomes unsupported.
1315)     if fmt == 'v0.2':
1316)         module = importlib.import_module(
1317)             'derivepassphrase.exporter.vault_native'
1318)         )
1319)         if module.STUBBED:
1320)             raise ModuleNotFoundError
1321)         with open(path, 'rb') as infile:
1322)             contents = base64.standard_b64decode(infile.read())
1323)         return module.export_vault_native_data(
1324)             contents, key, try_formats=['v0.2']
1325)         )
1326)     elif fmt == 'v0.3':  # noqa: RET505
1327)         module = importlib.import_module(
1328)             'derivepassphrase.exporter.vault_native'
1329)         )
1330)         if module.STUBBED:
1331)             raise ModuleNotFoundError
1332)         with open(path, 'rb') as infile:
1333)             contents = base64.standard_b64decode(infile.read())
1334)         return module.export_vault_native_data(
1335)             contents, key, try_formats=['v0.3']
1336)         )
1337)     elif fmt == 'storeroom':
1338)         module = importlib.import_module('derivepassphrase.exporter.storeroom')
1339)         if module.STUBBED:
1340)             raise ModuleNotFoundError
1341)         return module.export_storeroom_data(path, key)
1342)     else:  # pragma: no cover
1343)         assert_never(fmt)
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1344) 
1345) 
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1346) @derivepassphrase_export.command(
1347)     'vault',
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

1349)     cls=CommandWithHelpGroups,
1350)     help=(
1351)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EXPORT_VAULT_01),
1352)         _msg.TranslatedString(
1353)             _msg.Label.DERIVEPASSPHRASE_EXPORT_VAULT_02,
1354)             path_metavar=_msg.TranslatedString(
1355)                 _msg.Label.EXPORT_VAULT_METAVAR_PATH,
1356)             ),
1357)         ),
1358)         _msg.TranslatedString(
1359)             _msg.Label.DERIVEPASSPHRASE_EXPORT_VAULT_03,
1360)             path_metavar=_msg.TranslatedString(
1361)                 _msg.Label.EXPORT_VAULT_METAVAR_PATH,
1362)             ),
1363)         ),
1364)     ),
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1365) )
1366) @click.option(
1367)     '-f',
1368)     '--format',
1369)     'formats',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

1374)     help=_msg.TranslatedString(
1375)         _msg.Label.EXPORT_VAULT_FORMAT_HELP_TEXT,
1376)         defaults_hint=_msg.TranslatedString(
1377)             _msg.Label.EXPORT_VAULT_FORMAT_DEFAULTS_HELP_TEXT,
1378)         ),
1379)         metavar=_msg.TranslatedString(
1380)             _msg.Label.EXPORT_VAULT_FORMAT_METAVAR_FMT,
1381)         ),
1382)     ),
1383)     cls=StandardOption,
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1384) )
1385) @click.option(
1386)     '-k',
1387)     '--key',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1388)     metavar=_msg.TranslatedString(_msg.Label.EXPORT_VAULT_KEY_METAVAR_K),
1389)     help=_msg.TranslatedString(
1390)         _msg.Label.EXPORT_VAULT_KEY_HELP_TEXT,
1391)         metavar=_msg.TranslatedString(_msg.Label.EXPORT_VAULT_KEY_METAVAR_K),
1392)         defaults_hint=_msg.TranslatedString(
1393)             _msg.Label.EXPORT_VAULT_KEY_DEFAULTS_HELP_TEXT,
1394)         ),
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

1396)     cls=StandardOption,
1397) )
Marco Ricci Reimplement `--help` and `-...

Marco Ricci authored 1 week ago

1398) @version_option
1399) @standard_logging_options
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1400) @click.argument(
1401)     'path',
1402)     metavar=_msg.TranslatedString(_msg.Label.EXPORT_VAULT_METAVAR_PATH),
1403)     required=True,
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1404) )
1405) @click.pass_context
1406) def derivepassphrase_export_vault(
1407)     ctx: click.Context,
1408)     /,
1409)     *,
1410)     path: str | bytes | os.PathLike[str],
1411)     formats: Sequence[Literal['v0.2', 'v0.3', 'storeroom']] = (),
1412)     key: str | bytes | None = None,
1413) ) -> None:
1414)     """Export a vault-native configuration to standard output.
1415) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

1423) 
1424)     """
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 months ago

1426)     if path in {'VAULT_PATH', b'VAULT_PATH'}:
1427)         path = exporter.get_vault_path()
1428)     if key is None:
1429)         key = exporter.get_vault_key()
1430)     elif isinstance(key, str):  # pragma: no branch
1431)         key = key.encode('utf-8')
1432)     for fmt in formats:
1433)         try:
1434)             config = _load_data(fmt, path, key)
1435)         except (
1436)             IsADirectoryError,
1437)             NotADirectoryError,
1438)             ValueError,
1439)             RuntimeError,
1440)         ):
Marco Ricci Replace strings in `derivep...

Marco Ricci authored 1 week ago

1441)             logger.info(
1442)                 _msg.TranslatedString(
1443)                     _msg.InfoMsgTemplate.CANNOT_LOAD_AS_VAULT_CONFIG,
1444)                     path=path,
1445)                     fmt=fmt,
1446)                 ),
1447)             )
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

1451)                 _msg.TranslatedString(
1452)                     _msg.ErrMsgTemplate.CANNOT_PARSE_AS_VAULT_CONFIG_OSERROR,
1453)                     path=path,
1454)                     error=exc.strerror,
1455)                     filename=exc.filename,
1456)                 ).maybe_without_filename(),
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1457)             )
1458)             ctx.exit(1)
1459)         except ModuleNotFoundError:
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

1461)                 _msg.TranslatedString(
1462)                     _msg.ErrMsgTemplate.MISSING_MODULE,
1463)                     module='cryptography',
1464)                 ),
1465)             )
1466)             logger.info(
1467)                 _msg.TranslatedString(
1468)                     _msg.InfoMsgTemplate.PIP_INSTALL_EXTRA,
1469)                     extra_name='export',
1470)                 ),
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1471)             )
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1472)             ctx.exit(1)
1473)         else:
1474)             if not _types.is_vault_config(config):
Marco Ricci Replace strings in `derivep...

Marco Ricci authored 1 week ago

1475)                 logger.error(
1476)                     _msg.TranslatedString(
1477)                         _msg.ErrMsgTemplate.INVALID_VAULT_CONFIG,
1478)                         config=config,
1479)                     ),
1480)                 )
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1481)                 ctx.exit(1)
1482)             click.echo(json.dumps(config, indent=2, sort_keys=True))
1483)             break
1484)     else:
Marco Ricci Replace strings in `derivep...

Marco Ricci authored 1 week ago

1485)         logger.error(
1486)             _msg.TranslatedString(
1487)                 _msg.ErrMsgTemplate.CANNOT_PARSE_AS_VAULT_CONFIG,
1488)                 path=path,
1489)             ).maybe_without_filename(),
1490)         )
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1491)         ctx.exit(1)
1492) 
1493) 
1494) # Vault
1495) # =====
1496) 
1497) 
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 months ago

1500) ) -> str | bytes | pathlib.Path:
1501)     """Return the filename of the configuration file for the subsystem.
1502) 
1503)     The (implicit default) file is currently named `settings.json`,
1504)     located within the configuration directory as determined by the
1505)     `DERIVEPASSPHRASE_PATH` environment variable, or by
1506)     [`click.get_app_dir`][] in POSIX mode.  Depending on the requested
1507)     subsystem, this will usually be a different file within that
1508)     directory.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1509) 
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1510)     Args:
1511)         subsystem:
1512)             Name of the configuration subsystem whose configuration
1513)             filename to return.  If not given, return the old filename
1514)             from before the subcommand migration.  If `None`, return the
1515)             configuration directory instead.
1516) 
1517)     Raises:
1518)         AssertionError:
1519)             An unknown subsystem was passed.
1520) 
1521)     Deprecated:
1522)         Since v0.2.0: The implicit default subsystem and the old
1523)         configuration filename are deprecated, and will be removed in v1.0.
1524)         The subsystem will be mandatory to specify.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1525) 
1526)     """
1527)     path: str | bytes | pathlib.Path
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

1544) 
1545) 
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

1551) 
1552)     Returns:
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

1554) 
1555)     Raises:
1556)         OSError:
1557)             There was an OS error accessing the file.
1558)         ValueError:
1559)             The data loaded from the file is not a vault(1)-compatible
1560)             config.
1561) 
1562)     """
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

1568)     return data
1569) 
1570) 
Marco Ricci Permit one flaky test and f...

Marco Ricci authored 3 months ago

1571) def _migrate_and_load_old_config() -> tuple[
1572)     _types.VaultConfig, OSError | None
1573) ]:
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

1579) 
1580)     Returns:
1581)         The vault settings, and an optional exception encountered during
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

1584) 
1585)     Raises:
1586)         OSError:
1587)             There was an OS error accessing the old file.
1588)         ValueError:
1589)             The data loaded from the file is not a vault(1)-compatible
1590)             config.
1591) 
1592)     """
1593)     new_filename = _config_filename(subsystem='vault')
Marco Ricci Make obtaining the compatib...

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 months ago

1595)     with open(old_filename, 'rb') as fileobj:
1596)         data = json.load(fileobj)
1597)     if not _types.is_vault_config(data):
1598)         raise ValueError(_INVALID_VAULT_CONFIG)
1599)     try:
1600)         os.replace(old_filename, new_filename)
1601)     except OSError as exc:
1602)         return data, exc
1603)     else:
1604)         return data, None
1605) 
1606) 
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

1609) 
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

1612) 
1613)     Args:
1614)         config:
1615)             vault configuration to save.
1616) 
1617)     Raises:
1618)         OSError:
1619)             There was an OS error accessing or writing the file.
1620)         ValueError:
1621)             The data cannot be stored as a vault(1)-compatible config.
1622) 
1623)     """
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 5 months ago

1627)     filedir = os.path.dirname(os.path.abspath(filename))
1628)     try:
1629)         os.makedirs(filedir, exist_ok=False)
1630)     except FileExistsError:
1631)         if not os.path.isdir(filedir):
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

1634)         json.dump(config, fileobj)
1635) 
1636) 
Marco Ricci Introduce a central user co...

Marco Ricci authored 3 weeks ago

1637) def _load_user_config() -> dict[str, Any]:
1638)     """Load the user config from the application directory.
1639) 
1640)     The filename is obtained via [`_config_filename`][].
1641) 
1642)     Returns:
1643)         The user configuration, as a nested `dict`.
1644) 
1645)     Raises:
1646)         OSError:
1647)             There was an OS error accessing the file.
1648)         ValueError:
1649)             The data loaded from the file is not a valid configuration
1650)             file.
1651) 
1652)     """
1653)     filename = _config_filename(subsystem='user configuration')
1654)     with open(filename, 'rb') as fileobj:
1655)         return tomllib.load(fileobj)
1656) 
1657) 
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

1665) 
1666)     Args:
1667)         conn:
Marco Ricci Support one-off SSH agent c...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 6 months ago

1670) 
1671)     Yields:
Marco Ricci Convert old syntax for Yiel...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

1674) 
1675)     Raises:
Marco Ricci Document and handle other e...

Marco Ricci authored 4 months ago

1676)         KeyError:
1677)             `conn` was `None`, and the `SSH_AUTH_SOCK` environment
1678)             variable was not found.
Marco Ricci Fail gracefully if UNIX dom...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

1693) 
1694)     """
Marco Ricci Support one-off SSH agent c...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 month ago

1700)         suitable_keys = copy.copy(all_key_comment_pairs)
1701)         for pair in all_key_comment_pairs:
1702)             key, _comment = pair
1703)             if vault.Vault.is_suitable_ssh_key(key, client=client):
1704)                 yield pair
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

1707) 
1708) 
1709) def _prompt_for_selection(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

1712)     single_choice_prompt: str = 'Confirm this choice?',
1713) ) -> int:
1714)     """Prompt user for a choice among the given items.
1715) 
1716)     Print the heading, if any, then present the items to the user.  If
1717)     there are multiple items, prompt the user for a selection, validate
1718)     the choice, then return the list index of the selected item.  If
1719)     there is only a single item, request confirmation for that item
1720)     instead, and return the correct index.
1721) 
1722)     Args:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

1725)         heading:
1726)             A heading for the list of items, to print immediately
1727)             before.  Defaults to a reasonable standard heading.  If
1728)             explicitly empty, print no heading.
1729)         single_choice_prompt:
1730)             The confirmation prompt if there is only a single possible
1731)             choice.  Defaults to a reasonable standard prompt.
1732) 
1733)     Returns:
1734)         An index into the items sequence, indicating the user's
1735)         selection.
1736) 
1737)     Raises:
1738)         IndexError:
1739)             The user made an invalid or empty selection, or requested an
1740)             abort.
1741) 
1742)     """
1743)     n = len(items)
1744)     if heading:
1745)         click.echo(click.style(heading, bold=True))
1746)     for i, x in enumerate(items, start=1):
1747)         click.echo(click.style(f'[{i}]', bold=True), nl=False)
1748)         click.echo(' ', nl=False)
1749)         click.echo(x)
1750)     if n > 1:
1751)         choices = click.Choice([''] + [str(i) for i in range(1, n + 1)])
1752)         choice = click.prompt(
1753)             f'Your selection? (1-{n}, leave empty to abort)',
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1754)             err=True,
1755)             type=choices,
1756)             show_choices=False,
1757)             show_default=False,
1758)             default='',
1759)         )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

1763)     prompt_suffix = (
1764)         ' ' if single_choice_prompt.endswith(tuple('?.!')) else ': '
1765)     )
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

1766)     try:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1767)         click.confirm(
1768)             single_choice_prompt,
1769)             prompt_suffix=prompt_suffix,
1770)             err=True,
1771)             abort=True,
1772)             default=False,
1773)             show_default=False,
1774)         )
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

1775)     except click.Abort:
1776)         raise IndexError(_EMPTY_SELECTION) from None
1777)     return 0
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1778) 
1779) 
1780) def _select_ssh_key(
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 5 months ago

1781)     conn: ssh_agent.SSHAgentClient | socket.socket | None = None, /
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

1788) 
1789)     Args:
1790)         conn:
Marco Ricci Support one-off SSH agent c...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 6 months ago

1793) 
1794)     Returns:
1795)         The selected SSH key.
1796) 
1797)     Raises:
Marco Ricci Document and handle other e...

Marco Ricci authored 4 months ago

1798)         KeyError:
1799)             `conn` was `None`, and the `SSH_AUTH_SOCK` environment
1800)             variable was not found.
Marco Ricci Fail gracefully if UNIX dom...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

1808)         IndexError:
1809)             The user made an invalid or empty selection, or requested an
1810)             abort.
Marco Ricci Distinguish between a key l...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

1818)     """
1819)     suitable_keys = list(_get_suitable_ssh_keys(conn))
1820)     key_listing: list[str] = []
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 month ago

1825)         remaining_key_display_length = KEY_DISPLAY_LENGTH - 1 - len(keytype)
1826)         key_extract = min(
1827)             key_str,
1828)             '...' + key_str[-remaining_key_display_length:],
1829)             key=len,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

1834)         key_listing,
1835)         heading='Suitable SSH keys:',
1836)         single_choice_prompt='Use this key?',
1837)     )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1838)     return suitable_keys[choice].key
1839) 
1840) 
1841) def _prompt_for_passphrase() -> str:
1842)     """Interactively prompt for the passphrase.
1843) 
1844)     Calls [`click.prompt`][] internally.  Moved into a separate function
1845)     mainly for testing/mocking purposes.
1846) 
1847)     Returns:
1848)         The user input.
1849) 
1850)     """
Marco Ricci Fix typing issues in mypy s...

Marco Ricci authored 5 months ago

1851)     return cast(
1852)         str,
1853)         click.prompt(
1854)             'Passphrase',
1855)             default='',
1856)             hide_input=True,
1857)             show_default=False,
1858)             err=True,
1859)         ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

1861) 
1862) 
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

1865) 
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

1866)     def escape(string: str) -> str:
1867)         translated = string.translate({
1868)             0: r'\u0000',
1869)             1: r'\u0001',
1870)             2: r'\u0002',
1871)             3: r'\u0003',
1872)             4: r'\u0004',
1873)             5: r'\u0005',
1874)             6: r'\u0006',
1875)             7: r'\u0007',
1876)             8: r'\b',
1877)             9: r'\t',
1878)             10: r'\n',
1879)             11: r'\u000B',
1880)             12: r'\f',
1881)             13: r'\r',
1882)             14: r'\u000E',
1883)             15: r'\u000F',
1884)             ord('"'): r'\"',
1885)             ord('\\'): r'\\',
1886)             127: r'\u007F',
1887)         })
1888)         return f'"{translated}"' if translated != string else string
Marco Ricci Fix formatting, some covera...

Marco Ricci authored 2 weeks ago

1889) 
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

1890)     return '.'.join(map(escape, parts))
1891) 
1892) 
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 months ago

1895) 
1896) 
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 weeks ago

1901)     main_config: dict[str, Any],
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 weeks ago

1903)     form_key = 'unicode-normalization-form'
1904)     default_form: str = main_config.get('vault', {}).get(
1905)         f'default-{form_key}', 'NFC'
1906)     )
1907)     form_dict: dict[str, dict] = main_config.get('vault', {}).get(form_key, {})
1908)     form: Any = (
1909)         default_form
1910)         if isinstance(key, _ORIGIN) or key == ('global',)
1911)         else form_dict.get(key[1], default_form)
1912)     )
1913)     config_key = (
1914)         _toml_key('vault', key[1], form_key)
1915)         if isinstance(key, tuple) and len(key) > 1 and key[1] in form_dict
1916)         else f'vault.default-{form_key}'
1917)     )
1918)     if form not in {'NFC', 'NFD', 'NFKC', 'NFKD'}:
1919)         msg = f'Invalid value {form!r} for config key {config_key}'
1920)         raise AssertionError(msg)
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 weeks ago

1922)     formatted_key = (
1923)         key.value if isinstance(key, _ORIGIN) else _types.json_path(key)
1924)     )
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 1 month ago

1936)                 formatted_key,
1937)                 form,
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

1938)                 stacklevel=2,
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

1939)             )
1940) 
1941) 
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

1942) def _key_to_phrase(
1943)     key_: str | bytes | bytearray,
1944)     /,
1945)     *,
1946)     error_callback: Callable[..., NoReturn] = sys.exit,
1947) ) -> bytes | bytearray:
1948)     key = base64.standard_b64decode(key_)
1949)     try:
1950)         with ssh_agent.SSHAgentClient.ensure_agent_subcontext() as client:
1951)             try:
1952)                 return vault.Vault.phrase_from_key(key, conn=client)
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 3 weeks ago

1954)                 try:
1955)                     keylist = client.list_keys()
1956)                 except ssh_agent.SSHAgentFailedError:
1957)                     pass
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 3 weeks ago

1960)                 else:
1961)                     if not any(  # pragma: no branch
1962)                         k == key for k, _ in keylist
1963)                     ):
1964)                         error_callback(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1965)                             _msg.TranslatedString(
1966)                                 _msg.ErrMsgTemplate.SSH_KEY_NOT_LOADED
1967)                             )
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 week ago

1969)                 error_callback(
1970)                     _msg.TranslatedString(
1971)                         _msg.ErrMsgTemplate.AGENT_REFUSED_SIGNATURE
1972)                     ),
1973)                     exc_info=exc,
1974)                 )
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

1975)     except KeyError:
1976)         error_callback(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

1982)         error_callback(
1983)             _msg.TranslatedString(
1984)                 _msg.ErrMsgTemplate.CANNOT_CONNECT_TO_AGENT,
1985)                 error=exc.strerror,
1986)                 filename=exc.filename,
1987)             ).maybe_without_filename()
1988)         )
1989)     except RuntimeError as exc:
1990)         error_callback(
1991)             _msg.TranslatedString(_msg.ErrMsgTemplate.CANNOT_UNDERSTAND_AGENT),
1992)             exc_info=exc,
1993)         )
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

1994) 
1995) 
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

1996) def _print_config_as_sh_script(
1997)     config: _types.VaultConfig,
1998)     /,
1999)     *,
2000)     outfile: TextIO,
2001)     prog_name_list: Sequence[str],
2002) ) -> None:
2003)     service_keys = (
2004)         'length',
2005)         'repeat',
2006)         'lower',
2007)         'upper',
2008)         'number',
2009)         'space',
2010)         'dash',
2011)         'symbol',
2012)     )
2013)     print('#!/bin/sh -e', file=outfile)
2014)     print(file=outfile)
2015)     print(shlex.join([*prog_name_list, '--clear']), file=outfile)
2016)     sv_obj_pairs: list[
2017)         tuple[
2018)             str | None,
2019)             _types.VaultConfigGlobalSettings
2020)             | _types.VaultConfigServicesSettings,
2021)         ],
2022)     ] = list(config['services'].items())
2023)     if config.get('global', {}):
2024)         sv_obj_pairs.insert(0, (None, config['global']))
2025)     for sv, sv_obj in sv_obj_pairs:
2026)         this_service_keys = tuple(k for k in service_keys if k in sv_obj)
2027)         this_other_keys = tuple(k for k in sv_obj if k not in service_keys)
2028)         if this_other_keys:
2029)             other_sv_obj = {k: sv_obj[k] for k in this_other_keys}  # type: ignore[literal-required]
2030)             dumped_config = json.dumps(
2031)                 (
2032)                     {'services': {sv: other_sv_obj}}
2033)                     if sv is not None
2034)                     else {'global': other_sv_obj, 'services': {}}
2035)                 ),
2036)                 ensure_ascii=False,
2037)                 indent=None,
2038)             )
2039)             print(
2040)                 shlex.join([*prog_name_list, '--import', '-']) + " <<'HERE'",
2041)                 dumped_config,
2042)                 'HERE',
2043)                 sep='\n',
2044)                 file=outfile,
2045)             )
2046)         if not this_service_keys and not this_other_keys and sv:
2047)             dumped_config = json.dumps(
2048)                 {'services': {sv: {}}},
2049)                 ensure_ascii=False,
2050)                 indent=None,
2051)             )
2052)             print(
2053)                 shlex.join([*prog_name_list, '--import', '-']) + " <<'HERE'",
2054)                 dumped_config,
2055)                 'HERE',
2056)                 sep='\n',
2057)                 file=outfile,
2058)             )
2059)         elif this_service_keys:
2060)             tokens = [*prog_name_list, '--config']
2061)             for key in this_service_keys:
2062)                 tokens.extend([f'--{key}', str(sv_obj[key])])  # type: ignore[literal-required]
2063)             if sv is not None:
2064)                 tokens.extend(['--', sv])
2065)             print(shlex.join(tokens), file=outfile)
2066) 
2067) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

2072)     option_group_name = _msg.TranslatedString(
2073)         _msg.Label.PASSPHRASE_GENERATION_LABEL
2074)     )
2075)     epilog = _msg.TranslatedString(
2076)         _msg.Label.PASSPHRASE_GENERATION_EPILOG,
2077)         metavar=_msg.TranslatedString(
2078)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2079)         ),
2080)     )
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

2082) 
2083) class ConfigurationOption(OptionGroupOption):
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

2089) 
2090) class StorageManagementOption(OptionGroupOption):
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

2093)     option_group_name = _msg.TranslatedString(
2094)         _msg.Label.STORAGE_MANAGEMENT_LABEL
2095)     )
2096)     epilog = _msg.TranslatedString(
2097)         _msg.Label.STORAGE_MANAGEMENT_EPILOG,
2098)         metavar=_msg.TranslatedString(
2099)             _msg.Label.STORAGE_MANAGEMENT_METAVAR_PATH
2100)         ),
2101)     )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 weeks ago

2104) class CompatibilityOption(OptionGroupOption):
2105)     """Compatibility and incompatibility options for the CLI."""
2106) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2107)     option_group_name = _msg.TranslatedString(
2108)         _msg.Label.COMPATIBILITY_OPTION_LABEL
2109)     )
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2110) 
2111) 
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2112) def _validate_occurrence_constraint(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

2117)     """Check that the occurrence constraint is valid (int, 0 or larger).
2118) 
2119)     Args:
2120)         ctx: The `click` context.
2121)         param: The current command-line parameter.
2122)         value: The parameter value to be checked.
2123) 
2124)     Returns:
2125)         The parsed parameter value.
2126) 
2127)     Raises:
2128)         click.BadParameter: The parameter value is invalid.
2129) 
2130)     """
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

2133)     if value is None:
2134)         return value
2135)     if isinstance(value, int):
2136)         int_value = value
2137)     else:
2138)         try:
2139)             int_value = int(value, 10)
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

2144)     return int_value
2145) 
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2146) 
2147) def _validate_length(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

2152)     """Check that the length is valid (int, 1 or larger).
2153) 
2154)     Args:
2155)         ctx: The `click` context.
2156)         param: The current command-line parameter.
2157)         value: The parameter value to be checked.
2158) 
2159)     Returns:
2160)         The parsed parameter value.
2161) 
2162)     Raises:
2163)         click.BadParameter: The parameter value is invalid.
2164) 
2165)     """
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

2168)     if value is None:
2169)         return value
2170)     if isinstance(value, int):
2171)         int_value = value
2172)     else:
2173)         try:
2174)             int_value = int(value, 10)
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

2179)     return int_value
2180) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2181) 
2182) DEFAULT_NOTES_TEMPLATE = """\
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2183) # Enter notes below the line with the cut mark (ASCII scissors and
2184) # dashes).  Lines above the cut mark (such as this one) will be ignored.
2185) #
2186) # If you wish to clear the notes, leave everything beyond the cut mark
2187) # blank.  However, if you leave the *entire* file blank, also removing
2188) # the cut mark, then the edit is aborted, and the old notes contents are
2189) # retained.
2190) #
2191) # - - - - - >8 - - - - - >8 - - - - - >8 - - - - - >8 - - - - -
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

2193) DEFAULT_NOTES_MARKER = '# - - - - - >8 - - - - -'
2194) 
2195) 
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

2196) @derivepassphrase.command(
2197)     'vault',
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

2200)     help=(
2201)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_VAULT_01),
2202)         _msg.TranslatedString(
2203)             _msg.Label.DERIVEPASSPHRASE_VAULT_02,
2204)             service_metavar=_msg.TranslatedString(
2205)                 _msg.Label.VAULT_METAVAR_SERVICE
2206)             ),
2207)         ),
2208)     ),
2209)     epilog=(
2210)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_VAULT_EPILOG_01),
2211)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_VAULT_EPILOG_02),
2212)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2213) )
2214) @click.option(
2215)     '-p',
2216)     '--phrase',
2217)     'use_phrase',
2218)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2219)     help=_msg.TranslatedString(
2220)         _msg.Label.DERIVEPASSPHRASE_VAULT_PHRASE_HELP_TEXT
2221)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

2223) )
2224) @click.option(
2225)     '-k',
2226)     '--key',
2227)     'use_key',
2228)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2229)     help=_msg.TranslatedString(
2230)         _msg.Label.DERIVEPASSPHRASE_VAULT_KEY_HELP_TEXT
2231)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

2233) )
2234) @click.option(
2235)     '-l',
2236)     '--length',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2237)     metavar=_msg.TranslatedString(
2238)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2239)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

2241)     help=_msg.TranslatedString(
2242)         _msg.Label.DERIVEPASSPHRASE_VAULT_LENGTH_HELP_TEXT,
2243)         metavar=_msg.TranslatedString(
2244)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2245)         ),
2246)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

2248) )
2249) @click.option(
2250)     '-r',
2251)     '--repeat',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2252)     metavar=_msg.TranslatedString(
2253)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2254)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

2256)     help=_msg.TranslatedString(
2257)         _msg.Label.DERIVEPASSPHRASE_VAULT_REPEAT_HELP_TEXT,
2258)         metavar=_msg.TranslatedString(
2259)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2260)         ),
2261)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

2263) )
2264) @click.option(
2265)     '--lower',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2266)     metavar=_msg.TranslatedString(
2267)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2268)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

2270)     help=_msg.TranslatedString(
2271)         _msg.Label.DERIVEPASSPHRASE_VAULT_LOWER_HELP_TEXT,
2272)         metavar=_msg.TranslatedString(
2273)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2274)         ),
2275)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

2277) )
2278) @click.option(
2279)     '--upper',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2280)     metavar=_msg.TranslatedString(
2281)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2282)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

2284)     help=_msg.TranslatedString(
2285)         _msg.Label.DERIVEPASSPHRASE_VAULT_UPPER_HELP_TEXT,
2286)         metavar=_msg.TranslatedString(
2287)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2288)         ),
2289)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

2291) )
2292) @click.option(
2293)     '--number',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2294)     metavar=_msg.TranslatedString(
2295)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2296)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

2298)     help=_msg.TranslatedString(
2299)         _msg.Label.DERIVEPASSPHRASE_VAULT_NUMBER_HELP_TEXT,
2300)         metavar=_msg.TranslatedString(
2301)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2302)         ),
2303)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

2305) )
2306) @click.option(
2307)     '--space',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2308)     metavar=_msg.TranslatedString(
2309)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2310)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

2312)     help=_msg.TranslatedString(
2313)         _msg.Label.DERIVEPASSPHRASE_VAULT_SPACE_HELP_TEXT,
2314)         metavar=_msg.TranslatedString(
2315)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2316)         ),
2317)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

2319) )
2320) @click.option(
2321)     '--dash',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2322)     metavar=_msg.TranslatedString(
2323)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2324)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

2326)     help=_msg.TranslatedString(
2327)         _msg.Label.DERIVEPASSPHRASE_VAULT_DASH_HELP_TEXT,
2328)         metavar=_msg.TranslatedString(
2329)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2330)         ),
2331)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

2333) )
2334) @click.option(
2335)     '--symbol',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2336)     metavar=_msg.TranslatedString(
2337)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2338)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

2340)     help=_msg.TranslatedString(
2341)         _msg.Label.DERIVEPASSPHRASE_VAULT_SYMBOL_HELP_TEXT,
2342)         metavar=_msg.TranslatedString(
2343)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2344)         ),
2345)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

2347) )
2348) @click.option(
2349)     '-n',
2350)     '--notes',
2351)     'edit_notes',
2352)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2353)     help=_msg.TranslatedString(
2354)         _msg.Label.DERIVEPASSPHRASE_VAULT_NOTES_HELP_TEXT,
2355)         service_metavar=_msg.TranslatedString(
2356)             _msg.Label.VAULT_METAVAR_SERVICE
2357)         ),
2358)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2359)     cls=ConfigurationOption,
2360) )
2361) @click.option(
2362)     '-c',
2363)     '--config',
2364)     'store_config_only',
2365)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2366)     help=_msg.TranslatedString(
2367)         _msg.Label.DERIVEPASSPHRASE_VAULT_CONFIG_HELP_TEXT,
2368)         service_metavar=_msg.TranslatedString(
2369)             _msg.Label.VAULT_METAVAR_SERVICE
2370)         ),
2371)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2372)     cls=ConfigurationOption,
2373) )
2374) @click.option(
2375)     '-x',
2376)     '--delete',
2377)     'delete_service_settings',
2378)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2379)     help=_msg.TranslatedString(
2380)         _msg.Label.DERIVEPASSPHRASE_VAULT_DELETE_HELP_TEXT,
2381)         service_metavar=_msg.TranslatedString(
2382)             _msg.Label.VAULT_METAVAR_SERVICE
2383)         ),
2384)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2385)     cls=ConfigurationOption,
2386) )
2387) @click.option(
2388)     '--delete-globals',
2389)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2390)     help=_msg.TranslatedString(
2391)         _msg.Label.DERIVEPASSPHRASE_VAULT_DELETE_GLOBALS_HELP_TEXT,
2392)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2393)     cls=ConfigurationOption,
2394) )
2395) @click.option(
2396)     '-X',
2397)     '--clear',
2398)     'clear_all_settings',
2399)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2400)     help=_msg.TranslatedString(
2401)         _msg.Label.DERIVEPASSPHRASE_VAULT_DELETE_ALL_HELP_TEXT,
2402)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2403)     cls=ConfigurationOption,
2404) )
2405) @click.option(
2406)     '-e',
2407)     '--export',
2408)     'export_settings',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2409)     metavar=_msg.TranslatedString(
2410)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2411)     ),
2412)     help=_msg.TranslatedString(
2413)         _msg.Label.DERIVEPASSPHRASE_VAULT_EXPORT_HELP_TEXT,
2414)         metavar=_msg.TranslatedString(
2415)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2416)         ),
2417)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2418)     cls=StorageManagementOption,
2419) )
2420) @click.option(
2421)     '-i',
2422)     '--import',
2423)     'import_settings',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2424)     metavar=_msg.TranslatedString(
2425)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2426)     ),
2427)     help=_msg.TranslatedString(
2428)         _msg.Label.DERIVEPASSPHRASE_VAULT_IMPORT_HELP_TEXT,
2429)         metavar=_msg.TranslatedString(
2430)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2431)         ),
2432)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2433)     cls=StorageManagementOption,
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 weeks ago

2435) @click.option(
2436)     '--overwrite-existing/--merge-existing',
2437)     'overwrite_config',
2438)     default=False,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2439)     help=_msg.TranslatedString(
2440)         _msg.Label.DERIVEPASSPHRASE_VAULT_OVERWRITE_HELP_TEXT
2441)     ),
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2442)     cls=CompatibilityOption,
2443) )
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

2444) @click.option(
2445)     '--unset',
2446)     'unset_settings',
2447)     multiple=True,
2448)     type=click.Choice([
2449)         'phrase',
2450)         'key',
2451)         'length',
2452)         'repeat',
2453)         'lower',
2454)         'upper',
2455)         'number',
2456)         'space',
2457)         'dash',
2458)         'symbol',
2459)     ]),
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2460)     help=_msg.TranslatedString(
2461)         _msg.Label.DERIVEPASSPHRASE_VAULT_UNSET_HELP_TEXT
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

2462)     ),
2463)     cls=CompatibilityOption,
2464) )
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

2469)     help=_msg.TranslatedString(
2470)         _msg.Label.DERIVEPASSPHRASE_VAULT_EXPORT_AS_HELP_TEXT
2471)     ),
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

2472)     cls=CompatibilityOption,
2473) )
Marco Ricci Reimplement `--help` and `-...

Marco Ricci authored 1 week ago

2474) @version_option
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

2476) @click.argument(
2477)     'service',
2478)     metavar=_msg.TranslatedString(_msg.Label.VAULT_METAVAR_SERVICE),
2479)     required=False,
2480)     default=None,
2481) )
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 5 months ago

2484)     ctx: click.Context,
2485)     /,
2486)     *,
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2487)     service: str | None = None,
2488)     use_phrase: bool = False,
2489)     use_key: bool = False,
2490)     length: int | None = None,
2491)     repeat: int | None = None,
2492)     lower: int | None = None,
2493)     upper: int | None = None,
2494)     number: int | None = None,
2495)     space: int | None = None,
2496)     dash: int | None = None,
2497)     symbol: int | None = None,
2498)     edit_notes: bool = False,
2499)     store_config_only: bool = False,
2500)     delete_service_settings: bool = False,
2501)     delete_globals: bool = False,
2502)     clear_all_settings: bool = False,
2503)     export_settings: TextIO | pathlib.Path | os.PathLike[str] | None = None,
2504)     import_settings: TextIO | pathlib.Path | os.PathLike[str] | None = None,
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

2510) 
2511)     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

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

2518) 
2519)     Parameters:
2520)         ctx (click.Context):
2521)             The `click` context.
2522) 
2523)     Other Parameters:
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

2576)         export_settings:
2577)             Command-line argument `-e`/`--export`.  If a file object,
2578)             then it must be open for writing and accept `str` inputs.
2579)             Otherwise, a filename to open for writing.  Using `-` for
2580)             standard output is supported.
2581)         import_settings:
2582)             Command-line argument `-i`/`--import`.  If a file object, it
2583)             must be open for reading and yield `str` values.  Otherwise,
2584)             a filename to open for reading.  Using `-` for standard
2585)             input is supported.
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2586)         overwrite_config:
2587)             Command-line arguments `--overwrite-existing` (True) and
2588)             `--merge-existing` (False).  Controls whether config saving
2589)             and config importing overwrite existing configurations, or
2590)             merge them section-wise instead.
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 3 months ago

2612)             elif isinstance(param, ConfigurationOption):
2613)                 group = ConfigurationOption
2614)             elif isinstance(param, StorageManagementOption):
2615)                 group = StorageManagementOption
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 4 weeks ago

2618)             elif isinstance(param, CompatibilityOption):
2619)                 group = CompatibilityOption
Marco Ricci Fix coverage

Marco Ricci authored 1 week ago

2620)             elif isinstance(param, StandardOption):  # pragma: no branch
Marco Ricci Reimplement `--help` and `-...

Marco Ricci authored 1 week ago

2621)                 group = StandardOption
Marco Ricci Fix coverage

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

2623)                 raise AssertionError(  # noqa: DOC501,TRY003,TRY004
2624)                     f'Unknown option group for {param!r}'  # noqa: EM102
2625)                 )
Marco Ricci Fix coverage

Marco Ricci authored 1 week ago

2626)             else:  # pragma: no cover
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

2628)             options_in_group.setdefault(group, []).append(param)
2629)         params_by_str[param.human_readable_name] = param
2630)         for name in param.opts + param.secondary_opts:
2631)             params_by_str[name] = param
2632) 
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 weeks ago

2637)     def option_name(param: click.Parameter | str) -> str:
2638)         # Annoyingly, `param.human_readable_name` contains the *function*
2639)         # parameter name, not the list of option names.  *Those* are
2640)         # stashed in the `.opts` and `.secondary_opts` attributes, which
2641)         # are visible in the `.to_info_dict()` output, but not otherwise
2642)         # documented.
2643)         param = params_by_str[param] if isinstance(param, str) else param
2644)         names = [param.human_readable_name, *param.opts, *param.secondary_opts]
2645)         option_names = [n for n in names if n.startswith('--')]
2646)         return min(option_names, key=len)
2647) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 weeks ago

2652)         param1 = params_by_str[param1] if isinstance(param1, str) else param1
2653)         param2 = params_by_str[param2] if isinstance(param2, str) else param2
2654)         if param1 == param2:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2655)             return
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2656)         if not is_param_set(param1):
2657)             return
2658)         if is_param_set(param2):
Marco Ricci Make the mutually exclusive...

Marco Ricci authored 2 weeks ago

2659)             param1_str = option_name(param1)
2660)             param2_str = option_name(param2)
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

2663)                 str(
2664)                     _msg.TranslatedString(
2665)                         _msg.ErrMsgTemplate.PARAMS_MUTUALLY_EXCLUSIVE,
2666)                         param1=param1_str,
2667)                         param2=param2_str,
2668)                     )
2669)                 ),
Marco Ricci Make the mutually exclusive...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 3 weeks ago

2671)             )
2672)         return
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

2675)         stacklevel = kwargs.pop('stacklevel', 1)
2676)         stacklevel += 1
Marco Ricci Force logging calls in erro...

Marco Ricci authored 1 week ago

2677)         logger.error(msg, stacklevel=stacklevel, **kwargs)
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

2678)         ctx.exit(1)
2679) 
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

2681)         try:
2682)             return _load_config()
2683)         except FileNotFoundError:
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

2684)             try:
2685)                 backup_config, exc = _migrate_and_load_old_config()
2686)             except FileNotFoundError:
2687)                 return {'services': {}}
Marco Ricci Make obtaining the compatib...

Marco Ricci authored 3 weeks ago

2688)             old_name = os.path.basename(
2689)                 _config_filename(subsystem='old settings.json')
2690)             )
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

2693)                 _msg.TranslatedString(
2694)                     _msg.WarnMsgTemplate.V01_STYLE_CONFIG,
2695)                     old=old_name,
2696)                     new=new_name,
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

2697)                 ),
2698)             )
2699)             if isinstance(exc, OSError):
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

2701)                     _msg.TranslatedString(
2702)                         _msg.WarnMsgTemplate.FAILED_TO_MIGRATE_CONFIG,
2703)                         path=new_name,
2704)                         error=exc.strerror,
2705)                         filename=exc.filename,
2706)                     ).maybe_without_filename(),
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

2707)                 )
2708)             else:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2709)                 deprecation.info(
2710)                     _msg.TranslatedString(
2711)                         _msg.InfoMsgTemplate.SUCCESSFULLY_MIGRATED,
2712)                         path=new_name,
2713)                     ),
2714)                 )
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

2717)             err(
2718)                 _msg.TranslatedString(
2719)                     _msg.ErrMsgTemplate.CANNOT_LOAD_VAULT_SETTINGS,
2720)                     error=exc.strerror,
2721)                     filename=exc.filename,
2722)                 ).maybe_without_filename(),
2723)             )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

2725)             err(
2726)                 _msg.TranslatedString(
2727)                     _msg.ErrMsgTemplate.CANNOT_LOAD_VAULT_SETTINGS,
2728)                     error=str(exc),
2729)                     filename=None,
2730)                 ).maybe_without_filename(),
2731)                 exc_info=exc,
2732)             )
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

2733) 
2734)     def put_config(config: _types.VaultConfig, /) -> None:
2735)         try:
2736)             _save_config(config)
Marco Ricci Document and handle other e...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 1 week ago

2738)             err(
2739)                 _msg.TranslatedString(
2740)                     _msg.ErrMsgTemplate.CANNOT_STORE_VAULT_SETTINGS,
2741)                     error=exc.strerror,
2742)                     filename=exc.filename,
2743)                 ).maybe_without_filename(),
2744)             )
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 1 week ago

2746)             err(
2747)                 _msg.TranslatedString(
2748)                     _msg.ErrMsgTemplate.CANNOT_STORE_VAULT_SETTINGS,
2749)                     error=str(exc),
2750)                     filename=None,
2751)                 ).maybe_without_filename(),
2752)                 exc_info=exc,
2753)             )
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 weeks ago

2755)     def get_user_config() -> dict[str, Any]:
2756)         try:
2757)             return _load_user_config()
2758)         except FileNotFoundError:
2759)             return {}
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

2761)             err(
2762)                 _msg.TranslatedString(
2763)                     _msg.ErrMsgTemplate.CANNOT_LOAD_USER_CONFIG,
2764)                     error=exc.strerror,
2765)                     filename=exc.filename,
2766)                 ).maybe_without_filename(),
2767)             )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

2769)             err(
2770)                 _msg.TranslatedString(
2771)                     _msg.ErrMsgTemplate.CANNOT_LOAD_USER_CONFIG,
2772)                     error=str(exc),
2773)                     filename=None,
2774)                 ).maybe_without_filename(),
2775)                 exc_info=exc,
2776)             )
Marco Ricci Introduce a central user co...

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

2779) 
2780)     check_incompatible_options('--phrase', '--key')
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 weeks ago

2789)             for other_opt in options_in_group[ConfigurationOption]:
2790)                 check_incompatible_options(opt, other_opt)
2791)             for other_opt in options_in_group[StorageManagementOption]:
2792)                 check_incompatible_options(opt, other_opt)
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 5 months ago

2795)         if is_param_set(param) and not (
2796)             service or is_param_set(params_by_str['--config'])
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

2798)             err_msg = _msg.TranslatedString(
2799)                 _msg.ErrMsgTemplate.PARAMS_NEEDS_SERVICE_OR_CONFIG,
2800)                 param=param.opts[0],
2801)                 service_metavar=service_metavar,
2802)             )
2803)             raise click.UsageError(str(err_msg))  # noqa: DOC501
Marco Ricci Correctly model vault globa...

Marco Ricci authored 2 months ago

2804)     sv_options = [params_by_str['--notes'], params_by_str['--delete']]
2805)     for param in sv_options:
2806)         if is_param_set(param) and not service:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2807)             err_msg = _msg.TranslatedString(
2808)                 _msg.ErrMsgTemplate.PARAMS_NEEDS_SERVICE,
2809)                 param=param.opts[0],
2810)                 service_metavar=service_metavar,
2811)             )
2812)             raise click.UsageError(str(err_msg))
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2813)     no_sv_options = [
2814)         params_by_str['--delete-globals'],
2815)         params_by_str['--clear'],
2816)         *options_in_group[StorageManagementOption],
2817)     ]
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2818)     for param in no_sv_options:
2819)         if is_param_set(param) and service:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2820)             err_msg = _msg.TranslatedString(
2821)                 _msg.ErrMsgTemplate.PARAMS_NO_SERVICE,
2822)                 param=param.opts[0],
2823)                 service_metavar=service_metavar,
2824)             )
2825)             raise click.UsageError(str(err_msg))
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 weeks ago

2827)     user_config = get_user_config()
2828) 
Marco Ricci Warn the user upon supplyin...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

2831)             _msg.TranslatedString(
2832)                 _msg.WarnMsgTemplate.EMPTY_SERVICE_NOT_SUPPORTED,
2833)                 service_metavar=service_metavar,
2834)             )
Marco Ricci Warn the user upon supplyin...

Marco Ricci authored 2 months ago

2835)         )
2836) 
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2837)     if edit_notes:
2838)         assert service is not None
2839)         configuration = get_config()
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

2846)             while notes_lines:
2847)                 line = notes_lines.popleft()
2848)                 if line.startswith(DEFAULT_NOTES_MARKER):
2849)                     notes_value = ''.join(notes_lines)
2850)                     break
2851)             else:
2852)                 if not notes_value.strip():
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2853)                     err(
2854)                         _msg.TranslatedString(
2855)                             _msg.ErrMsgTemplate.USER_ABORTED_EDIT
2856)                         )
2857)                     )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

2859)                 notes_value.strip('\n')
2860)             )
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

2862)     elif delete_service_settings:
2863)         assert service is not None
2864)         configuration = get_config()
2865)         if service in configuration['services']:
2866)             del configuration['services'][service]
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

2868)     elif delete_globals:
2869)         configuration = get_config()
2870)         if 'global' in configuration:
2871)             del configuration['global']
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

2875)     elif import_settings:
2876)         try:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 weeks ago

2879)             infile = cast(
2880)                 TextIO,
2881)                 (
2882)                     import_settings
2883)                     if hasattr(import_settings, 'close')
2884)                     else click.open_file(os.fspath(import_settings), 'rt')
2885)                 ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

2895)             err(
2896)                 _msg.TranslatedString(
2897)                     _msg.ErrMsgTemplate.CANNOT_DECODEIMPORT_VAULT_SETTINGS,
2898)                     error=exc,
2899)                 )
2900)             )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

2902)             err(
2903)                 _msg.TranslatedString(
2904)                     _msg.ErrMsgTemplate.CANNOT_IMPORT_VAULT_SETTINGS,
2905)                     error=exc.strerror,
2906)                     filename=exc.filename,
2907)                 ).maybe_without_filename()
2908)             )
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

2911)             err(
2912)                 _msg.TranslatedString(
2913)                     _msg.ErrMsgTemplate.CANNOT_IMPORT_VAULT_SETTINGS,
2914)                     error=_msg.TranslatedString(
2915)                         _msg.ErrMsgTemplate.INVALID_VAULT_CONFIG,
2916)                         config=maybe_config,
2917)                     ),
2918)                     filename=None,
2919)                 ).maybe_without_filename()
2920)             )
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

2921)         assert cleaned is not None
2922)         for step in cleaned:
2923)             # These are never fatal errors, because the semantics of
2924)             # vault upon encountering these settings are ill-specified,
2925)             # but not ill-defined.
2926)             if step.action == 'replace':
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

2928)                     _msg.TranslatedString(
2929)                         _msg.WarnMsgTemplate.STEP_REPLACE_INVALID_VALUE,
2930)                         old=json.dumps(step.old_value),
2931)                         path=_types.json_path(step.path),
2932)                         new=json.dumps(step.new_value),
2933)                     ),
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

2934)                 )
2935)             else:
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

2937)                     _msg.TranslatedString(
2938)                         _msg.WarnMsgTemplate.STEP_REMOVE_INEFFECTIVE_VALUE,
2939)                         path=_types.json_path(step.path),
2940)                         old=json.dumps(step.old_value),
2941)                     ),
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

2945)                 _msg.TranslatedString(
2946)                     _msg.WarnMsgTemplate.EMPTY_SERVICE_SETTINGS_INACCESSIBLE,
2947)                     service_metavar=service_metavar,
2948)                     PROG_NAME=PROG_NAME,
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2949)                 ),
Marco Ricci Warn the user upon supplyin...

Marco Ricci authored 2 months ago

2950)             )
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 weeks ago

2953)                 ('global',),
2954)                 cast(dict[str, Any], maybe_config.get('global', {})),
2955)                 main_config=user_config,
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

2956)             )
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

2957)             for key, value in maybe_config['services'].items():
2958)                 _check_for_misleading_passphrase(
2959)                     ('services', key),
2960)                     cast(dict[str, Any], value),
2961)                     main_config=user_config,
2962)                 )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

2964)             err(
2965)                 _msg.TranslatedString(
2966)                     _msg.ErrMsgTemplate.INVALID_USER_CONFIG,
2967)                     error=exc,
2968)                     filename=None,
2969)                 ).maybe_without_filename(),
2970)             )
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 3 weeks ago

2971)         global_obj = maybe_config.get('global', {})
2972)         has_key = _types.js_truthiness(global_obj.get('key'))
2973)         has_phrase = _types.js_truthiness(global_obj.get('phrase'))
2974)         if has_key and has_phrase:
2975)             logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2976)                 _msg.TranslatedString(
2977)                     _msg.WarnMsgTemplate.GLOBAL_PASSPHRASE_INEFFECTIVE,
2978)                 )
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 3 weeks ago

2979)             )
2980)         for service_name, service_obj in maybe_config['services'].items():
2981)             has_key = _types.js_truthiness(
2982)                 service_obj.get('key')
2983)             ) or _types.js_truthiness(global_obj.get('key'))
2984)             has_phrase = _types.js_truthiness(
2985)                 service_obj.get('phrase')
2986)             ) or _types.js_truthiness(global_obj.get('phrase'))
2987)             if has_key and has_phrase:
2988)                 logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2989)                     _msg.TranslatedString(
2990)                         _msg.WarnMsgTemplate.SERVICE_PASSPHRASE_INEFFECTIVE,
2991)                         service=json.dumps(service_name),
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 3 weeks ago

2992)                     ),
2993)                 )
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2994)         if overwrite_config:
2995)             put_config(maybe_config)
2996)         else:
2997)             configuration = get_config()
2998)             merged_config: collections.ChainMap[str, Any] = (
2999)                 collections.ChainMap(
3000)                     {
3001)                         'services': collections.ChainMap(
3002)                             maybe_config['services'],
3003)                             configuration['services'],
3004)                         ),
3005)                     },
3006)                     {'global': maybe_config['global']}
3007)                     if 'global' in maybe_config
3008)                     else {},
3009)                     {'global': configuration['global']}
3010)                     if 'global' in configuration
3011)                     else {},
3012)                 )
3013)             )
3014)             new_config: Any = {
3015)                 k: dict(v) if isinstance(v, collections.ChainMap) else v
3016)                 for k, v in sorted(merged_config.items())
3017)             }
3018)             assert _types.is_vault_config(new_config)
3019)             put_config(new_config)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3020)     elif export_settings:
3021)         configuration = get_config()
3022)         try:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 weeks ago

3025)             outfile = cast(
3026)                 TextIO,
3027)                 (
3028)                     export_settings
3029)                     if hasattr(export_settings, 'close')
3030)                     else click.open_file(os.fspath(export_settings), 'wt')
3031)                 ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 weeks ago

3039)                 if export_as == 'sh':
3040)                     this_ctx = ctx
3041)                     prog_name_pieces = collections.deque([
3042)                         this_ctx.info_name or 'vault',
3043)                     ])
3044)                     while (
3045)                         this_ctx.parent is not None
3046)                         and this_ctx.parent.info_name is not None
3047)                     ):
3048)                         prog_name_pieces.appendleft(this_ctx.parent.info_name)
3049)                         this_ctx = this_ctx.parent
3050)                     _print_config_as_sh_script(
3051)                         configuration,
3052)                         outfile=outfile,
3053)                         prog_name_list=prog_name_pieces,
3054)                     )
3055)                 else:
3056)                     json.dump(configuration, outfile)
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

3058)             err(
3059)                 _msg.TranslatedString(
3060)                     _msg.ErrMsgTemplate.CANNOT_EXPORT_VAULT_SETTINGS,
3061)                     error=exc.strerror,
3062)                     filename=exc.filename,
3063)                 ).maybe_without_filename(),
3064)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

3072)         service_keys = {
3073)             'key',
3074)             'phrase',
3075)             'length',
3076)             'repeat',
3077)             'lower',
3078)             'upper',
3079)             'number',
3080)             'space',
3081)             'dash',
3082)             'symbol',
3083)         }
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

3085)             {
3086)                 k: v
3087)                 for k, v in locals().items()
3088)                 if k in service_keys and v is not None
3089)             },
3090)             cast(
3091)                 dict[str, Any],
3092)                 configuration['services'].get(service or '', {}),
3093)             ),
3094)             cast(dict[str, Any], configuration.get('global', {})),
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3095)         )
3096)         if use_key:
3097)             try:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3098)                 key = base64.standard_b64encode(_select_ssh_key()).decode(
3099)                     'ASCII'
3100)                 )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

3102)                 err(
3103)                     _msg.TranslatedString(
3104)                         _msg.ErrMsgTemplate.USER_ABORTED_SSH_KEY_SELECTION
3105)                     ),
3106)                 )
Marco Ricci Document and handle other e...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

3109)                     _msg.TranslatedString(
3110)                         _msg.ErrMsgTemplate.NO_SSH_AGENT_FOUND
3111)                     ),
3112)                 )
3113)             except LookupError:
3114)                 err(
3115)                     _msg.TranslatedString(
3116)                         _msg.ErrMsgTemplate.NO_SUITABLE_SSH_KEYS,
3117)                         PROG_NAME=PROG_NAME,
3118)                     )
Marco Ricci Fail gracefully if UNIX dom...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

3123)                 err(
3124)                     _msg.TranslatedString(
3125)                         _msg.ErrMsgTemplate.CANNOT_CONNECT_TO_AGENT,
3126)                         error=exc.strerror,
3127)                         filename=exc.filename,
3128)                     ).maybe_without_filename(),
3129)                 )
3130)             except ssh_agent.SSHAgentFailedError as exc:
3131)                 err(
3132)                     _msg.TranslatedString(
3133)                         _msg.ErrMsgTemplate.AGENT_REFUSED_LIST_KEYS
3134)                     ),
3135)                     exc_info=exc,
3136)                 )
3137)             except RuntimeError as exc:
3138)                 err(
3139)                     _msg.TranslatedString(
3140)                         _msg.ErrMsgTemplate.CANNOT_UNDERSTAND_AGENT
3141)                     ),
3142)                     exc_info=exc,
3143)                 )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3144)         elif use_phrase:
3145)             maybe_phrase = _prompt_for_passphrase()
3146)             if not maybe_phrase:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3147)                 err(
3148)                     _msg.TranslatedString(
3149)                         _msg.ErrMsgTemplate.USER_ABORTED_PASSPHRASE
3150)                     )
3151)                 )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3152)             else:
3153)                 phrase = maybe_phrase
3154)         if store_config_only:
3155)             view: collections.ChainMap[str, Any]
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3156)             view = (
3157)                 collections.ChainMap(*settings.maps[:2])
3158)                 if service
Marco Ricci Fix missing consideration o...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

3161)             if use_key:
3162)                 view['key'] = key
3163)             elif use_phrase:
Marco Ricci Fix missing consideration o...

Marco Ricci authored 2 months ago

3164)                 view['phrase'] = phrase
3165)                 settings_type = 'service' if service else 'global'
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

3166)                 try:
3167)                     _check_for_misleading_passphrase(
3168)                         ('services', service) if service else ('global',),
3169)                         {'phrase': phrase},
3170)                         main_config=user_config,
3171)                     )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

3173)                     err(
3174)                         _msg.TranslatedString(
3175)                             _msg.ErrMsgTemplate.INVALID_USER_CONFIG,
3176)                             error=exc,
3177)                             filename=None,
3178)                         ).maybe_without_filename(),
3179)                     )
Marco Ricci Fix missing consideration o...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 3 weeks ago

3181)                     if service:
3182)                         logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3183)                             _msg.TranslatedString(
3184)                                 _msg.WarnMsgTemplate.SERVICE_PASSPHRASE_INEFFECTIVE,
3185)                                 service=json.dumps(service),
3186)                             )
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 3 weeks ago

3187)                         )
3188)                     else:
3189)                         logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3190)                             _msg.TranslatedString(
3191)                                 _msg.WarnMsgTemplate.GLOBAL_PASSPHRASE_INEFFECTIVE
3192)                             )
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 3 weeks ago

3193)                         )
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

3196)                 err_msg = _msg.TranslatedString(
3197)                     _msg.ErrMsgTemplate.CANNOT_UPDATE_SETTINGS_NO_SETTINGS,
3198)                     settings_type=settings_type,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

3203)                     err_msg = _msg.TranslatedString(
3204)                         _msg.ErrMsgTemplate.SET_AND_UNSET_SAME_SETTING,
3205)                         setting=setting,
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

3207)                     raise click.UsageError(str(err_msg))
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

3208)             subtree: dict[str, Any] = (
3209)                 configuration['services'].setdefault(service, {})  # type: ignore[assignment]
3210)                 if service
3211)                 else configuration.setdefault('global', {})
3212)             )
3213)             if overwrite_config:
3214)                 subtree.clear()
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

3215)             else:
3216)                 for setting in unset_settings:
3217)                     subtree.pop(setting, None)
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

3218)             subtree.update(view)
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

3219)             assert _types.is_vault_config(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3220)                 configuration
Marco Ricci Fix error message capitaliz...

Marco Ricci authored 4 months ago

3221)             ), f'Invalid vault configuration: {configuration!r}'
Marco Ricci Fix error bubbling in outda...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

3223)         else:
3224)             if not service:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3225)                 err_msg = _msg.TranslatedString(
3226)                     _msg.ErrMsgTemplate.SERVICE_REQUIRED,
3227)                     service_metavar=_msg.TranslatedString(
3228)                         _msg.Label.VAULT_METAVAR_SERVICE
3229)                     ),
3230)                 )
3231)                 raise click.UsageError(str(err_msg))
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3232)             kwargs: dict[str, Any] = {
3233)                 k: v
3234)                 for k, v in settings.items()
3235)                 if k in service_keys and v is not None
3236)             }
3237) 
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

3238)             if use_phrase:
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

3239)                 try:
3240)                     _check_for_misleading_passphrase(
3241)                         _ORIGIN.INTERACTIVE,
3242)                         {'phrase': phrase},
3243)                         main_config=user_config,
3244)                     )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

3246)                     err(
3247)                         _msg.TranslatedString(
3248)                             _msg.ErrMsgTemplate.INVALID_USER_CONFIG,
3249)                             error=exc,
3250)                             filename=None,
3251)                         ).maybe_without_filename(),
3252)                     )
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

3254)             # If either --key or --phrase are given, use that setting.
3255)             # Otherwise, if both key and phrase are set in the config,
Marco Ricci Align behavior with vault c...

Marco Ricci authored 3 months ago

3256)             # use the key.  Otherwise, if only one of key and phrase is
3257)             # set in the config, use that one.  In all these above
3258)             # cases, set the phrase via vault.Vault.phrase_from_key if
3259)             # a key is given.  Finally, if nothing is set, error out.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3260)             if use_key or use_phrase:
Marco Ricci Fix formatting, some covera...

Marco Ricci authored 2 weeks ago

3261)                 kwargs['phrase'] = (
3262)                     _key_to_phrase(key, error_callback=err)
3263)                     if use_key
3264)                     else phrase
3265)                 )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3266)             elif kwargs.get('key'):
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

3267)                 kwargs['phrase'] = _key_to_phrase(
3268)                     kwargs['key'], error_callback=err
3269)                 )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3270)             elif kwargs.get('phrase'):
3271)                 pass
3272)             else:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3273)                 err_msg = _msg.TranslatedString(
3274)                     _msg.ErrMsgTemplate.NO_KEY_OR_PHRASE
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

3276)                 raise click.UsageError(str(err_msg))
Marco Ricci Avoid crashing when overrid...

Marco Ricci authored 5 months ago

3277)             kwargs.pop('key', '')
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 5 months ago

3278)             result = vault.Vault(**kwargs).generate(service)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3279)             click.echo(result.decode('ASCII'))