Coverage for silkaj/cli.py: 100%
76 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-22 12:04 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-22 12:04 +0000
1# Copyright 2016-2025 Maël Azimi <m.a@moul.re>
2#
3# Silkaj is free software: you can redistribute it and/or modify
4# it under the terms of the GNU Affero General Public License as published by
5# the Free Software Foundation, either version 3 of the License, or
6# (at your option) any later version.
7#
8# Silkaj is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU Affero General Public License for more details.
12#
13# You should have received a copy of the GNU Affero General Public License
14# along with Silkaj. If not, see <https://www.gnu.org/licenses/>.
16import contextlib
18import rich_click as click
19from duniterpy.api.endpoint import endpoint as du_endpoint
21from silkaj import tools
22from silkaj.about import about
23from silkaj.auth import generate_auth_file
24from silkaj.blockchain.blocks import list_blocks
25from silkaj.blockchain.difficulty import difficulties
26from silkaj.blockchain.information import currency_info
27from silkaj.checksum import checksum_command
28from silkaj.constants import (
29 G1_DEFAULT_ENDPOINT,
30 G1_TEST_DEFAULT_ENDPOINT,
31 SILKAJ_VERSION,
32)
33from silkaj.g1_monetary_license import license_command
34from silkaj.money.balance import balance_cmd
35from silkaj.money.history import transaction_history
36from silkaj.money.transfer import transfer_money
37from silkaj.wot import certify, revocation
38from silkaj.wot.lookup import lookup_cmd
39from silkaj.wot.membership import send_membership
40from silkaj.wot.status import status
42click.rich_click.SHOW_ARGUMENTS = True
43click.rich_click.OPTION_GROUPS = {
44 "silkaj": [
45 {
46 "name": "Basic options",
47 "options": ["--help", "--version"],
48 },
49 {
50 "name": "Endpoint and currency specification",
51 "options": ["--endpoint", "--gtest"],
52 },
53 {
54 "name": "Account and authentication specification",
55 "options": ["--account", "--password"],
56 },
57 ],
58}
61@click.group()
62@click.help_option("-h", "--help")
63@click.version_option(SILKAJ_VERSION, "-v", "--version")
64@click.option(
65 "--endpoint",
66 "-ep",
67 help=f"Without specifying this option, the default endpoint reaches Ğ1 currency on its official endpoint: https://{du_endpoint(G1_DEFAULT_ENDPOINT).host}. \
68--endpoint allows to specify a custom endpoint following `<host>:<port>/<path>` format. \
69`port` and `path` are optional. In case no port is specified, it defaults to 443.",
70 cls=tools.MutuallyExclusiveOption,
71 mutually_exclusive=["gtest"],
72)
73@click.option(
74 "--gtest",
75 "-gt",
76 is_flag=True,
77 help=f"Uses official ĞTest currency endpoint: https://{du_endpoint(G1_TEST_DEFAULT_ENDPOINT).host}",
78 cls=tools.MutuallyExclusiveOption,
79 mutually_exclusive=["endpoint"],
80)
81@click.option(
82 "account_name",
83 "--account",
84 "-a",
85 help="Account name used in storage `$HOME/.local/share/silkaj/$currency/$account_name` for authentication and revocation.",
86)
87@click.option(
88 "--password",
89 "-p",
90 help="EWIF authentication password. If you use this option, prefix the command \
91with a space so the password is not saved in your shell history. \
92In case of an encrypted file, password input will be prompted.",
93)
94@click.option(
95 "--display",
96 "-d",
97 is_flag=True,
98 help="Display the generated document before sending it",
99)
100@click.option(
101 "--dry-run",
102 "-n",
103 is_flag=True,
104 help="By-pass the licence and confirmation. Do not send the document, but display it instead",
105)
106@click.pass_context
107def cli(
108 ctx: click.Context,
109 endpoint: str,
110 gtest: bool,
111 account_name: str,
112 password: str,
113 display: bool,
114 dry_run: bool,
115) -> None:
116 if display and dry_run:
117 ctx.fail("Display and dry-run options can not be used together")
119 ctx.obj = {}
120 ctx.ensure_object(dict)
121 ctx.obj["ENDPOINT"] = endpoint
122 ctx.obj["GTEST"] = gtest
123 ctx.obj["ACCOUNT_NAME"] = account_name
124 ctx.obj["PASSWORD"] = password
125 ctx.obj["DISPLAY_DOCUMENT"] = display
126 ctx.obj["DRY_RUN"] = dry_run
127 ctx.help_option_names = ["-h", "--help"]
130cli.add_command(about)
131cli.add_command(generate_auth_file)
132cli.add_command(checksum_command)
133cli.add_command(license_command)
136@cli.group("blockchain", help="Blockchain related commands")
137def blockchain_group() -> None:
138 pass
141blockchain_group.add_command(list_blocks)
142blockchain_group.add_command(difficulties)
143blockchain_group.add_command(currency_info)
146@cli.group("money", help="Money management related commands")
147def money_group() -> None:
148 pass
151money_group.add_command(balance_cmd)
152money_group.add_command(transaction_history)
153money_group.add_command(transfer_money)
156@cli.group("wot", help="Web-of-Trust related commands")
157def wot_group() -> None:
158 pass
161wot_group.add_command(certify.certify)
162with contextlib.suppress(ModuleNotFoundError):
163 from silkaj.wot.exclusions import exclusions_command
165 wot_group.add_command(exclusions_command)
167wot_group.add_command(lookup_cmd)
168wot_group.add_command(send_membership)
169wot_group.add_command(status)
172@wot_group.group("revocation", help="Manage revocation document commands.")
173def revocation_group() -> None:
174 pass
177revocation_group.add_command(revocation.create)
178revocation_group.add_command(revocation.verify)
179revocation_group.add_command(revocation.publish)
180revocation_group.add_command(revocation.revoke_now)