jvcli 2.0.0__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.
jvcli/__init__.py ADDED
@@ -0,0 +1,8 @@
1
+ """
2
+ jvcli package initialization.
3
+
4
+ This package provides the CLI tool for Jivas Package Repository.
5
+ """
6
+
7
+ __version__ = "2.0.0"
8
+ __supported__jivas__versions__ = ["2.0.0"]
jvcli/api.py ADDED
@@ -0,0 +1,318 @@
1
+ """This module contains the API class for interacting with the Jivas Package Repository."""
2
+
3
+ from typing import Optional
4
+
5
+ import click
6
+ import requests
7
+
8
+
9
+ class RegistryAPI:
10
+ """Class for interacting with the Jivas Package Repository API."""
11
+
12
+ url = "https://api-jpr.trueselph.com/"
13
+
14
+ @staticmethod
15
+ def signup(username: str, email: str, password: str) -> dict:
16
+ """Sign up for a Jivas Package Repository account."""
17
+ endpoint = "signup"
18
+
19
+ try:
20
+ data = {"username": username, "email": email, "password": password}
21
+ response = requests.post(RegistryAPI.url + endpoint, json=data)
22
+
23
+ # Check if the response is successful
24
+ if response.status_code == 200:
25
+ # Include email in the response
26
+ response_data = response.json()
27
+ response_data["email"] = email
28
+ return response_data
29
+ else:
30
+ click.secho(f"Error signing up: {response.json()['error']}", fg="red")
31
+ return {}
32
+ except Exception as e:
33
+ click.secho(f"Error signing up: {e}", fg="red")
34
+ return {}
35
+
36
+ @staticmethod
37
+ def login(email: str, password: str) -> dict:
38
+ """Log in to your Jivas Package Repository account."""
39
+ endpoint = "login"
40
+
41
+ try:
42
+ data = {"emailOrUsername": email, "password": password}
43
+ response = requests.post(RegistryAPI.url + endpoint, json=data)
44
+
45
+ # Check if the response is successful
46
+ if response.status_code == 200:
47
+ # Include email in the response
48
+ response_data = response.json()
49
+ response_data["email"] = email
50
+ return response_data
51
+ else:
52
+ click.secho(f"Error logging in: {response.json()['error']}", fg="red")
53
+ return {}
54
+ except Exception as e:
55
+ click.secho(f"Error logging in: {e}", fg="red")
56
+ return {}
57
+
58
+ @staticmethod
59
+ def get_package_info(
60
+ name: str, version: str = "", token: Optional[str] = None
61
+ ) -> dict:
62
+ """Get action info.yaml content as json"""
63
+ endpoint = "info"
64
+
65
+ try:
66
+ headers = {"Authorization": f"Bearer {token}"} if token else None
67
+ data = {
68
+ "name": name,
69
+ "version": "" if version == "latest" else version,
70
+ }
71
+ response = requests.get(
72
+ RegistryAPI.url + endpoint, params=data, headers=headers
73
+ )
74
+ # Check if the response is successful
75
+ if response.status_code == 200:
76
+ return response.json()
77
+ else:
78
+ click.secho(
79
+ f"Error retrieving action: {response.json()['error']}",
80
+ fg="red",
81
+ )
82
+ return {}
83
+ except Exception as e:
84
+ click.secho(f"Error retrieving action: {e}", fg="red")
85
+ return {}
86
+
87
+ @staticmethod
88
+ def download_package(
89
+ name: str,
90
+ version: str = "",
91
+ info: bool = False,
92
+ suppress_error: bool = False,
93
+ token: Optional[str] = None,
94
+ ) -> dict:
95
+ """Download a Jivas Package."""
96
+ endpoint = "download"
97
+
98
+ try:
99
+ headers = {"Authorization": f"Bearer {token}"} if token else None
100
+
101
+ data = {
102
+ "name": name,
103
+ "info": "true" if info else "false",
104
+ "version": "" if version == "latest" else version,
105
+ }
106
+ response = requests.get(
107
+ RegistryAPI.url + endpoint,
108
+ params=data,
109
+ headers=headers,
110
+ )
111
+ # Check if the response is successful
112
+ if response.status_code == 200:
113
+ return response.json()
114
+ else:
115
+ if not suppress_error:
116
+ click.secho(
117
+ f"Error downloading package: {response.json()['error']}",
118
+ fg="red",
119
+ )
120
+ return {}
121
+ except Exception as e:
122
+ click.secho(f"Error downloading package: {e}", fg="red")
123
+ return {}
124
+
125
+ @staticmethod
126
+ def get_action_info(
127
+ name: str, version: str = "", token: Optional[str] = None
128
+ ) -> dict:
129
+ """Get action info.yaml content as json"""
130
+ endpoint = "info"
131
+
132
+ try:
133
+ headers = {"Authorization": f"Bearer {token}"} if token else None
134
+ data = {
135
+ "name": name,
136
+ "version": "" if version == "latest" else version,
137
+ }
138
+ response = requests.get(
139
+ RegistryAPI.url + endpoint, params=data, headers=headers
140
+ )
141
+ # Check if the response is successful
142
+ if response.status_code == 200:
143
+ return response.json()
144
+ else:
145
+ click.secho(
146
+ f"Error retrieving action: {response.json()['error']}",
147
+ fg="red",
148
+ )
149
+ return {}
150
+ except Exception as e:
151
+ click.secho(f"Error retrieving action: {e}", fg="red")
152
+ return {}
153
+
154
+ @staticmethod
155
+ def create_namespace(name: str, token: str) -> dict:
156
+ """Create a namespace."""
157
+ endpoint = "namespace"
158
+
159
+ try:
160
+ headers = {"Authorization": f"Bearer {token}"}
161
+
162
+ data = {"name": name}
163
+
164
+ response = requests.post(
165
+ RegistryAPI.url + endpoint, headers=headers, json=data
166
+ )
167
+ # Check if the response is successful
168
+ if response.status_code == 200:
169
+ return response.json()
170
+ else:
171
+ click.secho(
172
+ f"Error creating namespace: {response.json()['message']}", fg="red"
173
+ )
174
+ return {}
175
+ except Exception as e:
176
+ click.secho(f"Error creating namespace: {e}", fg="red")
177
+ return {}
178
+
179
+ @staticmethod
180
+ def invite_user_to_namespace(
181
+ namespace_name: str, user_email: str, token: str
182
+ ) -> dict:
183
+ """Invite a user to a namespace."""
184
+ endpoint = f"namespace/{namespace_name}/invite"
185
+
186
+ try:
187
+ headers = {"Authorization": f"Bearer {token}"}
188
+
189
+ data = {"emailOrUsername": user_email}
190
+
191
+ response = requests.post(
192
+ RegistryAPI.url + endpoint, headers=headers, json=data
193
+ )
194
+ # Check if the response is successful
195
+ if response.status_code == 200:
196
+ return response.json()
197
+ else:
198
+ click.secho(
199
+ f"Error inviting user to namespace: {response.json()['message']}",
200
+ fg="red",
201
+ )
202
+ return {}
203
+ except Exception as e:
204
+ click.secho(f"Error inviting user to namespace: {e}", fg="red")
205
+ return {}
206
+
207
+ @staticmethod
208
+ def transfer_namespace_ownership(
209
+ namespace_name: str, new_owner_email: str, token: str
210
+ ) -> dict:
211
+ """Transfer ownership of a namespace."""
212
+ endpoint = f"namespace/{namespace_name}/transfer-ownership​"
213
+
214
+ try:
215
+ headers = {"Authorization": f"Bearer {token}"}
216
+
217
+ data = {"emailOrUsername": new_owner_email}
218
+
219
+ response = requests.post(
220
+ RegistryAPI.url + endpoint, headers=headers, json=data
221
+ )
222
+ # Check if the response is successful
223
+ if response.status_code == 200:
224
+ return response.json()
225
+ else:
226
+ click.secho(
227
+ f"Error transferring ownership of namespace: {response.json()['message']}",
228
+ fg="red",
229
+ )
230
+ return {}
231
+ except Exception as e:
232
+ click.secho(f"Error transferring ownership of namespace: {e}", fg="red")
233
+ return {}
234
+
235
+ @staticmethod
236
+ def package_search(
237
+ query: str,
238
+ version: Optional[str] = None,
239
+ operator: Optional[str] = None,
240
+ limit: int = 15,
241
+ offset: int = 0,
242
+ ) -> dict:
243
+ """Search for packages in the Jivas Package Repository."""
244
+ endpoint = "packages/search"
245
+
246
+ try:
247
+ data = {
248
+ "q": query,
249
+ # "version": version, # TODO: Implement version filtering
250
+ # "operator": operator, # TODO: Implement operator filtering
251
+ "limit": limit,
252
+ "offset": offset,
253
+ }
254
+ response = requests.post(RegistryAPI.url + endpoint, json=data)
255
+ # Check if the response is successful
256
+ if response.status_code == 200:
257
+ return response.json()
258
+ else:
259
+ click.secho(
260
+ f"Error searching for packages: {response.json()['error']}",
261
+ fg="red",
262
+ )
263
+ return {}
264
+ except Exception as e:
265
+ click.secho(f"Error searching for packages: {e}", fg="red")
266
+ return {}
267
+
268
+ @staticmethod
269
+ def publish_action(
270
+ tgz_file_path: str, visibility: str, token: str, namespace: str
271
+ ) -> dict:
272
+ """Publish a Jivas Action to the repository."""
273
+ endpoint = "publish"
274
+
275
+ try:
276
+ headers = {
277
+ "Authorization": f"Bearer {token}",
278
+ }
279
+
280
+ # Open the .tgz file using a context manager to ensure it's closed after use
281
+ with open(tgz_file_path, "rb") as tgz_file:
282
+ files = {"file": tgz_file}
283
+ data = {
284
+ "visibility": visibility.capitalize(), # Ensure correct capitalization
285
+ "namespace": namespace,
286
+ }
287
+
288
+ # Send POST request
289
+ response = requests.post(
290
+ RegistryAPI.url + endpoint, headers=headers, files=files, data=data
291
+ )
292
+
293
+ if response.status_code == 401:
294
+ click.secho(
295
+ "Error publishing package: Invalid token. Please login again.",
296
+ fg="red",
297
+ )
298
+ return {}
299
+
300
+ # Check if the response is successful
301
+ if response.status_code == 200:
302
+ return response.json() # Return the response data if successful
303
+ else:
304
+ if response.json()["error"] == "VERSION_CONFLICT":
305
+ click.secho(
306
+ f"Error publishing package: {response.json()['message']}",
307
+ fg="red",
308
+ )
309
+ return {}
310
+ else:
311
+ # Print and show error message
312
+ click.secho(
313
+ f"Error publishing package: {response.json()}", fg="red"
314
+ )
315
+ return {}
316
+ except Exception as e:
317
+ click.secho(f"Error publishing package: {e}", fg="red")
318
+ return {}
jvcli/auth.py ADDED
@@ -0,0 +1,45 @@
1
+ """Authentication module for the CLI."""
2
+
3
+ import json
4
+ import os
5
+
6
+ TOKEN_FILE = os.path.expanduser("~/.jvcli_token")
7
+
8
+
9
+ def save_token(token: str, namespaces: dict, email: str) -> None:
10
+ """Save the token to a file."""
11
+ data = {"token": token, "namespaces": clean_namespaces(namespaces), "email": email}
12
+ with open(TOKEN_FILE, "w") as f:
13
+ json.dump(data, f)
14
+
15
+
16
+ def load_token() -> dict:
17
+ """Load the token from a file."""
18
+ if os.path.exists(TOKEN_FILE):
19
+ with open(TOKEN_FILE, "r") as f:
20
+ data = json.load(f)
21
+ return data
22
+ return {}
23
+
24
+
25
+ def delete_token() -> None:
26
+ """Delete the token file."""
27
+ if os.path.exists(TOKEN_FILE):
28
+ os.remove(TOKEN_FILE)
29
+
30
+
31
+ def clean_namespaces(namespaces: dict) -> dict:
32
+ """Clean up the namespaces dict."""
33
+ for k, v in namespaces.items():
34
+ if k == "default":
35
+ namespaces[k] = v.replace("@", "")
36
+ if k == "groups":
37
+ v = [group.replace("@", "") for group in v]
38
+ namespaces[k] = v
39
+ return namespaces
40
+
41
+
42
+ def load_namespaces() -> str:
43
+ """Load the namespaces from the token."""
44
+ token = load_token()
45
+ return token.get("namespaces", {}).get("default", "anonymous")
jvcli/cli.py ADDED
@@ -0,0 +1,36 @@
1
+ """Jivas Package Repository CLI tool."""
2
+
3
+ import click
4
+
5
+ from jvcli import __version__
6
+ from jvcli.commands.auth import login, logout, signup
7
+ from jvcli.commands.create import create
8
+ from jvcli.commands.download import download
9
+ from jvcli.commands.info import info
10
+ from jvcli.commands.publish import publish
11
+ from jvcli.commands.studio import studio
12
+ from jvcli.commands.update import update
13
+
14
+
15
+ @click.group()
16
+ @click.version_option(__version__, prog_name="jvcli")
17
+ def jvcli() -> None:
18
+ """Jivas Package Repository CLI tool."""
19
+ pass # pragma: no cover
20
+
21
+
22
+ # Register command groups
23
+ jvcli.add_command(create)
24
+ jvcli.add_command(update)
25
+ jvcli.add_command(download)
26
+ jvcli.add_command(publish)
27
+ jvcli.add_command(info)
28
+ jvcli.add_command(studio)
29
+
30
+ # Register standalone commands
31
+ jvcli.add_command(signup)
32
+ jvcli.add_command(login)
33
+ jvcli.add_command(logout)
34
+
35
+ if __name__ == "__main__":
36
+ jvcli() # pragma: no cover