steve-cli 0.3.1__tar.gz → 0.3.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: steve-cli
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: A simple CLI tool to run jobs from jobs.yaml with proper environment setup
5
5
  Author: Frank
6
6
  License: MIT
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
 
6
6
  [project]
7
7
  name = "steve-cli"
8
- version = "0.3.1"
8
+ version = "0.3.2"
9
9
  description = "A simple CLI tool to run jobs from jobs.yaml with proper environment setup"
10
10
  readme = "README.md"
11
11
  license = {text = "MIT"}
@@ -233,5 +233,100 @@ def setup_env():
233
233
  click.echo(f" 💡 Run: {click.style(f'source {out_file.name}', fg='yellow')}")
234
234
 
235
235
 
236
+ def _detect_workspaces() -> List[str]:
237
+ tiers = {"BRONZE", "SILVER", "GOLD"}
238
+ workspaces = set()
239
+ for key in os.environ:
240
+ if key.endswith("_ACCESS_KEY"):
241
+ prefix = key[: -len("_ACCESS_KEY")]
242
+ if prefix not in tiers:
243
+ workspaces.add(prefix)
244
+ return sorted(workspaces)
245
+
246
+
247
+ def _build_tree(keys: List[str]) -> Dict[str, Any]:
248
+ tree: Dict[str, Any] = {}
249
+ for key in keys:
250
+ parts = key.split("/")
251
+ node = tree
252
+ for part in parts[:-1]:
253
+ node = node.setdefault(part, {})
254
+ node[parts[-1]] = None
255
+ return tree
256
+
257
+
258
+ def _print_tree(node: Dict[str, Any], prefix: str = "", is_last: bool = True) -> None:
259
+ items = sorted(node.items())
260
+ for i, (name, child) in enumerate(items):
261
+ last = i == len(items) - 1
262
+ connector = "└── " if last else "├── "
263
+ click.echo(f"{prefix}{connector}{name}")
264
+ if child is not None:
265
+ extension = " " if last else "│ "
266
+ _print_tree(child, prefix + extension, last)
267
+
268
+
269
+ def _list_bucket(storage_kwargs: dict, label: str, bucket_name: str) -> None:
270
+ click.echo(f" {click.style(label, fg='cyan')} ({bucket_name})")
271
+ try:
272
+ from steve_cli.storage import S3Storage
273
+ storage = S3Storage(**storage_kwargs)
274
+ keys = storage.list_all()
275
+ if not keys:
276
+ click.echo(" (empty)")
277
+ else:
278
+ tree = _build_tree(keys)
279
+ _print_tree(tree, prefix=" ")
280
+ except EnvironmentError as e:
281
+ click.echo(f" ⚠️ {e}", err=True)
282
+ except Exception as e:
283
+ click.echo(f" ❌ {e}", err=True)
284
+
285
+
286
+ @main.command("buckets")
287
+ def buckets():
288
+ """List all S3 buckets detected from env variables and show their files as a tree."""
289
+ tiers = ["bronze", "silver", "gold"]
290
+
291
+ options: List[Dict[str, Any]] = []
292
+
293
+ bare_tiers = [t for t in tiers if os.getenv(f"{t.upper()}_ACCESS_KEY")]
294
+ for tier in bare_tiers:
295
+ bucket_name = os.getenv(f"{tier.upper()}_BUCKET", "")
296
+ options.append({
297
+ "label": f"default / {tier} ({bucket_name})",
298
+ "kwargs": {"tier": tier},
299
+ "bucket_name": bucket_name,
300
+ "tier": tier,
301
+ })
302
+
303
+ for ws in _detect_workspaces():
304
+ for tier in tiers:
305
+ bucket_name = os.getenv(f"{ws}_BUCKET_{tier.upper()}")
306
+ if not bucket_name:
307
+ continue
308
+ options.append({
309
+ "label": f"{ws} / {tier} ({bucket_name})",
310
+ "kwargs": {"tier": tier, "workspace": ws.lower().replace("_", "-")},
311
+ "bucket_name": bucket_name,
312
+ "tier": tier,
313
+ })
314
+
315
+ if not options:
316
+ click.echo("No bucket env variables found (expected: BRONZE_ACCESS_KEY or {WORKSPACE}_ACCESS_KEY).")
317
+ return
318
+
319
+ choice = questionary.select(
320
+ "Select a bucket to list:",
321
+ choices=[o["label"] for o in options],
322
+ ).ask()
323
+
324
+ if choice is None:
325
+ sys.exit(0)
326
+
327
+ selected = next(o for o in options if o["label"] == choice)
328
+ _list_bucket(selected["kwargs"], selected["tier"], selected["bucket_name"])
329
+
330
+
236
331
  if __name__ == '__main__':
237
332
  main()
@@ -161,6 +161,14 @@ class S3Storage:
161
161
  for obj in resp.get("Contents", [])
162
162
  ]
163
163
 
164
+ def list_all(self) -> List[str]:
165
+ keys = []
166
+ paginator = self.client.get_paginator("list_objects_v2")
167
+ for page in paginator.paginate(Bucket=self.bucket):
168
+ for obj in page.get("Contents", []):
169
+ keys.append(obj["Key"])
170
+ return keys
171
+
164
172
 
165
173
  def get_storage(tier: str = "bronze", workspace: str | None = None) -> Storage:
166
174
  return S3Storage(tier=tier, workspace=workspace)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: steve-cli
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: A simple CLI tool to run jobs from jobs.yaml with proper environment setup
5
5
  Author: Frank
6
6
  License: MIT
File without changes
File without changes