@codebend3r/che 1.0.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.
- package/README.md +65 -25
- package/bin/art.py +123 -0
- package/bin/che.py +209 -568
- package/bin/commands.py +220 -231
- package/bin/doctor.py +220 -0
- package/bin/drives/eject-all-drives.py +21 -38
- package/bin/drives/mount-all-drives.py +18 -62
- package/bin/drives/ping-nas.py +77 -105
- package/bin/files/compress-folders.py +7 -11
- package/bin/files/delete-by-ext.py +10 -14
- package/bin/files/delete-empty-folders.py +33 -37
- package/bin/files/delete-smb-files.py +12 -21
- package/bin/files/files-under-size.py +5 -11
- package/bin/files/find-largest-files.py +21 -25
- package/bin/files/list-permission.py +40 -0
- package/bin/files/make-alpha-dir.py +2 -0
- package/bin/git/all-actions.py +350 -253
- package/bin/git/checkout-my-branches.py +42 -63
- package/bin/git/clean-stale-branches.py +23 -48
- package/bin/git/prune-worktrees.py +12 -51
- package/bin/git/sync-all-branches.py +54 -283
- package/bin/git/update-local-branches.py +67 -73
- package/bin/gitutils.py +263 -0
- package/bin/install.py +393 -1188
- package/bin/machine.py +345 -0
- package/bin/media.py +127 -0
- package/bin/menu.py +437 -0
- package/bin/nas.py +102 -0
- package/bin/rcfile.py +380 -0
- package/bin/shellgen.py +508 -428
- package/bin/system/btop-launch.py +17 -13
- package/bin/system/update-brew.py +57 -68
- package/bin/tui.py +156 -153
- package/bin/utils.py +165 -237
- package/bin/video/delete-duplicate-videos.py +64 -62
- package/bin/video/detect-green-magenta-videos.py +105 -95
- package/bin/video/find-movie-by-year.py +3 -0
- package/bin/video/find-video-mkv-issues.py +48 -65
- package/bin/video/fix-codecs.py +25 -30
- package/bin/video/largest-tv-shows.py +60 -57
- package/bin/video/remove-metadata.py +3 -6
- package/bin/video/rename-video-file.py +74 -84
- package/bin/video/scan-videos-audio-language.py +16 -33
- package/bin/video/show-codecs.py +20 -24
- package/bin/video/validate-video-files.py +5 -8
- package/bin/video/video-list.py +17 -20
- package/package.json +4 -10
- package/shell/che.bash +33 -33
- package/shell/che.fish +7 -7
- package/shell/che.zsh +33 -33
- package/shell/completions/_che +19 -19
- package/shell/completions/che.bash +15 -15
- package/shell/completions/che.fish +34 -50
|
@@ -20,9 +20,9 @@ from pathlib import Path
|
|
|
20
20
|
|
|
21
21
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
22
22
|
|
|
23
|
-
from utils import info, require_binary, run, warning
|
|
23
|
+
from utils import atomic_write_text, info, require_binary, run, run_cli, warning
|
|
24
24
|
|
|
25
|
-
__version__ = "1.0
|
|
25
|
+
__version__ = "1.1.0"
|
|
26
26
|
|
|
27
27
|
CONF = Path.home() / ".config" / "btop" / "btop.conf"
|
|
28
28
|
LIGHT_THEME = "gruvbox_light"
|
|
@@ -37,10 +37,15 @@ Description:
|
|
|
37
37
|
Any extra arguments are passed straight through to btop.
|
|
38
38
|
"""
|
|
39
39
|
|
|
40
|
-
# `[^\S\n]` rather than `\s`: \s matches newlines, so a config with a line
|
|
40
|
+
# `[^\S\r\n]` rather than `\s`: \s matches newlines, so a config with a line
|
|
41
41
|
# break between "color_theme" and "=" would have two lines collapsed into one.
|
|
42
42
|
# perl -p works a line at a time and cannot do that.
|
|
43
|
-
|
|
43
|
+
#
|
|
44
|
+
# DELIBERATE DIVERGENCE: the value stops at `\r` as well as `\n`. perl's `.`
|
|
45
|
+
# (like Python's) matches `\r`, so the shell version turned the rewritten line
|
|
46
|
+
# of a CRLF config into LF. A CR-only config has no `\n` at all, so to both it
|
|
47
|
+
# was one long line, and the match replaced everything after the theme.
|
|
48
|
+
_COLOR_THEME_RE = re.compile(r"^color_theme[^\S\r\n]*=[^\r\n]*", re.MULTILINE)
|
|
44
49
|
|
|
45
50
|
|
|
46
51
|
def current_theme() -> str:
|
|
@@ -61,11 +66,12 @@ def apply_theme(theme: str) -> None:
|
|
|
61
66
|
return
|
|
62
67
|
|
|
63
68
|
try:
|
|
64
|
-
# newline="" so existing CRLF (or CR) line endings survive the
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
+
# newline="" so existing CRLF (or CR) line endings survive the read;
|
|
70
|
+
# read_text would turn every line ending in the file into \n, where
|
|
71
|
+
# `perl -i` only ever touched the matched line. surrogateescape so a
|
|
72
|
+
# config carrying non-UTF-8 bytes still round-trips instead of raising
|
|
73
|
+
# and leaving btop unlaunchable. atomic_write_text writes both back
|
|
74
|
+
# untouched.
|
|
69
75
|
with CONF.open("r", encoding="utf-8", errors="surrogateescape", newline="") as handle:
|
|
70
76
|
original = handle.read()
|
|
71
77
|
except OSError as exc:
|
|
@@ -79,8 +85,7 @@ def apply_theme(theme: str) -> None:
|
|
|
79
85
|
|
|
80
86
|
if updated != original:
|
|
81
87
|
try:
|
|
82
|
-
|
|
83
|
-
handle.write(updated)
|
|
88
|
+
atomic_write_text(CONF, updated)
|
|
84
89
|
except OSError as exc:
|
|
85
90
|
warning(f"Could not write {CONF}: {exc}; launching with existing theme")
|
|
86
91
|
return
|
|
@@ -107,8 +112,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
107
112
|
# identical to running btop directly, exactly like `exec btop "$@"`.
|
|
108
113
|
# argv[0] stays the bare name, which is what btop echoes in its own usage.
|
|
109
114
|
os.execv(btop, ["btop", *args]) # noqa: S606 - absolute path, no shell
|
|
110
|
-
return 0 # unreachable; execv never returns
|
|
111
115
|
|
|
112
116
|
|
|
113
117
|
if __name__ == "__main__":
|
|
114
|
-
|
|
118
|
+
run_cli(main)
|
|
@@ -19,12 +19,16 @@ from __future__ import annotations
|
|
|
19
19
|
|
|
20
20
|
import sys
|
|
21
21
|
from pathlib import Path
|
|
22
|
+
from typing import NamedTuple
|
|
22
23
|
|
|
23
24
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
24
25
|
|
|
25
26
|
from utils import (
|
|
26
27
|
add_bool_flag,
|
|
27
28
|
build_parser,
|
|
29
|
+
dry_run_complete,
|
|
30
|
+
footer_rule,
|
|
31
|
+
heading,
|
|
28
32
|
info,
|
|
29
33
|
log,
|
|
30
34
|
note,
|
|
@@ -35,34 +39,28 @@ from utils import (
|
|
|
35
39
|
warning,
|
|
36
40
|
)
|
|
37
41
|
|
|
38
|
-
__version__ = "1.
|
|
42
|
+
__version__ = "1.1.0"
|
|
39
43
|
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
*,
|
|
44
|
-
dry_run: bool,
|
|
45
|
-
dry_run_argv: list[str] | None = None,
|
|
46
|
-
echo: bool = False,
|
|
47
|
-
) -> None:
|
|
48
|
-
"""Run a brew subcommand, or its --dry-run form.
|
|
45
|
+
class Step(NamedTuple):
|
|
46
|
+
"""One brew command the update runs, and what skips it."""
|
|
49
47
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
banner: str
|
|
49
|
+
command: list[str]
|
|
50
|
+
skip: str = "" # what a passed --no-* flag skips, for the skip note
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def brew(command: list[str], *, dry_run: bool) -> None:
|
|
54
|
+
"""Run a brew subcommand, or preview it with Homebrew's own ``--dry-run``.
|
|
55
|
+
|
|
56
|
+
That ``--dry-run`` exits non-zero in some situations that are not really
|
|
57
|
+
failures, so the preview calls are non-fatal - the same ``|| true`` the
|
|
58
|
+
shell version used. The real calls stay fatal.
|
|
53
59
|
"""
|
|
54
60
|
if dry_run:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
run(dry_run_argv, check=False)
|
|
59
|
-
return
|
|
60
|
-
|
|
61
|
-
# Only `brew update` echoed its command in the shell version; the other
|
|
62
|
-
# steps called brew directly, and brew narrates itself.
|
|
63
|
-
if echo:
|
|
64
|
-
log(f" โถ {' '.join(argv)}")
|
|
65
|
-
run(argv)
|
|
61
|
+
run([*command, "--dry-run"], check=False)
|
|
62
|
+
else:
|
|
63
|
+
run(command)
|
|
66
64
|
|
|
67
65
|
|
|
68
66
|
def main(argv: list[str] | None = None) -> int:
|
|
@@ -71,9 +69,11 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
71
69
|
description="๐บ Update Homebrew, upgrade formulae and casks, then clean up.",
|
|
72
70
|
)
|
|
73
71
|
add_bool_flag(parser, "--dry-run", help="Show what would change, change nothing")
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
add_bool_flag(parser, "--no-
|
|
72
|
+
# Bare spellings only, as the shell version took them: `--no-cask=false`
|
|
73
|
+
# is a double negative, not a way to ask for casks.
|
|
74
|
+
add_bool_flag(parser, "--no-cask", allow_value=False, help="Skip upgrading casks")
|
|
75
|
+
add_bool_flag(parser, "--no-cleanup", allow_value=False, help="Skip 'brew cleanup'")
|
|
76
|
+
add_bool_flag(parser, "--no-autoremove", allow_value=False, help="Skip 'brew autoremove'")
|
|
77
77
|
add_bool_flag(parser, "--greedy", help="Pass --greedy to cask upgrade")
|
|
78
78
|
add_bool_flag(parser, "--doctor", help="Run 'brew doctor' at the very end")
|
|
79
79
|
args = parser.parse_args(argv)
|
|
@@ -81,50 +81,40 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
81
81
|
require_binary("brew", hint="Install Homebrew first: https://brew.sh")
|
|
82
82
|
|
|
83
83
|
dry = args.dry_run
|
|
84
|
-
|
|
85
|
-
note("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
|
|
86
|
-
note(f"๐บ update-brew{header_suffix}")
|
|
87
|
-
note("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
|
|
84
|
+
heading("๐บ update-brew", dry_run=dry)
|
|
88
85
|
|
|
89
|
-
# 1. Refresh Homebrew itself and tap metadata
|
|
86
|
+
# 1. Refresh Homebrew itself and tap metadata. brew has no preview for
|
|
87
|
+
# this, and it is the one step whose command the shell version echoed;
|
|
88
|
+
# brew narrates the others itself.
|
|
90
89
|
info("๐ก Updating Homebrew metadata...")
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
# 2. Upgrade formulae
|
|
94
|
-
info("โฌ๏ธ Upgrading formulae...")
|
|
95
|
-
brew(["brew", "upgrade"], dry_run=dry, dry_run_argv=["brew", "upgrade", "--dry-run"])
|
|
96
|
-
|
|
97
|
-
# 3. Upgrade casks (apps)
|
|
98
|
-
if args.no_cask:
|
|
99
|
-
note("โญ๏ธ Skipping cask upgrades (--no-cask)")
|
|
100
|
-
else:
|
|
101
|
-
info("๐ฆ Upgrading casks...")
|
|
102
|
-
cask_argv = ["brew", "upgrade", "--cask"]
|
|
103
|
-
if args.greedy:
|
|
104
|
-
cask_argv.append("--greedy")
|
|
105
|
-
brew(cask_argv, dry_run=dry, dry_run_argv=[*cask_argv, "--dry-run"])
|
|
106
|
-
|
|
107
|
-
# 4. Remove unused dependencies
|
|
108
|
-
if args.no_autoremove:
|
|
109
|
-
note("โญ๏ธ Skipping autoremove (--no-autoremove)")
|
|
90
|
+
if dry:
|
|
91
|
+
warning(" ๐ช Would run: brew update")
|
|
110
92
|
else:
|
|
111
|
-
|
|
112
|
-
brew
|
|
93
|
+
log(" โถ brew update")
|
|
94
|
+
run(["brew", "update"])
|
|
95
|
+
|
|
96
|
+
# 2-5.
|
|
97
|
+
cask = ["brew", "upgrade", "--cask", *(["--greedy"] if args.greedy else [])]
|
|
98
|
+
steps = (
|
|
99
|
+
Step("โฌ๏ธ Upgrading formulae...", ["brew", "upgrade"]),
|
|
100
|
+
Step("๐ฆ Upgrading casks...", cask, "cask upgrades (--no-cask)" if args.no_cask else ""),
|
|
101
|
+
Step(
|
|
102
|
+
"๐งน Removing unused dependencies...",
|
|
113
103
|
["brew", "autoremove"],
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
# 5. Cleanup old versions + cache
|
|
119
|
-
if args.no_cleanup:
|
|
120
|
-
note("โญ๏ธ Skipping cleanup (--no-cleanup)")
|
|
121
|
-
else:
|
|
122
|
-
info("๐๏ธ Cleaning up old versions and cache...")
|
|
123
|
-
brew(
|
|
104
|
+
"autoremove (--no-autoremove)" if args.no_autoremove else "",
|
|
105
|
+
),
|
|
106
|
+
Step(
|
|
107
|
+
"๐๏ธ Cleaning up old versions and cache...",
|
|
124
108
|
["brew", "cleanup", "-s"],
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
109
|
+
"cleanup (--no-cleanup)" if args.no_cleanup else "",
|
|
110
|
+
),
|
|
111
|
+
)
|
|
112
|
+
for step in steps:
|
|
113
|
+
if step.skip:
|
|
114
|
+
note(f"โญ๏ธ Skipping {step.skip}")
|
|
115
|
+
continue
|
|
116
|
+
info(step.banner)
|
|
117
|
+
brew(step.command, dry_run=dry)
|
|
128
118
|
|
|
129
119
|
# 6. Optional doctor pass - advisory, never fatal
|
|
130
120
|
if args.doctor:
|
|
@@ -133,10 +123,9 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
133
123
|
if completed.returncode != 0:
|
|
134
124
|
warning("โ ๏ธ brew doctor reported issues (non-fatal)")
|
|
135
125
|
|
|
136
|
-
|
|
137
|
-
note("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
|
|
126
|
+
footer_rule()
|
|
138
127
|
if dry:
|
|
139
|
-
|
|
128
|
+
dry_run_complete()
|
|
140
129
|
else:
|
|
141
130
|
success("๐ Homebrew is up to date and tidy! ๐บโจ")
|
|
142
131
|
return 0
|