Coverage for silkaj/cli.py: 100%

76 statements  

« 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/>. 

15 

16import contextlib 

17 

18import rich_click as click 

19from duniterpy.api.endpoint import endpoint as du_endpoint 

20 

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 

41 

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} 

59 

60 

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") 

118 

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"] 

128 

129 

130cli.add_command(about) 

131cli.add_command(generate_auth_file) 

132cli.add_command(checksum_command) 

133cli.add_command(license_command) 

134 

135 

136@cli.group("blockchain", help="Blockchain related commands") 

137def blockchain_group() -> None: 

138 pass 

139 

140 

141blockchain_group.add_command(list_blocks) 

142blockchain_group.add_command(difficulties) 

143blockchain_group.add_command(currency_info) 

144 

145 

146@cli.group("money", help="Money management related commands") 

147def money_group() -> None: 

148 pass 

149 

150 

151money_group.add_command(balance_cmd) 

152money_group.add_command(transaction_history) 

153money_group.add_command(transfer_money) 

154 

155 

156@cli.group("wot", help="Web-of-Trust related commands") 

157def wot_group() -> None: 

158 pass 

159 

160 

161wot_group.add_command(certify.certify) 

162with contextlib.suppress(ModuleNotFoundError): 

163 from silkaj.wot.exclusions import exclusions_command 

164 

165 wot_group.add_command(exclusions_command) 

166 

167wot_group.add_command(lookup_cmd) 

168wot_group.add_command(send_membership) 

169wot_group.add_command(status) 

170 

171 

172@wot_group.group("revocation", help="Manage revocation document commands.") 

173def revocation_group() -> None: 

174 pass 

175 

176 

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)