lockss-turtles 0.5.0.dev3__py3-none-any.whl → 0.6.0.dev1__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.
- lockss/turtles/__init__.py +7 -30
- lockss/turtles/__main__.py +3 -3
- lockss/turtles/app.py +82 -75
- lockss/turtles/cli.py +159 -320
- lockss/turtles/plugin.py +64 -55
- lockss/turtles/plugin_registry.py +90 -79
- lockss/turtles/plugin_set.py +95 -87
- lockss/turtles/resources/__init__.py +1 -1
- lockss/turtles/util.py +8 -10
- {lockss_turtles-0.5.0.dev3.dist-info → lockss_turtles-0.6.0.dev1.dist-info}/LICENSE +1 -1
- {lockss_turtles-0.5.0.dev3.dist-info → lockss_turtles-0.6.0.dev1.dist-info}/METADATA +17 -19
- lockss_turtles-0.6.0.dev1.dist-info/RECORD +19 -0
- {lockss_turtles-0.5.0.dev3.dist-info → lockss_turtles-0.6.0.dev1.dist-info}/WHEEL +1 -1
- CHANGELOG.rst +0 -113
- lockss_turtles-0.5.0.dev3.dist-info/RECORD +0 -20
- {lockss_turtles-0.5.0.dev3.dist-info → lockss_turtles-0.6.0.dev1.dist-info}/entry_points.txt +0 -0
lockss/turtles/cli.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
|
-
# Copyright (c) 2000-
|
|
3
|
+
# Copyright (c) 2000-2025, Board of Trustees of Leland Stanford Jr. University
|
|
4
4
|
#
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without
|
|
6
6
|
# modification, are permitted provided that the following conditions are met:
|
|
@@ -28,50 +28,123 @@
|
|
|
28
28
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
29
29
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
"""
|
|
32
|
+
Tool for managing LOCKSS plugin sets and LOCKSS plugin registries
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
from getpass import getpass
|
|
33
36
|
from pathlib import Path
|
|
34
|
-
import sys
|
|
35
37
|
|
|
36
|
-
import
|
|
38
|
+
from lockss.pybasic.cliutil import BaseCli, StringCommand, COPYRIGHT_DESCRIPTION, LICENSE_DESCRIPTION, VERSION_DESCRIPTION
|
|
39
|
+
from lockss.pybasic.fileutil import file_lines, path
|
|
40
|
+
from lockss.pybasic.outpututil import OutputFormatOptions
|
|
41
|
+
from pydantic.v1 import BaseModel, Field, FilePath
|
|
42
|
+
from pydantic.v1.class_validators import validator
|
|
37
43
|
import tabulate
|
|
44
|
+
from typing import List, Optional
|
|
45
|
+
|
|
46
|
+
from . import __copyright__, __license__, __version__
|
|
47
|
+
from .app import TurtlesApp
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class PluginBuildingOptions(BaseModel):
|
|
51
|
+
plugin_set_catalog: Optional[FilePath] = Field(aliases=['-s'], description=f'(plugin set catalog) load the plugin set catalog from the given file, or if none, from {" or ".join(map(str, TurtlesApp.default_plugin_set_catalogs()))}')
|
|
52
|
+
plugin_signing_credentials: Optional[FilePath] = Field(aliases=['-c'], description=f'(plugin signing credentials) load the plugin signing credentials from the given file, or if none, from {" or ".join(map(str, TurtlesApp.default_plugin_signing_credentials()))}')
|
|
53
|
+
plugin_signing_password: Optional[str] = Field(description='(plugin signing credentials) set the plugin signing password, or if none, prompt interactively')
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class PluginDeploymentOptions(BaseModel):
|
|
57
|
+
plugin_registry_catalog: Optional[FilePath] = Field(aliases=['-r'], description=f'(plugin registry catalog) load the plugin registry catalog from the given file, or if none, from {" or ".join(map(str, TurtlesApp.default_plugin_registry_catalogs()))}')
|
|
58
|
+
plugin_registry_layer: Optional[List[str]] = Field(aliases=['-l'], description='(plugin registry layers) add one or more plugin registry layers to the set of plugin registry layers to process')
|
|
59
|
+
plugin_registry_layers: Optional[List[FilePath]] = Field(aliases=['-L'], description='(plugin registry layers) add the plugin registry layers listed in one or more files to the set of plugin registry layers to process')
|
|
60
|
+
testing: Optional[bool] = Field(False, aliases=['-t'], description='(plugin registry layers) synonym for --plugin-registry-layer testing (i.e. add "testing" to the list of plugin registry layers to process)')
|
|
61
|
+
production: Optional[bool] = Field(False, aliases=['-p'], description='(plugin registry layers) synonym for --plugin-registry-layer production (i.e. add "production" to the list of plugin registry layers to process)')
|
|
62
|
+
|
|
63
|
+
@validator('plugin_registry_layers', each_item=True, pre=True)
|
|
64
|
+
def _expand_each_plugin_registry_layers_path(cls, v: Path):
|
|
65
|
+
return path(v)
|
|
66
|
+
|
|
67
|
+
def get_plugin_registry_layers(self):
|
|
68
|
+
ret = [*self.plugin_registry_layer[:], *[file_lines(file_path) for file_path in self.plugin_registry_layers]]
|
|
69
|
+
for layer in reversed(['testing', 'production']):
|
|
70
|
+
if getattr(self, layer, False):
|
|
71
|
+
ret.insert(0, layer)
|
|
72
|
+
if len(ret) == 0:
|
|
73
|
+
raise RuntimeError('empty list of plugin registry layers')
|
|
74
|
+
return ret
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class PluginIdentifierOptions(BaseModel):
|
|
78
|
+
"""
|
|
79
|
+
The --identifier/-i and --identifiers/-I options.
|
|
80
|
+
"""
|
|
81
|
+
plugin_identifier: Optional[List[str]] = Field([], aliases=['-i'], description='(plugin identifiers) add one or more plugin identifiers to the set of plugin identifiers to process')
|
|
82
|
+
plugin_identifiers: Optional[List[FilePath]] = Field([], aliases=['-I'], description='(plugin identifiers) add the plugin identifiers listed in one or more files to the set of plugin identifiers to process')
|
|
83
|
+
|
|
84
|
+
@validator('plugin_identifiers', each_item=True, pre=True)
|
|
85
|
+
def _expand_each_plugin_identifiers_path(cls, v: Path):
|
|
86
|
+
return path(v)
|
|
87
|
+
|
|
88
|
+
def get_plugin_identifiers(self) -> List[str]:
|
|
89
|
+
ret = [*self.plugin_identifier[:], *[file_lines(file_path) for file_path in self.plugin_identifiers]]
|
|
90
|
+
if len(ret) == 0:
|
|
91
|
+
raise RuntimeError('empty list of plugin identifiers')
|
|
92
|
+
return ret
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class PluginJarOptions(BaseModel):
|
|
96
|
+
"""
|
|
97
|
+
The --plugin-jar/-j and --plugin-jars/-J options.
|
|
98
|
+
"""
|
|
99
|
+
plugin_jar: Optional[List[FilePath]] = Field([], aliases=['-j'], description='(plugin JARs) add one or more plugin JARs to the set of plugin JARs to process')
|
|
100
|
+
plugin_jars: Optional[List[FilePath]] = Field([], aliases=['-J'], description='(plugin JARs) add the plugin JARs listed in one or more files to the set of plugin JARs to process')
|
|
101
|
+
|
|
102
|
+
@validator('plugin_jar', 'plugin_jars', each_item=True, pre=True)
|
|
103
|
+
def _expand_each_plugin_jars_path(cls, v: Path):
|
|
104
|
+
return path(v)
|
|
105
|
+
|
|
106
|
+
def get_plugin_jars(self):
|
|
107
|
+
ret = [*self.plugin_jar[:], *[file_lines(file_path) for file_path in self.plugin_jars]]
|
|
108
|
+
if len(ret) == 0:
|
|
109
|
+
raise RuntimeError('empty list of plugin JARs')
|
|
110
|
+
return ret
|
|
38
111
|
|
|
39
|
-
import lockss.turtles
|
|
40
|
-
from lockss.turtles.app import TurtlesApp
|
|
41
|
-
from lockss.turtles.plugin_registry import PluginRegistryLayer
|
|
42
|
-
from lockss.turtles.util import _path
|
|
43
112
|
|
|
113
|
+
class NonInteractiveOptions(BaseModel):
|
|
114
|
+
non_interactive: Optional[bool] = Field(False, description='(plugin signing credentials) disallow interactive prompts')
|
|
44
115
|
|
|
45
|
-
def _file_lines(path):
|
|
46
|
-
f = None
|
|
47
|
-
try:
|
|
48
|
-
f = open(_path(path), 'r') if path != '-' else sys.stdin
|
|
49
|
-
return [line for line in [line.partition('#')[0].strip() for line in f] if len(line) > 0]
|
|
50
|
-
finally:
|
|
51
|
-
if f is not None and path != '-':
|
|
52
|
-
f.close()
|
|
53
116
|
|
|
117
|
+
class BuildPluginCommand(OutputFormatOptions, NonInteractiveOptions, PluginBuildingOptions, PluginIdentifierOptions):
|
|
118
|
+
pass
|
|
54
119
|
|
|
55
|
-
class TurtlesCli(object):
|
|
56
120
|
|
|
57
|
-
|
|
121
|
+
class DeployPluginCommand(OutputFormatOptions, NonInteractiveOptions, PluginDeploymentOptions, PluginJarOptions):
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class ReleasePluginCommand(OutputFormatOptions, NonInteractiveOptions, PluginDeploymentOptions, PluginBuildingOptions, PluginIdentifierOptions):
|
|
126
|
+
pass
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class TurtlesCommand(BaseModel):
|
|
130
|
+
bp: Optional[BuildPluginCommand] = Field(description='synonym for: build-plugin')
|
|
131
|
+
build_plugin: Optional[BuildPluginCommand] = Field(description='build (package and sign) plugins')
|
|
132
|
+
copyright: Optional[StringCommand.type(__copyright__)] = Field(description=COPYRIGHT_DESCRIPTION)
|
|
133
|
+
deploy_plugin: Optional[DeployPluginCommand] = Field(description='deploy plugins')
|
|
134
|
+
dp: Optional[DeployPluginCommand] = Field(description='synonym for: deploy-plugin')
|
|
135
|
+
license: Optional[StringCommand.type(__license__)] = Field(description=LICENSE_DESCRIPTION)
|
|
136
|
+
release_plugin: Optional[ReleasePluginCommand] = Field(description='release (build and deploy) plugins')
|
|
137
|
+
rp: Optional[ReleasePluginCommand] = Field(description='synonym for: release-plugin')
|
|
138
|
+
version: Optional[StringCommand.type(__version__)] = Field(description=VERSION_DESCRIPTION)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class TurtlesCli(BaseCli[TurtlesCommand]):
|
|
58
142
|
|
|
59
143
|
def __init__(self):
|
|
60
|
-
super().__init__(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
self.
|
|
64
|
-
self._jars = None
|
|
65
|
-
self._layers = None
|
|
66
|
-
self._parser = None
|
|
67
|
-
self._subparsers = None
|
|
68
|
-
|
|
69
|
-
def run(self):
|
|
70
|
-
self._make_parser()
|
|
71
|
-
self._args = self._parser.parse_args()
|
|
72
|
-
if self._args.debug_cli:
|
|
73
|
-
print(self._args)
|
|
74
|
-
self._args.fun()
|
|
144
|
+
super().__init__(model=TurtlesCommand,
|
|
145
|
+
prog='turtles',
|
|
146
|
+
description='Tool for managing LOCKSS plugin sets and LOCKSS plugin registries')
|
|
147
|
+
self._app: TurtlesApp = TurtlesApp()
|
|
75
148
|
|
|
76
149
|
# def _analyze_registry(self):
|
|
77
150
|
# # Prerequisites
|
|
@@ -131,316 +204,82 @@ class TurtlesCli(object):
|
|
|
131
204
|
# if len(result) > 0:
|
|
132
205
|
# self._tabulate(title, result, headers)
|
|
133
206
|
|
|
134
|
-
def
|
|
207
|
+
def _bp(self, build_plugin_command: BuildPluginCommand) -> None:
|
|
208
|
+
return self._build_plugin(build_plugin_command)
|
|
209
|
+
|
|
210
|
+
def _build_plugin(self, build_plugin_command: BuildPluginCommand) -> None:
|
|
135
211
|
# Prerequisites
|
|
136
|
-
self._app.load_plugin_sets(
|
|
137
|
-
self._app.load_plugin_signing_credentials(
|
|
138
|
-
self._obtain_password()
|
|
212
|
+
self._app.load_plugin_sets(build_plugin_command.plugin_set_catalog)
|
|
213
|
+
self._app.load_plugin_signing_credentials(build_plugin_command.plugin_signing_credentials)
|
|
214
|
+
self._obtain_password(build_plugin_command)
|
|
139
215
|
# Action
|
|
140
216
|
# ... plugin_id -> (set_id, jar_path, plugin)
|
|
141
|
-
ret = self._app.build_plugin(
|
|
217
|
+
ret = self._app.build_plugin(build_plugin_command.get_plugin_identifiers())
|
|
142
218
|
# Output
|
|
143
219
|
print(tabulate.tabulate([[plugin_id, plugin.get_version(), set_id, jar_path] for plugin_id, (set_id, jar_path, plugin) in ret.items()],
|
|
144
220
|
headers=['Plugin identifier', 'Plugin version', 'Plugin set', 'Plugin JAR'],
|
|
145
|
-
tablefmt=
|
|
221
|
+
tablefmt=build_plugin_command.output_format))
|
|
146
222
|
|
|
147
|
-
def _copyright(self):
|
|
148
|
-
|
|
223
|
+
def _copyright(self, string_command: StringCommand) -> None:
|
|
224
|
+
self._do_string_command(string_command)
|
|
149
225
|
|
|
150
|
-
def _deploy_plugin(self):
|
|
226
|
+
def _deploy_plugin(self, deploy_plugin_command: DeployPluginCommand) -> None:
|
|
151
227
|
# Prerequisites
|
|
152
|
-
self._app.load_plugin_registries(
|
|
228
|
+
self._app.load_plugin_registries(deploy_plugin_command.plugin_registry_catalog)
|
|
153
229
|
# Action
|
|
154
230
|
# ... (src_path, plugin_id) -> list of (registry_id, layer_id, dst_path, plugin)
|
|
155
|
-
ret = self._app.deploy_plugin(
|
|
156
|
-
|
|
157
|
-
interactive=
|
|
231
|
+
ret = self._app.deploy_plugin(deploy_plugin_command.get_plugin_jars(),
|
|
232
|
+
deploy_plugin_command.get_plugin_registry_layers(),
|
|
233
|
+
interactive=not deploy_plugin_command.non_interactive)
|
|
158
234
|
# Output
|
|
159
235
|
print(tabulate.tabulate([[src_path, plugin_id, plugin.get_version(), registry_id, layer_id, dst_path] for (src_path, plugin_id), val in ret.items() for registry_id, layer_id, dst_path, plugin in val],
|
|
160
236
|
headers=['Plugin JAR', 'Plugin identifier', 'Plugin version', 'Plugin registry', 'Plugin registry layer', 'Deployed JAR'],
|
|
161
|
-
tablefmt=
|
|
162
|
-
|
|
163
|
-
def
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
self._jars.extend(self._args.remainder)
|
|
178
|
-
self._jars.extend(self._args.jar)
|
|
179
|
-
for path in self._args.jars:
|
|
180
|
-
self._jars.extend(_file_lines(path))
|
|
181
|
-
if len(self._jars) == 0:
|
|
182
|
-
self._parser.error('list of plugin JARs to deploy is empty')
|
|
183
|
-
return self._jars
|
|
184
|
-
|
|
185
|
-
def _get_layers(self):
|
|
186
|
-
if self._layers is None:
|
|
187
|
-
self._layers = list()
|
|
188
|
-
self._layers.extend(self._args.layer)
|
|
189
|
-
for path in self._args.layers:
|
|
190
|
-
self._layers.extend(_file_lines(path))
|
|
191
|
-
if len(self._layers) == 0:
|
|
192
|
-
self._parser.error('list of plugin registry layers to process is empty')
|
|
193
|
-
return self._layers
|
|
194
|
-
|
|
195
|
-
def _license(self):
|
|
196
|
-
print(lockss.turtles.__license__)
|
|
197
|
-
|
|
198
|
-
def _make_option_debug_cli(self, container):
|
|
199
|
-
container.add_argument('--debug-cli',
|
|
200
|
-
action='store_true',
|
|
201
|
-
help='print the result of parsing command line arguments')
|
|
202
|
-
|
|
203
|
-
def _make_option_non_interactive(self, container):
|
|
204
|
-
container.add_argument('--non-interactive', '-n',
|
|
205
|
-
dest='interactive',
|
|
206
|
-
action='store_false', # note: default True
|
|
207
|
-
help='disallow interactive prompts (default: allow)')
|
|
208
|
-
|
|
209
|
-
def _make_option_output_format(self, container):
|
|
210
|
-
container.add_argument('--output-format',
|
|
211
|
-
metavar='FMT',
|
|
212
|
-
choices=tabulate.tabulate_formats,
|
|
213
|
-
default='simple',
|
|
214
|
-
help='set tabular output format to %(metavar)s (default: %(default)s; choices: %(choices)s)')
|
|
215
|
-
|
|
216
|
-
def _make_option_password(self, container):
|
|
217
|
-
container.add_argument('--password',
|
|
218
|
-
metavar='PASS',
|
|
219
|
-
help='set the plugin signing password')
|
|
220
|
-
|
|
221
|
-
def _make_option_plugin_registry_catalog(self, container):
|
|
222
|
-
container.add_argument('--plugin-registry-catalog', '-r',
|
|
223
|
-
metavar='FILE',
|
|
224
|
-
type=Path,
|
|
225
|
-
help=f'load plugin registry catalog from %(metavar)s (default: {" or ".join(map(str, self._app.default_plugin_registry_catalogs()))})')
|
|
226
|
-
|
|
227
|
-
def _make_option_plugin_set_catalog(self, container):
|
|
228
|
-
container.add_argument('--plugin-set-catalog', '-s',
|
|
229
|
-
metavar='FILE',
|
|
230
|
-
type=Path,
|
|
231
|
-
help=f'load plugin set catalog from %(metavar)s (default: {" or ".join(map(str, self._app.default_plugin_set_catalogs()))})')
|
|
232
|
-
|
|
233
|
-
def _make_option_plugin_signing_credentials(self, container):
|
|
234
|
-
container.add_argument('--plugin-signing-credentials', '-c',
|
|
235
|
-
metavar='FILE',
|
|
236
|
-
type=Path,
|
|
237
|
-
help=f'load plugin signing credentials from %(metavar)s (default: {" or ".join(map(str, self._app.default_plugin_signing_credentials()))})')
|
|
238
|
-
|
|
239
|
-
def _make_option_production(self, container):
|
|
240
|
-
container.add_argument('--production', '-p',
|
|
241
|
-
dest='layer',
|
|
242
|
-
action='append_const',
|
|
243
|
-
const=PluginRegistryLayer.PRODUCTION,
|
|
244
|
-
help="synonym for --layer=%(const)s (i.e. add '%(const)s' to the list of plugin registry layers to process)")
|
|
245
|
-
|
|
246
|
-
def _make_option_testing(self, container):
|
|
247
|
-
container.add_argument('--testing', '-t',
|
|
248
|
-
dest='layer',
|
|
249
|
-
action='append_const',
|
|
250
|
-
const=PluginRegistryLayer.TESTING,
|
|
251
|
-
help="synonym for --layer=%(const)s (i.e. add '%(const)s' to the list of plugin registry layers to process)")
|
|
252
|
-
|
|
253
|
-
def _make_options_identifiers(self, container):
|
|
254
|
-
group = container.add_argument_group(title='plugin identifier arguments and options')
|
|
255
|
-
group.add_argument('--identifier', '-i',
|
|
256
|
-
metavar='PLUGID',
|
|
257
|
-
action='append',
|
|
258
|
-
default=list(),
|
|
259
|
-
help='add %(metavar)s to the list of plugin identifiers to build')
|
|
260
|
-
group.add_argument('--identifiers', '-I',
|
|
261
|
-
metavar='FILE',
|
|
262
|
-
action='append',
|
|
263
|
-
default=list(),
|
|
264
|
-
help='add the plugin identifiers in %(metavar)s to the list of plugin identifiers to build')
|
|
265
|
-
group.add_argument('remainder',
|
|
266
|
-
metavar='PLUGID',
|
|
267
|
-
nargs='*',
|
|
268
|
-
help='plugin identifier to build')
|
|
269
|
-
|
|
270
|
-
def _make_options_jars(self, container):
|
|
271
|
-
group = container.add_argument_group(title='plugin JAR arguments and options')
|
|
272
|
-
group.add_argument('--jar', '-j',
|
|
273
|
-
metavar='PLUGJAR',
|
|
274
|
-
type=Path,
|
|
275
|
-
action='append',
|
|
276
|
-
default=list(),
|
|
277
|
-
help='add %(metavar)s to the list of plugin JARs to deploy')
|
|
278
|
-
group.add_argument('--jars', '-J',
|
|
279
|
-
metavar='FILE',
|
|
280
|
-
action='append',
|
|
281
|
-
default=list(),
|
|
282
|
-
help='add the plugin JARs in %(metavar)s to the list of plugin JARs to deploy')
|
|
283
|
-
group.add_argument('remainder',
|
|
284
|
-
metavar='PLUGJAR',
|
|
285
|
-
nargs='*',
|
|
286
|
-
help='plugin JAR to deploy')
|
|
287
|
-
|
|
288
|
-
def _make_options_layers(self, container):
|
|
289
|
-
group = container.add_argument_group(title='plugin registry layer options')
|
|
290
|
-
group.add_argument('--layer', '-l',
|
|
291
|
-
metavar='LAYER',
|
|
292
|
-
action='append',
|
|
293
|
-
default=list(),
|
|
294
|
-
help='add %(metavar)s to the list of plugin registry layers to process')
|
|
295
|
-
group.add_argument('--layers', '-L',
|
|
296
|
-
metavar='FILE',
|
|
297
|
-
action='append',
|
|
298
|
-
default=list(),
|
|
299
|
-
help='add the layers in %(metavar)s to the list of plugin registry layers to process')
|
|
300
|
-
|
|
301
|
-
def _make_parser(self):
|
|
302
|
-
for cls in [rich_argparse.RichHelpFormatter]:
|
|
303
|
-
cls.styles.update({
|
|
304
|
-
'argparse.args': f'bold {cls.styles["argparse.args"]}',
|
|
305
|
-
'argparse.groups': f'bold {cls.styles["argparse.groups"]}',
|
|
306
|
-
'argparse.metavar': f'bold {cls.styles["argparse.metavar"]}',
|
|
307
|
-
'argparse.prog': f'bold {cls.styles["argparse.prog"]}',
|
|
308
|
-
})
|
|
309
|
-
self._parser = argparse.ArgumentParser(prog=TurtlesCli.PROG,
|
|
310
|
-
formatter_class=rich_argparse.RichHelpFormatter)
|
|
311
|
-
self._subparsers = self._parser.add_subparsers(title='commands',
|
|
312
|
-
description="Add --help to see the command's own help message.",
|
|
313
|
-
# With subparsers, metavar is also used as the heading of the column of subcommands
|
|
314
|
-
metavar='COMMAND',
|
|
315
|
-
# With subparsers, help is used as the heading of the column of subcommand descriptions
|
|
316
|
-
help='DESCRIPTION')
|
|
317
|
-
self._make_option_debug_cli(self._parser)
|
|
318
|
-
self._make_option_non_interactive(self._parser)
|
|
319
|
-
#self._make_parser_analyze_registry(self._subparsers)
|
|
320
|
-
self._make_parser_build_plugin(self._subparsers)
|
|
321
|
-
self._make_parser_copyright(self._subparsers)
|
|
322
|
-
self._make_parser_deploy_plugin(self._subparsers)
|
|
323
|
-
self._make_parser_license(self._subparsers)
|
|
324
|
-
self._make_parser_release_plugin(self._subparsers)
|
|
325
|
-
self._make_parser_usage(self._subparsers)
|
|
326
|
-
self._make_parser_version(self._subparsers)
|
|
327
|
-
|
|
328
|
-
# def _make_parser_analyze_registry(self, container):
|
|
329
|
-
# parser = container.add_parser('analyze-registry', aliases=['ar'],
|
|
330
|
-
# description='Analyze plugin registries',
|
|
331
|
-
# help='analyze plugin registries')
|
|
332
|
-
# parser.set_defaults(fun=self._analyze_registry)
|
|
333
|
-
# self._make_option_plugin_registry_catalog(parser)
|
|
334
|
-
# self._make_option_plugin_set_catalog(parser)
|
|
335
|
-
# self._make_option_plugin_signing(parser)
|
|
336
|
-
|
|
337
|
-
def _make_parser_build_plugin(self, container):
|
|
338
|
-
parser = container.add_parser('build-plugin', aliases=['bp'],
|
|
339
|
-
description='Build (package and sign) plugins.',
|
|
340
|
-
help='build (package and sign) plugins',
|
|
341
|
-
formatter_class=self._parser.formatter_class)
|
|
342
|
-
parser.set_defaults(fun=self._build_plugin)
|
|
343
|
-
self._make_option_output_format(parser)
|
|
344
|
-
self._make_option_password(parser)
|
|
345
|
-
self._make_option_plugin_set_catalog(parser)
|
|
346
|
-
self._make_option_plugin_signing_credentials(parser)
|
|
347
|
-
self._make_options_identifiers(parser)
|
|
348
|
-
|
|
349
|
-
def _make_parser_copyright(self, container):
|
|
350
|
-
parser = container.add_parser('copyright',
|
|
351
|
-
description='Show copyright and exit.',
|
|
352
|
-
help='show copyright and exit',
|
|
353
|
-
formatter_class=self._parser.formatter_class)
|
|
354
|
-
parser.set_defaults(fun=self._copyright)
|
|
355
|
-
|
|
356
|
-
def _make_parser_deploy_plugin(self, container):
|
|
357
|
-
parser = container.add_parser('deploy-plugin', aliases=['dp'],
|
|
358
|
-
description='Deploy plugins.',
|
|
359
|
-
help='deploy plugins',
|
|
360
|
-
formatter_class=self._parser.formatter_class)
|
|
361
|
-
parser.set_defaults(fun=self._deploy_plugin)
|
|
362
|
-
self._make_option_output_format(parser)
|
|
363
|
-
self._make_option_plugin_registry_catalog(parser)
|
|
364
|
-
self._make_option_production(parser)
|
|
365
|
-
self._make_option_testing(parser)
|
|
366
|
-
self._make_options_jars(parser)
|
|
367
|
-
self._make_options_layers(parser)
|
|
368
|
-
|
|
369
|
-
def _make_parser_license(self, container):
|
|
370
|
-
parser = container.add_parser('license',
|
|
371
|
-
description='Show license and exit.',
|
|
372
|
-
help='show license and exit',
|
|
373
|
-
formatter_class=self._parser.formatter_class)
|
|
374
|
-
parser.set_defaults(fun=self._license)
|
|
375
|
-
|
|
376
|
-
def _make_parser_release_plugin(self, container):
|
|
377
|
-
parser = container.add_parser('release-plugin', aliases=['rp'],
|
|
378
|
-
description='Release (build and deploy) plugins.',
|
|
379
|
-
help='release (build and deploy) plugins',
|
|
380
|
-
formatter_class=self._parser.formatter_class)
|
|
381
|
-
parser.set_defaults(fun=self._release_plugin)
|
|
382
|
-
self._make_option_output_format(parser)
|
|
383
|
-
self._make_option_password(parser)
|
|
384
|
-
self._make_option_plugin_registry_catalog(parser)
|
|
385
|
-
self._make_option_plugin_set_catalog(parser)
|
|
386
|
-
self._make_option_plugin_signing_credentials(parser)
|
|
387
|
-
self._make_option_production(parser)
|
|
388
|
-
self._make_option_testing(parser)
|
|
389
|
-
self._make_options_identifiers(parser)
|
|
390
|
-
self._make_options_layers(parser)
|
|
391
|
-
|
|
392
|
-
def _make_parser_usage(self, container):
|
|
393
|
-
parser = container.add_parser('usage',
|
|
394
|
-
description='Show detailed usage and exit.',
|
|
395
|
-
help='show detailed usage and exit',
|
|
396
|
-
formatter_class=self._parser.formatter_class)
|
|
397
|
-
parser.set_defaults(fun=self._usage)
|
|
398
|
-
|
|
399
|
-
def _make_parser_version(self, container):
|
|
400
|
-
parser = container.add_parser('version',
|
|
401
|
-
description='Show version and exit.',
|
|
402
|
-
help='show version and exit',
|
|
403
|
-
formatter_class=self._parser.formatter_class)
|
|
404
|
-
parser.set_defaults(fun=self._version)
|
|
405
|
-
|
|
406
|
-
def _obtain_password(self):
|
|
407
|
-
if self._args.password is not None:
|
|
408
|
-
_p = self._args.password
|
|
409
|
-
elif self._args.interactive:
|
|
410
|
-
_p = getpass.getpass('Plugin signing password: ')
|
|
237
|
+
tablefmt=deploy_plugin_command.output_format))
|
|
238
|
+
|
|
239
|
+
def _do_string_command(self, string_command: StringCommand) -> None:
|
|
240
|
+
string_command()
|
|
241
|
+
|
|
242
|
+
def _dp(self, deploy_plugin_command: DeployPluginCommand) -> None:
|
|
243
|
+
return self._deploy_plugin(deploy_plugin_command)
|
|
244
|
+
|
|
245
|
+
def _license(self, string_command: StringCommand) -> None:
|
|
246
|
+
self._do_string_command(string_command)
|
|
247
|
+
|
|
248
|
+
def _obtain_password(self, non_interactive_options: NonInteractiveOptions) -> None:
|
|
249
|
+
if non_interactive_options.plugin_signing_password is not None:
|
|
250
|
+
_p = non_interactive_options.plugin_signing_password
|
|
251
|
+
elif non_interactive_options.non_interactive:
|
|
252
|
+
_p = getpass('Plugin signing password: ')
|
|
411
253
|
else:
|
|
412
254
|
self._parser.error('no plugin signing password specified while in non-interactive mode')
|
|
413
255
|
self._app.set_password(lambda: _p)
|
|
414
256
|
|
|
415
|
-
def _release_plugin(self):
|
|
257
|
+
def _release_plugin(self, release_plugin_command: ReleasePluginCommand) -> None:
|
|
416
258
|
# Prerequisites
|
|
417
|
-
self._app.load_plugin_sets(
|
|
418
|
-
self._app.load_plugin_registries(
|
|
419
|
-
self._app.load_plugin_signing_credentials(
|
|
420
|
-
self._obtain_password()
|
|
259
|
+
self._app.load_plugin_sets(release_plugin_command.plugin_set_catalog)
|
|
260
|
+
self._app.load_plugin_registries(release_plugin_command.plugin_registry_catalog)
|
|
261
|
+
self._app.load_plugin_signing_credentials(release_plugin_command.plugin_signing_credentials)
|
|
262
|
+
self._obtain_password(release_plugin_command)
|
|
421
263
|
# Action
|
|
422
264
|
# ... plugin_id -> list of (registry_id, layer_id, dst_path, plugin)
|
|
423
|
-
ret = self._app.release_plugin(
|
|
424
|
-
|
|
425
|
-
interactive=
|
|
265
|
+
ret = self._app.release_plugin(release_plugin_command.get_plugin_identifiers(),
|
|
266
|
+
release_plugin_command.get_plugin_registry_layers(),
|
|
267
|
+
interactive=not release_plugin_command.non_interactive)
|
|
426
268
|
# Output
|
|
427
269
|
print(tabulate.tabulate([[plugin_id, plugin.get_version(), registry_id, layer_id, dst_path] for plugin_id, val in ret.items() for registry_id, layer_id, dst_path, plugin in val],
|
|
428
270
|
headers=['Plugin identifier', 'Plugin version', 'Plugin registry', 'Plugin registry layer', 'Deployed JAR'],
|
|
429
|
-
tablefmt=
|
|
430
|
-
|
|
431
|
-
def
|
|
432
|
-
self.
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
uniq.add(par)
|
|
438
|
-
for s in par.format_usage().split('\n'):
|
|
439
|
-
usage = 'usage: '
|
|
440
|
-
print(f'{" " * len(usage)}{s[len(usage):]}' if s.startswith(usage) else s)
|
|
441
|
-
|
|
442
|
-
def _version(self):
|
|
443
|
-
print(lockss.turtles.__version__)
|
|
271
|
+
tablefmt=release_plugin_command.output_format))
|
|
272
|
+
|
|
273
|
+
def _rp(self, release_plugin_command: ReleasePluginCommand) -> None:
|
|
274
|
+
self._release_plugin(release_plugin_command)
|
|
275
|
+
|
|
276
|
+
def _version(self, string_command: StringCommand) -> None:
|
|
277
|
+
self._do_string_command(string_command)
|
|
278
|
+
|
|
444
279
|
|
|
445
280
|
def main():
|
|
446
281
|
TurtlesCli().run()
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
if __name__ == '__main__':
|
|
285
|
+
main()
|