lockss-turtles 0.5.0.dev4__tar.gz → 0.6.0.dev2__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.dev2}/CHANGELOG.rst +37 -1
  2. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev2}/LICENSE +1 -1
  3. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev2}/PKG-INFO +20 -19
  4. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev2}/README.rst +1 -1
  5. lockss_turtles-0.6.0.dev2/pyproject.toml +85 -0
  6. lockss_turtles-0.6.0.dev2/src/lockss/turtles/__init__.py +40 -0
  7. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev2}/src/lockss/turtles/__main__.py +3 -3
  8. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev2}/src/lockss/turtles/app.py +83 -78
  9. lockss_turtles-0.6.0.dev2/src/lockss/turtles/cli.py +285 -0
  10. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev2}/src/lockss/turtles/plugin.py +64 -55
  11. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev2}/src/lockss/turtles/plugin_registry.py +90 -79
  12. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev2}/src/lockss/turtles/plugin_set.py +95 -87
  13. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev2}/src/lockss/turtles/resources/__init__.py +1 -1
  14. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev2}/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.dev2}/src/lockss/turtles/resources/plugin-registry-catalog-schema.json +0 -0
  19. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev2}/src/lockss/turtles/resources/plugin-registry-schema.json +0 -0
  20. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev2}/src/lockss/turtles/resources/plugin-set-catalog-schema.json +0 -0
  21. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev2}/src/lockss/turtles/resources/plugin-set-schema.json +0 -0
  22. {lockss_turtles-0.5.0.dev4 → lockss_turtles-0.6.0.dev2}/src/lockss/turtles/resources/plugin-signing-credentials-schema.json +0 -0
@@ -3,13 +3,49 @@ 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
+ * The configuration directory for Turtles in ``$XDG_CONFIG_HOME`` (by default ``$HOME/.config``), ``/usr/local/share``, and ``/etc`` is now called ``lockss-turtles`` instead of ``lockss.turtles``.
20
+
21
+ * Some long options have been renamed (the short options remain unchanged):
22
+
23
+ ============ ================= =============
24
+ Short option Version 0.5.0 Version 0.6.0
25
+ ============ ================= =============
26
+ ``-i`` ``--identifier`` ``--plugin-identifier``
27
+ ``-I`` ``--identifiers`` ``--plugin-identifiers``
28
+ ``-j`` ``--jar`` ``--plugin-jar``
29
+ ``-J`` ``--jars`` ``--plugin-jars``
30
+ ``-l`` ``--layer`` ``--plugin-registry-layer``
31
+ ``-L`` ``--layers`` ``--plugin-registry-layers``
32
+ n/a ``--password`` ``--plugin-signing-password``
33
+ ============ ================= =============
34
+
35
+ * 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.
36
+
37
+ * The ``usage`` command has been removed.
38
+
39
+ -----
40
+ 0.5.0
41
+ -----
42
+
43
+ Released: 2024-09-04
44
+
45
+ * **Features**
46
+
47
+ * ``AntPluginSet``: also include plugin auxiliary packages (``plugin_aux_packages``).
48
+
13
49
  -----
14
50
  0.4.0
15
51
  -----
@@ -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,39 +1,40 @@
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.dev2
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)
27
+ Project-URL: Documentation, https://docs.lockss.org/en/latest/software/turtles
29
28
  Project-URL: Repository, https://github.com/lockss/lockss-turtles
29
+ Project-URL: changelog, https://github.com/lockss/lockss-turtles/blob/main/CHANGELOG.rst
30
+ Project-URL: issues, https://github.com/lockss/lockss-turtles/issues
30
31
  Description-Content-Type: text/x-rst
31
32
 
32
33
  =======
33
34
  Turtles
34
35
  =======
35
36
 
36
- .. |RELEASE| replace:: 0.5.0-dev1
37
+ .. |RELEASE| replace:: 0.6.0-dev1
37
38
  .. |RELEASE_DATE| replace:: ?
38
39
 
39
40
  .. |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,85 @@
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-dev2" # 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
+ # See https://docs.pypi.org/project_metadata/
64
+ [project.urls]
65
+ changelog = "https://github.com/lockss/lockss-turtles/blob/main/CHANGELOG.rst"
66
+ documentation = "https://docs.lockss.org/en/latest/software/turtles"
67
+ issues = "https://github.com/lockss/lockss-turtles/issues"
68
+ repository = "https://github.com/lockss/lockss-turtles"
69
+
70
+ [tool.poetry]
71
+ include = [
72
+ "CHANGELOG.rst",
73
+ "LICENSE",
74
+ "README.rst",
75
+ ]
76
+ packages = [
77
+ { include = "lockss", from = "src" }
78
+ ]
79
+
80
+ [tool.poetry.scripts]
81
+ turtles = 'lockss.turtles.cli:main'
82
+
83
+ [build-system]
84
+ requires = ["poetry-core>=2.0.0,<3.0.0"]
85
+ 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-dev2'
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
+ CONFIG_DIR_NAME = 'lockss-turtles'
46
49
 
47
- USR_CONFIG_DIR = Path('/usr/local/share', __package__)
50
+ XDG_CONFIG_DIR: Path = xdg.xdg_config_home().joinpath(CONFIG_DIR_NAME)
48
51
 
49
- ETC_CONFIG_DIR = Path('/etc', __package__)
52
+ USR_CONFIG_DIR: Path = Path('/usr/local/share', CONFIG_DIR_NAME)
50
53
 
51
- CONFIG_DIRS = [XDG_CONFIG_DIR, USR_CONFIG_DIR, ETC_CONFIG_DIR]
54
+ ETC_CONFIG_DIR: Path = Path('/etc', CONFIG_DIR_NAME)
52
55
 
53
- PLUGIN_REGISTRY_CATALOG = 'plugin-registry-catalog.yaml'
56
+ CONFIG_DIRS: List[Path] = [XDG_CONFIG_DIR, USR_CONFIG_DIR, ETC_CONFIG_DIR]
54
57
 
55
- PLUGIN_SET_CATALOG = 'plugin-set-catalog.yaml'
58
+ PLUGIN_REGISTRY_CATALOG: str = 'plugin-registry-catalog.yaml'
56
59
 
57
- PLUGIN_SIGNING_CREDENTIALS = 'plugin-signing-credentials.yaml'
60
+ PLUGIN_SET_CATALOG: str = 'plugin-set-catalog.yaml'
58
61
 
59
- PLUGIN_SIGNING_CREDENTIALS_SCHEMA = 'plugin-signing-credentials-schema.json'
62
+ PLUGIN_SIGNING_CREDENTIALS: str = 'plugin-signing-credentials.yaml'
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
64
+ PLUGIN_SIGNING_CREDENTIALS_SCHEMA: str = 'plugin-signing-credentials-schema.json'
77
65
 
78
- def __init__(self):
66
+ def __init__(self) -> None:
79
67
  super().__init__()
80
- self._password = None
81
- self._plugin_registries = None
82
- self._plugin_sets = None
83
- self._plugin_signing_credentials = None
68
+ self._password: Optional[Callable[[], str]] = None
69
+ self._plugin_registries: Optional[List[PluginRegistry]] = None
70
+ self._plugin_sets: Optional[List[PluginSet]] = None
71
+ self._plugin_signing_credentials: YamlT = None
84
72
 
85
- # Returns plugin_id -> (set_id, jar_path, plugin)
86
- def build_plugin(self, plugin_ids):
73
+ def build_plugin(self, plugin_ids: List[str]) -> Dict[str, Tuple[str, Path, Plugin]]:
87
74
  return {plugin_id: self._build_one_plugin(plugin_id) for plugin_id in plugin_ids}
88
75
 
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
- # 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):
76
+ 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
77
  plugin_ids = [Plugin.id_from_jar(src_path) for src_path in src_paths]
101
78
  return {(src_path, plugin_id): self._deploy_one_plugin(src_path,
102
79
  plugin_id,
103
80
  layer_ids,
104
81
  interactive=interactive) for src_path, plugin_id in zip(src_paths, plugin_ids)}
105
82
 
106
- def load_plugin_registries(self, plugin_registry_catalog_path=None):
83
+ def load_plugin_registries(self, plugin_registry_catalog_path: Optional[Union[Path, str]]=None) -> None:
107
84
  if self._plugin_registries is None:
108
85
  plugin_registry_catalog = PluginRegistryCatalog.from_path(self.select_plugin_registry_catalog(plugin_registry_catalog_path))
109
86
  self._plugin_registries = list()
110
87
  for plugin_registry_file in plugin_registry_catalog.get_plugin_registry_files():
111
88
  self._plugin_registries.extend(PluginRegistry.from_path(plugin_registry_file))
112
89
 
113
- def load_plugin_sets(self, plugin_set_catalog_path=None):
90
+ def load_plugin_sets(self, plugin_set_catalog_path: Optional[Union[Path, str]]=None) -> None:
114
91
  if self._plugin_sets is None:
115
92
  plugin_set_catalog = PluginSetCatalog.from_path(self.select_plugin_set_catalog(plugin_set_catalog_path))
116
93
  self._plugin_sets = list()
117
94
  for plugin_set_file in plugin_set_catalog.get_plugin_set_files():
118
95
  self._plugin_sets.extend(PluginSet.from_path(plugin_set_file))
119
96
 
120
- def load_plugin_signing_credentials(self, plugin_signing_credentials_path=None):
97
+ def load_plugin_signing_credentials(self, plugin_signing_credentials_path: Optional[Union[Path, str]]=None) -> None:
121
98
  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)
99
+ plugin_signing_credentials_path = path(plugin_signing_credentials_path) if plugin_signing_credentials_path else self._select_file(TurtlesApp.PLUGIN_SIGNING_CREDENTIALS)
100
+ with IR.path(__resources__, TurtlesApp.PLUGIN_SIGNING_CREDENTIALS_SCHEMA) as plugin_signing_credentials_schema_path:
101
+ self._plugin_signing_credentials = load_and_validate(plugin_signing_credentials_schema_path, plugin_signing_credentials_path)
125
102
 
126
- # 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,83 @@ 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
- # Returns (set_id, jar_path, plugin)
150
- def _build_one_plugin(self, plugin_id):
125
+ def _build_one_plugin(self, plugin_id: str) -> Tuple[str, Optional[Path], Optional[Plugin]]:
151
126
  for plugin_set in self._plugin_sets:
152
127
  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()))
128
+ bp = plugin_set.build_plugin(plugin_id,
129
+ self._get_plugin_signing_keystore(),
130
+ self._get_plugin_signing_alias(),
131
+ self._get_plugin_signing_password())
132
+ return plugin_set.get_id(), bp[0] if bp else None, bp[1] if bp else None
158
133
  raise Exception(f'{plugin_id}: not found in any plugin set')
159
134
 
160
- # Returns list of (registry_id, layer_id, dst_path, plugin)
161
- def _deploy_one_plugin(self, src_jar, plugin_id, layer_ids, interactive=False):
135
+ 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
136
  ret = list()
163
137
  for plugin_registry in self._plugin_registries:
164
138
  if plugin_registry.has_plugin(plugin_id):
165
139
  for layer_id in layer_ids:
166
140
  layer = plugin_registry.get_layer(layer_id)
167
141
  if layer is not None:
142
+ dp = layer.deploy_plugin(plugin_id,
143
+ src_jar,
144
+ interactive=interactive)
168
145
  ret.append((plugin_registry.get_id(),
169
146
  layer.get_id(),
170
- *layer.deploy_plugin(plugin_id,
171
- src_jar,
172
- interactive=interactive)))
147
+ dp[0] if dp else None,
148
+ dp[1] if dp else None))
173
149
  if len(ret) == 0:
174
150
  raise Exception(f'{src_jar}: {plugin_id} not declared in any plugin registry')
175
151
  return ret
176
152
 
177
- def _get_password(self):
153
+ def _get_password(self) -> Optional[str]:
178
154
  return self._password() if self._password else None
179
155
 
180
- def _get_plugin_signing_alias(self):
156
+ def _get_plugin_signing_alias(self) -> str:
181
157
  return self._plugin_signing_credentials['plugin-signing-alias']
182
158
 
183
- def _get_plugin_signing_keystore(self):
159
+ def _get_plugin_signing_keystore(self) -> str:
184
160
  return self._plugin_signing_credentials['plugin-signing-keystore']
185
161
 
186
- def _get_plugin_signing_password(self):
162
+ def _get_plugin_signing_password(self) -> str:
187
163
  return self._get_password()
164
+
165
+ @staticmethod
166
+ def default_plugin_registry_catalogs() -> List[Path]:
167
+ return TurtlesApp._default_files(TurtlesApp.PLUGIN_REGISTRY_CATALOG)
168
+
169
+ @staticmethod
170
+ def default_plugin_set_catalogs() -> List[Path]:
171
+ return TurtlesApp._default_files(TurtlesApp.PLUGIN_SET_CATALOG)
172
+
173
+ @staticmethod
174
+ def default_plugin_signing_credentials() -> List[Path]:
175
+ return TurtlesApp._default_files(TurtlesApp.PLUGIN_SIGNING_CREDENTIALS)
176
+
177
+ @staticmethod
178
+ def _default_files(file_str) -> List[Path]:
179
+ return [dir_path.joinpath(file_str) for dir_path in TurtlesApp.CONFIG_DIRS]
180
+
181
+ @staticmethod
182
+ def _select_file(file_str, preselected: Optional[Union[Path, str]]=None) -> Path:
183
+ if preselected:
184
+ preselected = path(preselected)
185
+ if not preselected.is_file():
186
+ raise FileNotFoundError(str(preselected))
187
+ return preselected
188
+ choices = TurtlesApp._default_files(file_str)
189
+ ret = next(filter(lambda f: f.is_file(), choices), None)
190
+ if ret is None:
191
+ raise FileNotFoundError(' or '.join(map(str, choices)))
192
+ return ret