lockss-turtles 0.5.0.dev4__tar.gz → 0.6.0.dev1__tar.gz

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 (22) hide show
  1. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev1}/CHANGELOG.rst +35 -1
  2. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev1}/LICENSE +1 -1
  3. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev1}/PKG-INFO +17 -19
  4. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev1}/README.rst +1 -1
  5. lockss_turtles-0.6.0.dev1/pyproject.toml +81 -0
  6. lockss_turtles-0.6.0.dev1/src/lockss/turtles/__init__.py +40 -0
  7. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev1}/src/lockss/turtles/__main__.py +3 -3
  8. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev1}/src/lockss/turtles/app.py +82 -75
  9. lockss_turtles-0.6.0.dev1/src/lockss/turtles/cli.py +285 -0
  10. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev1}/src/lockss/turtles/plugin.py +64 -55
  11. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev1}/src/lockss/turtles/plugin_registry.py +90 -79
  12. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev1}/src/lockss/turtles/plugin_set.py +95 -87
  13. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev1}/src/lockss/turtles/resources/__init__.py +1 -1
  14. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev1}/src/lockss/turtles/util.py +8 -10
  15. lockss_turtles-0.5.0.dev4/pyproject.toml +0 -41
  16. lockss_turtles-0.5.0.dev4/src/lockss/turtles/__init__.py +0 -63
  17. lockss_turtles-0.5.0.dev4/src/lockss/turtles/cli.py +0 -446
  18. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev1}/src/lockss/turtles/resources/plugin-registry-catalog-schema.json +0 -0
  19. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev1}/src/lockss/turtles/resources/plugin-registry-schema.json +0 -0
  20. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev1}/src/lockss/turtles/resources/plugin-set-catalog-schema.json +0 -0
  21. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev1}/src/lockss/turtles/resources/plugin-set-schema.json +0 -0
  22. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev1}/src/lockss/turtles/resources/plugin-signing-credentials-schema.json +0 -0
@@ -3,13 +3,47 @@ Release Notes
3
3
  =============
4
4
 
5
5
  -----
6
- 0.5.0
6
+ 0.6.0
7
7
  -----
8
8
 
9
9
  Released: ?
10
10
 
11
11
  * **Features**
12
12
 
13
+ * Now using type hinting throughout.
14
+
15
+ * Now using *lockss-pybasic* and *pydantic-argparse* internally.
16
+
17
+ * **Changes**
18
+
19
+ * Some long options have been renamed (the short options remain unchanged):
20
+
21
+ ============ ================= =============
22
+ Short option Version 0.5.0 Version 0.6.0
23
+ ============ ================= =============
24
+ ``-i`` ``--identifier`` ``--plugin-identifier``
25
+ ``-I`` ``--identifiers`` ``--plugin-identifiers``
26
+ ``-j`` ``--jar`` ``--plugin-jar``
27
+ ``-J`` ``--jars`` ``--plugin-jars``
28
+ ``-l`` ``--layer`` ``--plugin-registry-layer``
29
+ ``-L`` ``--layers`` ``--plugin-registry-layers``
30
+ n/a ``--password`` ``--plugin-signing-password``
31
+ ============ ================= =============
32
+
33
+ * Bare arguments are no longer allowed and treated as plugin identifiers or plugin JARs; all plugin identifiers must be specified via ``--plugin-identifier/-i`` or ``--plugin-identifiers/-I`` options and all plugin JARS via ``--plugin-jar/-j`` or ``--plugin-jars/-J`` options.
34
+
35
+ * The ``usage`` command has been removed.
36
+
37
+ -----
38
+ 0.5.0
39
+ -----
40
+
41
+ Released: 2024-09-04
42
+
43
+ * **Features**
44
+
45
+ * ``AntPluginSet``: also include plugin auxiliary packages (``plugin_aux_packages``).
46
+
13
47
  -----
14
48
  0.4.0
15
49
  -----
@@ -1,4 +1,4 @@
1
- Copyright (c) 2000-2023, Board of Trustees of Leland Stanford Jr. University
1
+ Copyright (c) 2000-2025, Board of Trustees of Leland Stanford Jr. University
2
2
 
3
3
  Redistribution and use in source and binary forms, with or without
4
4
  modification, are permitted provided that the following conditions are met:
@@ -1,31 +1,29 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: lockss-turtles
3
- Version: 0.5.0.dev4
4
- Summary: Tool to manage LOCKSS plugin sets and LOCKSS plugin registries
5
- Home-page: https://www.lockss.org/
3
+ Version: 0.6.0.dev1
4
+ Summary: Library and command line tool to manage LOCKSS plugin sets and LOCKSS plugin registries
6
5
  License: BSD-3-Clause
7
6
  Author: Thib Guicherd-Callin
8
7
  Author-email: thib@cs.stanford.edu
9
- Requires-Python: >=3.8,<4.0
8
+ Maintainer: Thib Guicherd-Callin
9
+ Maintainer-email: thib@cs.stanford.edu
10
+ Requires-Python: >=3.9,<4.0
10
11
  Classifier: Development Status :: 5 - Production/Stable
11
12
  Classifier: Environment :: Console
13
+ Classifier: Framework :: Pydantic :: 2
12
14
  Classifier: Intended Audience :: Developers
13
15
  Classifier: Intended Audience :: System Administrators
14
16
  Classifier: License :: OSI Approved :: BSD License
15
- Classifier: Operating System :: POSIX :: Linux
16
- Classifier: Programming Language :: Python :: 3
17
- Classifier: Programming Language :: Python :: 3.8
18
- Classifier: Programming Language :: Python :: 3.9
19
- Classifier: Programming Language :: Python :: 3.10
20
- Classifier: Programming Language :: Python :: 3.11
21
- Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python
18
+ Classifier: Topic :: Software Development :: Libraries
19
+ Classifier: Topic :: System :: Archiving
22
20
  Classifier: Topic :: Utilities
23
- Requires-Dist: java-manifest (>=1.1.0,<2.0.0)
24
- Requires-Dist: jsonschema (>=4.23.0,<5.0.0)
25
- Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
26
- Requires-Dist: rich-argparse (>=1.5.2,<2.0.0)
27
- Requires-Dist: tabulate (>=0.9.0,<0.10.0)
28
- Requires-Dist: xdg (>=6.0.0,<7.0.0)
21
+ Requires-Dist: java-manifest (>=1.1.0,<1.2.0)
22
+ Requires-Dist: jsonschema (>=4.24.0,<4.25.0)
23
+ Requires-Dist: lockss-pybasic (>=0.1.0,<0.2.0)
24
+ Requires-Dist: pydantic (>=2.11.7,<3.0.0)
25
+ Requires-Dist: pyyaml (>=6.0.0,<6.1.0)
26
+ Requires-Dist: xdg (>=6.0.0,<6.1.0)
29
27
  Project-URL: Repository, https://github.com/lockss/lockss-turtles
30
28
  Description-Content-Type: text/x-rst
31
29
 
@@ -33,7 +31,7 @@ Description-Content-Type: text/x-rst
33
31
  Turtles
34
32
  =======
35
33
 
36
- .. |RELEASE| replace:: 0.5.0-dev1
34
+ .. |RELEASE| replace:: 0.6.0-dev1
37
35
  .. |RELEASE_DATE| replace:: ?
38
36
 
39
37
  .. |HELP| replace:: ``--help/-h``
@@ -2,7 +2,7 @@
2
2
  Turtles
3
3
  =======
4
4
 
5
- .. |RELEASE| replace:: 0.5.0-dev1
5
+ .. |RELEASE| replace:: 0.6.0-dev1
6
6
  .. |RELEASE_DATE| replace:: ?
7
7
 
8
8
  .. |HELP| replace:: ``--help/-h``
@@ -0,0 +1,81 @@
1
+ # Copyright (c) 2000-2025, Board of Trustees of Leland Stanford Jr. University
2
+ #
3
+ # Redistribution and use in source and binary forms, with or without
4
+ # modification, are permitted provided that the following conditions are met:
5
+ #
6
+ # 1. Redistributions of source code must retain the above copyright notice,
7
+ # this list of conditions and the following disclaimer.
8
+ #
9
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ # this list of conditions and the following disclaimer in the documentation
11
+ # and/or other materials provided with the distribution.
12
+ #
13
+ # 3. Neither the name of the copyright holder nor the names of its contributors
14
+ # may be used to endorse or promote products derived from this software without
15
+ # specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ [project]
30
+ name = "lockss-turtles"
31
+ version = "0.6.0-dev1" # Always change in __init__.py, and at release time in README.rst and CHANGELOG.rst
32
+ description = "Library and command line tool to manage LOCKSS plugin sets and LOCKSS plugin registries"
33
+ license = { text = "BSD-3-Clause" }
34
+ readme = "README.rst"
35
+ requires-python = ">=3.9,<4.0"
36
+ authors = [
37
+ { name = "Thib Guicherd-Callin", email = "thib@cs.stanford.edu" },
38
+ ]
39
+ maintainers = [
40
+ { name = "Thib Guicherd-Callin", email = "thib@cs.stanford.edu" }
41
+ ]
42
+ dependencies = [
43
+ "java-manifest (>=1.1.0,<1.2.0)",
44
+ "jsonschema (>=4.24.0,<4.25.0)",
45
+ "lockss-pybasic (>=0.1.0,<0.2.0)",
46
+ "pyyaml (>=6.0.0,<6.1.0)",
47
+ "xdg (>=6.0.0,<6.1.0)",
48
+ "pydantic (>=2.11.7,<3.0.0)",
49
+ ]
50
+ classifiers = [
51
+ "Development Status :: 5 - Production/Stable",
52
+ "Environment :: Console",
53
+ "Framework :: Pydantic :: 2",
54
+ "Intended Audience :: Developers",
55
+ "Intended Audience :: System Administrators",
56
+ "License :: OSI Approved :: BSD License",
57
+ "Programming Language :: Python",
58
+ "Topic :: Software Development :: Libraries",
59
+ "Topic :: System :: Archiving",
60
+ "Topic :: Utilities",
61
+ ]
62
+
63
+ [project.urls]
64
+ repository = "https://github.com/lockss/lockss-turtles"
65
+
66
+ [tool.poetry]
67
+ include = [
68
+ "CHANGELOG.rst",
69
+ "LICENSE",
70
+ "README.rst",
71
+ ]
72
+ packages = [
73
+ { include = "lockss", from = "src" }
74
+ ]
75
+
76
+ [tool.poetry.scripts]
77
+ turtles = 'lockss.turtles.cli:main'
78
+
79
+ [build-system]
80
+ requires = ["poetry-core>=2.0.0,<3.0.0"]
81
+ build-backend = "poetry.core.masonry.api"
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env python3
2
+
3
+ """
4
+ Library and command line tool to manage LOCKSS plugin sets and LOCKSS plugin
5
+ registries.
6
+ """
7
+
8
+ __version__ = '0.6.0-dev1'
9
+
10
+ __copyright__ = '''
11
+ Copyright (c) 2000-2025, Board of Trustees of Leland Stanford Jr. University
12
+ '''.strip()
13
+
14
+ __license__ = __copyright__ + '\n\n' + '''
15
+ Redistribution and use in source and binary forms, with or without
16
+ modification, are permitted provided that the following conditions are met:
17
+
18
+ 1. Redistributions of source code must retain the above copyright notice,
19
+ this list of conditions and the following disclaimer.
20
+
21
+ 2. Redistributions in binary form must reproduce the above copyright notice,
22
+ this list of conditions and the following disclaimer in the documentation
23
+ and/or other materials provided with the distribution.
24
+
25
+ 3. Neither the name of the copyright holder nor the names of its contributors
26
+ may be used to endorse or promote products derived from this software without
27
+ specific prior written permission.
28
+
29
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
30
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
33
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39
+ POSSIBILITY OF SUCH DAMAGE.
40
+ '''.strip()
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
- # Copyright (c) 2000-2023, Board of Trustees of Leland Stanford Jr. University
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,6 +28,6 @@
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
- import lockss.turtles.cli
31
+ from lockss.turtles.cli import main
32
32
 
33
- lockss.turtles.cli.main()
33
+ main()
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
- # Copyright (c) 2000-2023, Board of Trustees of Leland Stanford Jr. University
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,103 +28,79 @@
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
- import importlib.resources
31
+ from collections.abc import Callable
32
+ import importlib.resources as IR
32
33
  from pathlib import Path
34
+ from typing import Dict, List, Optional, Tuple, Union
33
35
 
36
+ from lockss.pybasic.fileutil import path
34
37
  import xdg
35
38
 
36
- from lockss.turtles.plugin import Plugin
37
- from lockss.turtles.plugin_registry import PluginRegistry, PluginRegistryCatalog
38
- from lockss.turtles.plugin_set import PluginSet, PluginSetCatalog
39
- import lockss.turtles.resources
40
- from lockss.turtles.util import _load_and_validate, _path
39
+ from . import resources as __resources__
40
+ from .plugin import Plugin
41
+ from .plugin_registry import PluginRegistry, PluginRegistryCatalog
42
+ from .plugin_set import PluginSet, PluginSetCatalog
43
+ from .util import YamlT, load_and_validate
41
44
 
42
45
 
43
46
  class TurtlesApp(object):
44
47
 
45
- XDG_CONFIG_DIR = xdg.xdg_config_home().joinpath(__package__)
48
+ XDG_CONFIG_DIR: Path = xdg.xdg_config_home().joinpath(__package__)
46
49
 
47
- USR_CONFIG_DIR = Path('/usr/local/share', __package__)
50
+ USR_CONFIG_DIR: Path = Path('/usr/local/share', __package__)
48
51
 
49
- ETC_CONFIG_DIR = Path('/etc', __package__)
52
+ ETC_CONFIG_DIR: Path = Path('/etc', __package__)
50
53
 
51
- CONFIG_DIRS = [XDG_CONFIG_DIR, USR_CONFIG_DIR, ETC_CONFIG_DIR]
54
+ CONFIG_DIRS: List[Path] = [XDG_CONFIG_DIR, USR_CONFIG_DIR, ETC_CONFIG_DIR]
52
55
 
53
- PLUGIN_REGISTRY_CATALOG = 'plugin-registry-catalog.yaml'
56
+ PLUGIN_REGISTRY_CATALOG: str = 'plugin-registry-catalog.yaml'
54
57
 
55
- PLUGIN_SET_CATALOG = 'plugin-set-catalog.yaml'
58
+ PLUGIN_SET_CATALOG: str = 'plugin-set-catalog.yaml'
56
59
 
57
- PLUGIN_SIGNING_CREDENTIALS = 'plugin-signing-credentials.yaml'
60
+ PLUGIN_SIGNING_CREDENTIALS: str = 'plugin-signing-credentials.yaml'
58
61
 
59
- PLUGIN_SIGNING_CREDENTIALS_SCHEMA = 'plugin-signing-credentials-schema.json'
62
+ PLUGIN_SIGNING_CREDENTIALS_SCHEMA: str = 'plugin-signing-credentials-schema.json'
60
63
 
61
- @staticmethod
62
- def _default_files(file_str):
63
- return [dir_path.joinpath(file_str) for dir_path in TurtlesApp.CONFIG_DIRS]
64
-
65
- @staticmethod
66
- def _select_file(file_str, preselected=None):
67
- if preselected:
68
- preselected = _path(preselected)
69
- if not preselected.is_file():
70
- raise FileNotFoundError(str(preselected))
71
- return preselected
72
- choices = TurtlesApp._default_files(file_str)
73
- ret = next(filter(Path.is_file, choices), None)
74
- if ret is None:
75
- raise FileNotFoundError(' or '.join(map(str, choices)))
76
- return ret
77
-
78
- def __init__(self):
64
+ def __init__(self) -> None:
79
65
  super().__init__()
80
- self._password = None
81
- self._plugin_registries = None
82
- self._plugin_sets = None
83
- self._plugin_signing_credentials = None
66
+ self._password: Optional[Callable[[], str]] = None
67
+ self._plugin_registries: Optional[List[PluginRegistry]] = None
68
+ self._plugin_sets: Optional[List[PluginSet]] = None
69
+ self._plugin_signing_credentials: YamlT = None
84
70
 
85
- # Returns plugin_id -> (set_id, jar_path, plugin)
86
- def build_plugin(self, plugin_ids):
71
+ def build_plugin(self, plugin_ids: List[str]) -> Dict[str, Tuple[str, Path, Plugin]]:
87
72
  return {plugin_id: self._build_one_plugin(plugin_id) for plugin_id in plugin_ids}
88
73
 
89
- def default_plugin_registry_catalogs(self):
90
- return TurtlesApp._default_files(TurtlesApp.PLUGIN_REGISTRY_CATALOG)
91
-
92
- def default_plugin_set_catalogs(self):
93
- return TurtlesApp._default_files(TurtlesApp.PLUGIN_SET_CATALOG)
94
-
95
- def default_plugin_signing_credentials(self):
96
- return TurtlesApp._default_files(TurtlesApp.PLUGIN_SIGNING_CREDENTIALS)
97
-
98
74
  # Returns (src_path, plugin_id) -> list of (registry_id, layer_id, dst_path, plugin)
99
- def deploy_plugin(self, src_paths, layer_ids, interactive=False):
75
+ def deploy_plugin(self, src_paths: List[Path], layer_ids: List[str], interactive: bool=False) -> Dict[Tuple[Path, str], List[Tuple[str, str, Optional[Path], Optional[Plugin]]]]:
100
76
  plugin_ids = [Plugin.id_from_jar(src_path) for src_path in src_paths]
101
77
  return {(src_path, plugin_id): self._deploy_one_plugin(src_path,
102
78
  plugin_id,
103
79
  layer_ids,
104
80
  interactive=interactive) for src_path, plugin_id in zip(src_paths, plugin_ids)}
105
81
 
106
- def load_plugin_registries(self, plugin_registry_catalog_path=None):
82
+ def load_plugin_registries(self, plugin_registry_catalog_path: Optional[Union[Path, str]]=None) -> None:
107
83
  if self._plugin_registries is None:
108
84
  plugin_registry_catalog = PluginRegistryCatalog.from_path(self.select_plugin_registry_catalog(plugin_registry_catalog_path))
109
85
  self._plugin_registries = list()
110
86
  for plugin_registry_file in plugin_registry_catalog.get_plugin_registry_files():
111
87
  self._plugin_registries.extend(PluginRegistry.from_path(plugin_registry_file))
112
88
 
113
- def load_plugin_sets(self, plugin_set_catalog_path=None):
89
+ def load_plugin_sets(self, plugin_set_catalog_path: Optional[Union[Path, str]]=None) -> None:
114
90
  if self._plugin_sets is None:
115
91
  plugin_set_catalog = PluginSetCatalog.from_path(self.select_plugin_set_catalog(plugin_set_catalog_path))
116
92
  self._plugin_sets = list()
117
93
  for plugin_set_file in plugin_set_catalog.get_plugin_set_files():
118
94
  self._plugin_sets.extend(PluginSet.from_path(plugin_set_file))
119
95
 
120
- def load_plugin_signing_credentials(self, plugin_signing_credentials_path=None):
96
+ def load_plugin_signing_credentials(self, plugin_signing_credentials_path: Optional[Union[Path, str]]=None) -> None:
121
97
  if self._plugin_signing_credentials is None:
122
- plugin_signing_credentials_path = _path(plugin_signing_credentials_path) if plugin_signing_credentials_path else self._select_file(TurtlesApp.PLUGIN_SIGNING_CREDENTIALS)
123
- with importlib.resources.path(lockss.turtles.resources, TurtlesApp.PLUGIN_SIGNING_CREDENTIALS_SCHEMA) as plugin_signing_credentials_schema_path:
124
- self._plugin_signing_credentials = _load_and_validate(plugin_signing_credentials_schema_path, plugin_signing_credentials_path)
98
+ plugin_signing_credentials_path = path(plugin_signing_credentials_path) if plugin_signing_credentials_path else self._select_file(TurtlesApp.PLUGIN_SIGNING_CREDENTIALS)
99
+ with IR.path(__resources__, TurtlesApp.PLUGIN_SIGNING_CREDENTIALS_SCHEMA) as plugin_signing_credentials_schema_path:
100
+ self._plugin_signing_credentials = load_and_validate(plugin_signing_credentials_schema_path, plugin_signing_credentials_path)
125
101
 
126
102
  # Returns plugin_id -> list of (registry_id, layer_id, dst_path, plugin)
127
- def release_plugin(self, plugin_ids, layer_ids, interactive=False):
103
+ def release_plugin(self, plugin_ids: List[str], layer_ids: List[str], interactive: bool=False) -> Dict[str, List[Tuple[str, str, Path, Plugin]]]:
128
104
  # ... plugin_id -> (set_id, jar_path, plugin)
129
105
  ret1 = self.build_plugin(plugin_ids)
130
106
  jar_paths = [jar_path for set_id, jar_path, plugin in ret1.values()]
@@ -134,54 +110,85 @@ class TurtlesApp(object):
134
110
  interactive=interactive)
135
111
  return {plugin_id: val for (jar_path, plugin_id), val in ret2.items()}
136
112
 
137
- def select_plugin_registry_catalog(self, preselected=None):
113
+ def select_plugin_registry_catalog(self, preselected: Optional[Union[Path, str]]=None) -> Path:
138
114
  return TurtlesApp._select_file(TurtlesApp.PLUGIN_REGISTRY_CATALOG, preselected)
139
115
 
140
- def select_plugin_set_catalog(self, preselected=None):
116
+ def select_plugin_set_catalog(self, preselected: Optional[Union[Path, str]]=None) -> Path:
141
117
  return TurtlesApp._select_file(TurtlesApp.PLUGIN_SET_CATALOG, preselected)
142
118
 
143
- def select_plugin_signing_credentials(self, preselected=None):
119
+ def select_plugin_signing_credentials(self, preselected: Optional[Union[Path, str]]=None) -> Path:
144
120
  return TurtlesApp._select_file(TurtlesApp.PLUGIN_SIGNING_CREDENTIALS, preselected)
145
121
 
146
- def set_password(self, pw):
147
- self._password = pw if callable(pw) else lambda x: pw
122
+ def set_password(self, pw: Union[Callable[[], str], str]) -> None:
123
+ self._password = pw if callable(pw) else lambda: pw
148
124
 
149
125
  # Returns (set_id, jar_path, plugin)
150
- def _build_one_plugin(self, plugin_id):
126
+ def _build_one_plugin(self, plugin_id: str) -> Tuple[str, Optional[Path], Optional[Plugin]]:
151
127
  for plugin_set in self._plugin_sets:
152
128
  if plugin_set.has_plugin(plugin_id):
153
- return (plugin_set.get_id(),
154
- *plugin_set.build_plugin(plugin_id,
155
- self._get_plugin_signing_keystore(),
156
- self._get_plugin_signing_alias(),
157
- self._get_plugin_signing_password()))
129
+ bp = plugin_set.build_plugin(plugin_id,
130
+ self._get_plugin_signing_keystore(),
131
+ self._get_plugin_signing_alias(),
132
+ self._get_plugin_signing_password())
133
+ return plugin_set.get_id(), bp[0] if bp else None, bp[1] if bp else None
158
134
  raise Exception(f'{plugin_id}: not found in any plugin set')
159
135
 
160
136
  # Returns list of (registry_id, layer_id, dst_path, plugin)
161
- def _deploy_one_plugin(self, src_jar, plugin_id, layer_ids, interactive=False):
137
+ def _deploy_one_plugin(self, src_jar: Path, plugin_id: str, layer_ids: List[str], interactive: bool=False) -> List[Tuple[str, str, Optional[Path], Optional[Plugin]]]:
162
138
  ret = list()
163
139
  for plugin_registry in self._plugin_registries:
164
140
  if plugin_registry.has_plugin(plugin_id):
165
141
  for layer_id in layer_ids:
166
142
  layer = plugin_registry.get_layer(layer_id)
167
143
  if layer is not None:
144
+ dp = layer.deploy_plugin(plugin_id,
145
+ src_jar,
146
+ interactive=interactive)
168
147
  ret.append((plugin_registry.get_id(),
169
148
  layer.get_id(),
170
- *layer.deploy_plugin(plugin_id,
171
- src_jar,
172
- interactive=interactive)))
149
+ dp[0] if dp else None,
150
+ dp[1] if dp else None))
173
151
  if len(ret) == 0:
174
152
  raise Exception(f'{src_jar}: {plugin_id} not declared in any plugin registry')
175
153
  return ret
176
154
 
177
- def _get_password(self):
155
+ def _get_password(self) -> Optional[str]:
178
156
  return self._password() if self._password else None
179
157
 
180
- def _get_plugin_signing_alias(self):
158
+ def _get_plugin_signing_alias(self) -> str:
181
159
  return self._plugin_signing_credentials['plugin-signing-alias']
182
160
 
183
- def _get_plugin_signing_keystore(self):
161
+ def _get_plugin_signing_keystore(self) -> str:
184
162
  return self._plugin_signing_credentials['plugin-signing-keystore']
185
163
 
186
- def _get_plugin_signing_password(self):
164
+ def _get_plugin_signing_password(self) -> str:
187
165
  return self._get_password()
166
+
167
+ @staticmethod
168
+ def default_plugin_registry_catalogs() -> List[Path]:
169
+ return TurtlesApp._default_files(TurtlesApp.PLUGIN_REGISTRY_CATALOG)
170
+
171
+ @staticmethod
172
+ def default_plugin_set_catalogs() -> List[Path]:
173
+ return TurtlesApp._default_files(TurtlesApp.PLUGIN_SET_CATALOG)
174
+
175
+ @staticmethod
176
+ def default_plugin_signing_credentials() -> List[Path]:
177
+ return TurtlesApp._default_files(TurtlesApp.PLUGIN_SIGNING_CREDENTIALS)
178
+
179
+ @staticmethod
180
+ def _default_files(file_str) -> List[Path]:
181
+ return [dir_path.joinpath(file_str) for dir_path in TurtlesApp.CONFIG_DIRS]
182
+
183
+ @staticmethod
184
+ def _select_file(file_str, preselected: Optional[Union[Path, str]]=None) -> Path:
185
+ if preselected:
186
+ preselected = path(preselected)
187
+ if not preselected.is_file():
188
+ raise FileNotFoundError(str(preselected))
189
+ return preselected
190
+ choices = TurtlesApp._default_files(file_str)
191
+ ret = next(filter(lambda f: f.is_file(), choices), None)
192
+ if ret is None:
193
+ raise FileNotFoundError(' or '.join(map(str, choices)))
194
+ return ret