@codebend3r/che 1.1.0 → 1.2.0

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 (53) hide show
  1. package/README.md +38 -24
  2. package/bin/art.py +22 -20
  3. package/bin/che.py +208 -587
  4. package/bin/commands.py +220 -231
  5. package/bin/doctor.py +220 -0
  6. package/bin/drives/eject-all-drives.py +21 -38
  7. package/bin/drives/mount-all-drives.py +18 -62
  8. package/bin/drives/ping-nas.py +77 -105
  9. package/bin/files/compress-folders.py +7 -11
  10. package/bin/files/delete-by-ext.py +10 -14
  11. package/bin/files/delete-empty-folders.py +33 -37
  12. package/bin/files/delete-smb-files.py +12 -21
  13. package/bin/files/files-under-size.py +5 -11
  14. package/bin/files/find-largest-files.py +21 -25
  15. package/bin/files/list-permission.py +40 -0
  16. package/bin/files/make-alpha-dir.py +2 -0
  17. package/bin/git/all-actions.py +350 -253
  18. package/bin/git/checkout-my-branches.py +42 -63
  19. package/bin/git/clean-stale-branches.py +23 -48
  20. package/bin/git/prune-worktrees.py +12 -51
  21. package/bin/git/sync-all-branches.py +54 -283
  22. package/bin/git/update-local-branches.py +67 -73
  23. package/bin/gitutils.py +263 -0
  24. package/bin/install.py +393 -1182
  25. package/bin/machine.py +345 -0
  26. package/bin/media.py +127 -0
  27. package/bin/menu.py +437 -0
  28. package/bin/nas.py +102 -0
  29. package/bin/rcfile.py +380 -0
  30. package/bin/shellgen.py +503 -431
  31. package/bin/system/btop-launch.py +17 -13
  32. package/bin/system/update-brew.py +57 -68
  33. package/bin/tui.py +156 -153
  34. package/bin/utils.py +165 -237
  35. package/bin/video/delete-duplicate-videos.py +64 -62
  36. package/bin/video/detect-green-magenta-videos.py +105 -95
  37. package/bin/video/find-movie-by-year.py +3 -0
  38. package/bin/video/find-video-mkv-issues.py +48 -65
  39. package/bin/video/fix-codecs.py +25 -30
  40. package/bin/video/largest-tv-shows.py +60 -57
  41. package/bin/video/remove-metadata.py +3 -6
  42. package/bin/video/rename-video-file.py +74 -84
  43. package/bin/video/scan-videos-audio-language.py +16 -33
  44. package/bin/video/show-codecs.py +20 -24
  45. package/bin/video/validate-video-files.py +5 -8
  46. package/bin/video/video-list.py +17 -20
  47. package/package.json +4 -10
  48. package/shell/che.bash +33 -33
  49. package/shell/che.fish +7 -7
  50. package/shell/che.zsh +33 -33
  51. package/shell/completions/_che +19 -19
  52. package/shell/completions/che.bash +15 -15
  53. package/shell/completions/che.fish +34 -50
@@ -14,8 +14,8 @@ Options:
14
14
  from __future__ import annotations
15
15
 
16
16
  import heapq
17
- import re
18
17
  import sys
18
+ from collections.abc import Iterator
19
19
  from pathlib import Path
20
20
 
21
21
  sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
@@ -26,15 +26,13 @@ from utils import (
26
26
  format_bytes,
27
27
  info,
28
28
  iter_files,
29
- note,
29
+ note_settings,
30
+ parse_count,
30
31
  run_cli,
31
32
  scan_root,
32
- warning,
33
33
  )
34
34
 
35
- __version__ = "2.0.4"
36
-
37
- _NON_NEGATIVE_INT = re.compile(r"[0-9]+")
35
+ __version__ = "2.1.0"
38
36
 
39
37
 
40
38
  def main(argv: list[str] | None = None) -> int:
@@ -43,32 +41,29 @@ def main(argv: list[str] | None = None) -> int:
43
41
  description="📊 List the largest files under a path, biggest first.",
44
42
  )
45
43
  parser.add_argument("--path", default=".", metavar="DIR", help="Directory to scan (default: .)")
46
- # Kept as a string, not `type=int`: argparse's int conversion would own the
47
- # error and exit before the shell version's own message could be produced.
44
+ # A string, validated by parse_count below rather than `type=int`.
48
45
  parser.add_argument(
49
46
  "--length", default="10", metavar="N", help="How many files to list (default: 10)"
50
47
  )
51
- add_bool_flag(parser, "--full-path", dest="full_path", help="Print the whole path")
48
+ add_bool_flag(parser, "--full-path", help="Print the whole path")
52
49
 
53
50
  info(f"Running command in {Path.cwd()}")
54
51
  args = parser.parse_args(argv)
55
52
 
56
- if not _NON_NEGATIVE_INT.fullmatch(args.length):
57
- warning("❌ --length must be a non-negative integer")
58
- return 1
59
- length = int(args.length)
60
-
61
- if not args.path:
62
- warning("❌ --path cannot be empty")
63
- return 1
53
+ length = parse_count(args.length, "--length")
64
54
 
65
- note(f"Searching in: {args.path}")
66
- note(f"List length: {length}")
67
- note(f"Show full path: {str(args.full_path).lower()}")
55
+ note_settings(
56
+ ("Searching in", args.path),
57
+ ("List length", length),
58
+ ("Show full path", args.full_path),
59
+ rule=False,
60
+ )
68
61
 
62
+ # An empty --path reads "--path is required" after the settings, where the
63
+ # shell version printed "--path cannot be empty" before them.
69
64
  root = scan_root(args.path)
70
65
 
71
- def sized() -> list[tuple[int, str, Path]]:
66
+ def sized() -> Iterator[tuple[int, str, Path]]:
72
67
  for path in iter_files(root, skip_macos_metadata=False):
73
68
  try:
74
69
  size = path.stat().st_size
@@ -80,10 +75,11 @@ def main(argv: list[str] | None = None) -> int:
80
75
  yield size, str(path), path
81
76
 
82
77
  # `sort -nr | head -n N` ties break on the whole line DESCENDING, because
83
- # -r reverses the last-resort comparison too. nlargest on (size, str) gives
84
- # the same ordering, and holds only N entries rather than the whole tree -
85
- # a million-file media root would otherwise cost about a gigabyte.
86
- top = heapq.nlargest(length, sized(), key=lambda item: (item[0], item[1]))
78
+ # -r reverses the last-resort comparison too. nlargest on (size, str, ...)
79
+ # gives the same ordering - the path string is unique, so the comparison
80
+ # never reaches the Path - and holds only N entries rather than the whole
81
+ # tree: a million-file media root would otherwise cost about a gigabyte.
82
+ top = heapq.nlargest(length, sized())
87
83
 
88
84
  for size, _, path in top:
89
85
  if args.full_path:
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env python3
2
+ """🔐 Show the ownership and mode of a volume under ``/Volumes``.
3
+
4
+ Usage:
5
+ list-permission.py [VOLUME] (no VOLUME lists /Volumes itself)
6
+
7
+ Options:
8
+ --help Show help
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import sys
14
+ from pathlib import Path
15
+
16
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
17
+
18
+ from utils import build_parser, run, run_cli
19
+
20
+ __version__ = "1.0.0"
21
+
22
+
23
+ def main(argv: list[str] | None = None) -> int:
24
+ parser = build_parser(
25
+ prog="list-permission",
26
+ description="🔐 Show ownership and mode of a volume under /Volumes.",
27
+ )
28
+ parser.add_argument("volume", nargs="?", default="", help="Volume name (default: /Volumes)")
29
+ # DELIBERATE DIVERGENCE from the shell wrapper, `command ls -ld
30
+ # "/Volumes/$1"`, which ignored any argument after the first. A second one
31
+ # is an error here rather than silently dropped.
32
+ args = parser.parse_args(argv)
33
+
34
+ # `ls` runs as a program, so a user's `alias ls=eza` never replaces the
35
+ # `ls -l` listing - the reason the wrapper spelled it `command ls`.
36
+ return run(["ls", "-ld", f"/Volumes/{args.volume}"], check=False).returncode
37
+
38
+
39
+ if __name__ == "__main__":
40
+ run_cli(main)
@@ -19,6 +19,8 @@ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
19
19
 
20
20
  from utils import build_parser, info, run_cli, warning
21
21
 
22
+ __version__ = "1.0.0"
23
+
22
24
  BUCKETS = ("#", *string.ascii_uppercase)
23
25
 
24
26