b3fcb7eb5a39c0982bbcf859a7bfc0a3647093e4
Marco Ricci Update copyright notices to...

Marco Ricci authored 3 days ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 days ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 days ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 3 days ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 1 month ago

1106) 
Marco Ricci Format everything with ruff...

Marco Ricci authored 2 days ago

1107) 
Marco Ricci Consolidate shell completio...

Marco Ricci authored 3 days ago

1108) # Shell completion
1109) # ================
1110) 
1111) # Use naive filename completion for the `path` argument of
1112) # `derivepassphrase vault`'s `--import` and `--export` options, as well
1113) # as the `path` argument of `derivepassphrase export vault`.  The latter
1114) # treats the pseudo-filename `VAULT_PATH` specially, but this is awkward
1115) # to combine with standard filename completion, particularly in bash, so
1116) # we would probably have to implement *all* completion (`VAULT_PATH` and
1117) # filename completion) ourselves, lacking some niceties of bash's
1118) # built-in completion (e.g., adding spaces or slashes depending on
1119) # whether the completion is a directory or a complete filename).
1120) 
1121) 
1122) def _shell_complete_path(
1123)     ctx: click.Context,
1124)     parameter: click.Parameter,
1125)     value: str,
1126) ) -> list[str | click.shell_completion.CompletionItem]:
Marco Ricci Update ruff to v0.8.x, refo...

Marco Ricci authored 2 days ago

1127)     """Request standard path completion for the `path` argument."""  # noqa: DOC201
Marco Ricci Consolidate shell completio...

Marco Ricci authored 3 days ago

1128)     del ctx, parameter, value
Marco Ricci Update ruff to v0.8.x, refo...

Marco Ricci authored 2 days ago

1129)     return [click.shell_completion.CompletionItem('', type='file')]
Marco Ricci Consolidate shell completio...

Marco Ricci authored 3 days ago

1130) 
1131) 
1132) # The standard `click` shell completion scripts serialize the completion
1133) # items as newline-separated one-line entries, which get silently
1134) # corrupted if the value contains newlines.  Each shell imposes
1135) # additional restrictions: Fish uses newlines in all internal completion
1136) # helper scripts, so it is difficult, if not impossible, to register
1137) # completion entries containing newlines if completion comes from within
1138) # a Fish completion function (instead of a Fish builtin).  Zsh's
1139) # completion system supports descriptions for each completion item, and
1140) # the completion helper functions parse every entry as a colon-separated
1141) # 2-tuple of item and description, meaning any colon in the item value
1142) # must be escaped.  Finally, Bash requires the result array to be
1143) # populated at the completion function's top-level scope, but for/while
1144) # loops within pipelines do not run at top-level scope, and Bash *also*
1145) # strips NUL characters from command substitution output, making it
1146) # difficult to read in external data into an array in a cross-platform
1147) # manner from entirely within Bash.
1148) #
1149) # We capitulate in front of these problems---most egregiously because of
1150) # Fish---and ensure that completion items (in this case: service names)
1151) # never contain ASCII control characters by refusing to offer such
1152) # items as valid completions.  On the other side, `derivepassphrase`
1153) # will warn the user when configuring or importing a service with such
1154) # a name that it will not be available for shell completion.
1155) 
1156) 
1157) def _is_completable_item(obj: object) -> bool:
1158)     """Return whether the item is completable on the command-line.
1159) 
1160)     The item is completable if and only if it contains no ASCII control
1161)     characters (U+0000 through U+001F, and U+007F).
1162) 
1163)     """
1164)     obj = str(obj)
Marco Ricci Format everything with ruff...

Marco Ricci authored 2 days ago

1165)     forbidden = frozenset(chr(i) for i in range(32)) | {'\x7f'}
Marco Ricci Consolidate shell completio...

Marco Ricci authored 3 days ago

1166)     return not any(f in obj for f in forbidden)
1167) 
1168) 
1169) def _shell_complete_service(
1170)     ctx: click.Context,
1171)     parameter: click.Parameter,
1172)     value: str,
1173) ) -> list[str | click.shell_completion.CompletionItem]:
1174)     """Return known vault service names as completion items.
1175) 
1176)     Service names are looked up in the vault configuration file.  All
1177)     errors will be suppressed.  Additionally, any service names deemed
1178)     not completable as per [`_is_completable_item`][] will be silently
1179)     skipped.
1180) 
1181)     """
1182)     del ctx, parameter
1183)     try:
1184)         config = _load_config()
1185)         return sorted(
1186)             sv
1187)             for sv in config['services']
1188)             if sv.startswith(value) and _is_completable_item(sv)
1189)         )
1190)     except FileNotFoundError:
1191)         try:
1192)             config, _exc = _migrate_and_load_old_config()
1193)             return sorted(
1194)                 sv
1195)                 for sv in config['services']
1196)                 if sv.startswith(value) and _is_completable_item(sv)
1197)             )
1198)         except FileNotFoundError:
1199)             return []
1200)     except Exception:  # noqa: BLE001
1201)         return []
1202) 
1203) 
1204) class ZshComplete(click.shell_completion.ZshComplete):
1205)     """Zsh completion class that supports colons.
1206) 
1207)     `click`'s Zsh completion class (at least v8.1.7 and v8.1.8) uses
1208)     completion helper functions (provided by Zsh) that parse each
1209)     completion item into value-description pairs, separated by a colon.
1210)     Correspondingly, any internal colons in the completion item's value
1211)     need to be escaped.  `click` doesn't do this.  So, this subclass
1212)     overrides those parts, and adds the missing escaping.
1213) 
1214)     """
1215) 
1216)     @override
1217)     def format_completion(
1218)         self,
1219)         item: click.shell_completion.CompletionItem,
1220)     ) -> str:
1221)         """Return a suitable serialization of the CompletionItem.
1222) 
1223)         This serialization ensures colons in the item value are properly
1224)         escaped.
1225) 
1226)         """
1227)         type, value, help = (  # noqa: A001
1228)             item.type,
1229)             item.value.replace(':', '\\:'),
1230)             item.help or '_',
1231)         )
1232)         return f'{type}\n{value}\n{help}'
1233) 
1234) 
1235) click.shell_completion.add_completion_class(ZshComplete)
1236) 
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1237) 
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

1243)     """A helper class to implement the default-to-"vault"-subcommand behavior.
1244) 
1245)     Modifies internal [`click.MultiCommand`][] methods, and thus is both
1246)     an implementation detail and a kludge.
1247) 
1248)     """
1249) 
1250)     def resolve_command(
1251)         self, ctx: click.Context, args: list[str]
1252)     ) -> tuple[str | None, click.Command | None, list[str]]:
1253)         """Resolve a command, but default to "vault" instead of erroring out.
1254) 
1255)         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

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

Marco Ricci authored 1 month ago

1296) 
Marco Ricci Update ruff to v0.8.x, refo...

Marco Ricci authored 2 days ago

1297)         """  # noqa: DOC201
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

1335)             #
1336)             # END modifications for derivepassphrase
1337)             ####
Marco Ricci Update ruff to v0.8.x, refo...

Marco Ricci authored 2 days ago

1338)         return cmd_name if cmd else None, cmd, args[1:]
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1339) 
1340) 
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 months ago

1391)     """Derive a strong passphrase, deterministically, from a master secret.
1392) 
1393)     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

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

1409)         )
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 months ago

1444)     """Export a foreign configuration to standard output.
1445) 
1446)     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

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

1462)         )
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 days ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

1619)             )
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

1646)             )
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

1656)                 )
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

1670)         )
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

1689) 
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

1789) 
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

1792) 
1793)     Args:
1794)         config:
1795)             vault configuration to save.
1796) 
1797)     Raises:
1798)         OSError:
1799)             There was an OS error accessing or writing the file.
1800)         ValueError:
1801)             The data cannot be stored as a vault(1)-compatible config.
1802) 
Marco Ricci Update ruff to v0.8.x, refo...

Marco Ricci authored 2 days ago

1803)     """  # noqa: DOC501
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 5 months ago

1807)     filedir = os.path.dirname(os.path.abspath(filename))
1808)     try:
1809)         os.makedirs(filedir, exist_ok=False)
1810)     except FileExistsError:
1811)         if not os.path.isdir(filedir):
Marco Ricci Update ruff to v0.8.x, refo...

Marco Ricci authored 2 days ago

1812)             raise
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

1951)     try:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

2043)     return cast(
Marco Ricci Add remaining re-linting ch...

Marco Ricci authored 2 days ago

2044)         'str',
Marco Ricci Fix typing issues in mypy s...

Marco Ricci authored 5 months ago

2045)         click.prompt(
2046)             'Passphrase',
2047)             default='',
2048)             hide_input=True,
2049)             show_default=False,
2050)             err=True,
2051)         ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

2057) 
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

2081) 
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 6 months ago

2306) def _validate_occurrence_constraint(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

2708) 
2709)     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

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 6 months ago

2797) 
Marco Ricci Update ruff to v0.8.x, refo...

Marco Ricci authored 2 days ago

2798)     """  # noqa: DOC501
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

2819)                 group = StandardOption
Marco Ricci Fix coverage

Marco Ricci authored 1 week ago

2820)             elif isinstance(param, OptionGroupOption):  # pragma: no cover
Marco Ricci Update ruff to v0.8.x, refo...

Marco Ricci authored 2 days ago

2821)                 raise AssertionError(  # noqa: TRY003,TRY004
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

2822)                     f'Unknown option group for {param!r}'  # noqa: EM102
2823)                 )
Marco Ricci Add tests for help and vers...

Marco Ricci authored 1 week ago

2824)             else:
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 6 months ago

2853)             return
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

2963)         except OSError 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.CANNOT_LOAD_USER_CONFIG,
2967)                     error=exc.strerror,
2968)                     filename=exc.filename,
2969)                 ).maybe_without_filename(),
2970)             )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

3001)             err_msg = _msg.TranslatedString(
3002)                 _msg.ErrMsgTemplate.PARAMS_NEEDS_SERVICE_OR_CONFIG,
3003)                 param=param.opts[0],
3004)                 service_metavar=service_metavar,
3005)             )
Marco Ricci Update ruff to v0.8.x, refo...

Marco Ricci authored 2 days ago

3006)             raise click.UsageError(str(err_msg))
Marco Ricci Correctly model vault globa...

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

3044)         text = DEFAULT_NOTES_TEMPLATE + configuration['services'].get(
Marco Ricci Add remaining re-linting ch...

Marco Ricci authored 2 days ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 weeks ago

3083)             infile = cast(
Marco Ricci Add remaining re-linting ch...

Marco Ricci authored 2 days ago

3084)                 'TextIO',
Marco Ricci Document handling of file o...

Marco Ricci authored 3 weeks ago

3085)                 (
3086)                     import_settings
3087)                     if hasattr(import_settings, 'close')
3088)                     else click.open_file(os.fspath(import_settings), 'rt')
3089)                 ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 month ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 months ago

3157)             )
Marco Ricci Consolidate shell completio...

Marco Ricci authored 3 days ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 weeks ago

3169)                 ('global',),
Marco Ricci Add remaining re-linting ch...

Marco Ricci authored 2 days ago

3170)                 cast('dict[str, Any]', maybe_config.get('global', {})),
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

3171)                 main_config=user_config,
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 4 months ago

3173)             )
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

3174)             for key, value in maybe_config['services'].items():
3175)                 _check_for_misleading_passphrase(
3176)                     ('services', key),
Marco Ricci Add remaining re-linting ch...

Marco Ricci authored 2 days ago

3177)                     cast('dict[str, Any]', value),
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

3178)                     main_config=user_config,
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 weeks ago

3245)             outfile = cast(
Marco Ricci Add remaining re-linting ch...

Marco Ricci authored 2 days ago

3246)                 'TextIO',
Marco Ricci Document handling of file o...

Marco Ricci authored 3 weeks ago

3247)                 (
3248)                     export_settings
3249)                     if hasattr(export_settings, 'close')
3250)                     else click.open_file(os.fspath(export_settings), 'wt')
3251)                 ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

3305)             {
3306)                 k: v
3307)                 for k, v in locals().items()
3308)                 if k in service_keys and v is not None
3309)             },
3310)             cast(
Marco Ricci Add remaining re-linting ch...

Marco Ricci authored 2 days ago

3311)                 'dict[str, Any]',
Marco Ricci Fix check of empty service...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

3313)             ),
Marco Ricci Add remaining re-linting ch...

Marco Ricci authored 2 days ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 2 months ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 days ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 days ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 3 days ago

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

Marco Ricci authored 3 weeks ago

3419)             if not view.maps[0] and not unset_settings:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3420)                 err_msg = _msg.TranslatedString(
3421)                     _msg.ErrMsgTemplate.CANNOT_UPDATE_SETTINGS_NO_SETTINGS,
Marco Ricci Fix phrasing of "Cannot upd...

Marco Ricci authored 2 days ago

3422)                     settings_type=_msg.TranslatedString(
3423)                         _msg.Label.CANNOT_UPDATE_SETTINGS_METAVAR_SETTINGS_TYPE_SERVICE
3424)                         if service
3425)                         else _msg.Label.CANNOT_UPDATE_SETTINGS_METAVAR_SETTINGS_TYPE_GLOBAL  # noqa: E501
3426)                     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 week ago

3431)                     err_msg = _msg.TranslatedString(
3432)                         _msg.ErrMsgTemplate.SET_AND_UNSET_SAME_SETTING,
3433)                         setting=setting,
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 days ago

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

Marco Ricci authored 4 weeks ago

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

Marco Ricci authored 3 weeks ago

3451)             else:
3452)                 for setting in unset_settings:
3453)                     subtree.pop(setting, None)
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

3454)             subtree.update(view)
Marco Ricci Update ruff to v0.8.x, refo...

Marco Ricci authored 2 days ago

3455)             assert _types.is_vault_config(configuration), (
3456)                 f'Invalid vault configuration: {configuration!r}'
3457)             )
Marco Ricci Fix error bubbling in outda...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

3459)         else:
Marco Ricci Fix check of empty service...

Marco Ricci authored 1 week ago

3460)             assert service is not None
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3461)             kwargs: dict[str, Any] = {
3462)                 k: v
3463)                 for k, v in settings.items()
3464)                 if k in service_keys and v is not None
3465)             }
3466) 
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 3 weeks ago

3468)                 try:
3469)                     _check_for_misleading_passphrase(
3470)                         _ORIGIN.INTERACTIVE,
3471)                         {'phrase': phrase},
3472)                         main_config=user_config,
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

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

Marco Ricci authored 3 weeks ago

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

Marco Ricci authored 2 weeks ago

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

Marco Ricci authored 1 week ago

3476)                     err(
3477)                         _msg.TranslatedString(
3478)                             _msg.ErrMsgTemplate.INVALID_USER_CONFIG,
3479)                             error=exc,
3480)                             filename=None,
3481)                         ).maybe_without_filename(),
3482)                     )
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 months ago

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

Marco Ricci authored 6 months ago

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

Marco Ricci authored 2 weeks ago

3491)                 kwargs['phrase'] = (
3492)                     _key_to_phrase(key, error_callback=err)
3493)                     if use_key
3494)                     else phrase
3495)                 )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

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

Marco Ricci authored 3 weeks ago

3497)                 kwargs['phrase'] = _key_to_phrase(
3498)                     kwargs['key'], error_callback=err
3499)                 )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3500)             elif kwargs.get('phrase'):
3501)                 pass
3502)             else:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3503)                 err_msg = _msg.TranslatedString(
3504)                     _msg.ErrMsgTemplate.NO_KEY_OR_PHRASE
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

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

Marco Ricci authored 1 week ago

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

Marco Ricci authored 5 months ago

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

Marco Ricci authored 5 months ago

3508)             result = vault.Vault(**kwargs).generate(service)
Marco Ricci Support suppressing or forc...

Marco Ricci authored 1 week ago

3509)             click.echo(result.decode('ASCII'), color=ctx.color)