lockss-pyclient 0.1.0.dev2__py3-none-any.whl → 0.1.0.dev3__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 (93) hide show
  1. lockss/pyclient/__init__.py +8 -29
  2. lockss/pyclient/__main__.py +37 -0
  3. lockss/pyclient/_internal_common.py +395 -0
  4. lockss/pyclient/_internal_config.py +207 -0
  5. lockss/pyclient/_internal_crawler.py +251 -0
  6. lockss/pyclient/_internal_md.py +111 -0
  7. lockss/pyclient/_internal_poller.py +174 -0
  8. lockss/pyclient/_internal_rs.py +232 -0
  9. lockss/pyclient/cli.py +839 -0
  10. lockss/pyclient/config/__init__.py +15 -0
  11. lockss/pyclient/config/api/aus_api.py +14 -6
  12. lockss/pyclient/config/api/config_api.py +12 -12
  13. lockss/pyclient/config/api/utils_api.py +2 -2
  14. lockss/pyclient/config/configuration.py +1 -1
  15. lockss/pyclient/config/models/__init__.py +15 -0
  16. lockss/pyclient/config/models/access_type.py +90 -0
  17. lockss/pyclient/config/models/au_agreements.py +136 -0
  18. lockss/pyclient/config/models/au_config_page_info.py +140 -0
  19. lockss/pyclient/config/models/au_state_bean.py +942 -0
  20. lockss/pyclient/config/models/au_status.py +837 -8
  21. lockss/pyclient/config/models/au_suspect_url_versions.py +136 -0
  22. lockss/pyclient/config/models/check_substance_result.py +6 -22
  23. lockss/pyclient/config/models/dated_peer_id_set_impl.py +162 -0
  24. lockss/pyclient/config/models/hash_result.py +136 -0
  25. lockss/pyclient/config/models/page_info.py +226 -0
  26. lockss/pyclient/config/models/peer_agreement.py +188 -0
  27. lockss/pyclient/config/models/peer_agreements.py +136 -0
  28. lockss/pyclient/config/models/platform_configuration_ws_result.py +421 -8
  29. lockss/pyclient/config/models/platform_configuration_ws_result_daemon_version.py +188 -0
  30. lockss/pyclient/config/models/platform_configuration_ws_result_java_version.py +188 -0
  31. lockss/pyclient/config/models/platform_configuration_ws_result_platform.py +162 -0
  32. lockss/pyclient/config/models/substance_checker_state.py +91 -0
  33. lockss/pyclient/config/models/suspect_url_version.py +214 -0
  34. lockss/pyclient/config/swagger.yaml +2031 -0
  35. lockss/pyclient/crawler/__init__.py +1 -0
  36. lockss/pyclient/crawler/api/crawls_api.py +2 -2
  37. lockss/pyclient/crawler/configuration.py +1 -1
  38. lockss/pyclient/crawler/models/__init__.py +1 -0
  39. lockss/pyclient/crawler/models/crawl_desc.py +4 -12
  40. lockss/pyclient/crawler/models/crawl_kind_enum.py +90 -0
  41. lockss/pyclient/crawler/models/page_info.py +22 -24
  42. lockss/pyclient/crawler/swagger.yaml +1197 -0
  43. lockss/pyclient/md/configuration.py +1 -1
  44. lockss/pyclient/md/models/page_info.py +22 -24
  45. lockss/pyclient/md/swagger.yaml +583 -0
  46. lockss/pyclient/output.py +131 -0
  47. lockss/pyclient/poller/__init__.py +11 -5
  48. lockss/pyclient/poller/api/export_api.py +5 -5
  49. lockss/pyclient/poller/api/hash_api.py +3 -3
  50. lockss/pyclient/poller/api/poll_detail_api.py +42 -42
  51. lockss/pyclient/poller/api/poller_polls_api.py +18 -18
  52. lockss/pyclient/poller/api/service_api.py +2 -2
  53. lockss/pyclient/poller/api/voter_polls_api.py +18 -18
  54. lockss/pyclient/poller/configuration.py +1 -1
  55. lockss/pyclient/poller/models/__init__.py +11 -5
  56. lockss/pyclient/poller/models/export_file_type_enum.py +93 -0
  57. lockss/pyclient/poller/models/export_filename_translation_enum.py +91 -0
  58. lockss/pyclient/poller/models/page_info.py +226 -0
  59. lockss/pyclient/poller/models/poll_desc.py +3 -11
  60. lockss/pyclient/poller/models/poll_variant_enum.py +92 -0
  61. lockss/pyclient/poller/models/poller_page_info.py +140 -0
  62. lockss/pyclient/poller/models/repair_page_info.py +140 -0
  63. lockss/pyclient/poller/models/repair_type_enum.py +91 -0
  64. lockss/pyclient/poller/models/tally_type_enum.py +93 -0
  65. lockss/pyclient/poller/models/url_page_info.py +140 -0
  66. lockss/pyclient/poller/models/voter_page_info.py +140 -0
  67. lockss/pyclient/poller/models/voter_urls_enum.py +92 -0
  68. lockss/pyclient/poller/swagger.yaml +1658 -0
  69. lockss/pyclient/rs/__init__.py +6 -0
  70. lockss/pyclient/rs/api/artifacts_api.py +20 -20
  71. lockss/pyclient/rs/api/aus_api.py +5 -5
  72. lockss/pyclient/rs/api/repo_api.py +4 -4
  73. lockss/pyclient/rs/api/status_api.py +1 -1
  74. lockss/pyclient/rs/api/wayback_api.py +12 -12
  75. lockss/pyclient/rs/configuration.py +8 -1
  76. lockss/pyclient/rs/models/__init__.py +6 -0
  77. lockss/pyclient/rs/models/artifact.py +111 -81
  78. lockss/pyclient/rs/models/au_size.py +6 -0
  79. lockss/pyclient/rs/models/auid_page_info.py +2 -2
  80. lockss/pyclient/rs/models/bulk_au_op_enum.py +90 -0
  81. lockss/pyclient/rs/models/include_content_enum.py +91 -0
  82. lockss/pyclient/rs/models/page_info.py +26 -29
  83. lockss/pyclient/rs/models/pywb_match_enum.py +93 -0
  84. lockss/pyclient/rs/models/pywb_output_enum.py +90 -0
  85. lockss/pyclient/rs/models/pywb_sort_enum.py +91 -0
  86. lockss/pyclient/rs/models/storage_info.py +131 -80
  87. lockss/pyclient/rs/models/versions_enum.py +90 -0
  88. lockss/pyclient/rs/swagger.yaml +1306 -0
  89. {lockss_pyclient-0.1.0.dev2.dist-info → lockss_pyclient-0.1.0.dev3.dist-info}/METADATA +10 -3
  90. {lockss_pyclient-0.1.0.dev2.dist-info → lockss_pyclient-0.1.0.dev3.dist-info}/RECORD +93 -45
  91. {lockss_pyclient-0.1.0.dev2.dist-info → lockss_pyclient-0.1.0.dev3.dist-info}/WHEEL +1 -1
  92. lockss_pyclient-0.1.0.dev3.dist-info/entry_points.txt +3 -0
  93. {lockss_pyclient-0.1.0.dev2.dist-info → lockss_pyclient-0.1.0.dev3.dist-info/licenses}/LICENSE +0 -0
lockss/pyclient/cli.py ADDED
@@ -0,0 +1,839 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Copyright (c) 2000-2025, Board of Trustees of Leland Stanford Jr. University
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # 1. Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # 3. Neither the name of the copyright holder nor the names of its contributors
16
+ # may be used to endorse or promote products derived from this software without
17
+ # specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+
31
+ from io import TextIOWrapper
32
+ from pathlib import Path
33
+ from typing import Literal
34
+ import sys
35
+
36
+ from lockss.pybasic.cliutil import BaseCli, COPYRIGHT_DESCRIPTION, LICENSE_DESCRIPTION, VERSION_DESCRIPTION
37
+ from lockss.pybasic.errorutil import InternalError
38
+ from pydantic.v1 import BaseModel as BaseModel1, Field as Field1, NonNegativeInt as NonNegativeInt1, root_validator as root_validator1
39
+
40
+ from .output import output_options
41
+ from . import *
42
+ from . import __copyright__, __license__, __version__
43
+ from ._internal_common import _param_default, _RS
44
+ from . import config, crawler, md, poller, rs
45
+
46
+
47
+ class NodeOptions(BaseModel1):
48
+ host: str = Field1(aliases=["-H"], description="The IP address or FQDN of the LOCKSS node, optionally followed by a colon and port number")
49
+ repo: NonNegativeInt1 = Field1(RS_DEFAULT_PORT, aliases=['--repository-port', '-R'], description='Repository Service port')
50
+ config: NonNegativeInt1 = Field1(CONFIG_DEFAULT_PORT, aliases=['--configuration-port', '-C'], description='Configuration Service port')
51
+ poller: NonNegativeInt1 = Field1(POLLER_DEFAULT_PORT, aliases=['--poller-port', '-L'], description='Poller Service port')
52
+ crawler: NonNegativeInt1 = Field1(CRAWLER_DEFAULT_PORT, aliases=['--crawler-port', '-W'], description='Crawler Service port')
53
+ md: NonNegativeInt1 = Field1(MD_DEFAULT_PORT, aliases=['--metadata-port', '-M'], description='Metadata Service port')
54
+
55
+ def make_node(self, **kwargs) -> Node:
56
+ return Node(self.host,
57
+ rs_port=self.repo,
58
+ config_port=self.config,
59
+ poller_port=self.poller,
60
+ crawler_port=self.crawler,
61
+ md_port=self.md,
62
+ **kwargs)
63
+
64
+
65
+ class AuthOptions(NodeOptions):
66
+ username: str = Field1(aliases=["-U"], description="Username")
67
+ password: Optional[str] = Field1(aliases=["-P"], description="Password")
68
+
69
+ def make_node(self) -> Node:
70
+ return super().make_node(username=self.username,
71
+ password=self.password)
72
+
73
+
74
+ class NamespaceOptions(BaseModel1):
75
+ namespace: Optional[str] = Field1(aliases=["-n"], description="Namespace")
76
+
77
+ def get_namespace(self, default: str):
78
+ return self.namespace if self.namespace else default
79
+
80
+
81
+ class AuidOptions(NamespaceOptions):
82
+ auid: str = Field1(aliases=['-a'], description='Archival Unit identifier (AUID)')
83
+
84
+
85
+ class CrawlerIdOptions(BaseModel1):
86
+ crawler_id: str = Field1(alias='crawler-id', aliases=['-c'], description='crawler identifier')
87
+
88
+
89
+ class DoiOptions(BaseModel1):
90
+ doi: str = Field1(aliases=['-d'], description='DOI')
91
+
92
+
93
+ class IfMatchOptions(BaseModel1):
94
+ if_match: Optional[str] = Field1(description='set the If-Match HTTP header to the given value')
95
+ if_modified_since: Optional[str] = Field1(description='set the If-Modified-Since HTTP header to the given value')
96
+ if_none_match: Optional[str] = Field1(description='set the If-None-Match HTTP header to the given value')
97
+ if_unmodified_since: Optional[str] = Field1(description='set the If-Unmodified-Since HTTP header to the given value')
98
+
99
+
100
+ class JobOptions(BaseModel1):
101
+ job: str = Field1(description='job identifier')
102
+
103
+
104
+ class OpenUrlOptions(BaseModel1):
105
+ params: list[str] = Field1(aliases=['-p'], description='cumulative list of OpenURL parameters')
106
+
107
+
108
+ class OutputOptions(BaseModel1):
109
+ output: Optional[Path] = Field1(aliases=['-o'], description='write output to the given file')
110
+
111
+
112
+ class PollKeyOptions(BaseModel1):
113
+ poll_key: str = Field1(aliases=['-k'], description='poll key')
114
+
115
+
116
+ class PeerIdOptions(PollKeyOptions):
117
+ peer_id: str = Field1(aliases=['-p'], description='peer identifier')
118
+ agreed: bool = Field1(False, description='return the agreed peer URLs')
119
+ disagreed: bool = Field1(False, description='return the disagreed peer URLs')
120
+ poller_only: bool = Field1(False, description='return the poller-only peer URLs')
121
+ voter_only: bool = Field1(False, description='return the voter-only peer URLs')
122
+
123
+ @root_validator1
124
+ def _validate_exactly_one(cls, values):
125
+ attrs = ('agreed', 'disagreed', 'poller_only', 'voter_only')
126
+ if len([attr for attr in attrs if values.get(attr)]) != 1:
127
+ raise ValueError('Expected exactly one of {", ".join(f"--{hattr}" for hattr in [attr.replace("_", "-") for attr in attrs])}')
128
+ return values
129
+
130
+ def get_voter_urls_enum(self) -> poller.VoterUrlsEnum:
131
+ if self.agreed: return poller.VoterUrlsEnum.AGREED
132
+ elif self.disagreed: return poller.VoterUrlsEnum.DISAGREED
133
+ elif self.poller_only: return poller.VoterUrlsEnum.POLLERONLY
134
+ elif self.voter_only: return poller.VoterUrlsEnum.VOTERONLY
135
+ else: raise InternalError from ValueError(self.json())
136
+
137
+ class RepairTypeOptions(BaseModel1):
138
+ active: bool = Field1(False, description='return the active repairs')
139
+ completed: bool = Field1(False, description='return the completed repairs')
140
+ pending: bool = Field1(False, description='return the pending repairs')
141
+
142
+ @root_validator1
143
+ def _validate_exactly_one(cls, values):
144
+ attrs = ('active', 'completed', 'pending')
145
+ if len([attr for attr in attrs if values.get(attr)]) != 1:
146
+ raise ValueError('Expected exactly one of {", ".join(f"--{hattr}" for hattr in [attr.replace("_", "-") for attr in attrs])}')
147
+ return values
148
+
149
+ def get_repair_type_enum(self) -> poller.RepairTypeEnum:
150
+ if self.active: return poller.RepairTypeEnum.ACTIVE
151
+ elif self.completed: return poller.RepairTypeEnum.COMPLETED
152
+ elif self.pending: return poller.RepairTypeEnum.PENDING
153
+ else: raise InternalError from ValueError(self.json())
154
+
155
+
156
+ class TallyTypeOptions(BaseModel1):
157
+ agree: bool = Field1(False, description='return the tallies for URLs that agree')
158
+ disagree: bool = Field1(False, description='return the tallies for URLs that disagree')
159
+ error: bool = Field1(False, description='return the tallies for URLs that have errors')
160
+ no_quorum: bool = Field1(False, description='return the tallies for URLs that have no quorum')
161
+ too_close: bool = Field1(False, description='return the tallies for URLs that are too close')
162
+
163
+ @root_validator1
164
+ def _validate_exactly_one(cls, values):
165
+ attrs = ('active', 'completed', 'pending')
166
+ if len([attr for attr in attrs if values.get(attr)]) != 1:
167
+ raise ValueError('Expected exactly one of {", ".join(f"--{hattr}" for hattr in [attr.replace("_", "-") for attr in attrs])}')
168
+ return values
169
+
170
+ def get_tally_type_enum(self) -> poller.TallyTypeEnum:
171
+ if self.agree: return poller.TallyTypeEnum.AGREE
172
+ elif self.disagree: return poller.TallyTypeEnum.DISAGREE
173
+ elif self.error: return poller.TallyTypeEnum.ERROR
174
+ elif self.no_quorum: return poller.TallyTypeEnum.NOQUORUM
175
+ elif self.too_close: return poller.TallyTypeEnum.TOOCLOSE
176
+ else: raise InternalError from ValueError(self.json())
177
+
178
+
179
+ class UrlOptions(BaseModel1):
180
+ url: Optional[str] = Field1(aliases=['-u'], description='URL')
181
+
182
+
183
+ class UrlPrefixOptions(UrlOptions):
184
+ url_prefix: Optional[str] = Field1(aliases=['-p'], description='URL prefix')
185
+
186
+ @root_validator1
187
+ def _validate_exactly_one(cls, values):
188
+ attrs = ('url', 'url_prefix')
189
+ if len([attr for attr in attrs if values.get(attr)]) != 1:
190
+ raise ValueError('Expected exactly one of {", ".join(f"--{hattr}" for hattr in [attr.replace("_", "-") for attr in attrs])}')
191
+ return values
192
+
193
+
194
+ class UuidOptions(NamespaceOptions):
195
+ uuid: str = Field1(aliases=['-w'], description='artifact identifier')
196
+
197
+
198
+ class UncommittedOptions(BaseModel1):
199
+ uncommitted: bool = Field1(False, description='include uncommitted artifacts in results')
200
+
201
+
202
+ class UserAccountOptions(BaseModel1):
203
+ user_account: str = Field1(description='user account name')
204
+
205
+
206
+ class VersionsOptions(BaseModel1):
207
+ all: bool = Field1(False, description='include all versions of artifacts in results')
208
+ latest: bool = Field1(False, description='include only the latest version of artifacts in results')
209
+
210
+ @root_validator1
211
+ def _validate_at_most_one(cls, values):
212
+ attrs = ('all', 'latest')
213
+ if len([attr for attr in attrs if values.get(attr)]) > 1:
214
+ raise ValueError('Expected at most one of {", ".join(f"--{hattr}" for hattr in [attr.replace("_", "-") for attr in attrs])}')
215
+ return values
216
+
217
+ def get_versions_enum(self, default: rs.VersionsEnum) -> rs.VersionsEnum:
218
+ if self.all: return rs.VersionsEnum.ALL
219
+ elif self.latest: return rs.VersionsEnum.LATEST
220
+ else: return default
221
+
222
+
223
+ ArtifactOptions = output_options('ArtifactOptions', rs.Artifact, disambiguate=['auid', 'namespace'])
224
+
225
+
226
+ AuConfigurationOptions = output_options('AuConfigurationOptions', config.AuConfiguration)
227
+
228
+
229
+ CrawlJobOptions = output_options('CrawlJobOptions', crawler.CrawlJob)
230
+
231
+
232
+ CrawlStatusOptions = output_options('CrawlStatusOptions', crawler.CrawlStatus)
233
+
234
+
235
+ CrawlUrlInfoOptions = output_options('CrawlUrlInfoOptions', crawler.UrlInfo)
236
+
237
+
238
+ MdJobOptions = output_options('MdJobOptions', md.Job)
239
+
240
+
241
+ MdUrlInfoOptions = output_options('MdUrlInfoOptions', md.UrlInfo)
242
+
243
+
244
+ class LockssApi(BaseModel1):
245
+
246
+ class Config(BaseModel1):
247
+
248
+ class Aus(BaseModel1):
249
+
250
+ class Agreements(AuidOptions, AuthOptions): pass
251
+
252
+ class Configuration(BaseModel1):
253
+
254
+ class Get(AuConfigurationOptions, AuidOptions, AuthOptions): pass
255
+
256
+ class GetAll(AuConfigurationOptions, AuthOptions): pass
257
+
258
+ get: Optional[Get] = Field1(description='Get the configuration of an AU')
259
+ get_all: Optional[GetAll] = Field1(alias='get-all', description='Get the configurations of all AUs')
260
+
261
+ class NoAuPeerSet(output_options('DatedPeerIdSetImplOptions', config.DatedPeerIdSetImpl), AuidOptions, AuthOptions): pass
262
+
263
+ class State(output_options('AuStateBeanOptions', config.AuStateBean, disambiguate=['auid']), AuidOptions, AuthOptions): pass
264
+
265
+ class Status(output_options('AuStatusOptions', config.AuStatus), AuidOptions, AuthOptions): pass
266
+
267
+ class SuspectUrls(output_options('SuspectUrlVersionOptions', config.SuspectUrlVersion), AuidOptions, AuthOptions): pass
268
+
269
+ agreements: Optional[Agreements] = Field1(descriptions='Get the poll agreements of an AU')
270
+ configuration: Optional[Configuration] = Field1(description='AU configuration operations')
271
+ no_au_peer_set: Optional[NoAuPeerSet] = Field1(alias='no-au-peer-set', description='Get the NoAuPeerSet object of an AU')
272
+ state: Optional[State] = Field1(description='Get the state of an AU')
273
+ status: Optional[Status] = Field1(description='Get the status of an AU')
274
+ suspect_urls: Optional[SuspectUrls] = Field1(description='Get the suspect URL versions of an AU')
275
+
276
+ class LastUpdateTime(AuthOptions): pass
277
+
278
+ class LoadedUrls(AuthOptions): pass
279
+
280
+ class Platform(output_options('PlatformConfigurationWsResultOptions', config.PlatformConfigurationWsResult), AuthOptions): pass
281
+
282
+ class Section(BaseModel1):
283
+
284
+ class Get(IfMatchOptions, OutputOptions, AuthOptions):
285
+ section: str = Field1(description='the name of the section for which the configuration file is requested')
286
+
287
+ get: Optional[Get] = Field1(description='Get the named configuration file')
288
+
289
+ class Status(output_options('ConfigApiStatusOptions', config.ApiStatus), NodeOptions): pass
290
+
291
+ class Url(IfMatchOptions, OutputOptions, AuthOptions):
292
+ url: str = Field1(aliases=['-u'], description='the URL for which the configuration is requested')
293
+
294
+ class Users(BaseModel1):
295
+
296
+ class Get(UserAccountOptions, AuthOptions): pass
297
+
298
+ class Usernames(AuthOptions): pass
299
+
300
+ get: Optional[Get] = Field1(description='Get user account details')
301
+ usernames: Optional[Usernames] = Field1(description='Get the usernames configured in the system')
302
+
303
+ aus: Optional[Aus] = Field1(description='AU operations')
304
+ last_update_time: Optional[LastUpdateTime] = Field1(alias='last-update-time', description='Get the timestamp when the configuration was last updated')
305
+ loaded_urls: Optional[LoadedUrls] = Field1(alias='loaded-urls', description='Get the URLs from which the cofniguration was loaded')
306
+ platform: Optional[Platform] = Field1(description='Get the platform configuration')
307
+ section: Optional[Section] = Field1(description='Section operations')
308
+ status: Optional[Status] = Field1(description='Get the status of the service')
309
+ url: Optional[Url] = Field1(description='Get the configuration file for a URL')
310
+ users: Optional[Users] = Field1(description='User operations')
311
+
312
+ class Crawler(BaseModel1):
313
+
314
+ class Crawlers(BaseModel1):
315
+
316
+ class Get(output_options('CrawlerConfigOptions', crawler.CrawlerConfig, disambiguate=['crawler-id']), CrawlerIdOptions, AuthOptions): pass
317
+
318
+ class GetAll(output_options('CrawlerStatusesOptions', crawler.CrawlerStatuses), AuthOptions): pass
319
+
320
+ get: Optional[Get] = Field1(description='Get queued crawl job')
321
+ get_all: Optional[GetAll] = Field1(alias='get-all', description='Get the list of crawl jobs')
322
+
323
+ class Crawls(BaseModel1):
324
+
325
+ class Get(CrawlStatusOptions, JobOptions, AuthOptions): pass
326
+
327
+ class GetAll(CrawlStatusOptions, AuthOptions): pass
328
+
329
+ class Urls(BaseModel1):
330
+
331
+ class Errors(CrawlUrlInfoOptions, JobOptions, AuthOptions): pass
332
+
333
+ class Excluded(CrawlUrlInfoOptions, JobOptions, AuthOptions): pass
334
+
335
+ class Fetched(CrawlUrlInfoOptions, JobOptions, AuthOptions): pass
336
+
337
+ class MediaTypes(BaseModel1):
338
+
339
+ class Get(CrawlUrlInfoOptions, JobOptions, AuthOptions):
340
+ media_type: str = Field1(description='the media type (e.g. application/pdf)')
341
+
342
+ #class GetAll(JobOptions, AuthOptions): pass
343
+
344
+ get: Optional[Get] = Field1(description='Get the URLs of a given media type for a crawl')
345
+ #get_all: Optional[GetAll] = Field1(alias='get-all', description='Get the media types for a crawl')
346
+
347
+ class NotModified(CrawlUrlInfoOptions, JobOptions, AuthOptions): pass
348
+
349
+ class Parsed(CrawlUrlInfoOptions, JobOptions, AuthOptions): pass
350
+
351
+ class Pending(CrawlUrlInfoOptions, JobOptions, AuthOptions): pass
352
+
353
+ errors: Optional[Errors] = Field1(description='Get the error URLs for a crawl')
354
+ excluded: Optional[Excluded] = Field1(description='Get the excluded URLs for a crawl')
355
+ fetched: Optional[Fetched] = Field1(description='Get the fetched URLs for a crawl')
356
+ media_types: Optional[MediaTypes] = Field1(alias='media-types', description='Subcommand for media type operations')
357
+ not_modified: Optional[NotModified] = Field1(alias='not-modified', description='Get the not modified URLs for a crawl')
358
+ parsed: Optional[Parsed] = Field1(description='Get the parsed URLs for a crawl')
359
+ pending: Optional[Pending] = Field1(description='Get the pending URLs for a crawl')
360
+
361
+ get: Optional[Get] = Field1(description='Get the list of crawls')
362
+ get_all: Optional[GetAll] = Field1(alias='get-all', description='Get the crawl status of a job')
363
+ urls: Optional[Urls] = Field1(description='Subcommand for crawl URL operations')
364
+
365
+ class Jobs(BaseModel1):
366
+
367
+ class Delete(AuthOptions): pass # FIXME
368
+
369
+ class DeleteAll(AuthOptions): pass # FIXME
370
+
371
+ class Get(CrawlJobOptions, JobOptions, AuthOptions): pass
372
+
373
+ class GetAll(CrawlJobOptions, AuthOptions): pass
374
+
375
+ class Request(AuthOptions): pass # FIXME
376
+
377
+ delete: Optional[Delete] = Field1(description='Remove or stop a crawl job') # FIXME
378
+ delete_all: Optional[DeleteAll] = Field1(alias='delete-all', description='Delete all of the currently queued and active crawl jobs') # FIXME
379
+ get: Optional[Get] = Field1(description='Get queued poll status')
380
+ get_all: Optional[GetAll] = Field1(alias='get-all', description='Get the list of crawl jobs')
381
+ request: Optional[Request] = Field1(description='Request a crawl as defined by the descriptor') # FIXME
382
+
383
+ class Status(output_options('CrawlerApiStatusOptions', crawler.ApiStatus), NodeOptions): pass
384
+
385
+ crawlers: Optional[Crawlers] = Field1(description='Subcommand for crawler information operations')
386
+ crawls: Optional[Crawls] = Field1(description='Subcommand for crawl status operations')
387
+ jobs: Optional[Jobs] = Field1(description='Subcommand for crawler job operations')
388
+ status: Optional[Status] = Field1(description='Get the status of the service')
389
+
390
+ class Md(BaseModel1):
391
+
392
+ class Get(output_options('ItemMetadataOptions', md.ItemMetadata), AuidOptions, AuthOptions): pass
393
+
394
+ class Jobs(BaseModel1):
395
+
396
+ class Delete(AuthOptions): pass # FIXME
397
+
398
+ class DeleteAll(AuthOptions): pass # FIXME
399
+
400
+ class Get(MdJobOptions, JobOptions, AuthOptions): pass
401
+
402
+ class GetAll(MdJobOptions, AuthOptions): pass
403
+
404
+ class Request(AuthOptions): pass # FIXME
405
+
406
+ delete: Optional[Delete] = Field1(description='Delete a metadata job') # FIXME
407
+ delete_all: Optional[DeleteAll] = Field1(alias='delete-all', description='Delete all of the currently queued and active metadata jobs') # FIXME
408
+ get: Optional[Get] = Field1(description='Get queued job status')
409
+ get_all: Optional[GetAll] = Field1(alias='get-all', description='Get the list of queued jobs')
410
+ request: Optional[Request] = Field1(description='Request a metadata update operation') # FIXME
411
+
412
+ class Query(BaseModel1):
413
+
414
+ class Doi(MdUrlInfoOptions, DoiOptions, AuthOptions): pass
415
+
416
+ class OpenUrl(MdUrlInfoOptions, OpenUrlOptions, AuthOptions): pass
417
+
418
+ doi: Optional[Doi] = Field1(description='Perform a DOI query')
419
+ openurl: Optional[OpenUrl] = Field1(description='Perform an OpenURL query')
420
+
421
+ class Status(output_options('MdApiStatusOptions', md.ApiStatus), NodeOptions): pass
422
+
423
+ get: Optional[Get] = Field1(description='Get the metadata stored for an AU')
424
+ jobs: Optional[Jobs] = Field1(description='Subcommand for metadata job operations')
425
+ query: Optional[Query] = Field1(description='Subcommand for query operations')
426
+ status: Optional[Status] = Field1(description='Get the status of the service')
427
+
428
+ class Poller(BaseModel1):
429
+
430
+ class Jobs(BaseModel1):
431
+
432
+ class Get(output_options('PollerSummaryOptions', poller.PollerSummary, disambiguate=['poll-key']), JobOptions, AuthOptions): pass
433
+
434
+ class Request(AuthOptions): pass # FIXME
435
+
436
+ get: Optional[Get] = Field1(description='Get queued poll status')
437
+ request: Optional[Request] = Field1(description='Request to call a poll as the poller') # FIXME
438
+
439
+ class Polls(BaseModel1):
440
+
441
+ class AsPoller(BaseModel1):
442
+
443
+ class Get(output_options('PollerDetailOptions', poller.PollerDetail, disambiguate=['poll-key']), PollKeyOptions, AuthOptions): pass
444
+
445
+ class GetAll(output_options('PollerSummaryOptions', poller.PollerSummary, disambiguate=['poll-key']), AuthOptions): pass
446
+
447
+ get: Optional[Get] = Field1(description='Get the detailed information about a poll in which a node is the poller')
448
+ get_all: Optional[GetAll] = Field1(alias='get-all', description='Get the list of recent polls in which a node is the poller')
449
+
450
+ class AsVoter(BaseModel1):
451
+
452
+ class Get(output_options('VoterDetailOptions', poller.VoterDetail, disambiguate=['poll-key']), PollKeyOptions, AuthOptions): pass
453
+
454
+ class GetAll(output_options('VoterSummaryOptions', poller.VoterSummary, disambiguate=['poll-key']), AuthOptions): pass
455
+
456
+ get: Optional[Get] = Field1(description='Get the detailed information about a poll in which a node is a voter')
457
+ get_all: Optional[GetAll] = Field1(alias='get-all', description='Get the list of recent polls in which a node is a voter')
458
+
459
+ class PeerData(PeerIdOptions, AuthOptions): pass
460
+
461
+ class Repairs(output_options('RepairDataOptions', poller.RepairData), RepairTypeOptions, PollKeyOptions, AuthOptions): pass
462
+
463
+ class Tallies(TallyTypeOptions, PollKeyOptions, AuthOptions): pass
464
+
465
+ as_poller: Optional[AsPoller] = Field1(alias='as-poller', description='Subcommand for polls in which a node is the poller')
466
+ as_voter: Optional[AsVoter] = Field1(alias='as-voter', description='Subcommand for polls in which a node is the voter')
467
+ peer_data: Optional[PeerData] = Field1(alias='peer-data', description='Get peer data for a poll')
468
+ repairs: Optional[Repairs] = Field1(description='Get the repairs for a poll')
469
+ tallies: Optional[Tallies] = Field1(description='Get the tallies for a poll')
470
+
471
+ class Status(output_options('PollerApiStatusOptions', poller.ApiStatus), NodeOptions): pass
472
+
473
+ jobs: Optional[Jobs] = Field1(description='Subcommand for poller job operations')
474
+ polls: Optional[Polls] = Field1(description='Subcommand for poll status operations')
475
+ status: Optional[Status] = Field1(description='Get the status of the service')
476
+
477
+ class Repo(BaseModel1):
478
+
479
+ class Artifacts(BaseModel1):
480
+
481
+ class Delete(UuidOptions, NamespaceOptions, AuthOptions): pass
482
+
483
+ class Get(BaseModel1):
484
+
485
+ class ByAuid(ArtifactOptions, UncommittedOptions, VersionsOptions, UrlPrefixOptions, AuidOptions, AuthOptions): pass
486
+
487
+ class ByUrl(ArtifactOptions, VersionsOptions, UrlPrefixOptions, NamespaceOptions, AuthOptions): pass
488
+
489
+ class ByUuid(UuidOptions, AuthOptions):
490
+ response: Optional[Union[Path, Literal['-']]] = Field1(description='write the response headers to the given file, or "-" for standard output')
491
+ payload: Optional[Union[Path, Literal['-']]] = Field1(description='write the payload to the given file, or "-" for standard output')
492
+
493
+ by_auid: Optional[ByAuid] = Field1(alias='by-auid', description='Get artifacts in an Archival Unit')
494
+ by_url: Optional[ByUrl] = Field1(alias="by-url", description="Returns all artifacts that match a given URL or URL prefix and/or version")
495
+ by_uuid: Optional[ByUuid] = Field1(alias="by-uuid", description="Gets artifacts and artifact metadata")
496
+
497
+ class Update(UuidOptions, NamespaceOptions, AuthOptions):
498
+ commit: bool = Field1(description='Whether the artifact should be marked as committed or not committed')
499
+
500
+ delete: Optional[Delete] = Field1(description='Deletes an artifact')
501
+ get: Optional[Get] = Field1(description='Gets one or more artifacts')
502
+ update: Optional[Update] = Field1(description='Updates an artifact')
503
+
504
+ class Aus(BaseModel1):
505
+
506
+ class Auids(NamespaceOptions, AuthOptions): pass
507
+
508
+ class Size(output_options('AuSizeOptions', rs.AuSize), AuidOptions, AuthOptions): pass
509
+
510
+ auids: Optional[Auids] = Field1(description='Get Archival Unit IDs (AUIDs) in a namespace')
511
+ size: Optional[Size] = Field1(description='Get the size of Archival Unit artifacts in a namespace')
512
+
513
+ class ChecksumAlgorithms(AuthOptions): pass
514
+
515
+ class Info(output_options('RepositoryInfoOptions', rs.RepositoryInfo), AuthOptions): pass
516
+
517
+ class Namespaces(AuthOptions): pass
518
+
519
+ class Status(output_options('RsApiStatusOptions', rs.ApiStatus), NodeOptions): pass
520
+
521
+ class StorageInfo(AuthOptions): pass
522
+
523
+ artifacts: Optional[Artifacts] = Field1(description="LOCKSS Repository Service API artifacts commands")
524
+ aus: Optional[Aus] = Field1(description='LOCKSS Repository Service API archival unit (AU) commands')
525
+ checksum_algorithms: Optional[ChecksumAlgorithms] = Field1(alias='checksum-algorithms', description='Get the supported checksum algorithms')
526
+ info: Optional[Info] = Field1(description='Get repository information')
527
+ namespaces: Optional[Namespaces] = Field1(description='Get namespaces of the committed artifacts in the repository')
528
+ status: Optional[Status] = Field1(description="Get the status of the service")
529
+ storage_info: Optional[StorageInfo] = Field1(alias='storage-info', description="Get repository storage information")
530
+
531
+ config: Optional[Config] = Field1(description='Subcommand for Configuration Service operations')
532
+ copyright: Optional[BaseModel1] = Field1(description=COPYRIGHT_DESCRIPTION)
533
+ crawler: Optional[Crawler] = Field1(description='Subcommand for Crawler Service operations')
534
+ license: Optional[BaseModel1] = Field1(description=LICENSE_DESCRIPTION)
535
+ md: Optional[Md] = Field1(description='Subcommand for Metadata Service operations')
536
+ poller: Optional[Poller] = Field1(description='Subcommand for Poller Service operations')
537
+ repo: Optional[Repo] = Field1(description='Subcommand for Repository Service operations')
538
+ version: Optional[BaseModel1] = Field1(description=VERSION_DESCRIPTION)
539
+
540
+
541
+ class LockssApiCli(BaseCli[LockssApi]):
542
+
543
+ def __init__(self):
544
+ """
545
+ Constructs a new ``DebugPanelCli`` instance.
546
+ """
547
+ super().__init__(model=LockssApi,
548
+ prog='lockssapi',
549
+ description='LOCKSS Python client')
550
+
551
+ def _config_aus_agreements(self, cmd: LockssApi.Config.Aus.Agreements) -> None:
552
+ print(config_get_au_agreements(cmd.make_node(),
553
+ cmd.auid).to_dict())
554
+
555
+ def _config_aus_configuration_get(self, cmd: LockssApi.Config.Aus.Configuration.Get) -> None:
556
+ cmd.display(config_get_au_config(cmd.make_node(),
557
+ cmd.auid))
558
+
559
+ def _config_aus_configuration_get_all(self, cmd: LockssApi.Config.Aus.Configuration.GetAll) -> None:
560
+ cmd.display(config_get_au_configs(cmd.make_node()))
561
+
562
+ def _config_aus_no_au_peer_set(self, cmd: LockssApi.Config.Aus.NoAuPeerSet) -> None:
563
+ cmd.display(config_get_no_au_peer_set(cmd.make_node(),
564
+ cmd.auid))
565
+
566
+ def _config_aus_state(self, cmd: LockssApi.Config.Aus.State) -> None:
567
+ cmd.display(config_get_au_state(cmd.make_node(),
568
+ cmd.auid))
569
+
570
+ def _config_aus_status(self, cmd: LockssApi.Config.Aus.Status) -> None:
571
+ cmd.display(config_get_au_status(cmd.make_node(),
572
+ cmd.auid))
573
+
574
+ def _config_aus_suspect_urls(self, cmd: LockssApi.Config.Aus.SuspectUrls) -> None:
575
+ cmd.display(config_get_au_suspect_url_versions(cmd.make_node(),
576
+ cmd.auid).suspect_versions)
577
+
578
+ def _config_last_update_time(self, cmd: LockssApi.Config.LastUpdateTime) -> None:
579
+ print(config_last_update_time(cmd.make_node()))
580
+
581
+ def _config_loaded_urls(self, cmd: LockssApi.Config.LoadedUrls) -> None:
582
+ for url in config_get_loaded_urls(cmd.make_node()):
583
+ print(url)
584
+
585
+ def _config_platform(self, cmd: LockssApi.Config.Platform) -> None:
586
+ cmd.display(config_get_platform_config(cmd.make_node()))
587
+
588
+ def _config_section_get(self, cmd: LockssApi.Config.Section.Get) -> None:
589
+ mp = config_get_section(cmd.make_node(),
590
+ cmd.section,
591
+ if_match=cmd.if_match,
592
+ if_modified_since=cmd.if_modified_since,
593
+ if_none_match=cmd.if_none_match,
594
+ if_unmodified_since=cmd.if_unmodified_since)
595
+ part = None
596
+ try:
597
+ part = mp.get('configFile')
598
+ if cmd.output:
599
+ part.save_as(cmd.output)
600
+ else:
601
+ for line in TextIOWrapper(part.file):
602
+ print(line, end='')
603
+ finally:
604
+ if part:
605
+ part.close()
606
+
607
+ def _config_status(self, cmd: LockssApi.Config.Status) -> None:
608
+ cmd.display(config_get_status(cmd.make_node()))
609
+
610
+ def _config_url(self, cmd: LockssApi.Config.Url) -> None:
611
+ mp = config_get_url(cmd.make_node(),
612
+ cmd.url,
613
+ if_match=cmd.if_match,
614
+ if_modified_since=cmd.if_modified_since,
615
+ if_none_match=cmd.if_none_match,
616
+ if_unmodified_since=cmd.if_unmodified_since)
617
+ part = None
618
+ try:
619
+ part = mp.get('configFile')
620
+ if cmd.output:
621
+ part.save_as(cmd.output)
622
+ else:
623
+ for line in TextIOWrapper(part.file):
624
+ print(line, end='')
625
+ finally:
626
+ if part:
627
+ part.close()
628
+
629
+ def _config_users_get(self, cmd: LockssApi.Config.Users.Get) -> None:
630
+ print(config_get_user_account(cmd.make_node(),
631
+ cmd.user_account))
632
+
633
+ def _config_users_usernames(self, cmd: LockssApi.Config.Users.Usernames) -> None:
634
+ for username in sorted(config_get_usernames(cmd.make_node())):
635
+ print(username)
636
+
637
+ def _copyright(self, cmd: BaseModel1) -> None:
638
+ self._parser.exit(0, __copyright__)
639
+
640
+ def _crawler_crawlers_get(self, cmd: LockssApi.Crawler.Crawlers.Get) -> None:
641
+ cmd.display(crawler_get_crawler(cmd.make_node(),
642
+ cmd.crawler_id))
643
+
644
+ def _crawler_crawlers_get_all(self, cmd: LockssApi.Crawler.Crawlers.GetAll) -> None:
645
+ cmd.display(crawler_get_crawlers(cmd.make_node()))
646
+
647
+ def _crawler_crawls_urls_errors(self, cmd: LockssApi.Crawler.Crawls.Urls.Errors) -> None:
648
+ cmd.display(crawler_get_crawl_errors(cmd.make_node(),
649
+ cmd.job))
650
+
651
+ def _crawler_crawls_urls_excluded(self, cmd: LockssApi.Crawler.Crawls.Urls.Excluded) -> None:
652
+ cmd.display(crawler_get_crawl_excluded(cmd.make_node(),
653
+ cmd.job))
654
+
655
+ def _crawler_crawls_urls_fetched(self, cmd: LockssApi.Crawler.Crawls.Urls.Fetched) -> None:
656
+ cmd.display(crawler_get_crawl_fetched(cmd.make_node(),
657
+ cmd.job))
658
+
659
+ def _crawler_crawls_get(self, cmd: LockssApi.Crawler.Crawls.Get) -> None:
660
+ cmd.display(crawler_get_crawl(cmd.make_node(),
661
+ cmd.job))
662
+
663
+ def _crawler_crawls_get_all(self, cmd: LockssApi.Crawler.Crawls.GetAll) -> None:
664
+ cmd.display(crawler_get_crawls(cmd.make_node()))
665
+
666
+ def _crawler_crawls_urls_media_types_get(self, cmd: LockssApi.Crawler.Crawls.Urls.MediaTypes.Get) -> None:
667
+ cmd.display(crawler_get_crawl_by_media_type(cmd.make_node(),
668
+ cmd.job,
669
+ cmd.media_type))
670
+
671
+ def _crawler_crawls_urls_not_modified(self, cmd: LockssApi.Crawler.Crawls.Urls.NotModified) -> None:
672
+ cmd.display(crawler_get_crawl_not_modified(cmd.make_node(),
673
+ cmd.job))
674
+
675
+ def _crawler_crawls_urls_parsed(self, cmd: LockssApi.Crawler.Crawls.Urls.Parsed) -> None:
676
+ cmd.display(crawler_get_crawl_parsed(cmd.make_node(),
677
+ cmd.job))
678
+
679
+ def _crawler_crawls_urls_pending(self, cmd: LockssApi.Crawler.Crawls.Urls.Pending) -> None:
680
+ cmd.display(crawler_get_crawl_pending(cmd.make_node(),
681
+ cmd.job))
682
+
683
+ def _crawler_jobs_get(self, cmd: LockssApi.Crawler.Jobs.Get) -> None:
684
+ cmd.display(crawler_get_job(cmd.make_node(),
685
+ cmd.job))
686
+
687
+ def _crawler_jobs_get_all(self, cmd: LockssApi.Crawler.Jobs.GetAll) -> None:
688
+ cmd.display(crawler_get_jobs(cmd.make_node()))
689
+
690
+ def _crawler_status(self, cmd: LockssApi.Crawler.Status) -> None:
691
+ cmd.display(crawler_get_status(cmd.make_node()))
692
+
693
+ def _license(self, cmd: BaseModel1) -> None:
694
+ self._parser.exit(0, __license__)
695
+
696
+ def _md_get(self, cmd: LockssApi.Md.Get) -> None:
697
+ cmd.display(md_get_metadata(cmd.make_node(),
698
+ cmd.auid))
699
+
700
+ def _md_jobs_get(self, cmd: LockssApi.Md.Jobs.Get) -> None:
701
+ cmd.display(md_get_job(cmd.make_node(),
702
+ cmd.job))
703
+
704
+ def _md_jobs_get_all(self, cmd: LockssApi.Md.Jobs.GetAll) -> None:
705
+ cmd.display(md_get_jobs(cmd.make_node()))
706
+
707
+ def _md_query_doi(self, cmd: LockssApi.Md.Query.Doi) -> None:
708
+ cmd.display(md_doi_query(cmd.make_node(),
709
+ cmd.doi))
710
+
711
+ def _md_query_openurl(self, cmd: LockssApi.Md.Query.OpenUrl) -> None:
712
+ cmd.display(md_openurl_query(cmd.make_node(),
713
+ cmd.params))
714
+
715
+ def _md_status(self, cmd: LockssApi.Md.Status) -> None:
716
+ cmd.display(md_get_status(cmd.make_node()))
717
+
718
+ def _poller_jobs_get(self, cmd: LockssApi.Poller.Jobs.Get) -> None:
719
+ cmd.display(poller_get_poll_status(cmd.make_node(),
720
+ cmd.job))
721
+
722
+ def _poller_polls_as_poller_get(self, cmd: LockssApi.Poller.Polls.AsPoller.Get) -> None:
723
+ cmd.display(poller_get_poller_poll(cmd.make_node(),
724
+ cmd.poll_key))
725
+
726
+ def _poller_polls_as_poller_get_all(self, cmd: LockssApi.Poller.Polls.AsPoller.GetAll) -> None:
727
+ cmd.display(poller_get_poller_polls(cmd.make_node()))
728
+
729
+ def _poller_polls_as_voter_get(self, cmd: LockssApi.Poller.Polls.AsVoter.Get) -> None:
730
+ cmd.display(poller_get_voter_poll(cmd.make_node(),
731
+ cmd.poll_key))
732
+
733
+ def _poller_polls_as_voter_get_all(self, cmd: LockssApi.Poller.Polls.AsVoter.GetAll) -> None:
734
+ cmd.display(poller_get_voter_polls(cmd.make_node()))
735
+
736
+ def _poller_polls_peer_data(self, cmd: LockssApi.Poller.Polls.PeerData) -> None:
737
+ for url in poller_get_peer_data(cmd.make_node(),
738
+ cmd.poll_key,
739
+ cmd.peer_id,
740
+ cmd.get_voter_urls_enum()):
741
+ print(url)
742
+
743
+ def _poller_polls_repairs(self, cmd: LockssApi.Poller.Polls.Repairs) -> None:
744
+ cmd.display(poller_get_repair_data(cmd.make_node(),
745
+ cmd.poll_key,
746
+ cmd.get_repair_type_enum()))
747
+
748
+ def _poller_polls_tallies(self, cmd: LockssApi.Poller.Polls.Tallies) -> None:
749
+ for url in poller_get_tally_urls(cmd.make_node(),
750
+ cmd.poll_key,
751
+ cmd.get_tally_type_enum()):
752
+ print(url)
753
+
754
+ def _poller_status(self, cmd: LockssApi.Poller.Status) -> None:
755
+ cmd.display(poller_get_status(cmd.make_node()))
756
+
757
+ def _repo_artifacts_delete(self, cmd: LockssApi.Repo.Artifacts.Delete) -> None:
758
+ repo_delete_artifact(cmd.make_node(),
759
+ cmd.uuid,
760
+ namespace=cmd.get_namespace(_param_default(_RS, '/artifacts/{uuid}', 'delete', 'namespace')))
761
+ print(cmd.uuid)
762
+
763
+ def _repo_artifacts_get_by_auid(self, cmd: LockssApi.Repo.Artifacts.Get.ByAuid) -> None:
764
+ cmd.display(repo_get_artifacts_by_auid(cmd.make_node(),
765
+ cmd.auid,
766
+ url=cmd.url,
767
+ url_prefix=cmd.url_prefix,
768
+ namespace=cmd.get_namespace(_param_default(_RS, '/aus/{auid}/artifacts', 'get', 'namespace')),
769
+ versions=cmd.get_versions_enum(rs.VersionsEnum.LATEST),
770
+ include_uncommitted=cmd.uncommitted))
771
+
772
+ def _repo_artifacts_by_url(self, cmd: LockssApi.Repo.Artifacts.Get.ByUrl) -> None:
773
+ cmd.display(repo_get_artifacts_by_url(cmd.make_node(),
774
+ url=cmd.url,
775
+ url_prefix=cmd.url_prefix,
776
+ namespace=cmd.get_namespace(_param_default(_RS, '/artifacts', 'get', 'namespace')),
777
+ versions=cmd.get_versions_enum(rs.VersionsEnum.LATEST)))
778
+
779
+ def _repo_artifacts_get_by_uuid(self, cmd: LockssApi.Repo.Artifacts.Get.ByUuid) -> None:
780
+ mp = repo_get_artifact_by_uuid(cmd.make_node(),
781
+ cmd.uuid,
782
+ namespace=_param_default(_RS, '/artifacts/{uuid}', 'get', 'namespace'),
783
+ include_content=rs.IncludeContentEnum.ALWAYS if cmd.payload else rs.IncludeContentEnum.NEVER)
784
+ print(mp.get('artifactProps').value)
785
+ for path, part_name in ((cmd.response, 'httpResponseHeader'), (cmd.payload, 'payload')):
786
+ if path is None:
787
+ continue
788
+ part = None
789
+ try:
790
+ part = mp.get(part_name)
791
+ if path == '-':
792
+ print()
793
+ while len((bytez := part.file.read(1024))) > 0:
794
+ sys.stdout.write(bytez)
795
+ else:
796
+ part.save_as(path)
797
+ finally:
798
+ if part:
799
+ part.close()
800
+
801
+ def _repo_aus_auids(self, cmd: LockssApi.Repo.Aus.Auids) -> None:
802
+ for auid in sorted(repo_get_auids(cmd.make_node())):
803
+ print(auid)
804
+
805
+ def _repo_aus_size(self, cmd: LockssApi.Repo.Aus.Size) -> None:
806
+ cmd.display(repo_get_au_size(cmd.make_node(),
807
+ cmd.auid,
808
+ namespace=cmd.get_namespace(_param_default(_RS, '/aus/{auid}/size', 'get', 'namespace'))))
809
+
810
+ def _repo_checksum_algorithms(self, cmd: LockssApi.Repo.ChecksumAlgorithms) -> None:
811
+ for checksum_algorithm in sorted(repo_get_checksum_algorithms(cmd.make_node())):
812
+ print(checksum_algorithm)
813
+
814
+ def _repo_info(self, cmd: LockssApi.Repo.Info) -> None:
815
+ cmd.display(repo_get_info(cmd.make_node()))
816
+
817
+ def _repo_namespaces(self, cmd: LockssApi.Repo.Namespaces) -> None:
818
+ for namespace in sorted(repo_get_namespaces(cmd.make_node())):
819
+ print(namespace)
820
+
821
+ def _repo_status(self, cmd: LockssApi.Repo.Status) -> None:
822
+ cmd.display(repo_get_status(cmd.make_node()))
823
+
824
+ def _repo_storage_info(self, cmd: LockssApi.Repo.StorageInfo) -> None:
825
+ print(repo_get_storage_info(cmd.make_node()).to_dict())
826
+
827
+ def _version(self, cmd: BaseModel1) -> None:
828
+ self._parser.exit(0, __version__)
829
+
830
+
831
+ def main() -> None:
832
+ """
833
+ Entry point for the lockssapi command line tool.
834
+ """
835
+ LockssApiCli().run()
836
+
837
+
838
+ if __name__ == '__main__':
839
+ main()