pubanon 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. pubanon/__init__.py +7 -0
  2. pubanon/__main__.py +5 -0
  3. pubanon/_cli/__init__.py +167 -0
  4. pubanon/_cli/_arguments.py +544 -0
  5. pubanon/_cli/_context.py +109 -0
  6. pubanon/_cli/_history.py +463 -0
  7. pubanon/_cli/_init.py +624 -0
  8. pubanon/_cli/_init_draft.py +338 -0
  9. pubanon/_cli/_inspect.py +248 -0
  10. pubanon/_cli/_prepare.py +412 -0
  11. pubanon/_cli/_remote.py +319 -0
  12. pubanon/_cli/_selection.py +215 -0
  13. pubanon/_cli/_setup.py +488 -0
  14. pubanon/_cli/_status.py +413 -0
  15. pubanon/_cli/_workflow.py +528 -0
  16. pubanon/_config.py +1659 -0
  17. pubanon/_errors.py +97 -0
  18. pubanon/_filesystem.py +94 -0
  19. pubanon/_gate.py +188 -0
  20. pubanon/_locking.py +37 -0
  21. pubanon/_policy.py +173 -0
  22. pubanon/_remote/__init__.py +1 -0
  23. pubanon/_remote/_host.py +1213 -0
  24. pubanon/_remote/_lifecycle.py +708 -0
  25. pubanon/_remote/_package.py +277 -0
  26. pubanon/_remote/_publish.py +1494 -0
  27. pubanon/_remote/_stage.py +679 -0
  28. pubanon/_remote/_watch.py +536 -0
  29. pubanon/_remote/_workflow_checks.py +320 -0
  30. pubanon/_run.py +220 -0
  31. pubanon/_snapshots/__init__.py +1 -0
  32. pubanon/_snapshots/_audit.py +866 -0
  33. pubanon/_snapshots/_candidate.py +2198 -0
  34. pubanon/_snapshots/_conflicts.py +636 -0
  35. pubanon/_snapshots/_history.py +822 -0
  36. pubanon/_snapshots/_records.py +1358 -0
  37. pubanon/_snapshots/_rewrite.py +314 -0
  38. pubanon/_snapshots/_source.py +810 -0
  39. pubanon/_snapshots/_store.py +47 -0
  40. pubanon/_terminal.py +464 -0
  41. pubanon/_toml.py +39 -0
  42. pubanon/_windows_fs.py +101 -0
  43. pubanon/py.typed +0 -0
  44. pubanon-0.1.0.dist-info/METADATA +152 -0
  45. pubanon-0.1.0.dist-info/RECORD +48 -0
  46. pubanon-0.1.0.dist-info/WHEEL +4 -0
  47. pubanon-0.1.0.dist-info/entry_points.txt +2 -0
  48. pubanon-0.1.0.dist-info/licenses/LICENSE +21 -0
pubanon/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ """Publish private repositories under a separate publication identity.
2
+
3
+ Use the `pubanon` command or `python -m pubanon`. The package root exports no
4
+ public Python API.
5
+ """
6
+
7
+ __all__: list[str] = []
pubanon/__main__.py ADDED
@@ -0,0 +1,5 @@
1
+ """Run the pubanon command-line interface with `python -m pubanon`."""
2
+
3
+ from pubanon._cli import main
4
+
5
+ raise SystemExit(main())
@@ -0,0 +1,167 @@
1
+ """Provide the Pubanon command-line entry point."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import sys
7
+ from contextlib import ExitStack
8
+ from pathlib import Path
9
+ from typing import TYPE_CHECKING
10
+
11
+ from pubanon import (
12
+ _config,
13
+ _run,
14
+ )
15
+ from pubanon._cli import (
16
+ _arguments,
17
+ _init,
18
+ _inspect,
19
+ _prepare,
20
+ _setup,
21
+ _status,
22
+ _workflow,
23
+ )
24
+ from pubanon._cli import _history as cli_history
25
+ from pubanon._cli import _remote as cli_remote
26
+ from pubanon._errors import OperationCancelled, PubanonError
27
+ from pubanon._terminal import (
28
+ color_context,
29
+ diagnostic,
30
+ guidance,
31
+ guidance_context,
32
+ output_encoding_context,
33
+ )
34
+
35
+ if TYPE_CHECKING:
36
+ import argparse
37
+ from collections.abc import Callable, Iterable, Sequence
38
+
39
+
40
+ def _dispatch(args: argparse.Namespace) -> None:
41
+ """Dispatch one parsed command."""
42
+
43
+ def _dispatch_doctor(_args: argparse.Namespace) -> None:
44
+ _setup.doctor()
45
+
46
+ def _dispatch_setup(args: argparse.Namespace) -> None:
47
+ if args.edit:
48
+ _setup.setup(edit=True)
49
+ else:
50
+ _setup.setup()
51
+
52
+ handlers: dict[str, Callable[[argparse.Namespace], None]] = {
53
+ 'clean': cli_history.command_clean,
54
+ 'delete': cli_history.command_delete,
55
+ 'discard': cli_history.command_discard,
56
+ 'doctor': _dispatch_doctor,
57
+ 'list': cli_history.command_list,
58
+ 'init': _init.command_init,
59
+ 'inspect': _inspect.command_inspect,
60
+ 'prepare': _prepare.command_prepare,
61
+ 'publish': cli_remote.command_publish,
62
+ 'release': _workflow.command_release,
63
+ 'run': _workflow.command_run,
64
+ 'setup': _dispatch_setup,
65
+ 'show': cli_history.command_show,
66
+ 'status': _status.command_status,
67
+ }
68
+ if args.command == 'repo':
69
+ handler = {
70
+ 'create': cli_remote.repo_create,
71
+ 'reveal': cli_remote.repo_reveal,
72
+ 'verify': cli_remote.verify_repo,
73
+ }.get(args.repo_command)
74
+ elif args.command == 'stage':
75
+ handler = {
76
+ 'clean': cli_remote.stage_clean,
77
+ 'push': cli_remote.stage_push,
78
+ 'status': cli_remote.stage_status,
79
+ }.get(args.stage_command)
80
+ elif args.command == 'watch':
81
+ handler = {'ci': cli_remote.watch_ci, 'package': cli_remote.watch_package}.get(
82
+ args.watch_command
83
+ )
84
+ else:
85
+ handler = handlers.get(args.command)
86
+ if handler is None:
87
+ raise PubanonError('unsupported command')
88
+ if args.command != 'setup':
89
+ _run.check_floors()
90
+ handler(args)
91
+
92
+
93
+ def _implicit_guidance_project(args: argparse.Namespace) -> str | None:
94
+ """Omit redundant project advice when registry lookup is available."""
95
+ if args.command in {'setup', 'doctor'}:
96
+ return None
97
+ try:
98
+ paths = _config.derive_paths(os.environ)
99
+ if not paths.registry.exists():
100
+ return None
101
+ return _config.registry_lookup(paths, Path.cwd())
102
+ except PubanonError:
103
+ # Advice must not add a registry dependency to explicit project selection.
104
+ return None
105
+
106
+
107
+ def _report_error(error: PubanonError) -> None:
108
+ """Report a refusal with its diagnostic values."""
109
+ print(diagnostic(error, stream=sys.stderr), file=sys.stderr)
110
+
111
+
112
+ def _main(argv: Sequence[str] | None = None) -> int:
113
+ """Parse and dispatch one command, translating failures to process exit statuses."""
114
+ with ExitStack() as contexts:
115
+ try:
116
+ parser = _arguments.build_parser()
117
+ arguments = list(sys.argv[1:] if argv is None else argv)
118
+ contexts.enter_context(color_context(parser.selected_color_mode(arguments)))
119
+ args = parser.parse_args(arguments)
120
+ _arguments.validate_options(parser, args)
121
+ try:
122
+ selected = getattr(args, 'project', None)
123
+ implicit = _implicit_guidance_project(args)
124
+ with guidance_context(
125
+ project=selected,
126
+ implicit_project=implicit if selected in {None, implicit} else None,
127
+ ):
128
+ try:
129
+ _dispatch(args)
130
+ except PubanonError as error:
131
+ if error.recovery is not None:
132
+ error.recovery = guidance(error.recovery)
133
+ raise
134
+ except OperationCancelled:
135
+ raise
136
+ except PubanonError as error:
137
+ _report_error(error)
138
+ return 1
139
+ except SystemExit as exc:
140
+ return exc.code if isinstance(exc.code, int) else 2
141
+ except OperationCancelled as error:
142
+ print(diagnostic(error, stream=sys.stderr), file=sys.stderr)
143
+ return 130
144
+ except KeyboardInterrupt:
145
+ error = OperationCancelled('operation cancelled')
146
+ print(diagnostic(error, stream=sys.stderr), file=sys.stderr)
147
+ return 130
148
+ except PubanonError as error:
149
+ print(diagnostic(error, stream=sys.stderr), file=sys.stderr)
150
+ return 1
151
+ return 0
152
+
153
+
154
+ def main(argv: Iterable[str] | None = None) -> int:
155
+ """Run one command with consistent color policy, including help and errors.
156
+
157
+ Args:
158
+ argv: Arguments excluding the executable, or None for process
159
+ arguments.
160
+
161
+ Returns:
162
+ Zero for success, one for refusal, two for usage errors, or 130 for
163
+ interruption.
164
+ """
165
+ arguments = list(sys.argv[1:] if argv is None else argv)
166
+ with output_encoding_context():
167
+ return _main(arguments)