machineconfig 1.94__py3-none-any.whl → 1.95__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.
Potentially problematic release.
This version of machineconfig might be problematic. Click here for more details.
- machineconfig/cluster/data_transfer.py +2 -1
- machineconfig/cluster/job_params.py +1 -1
- machineconfig/cluster/script_execution.py +1 -1
- machineconfig/jobs/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/linux/msc/lid.sh +2 -4
- machineconfig/jobs/linux/msc/network.sh +3 -6
- machineconfig/jobs/python/check_installations.py +6 -6
- machineconfig/jobs/python/checkout_version.py +4 -4
- machineconfig/jobs/python/python_cargo_build_share.py +2 -2
- machineconfig/jobs/python/python_ve_symlink.py +4 -4
- machineconfig/jobs/python/vscode/api.py +2 -2
- machineconfig/jobs/python/vscode/link_ve.py +4 -4
- machineconfig/jobs/python/vscode/select_interpreter.py +4 -4
- machineconfig/jobs/python/vscode/sync_code.py +6 -6
- machineconfig/jobs/python_custom_installers/archive/ngrok.py +4 -4
- machineconfig/jobs/python_custom_installers/dev/aider.py +4 -4
- machineconfig/jobs/python_custom_installers/dev/alacritty.py +4 -4
- machineconfig/jobs/python_custom_installers/dev/brave.py +4 -4
- machineconfig/jobs/python_custom_installers/dev/bypass_paywall.py +4 -4
- machineconfig/jobs/python_custom_installers/dev/code.py +4 -4
- machineconfig/jobs/python_custom_installers/dev/docker.py +4 -4
- machineconfig/jobs/python_custom_installers/dev/docker_desktop.py +4 -4
- machineconfig/jobs/python_custom_installers/dev/espanso.py +8 -8
- machineconfig/jobs/python_custom_installers/dev/goes.py +4 -4
- machineconfig/jobs/python_custom_installers/dev/lvim.py +4 -4
- machineconfig/jobs/python_custom_installers/dev/nerdfont.py +4 -4
- machineconfig/jobs/python_custom_installers/dev/redis.py +4 -4
- machineconfig/jobs/python_custom_installers/dev/warp-cli.py +4 -4
- machineconfig/jobs/python_custom_installers/dev/wezterm.py +4 -4
- machineconfig/jobs/python_custom_installers/gh.py +6 -6
- machineconfig/jobs/python_custom_installers/hx.py +28 -58
- machineconfig/jobs/python_custom_installers/scripts/linux/brave.sh +4 -8
- machineconfig/jobs/python_custom_installers/scripts/linux/docker.sh +5 -10
- machineconfig/jobs/python_custom_installers/scripts/linux/docker_start.sh +3 -6
- machineconfig/jobs/python_custom_installers/scripts/linux/edge.sh +3 -6
- machineconfig/jobs/python_custom_installers/scripts/linux/nerdfont.sh +5 -10
- machineconfig/jobs/python_custom_installers/scripts/linux/pgsql.sh +4 -8
- machineconfig/jobs/python_custom_installers/scripts/linux/redis.sh +5 -10
- machineconfig/jobs/python_custom_installers/scripts/linux/timescaledb.sh +6 -12
- machineconfig/jobs/python_custom_installers/scripts/linux/vscode.sh +9 -8
- machineconfig/jobs/python_custom_installers/scripts/linux/warp-cli.sh +5 -10
- machineconfig/jobs/python_custom_installers/scripts/linux/wezterm.sh +3 -6
- machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/profile/shell.py +26 -47
- machineconfig/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/cloud/init.sh +9 -18
- machineconfig/scripts/linux/fire +5 -24
- machineconfig/scripts/linux/share_cloud.sh +6 -12
- machineconfig/scripts/python/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_copy.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_mount.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_repo_sync.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_sync.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/croshell.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_jobs.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/get_zellij_cmd.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/repos.cpython-311.pyc +0 -0
- machineconfig/scripts/python/archive/im2text.py +30 -30
- machineconfig/scripts/python/archive/tmate_conn.py +10 -13
- machineconfig/scripts/python/archive/tmate_start.py +12 -16
- machineconfig/scripts/python/choose_wezterm_theme.py +9 -18
- machineconfig/scripts/python/cloud_copy.py +38 -93
- machineconfig/scripts/python/cloud_manager.py +61 -53
- machineconfig/scripts/python/cloud_mount.py +23 -34
- machineconfig/scripts/python/cloud_repo_sync.py +20 -69
- machineconfig/scripts/python/cloud_sync.py +35 -45
- machineconfig/scripts/python/croshell.py +48 -73
- machineconfig/scripts/python/devops.py +50 -104
- machineconfig/scripts/python/devops_add_identity.py +41 -101
- machineconfig/scripts/python/devops_add_ssh_key.py +33 -140
- machineconfig/scripts/python/devops_backup_retrieve.py +23 -112
- machineconfig/scripts/python/devops_devapps_install.py +0 -4
- machineconfig/scripts/python/devops_update_repos.py +1 -1
- machineconfig/scripts/python/fire_jobs.py +73 -25
- machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/cloud_helpers.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers2.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/repo_sync_helpers.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/cloud_helpers.py +37 -34
- machineconfig/scripts/python/helpers/helpers2.py +17 -31
- machineconfig/scripts/python/helpers/repo_sync_helpers.py +19 -54
- machineconfig/scripts/python/pomodoro.py +1 -1
- machineconfig/scripts/python/repos.py +49 -34
- machineconfig/scripts/python/wifi_conn.py +5 -3
- machineconfig/scripts/windows/fire.ps1 +27 -15
- machineconfig/settings/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/settings/shells/ipy/profiles/default/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/settings/shells/ipy/profiles/default/startup/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/settings/shells/ipy/profiles/default/startup/__pycache__/playext.cpython-311.pyc +0 -0
- machineconfig/setup_linux/nix/cli_installation.sh +9 -18
- machineconfig/setup_linux/others/openssh-server_add_pub_key.sh +3 -6
- machineconfig/setup_linux/web_shortcuts/all.sh +5 -10
- machineconfig/setup_linux/web_shortcuts/ascii_art.sh +7 -14
- machineconfig/setup_linux/web_shortcuts/croshell.sh +6 -12
- machineconfig/setup_linux/web_shortcuts/interactive.sh +34 -68
- machineconfig/setup_linux/web_shortcuts/ssh.sh +8 -16
- machineconfig/setup_linux/web_shortcuts/update_system.sh +7 -14
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +16 -12
- machineconfig/utils/ai/browser_user_wrapper.py +60 -45
- machineconfig/utils/ai/generate_file_checklist.py +4 -7
- machineconfig/utils/ai/url2md.py +13 -5
- machineconfig/utils/{utils_code.py → code.py} +4 -10
- machineconfig/utils/installer.py +4 -10
- machineconfig/utils/{utils_links.py → links.py} +9 -20
- machineconfig/utils/{utils_options.py → options.py} +10 -20
- machineconfig/utils/{utils_path.py → path.py} +28 -80
- machineconfig/utils/procs.py +26 -30
- machineconfig/utils/scheduling.py +11 -11
- machineconfig/utils/utils.py +12 -19
- machineconfig/utils/ve.py +5 -21
- machineconfig/utils/ve_utils/ve2.py +15 -2
- {machineconfig-1.94.dist-info → machineconfig-1.95.dist-info}/METADATA +4 -2
- {machineconfig-1.94.dist-info → machineconfig-1.95.dist-info}/RECORD +120 -118
- {machineconfig-1.94.dist-info → machineconfig-1.95.dist-info}/WHEEL +1 -1
- {machineconfig-1.94.dist-info → machineconfig-1.95.dist-info}/top_level.txt +0 -0
|
@@ -1,51 +1,66 @@
|
|
|
1
|
-
"""
|
|
2
|
-
playwright install
|
|
3
|
-
sudo nala install libavif13
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import os
|
|
7
|
-
os.environ["ANONYMIZED_TELEMETRY"] = "false"
|
|
8
|
-
|
|
9
|
-
from langchain_ollama import ChatOllama
|
|
10
|
-
from browser_use import Agent
|
|
11
|
-
import asyncio
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
""")
|
|
21
|
-
|
|
22
|
-
print("🔄 Initializing LLM model (llama3.1:8b)...")
|
|
23
|
-
llm = ChatOllama(model="llama3.1:8b")
|
|
24
|
-
print("✅ LLM model initialized")
|
|
1
|
+
# """
|
|
2
|
+
# playwright install
|
|
3
|
+
# sudo nala install libavif13
|
|
4
|
+
# """
|
|
5
|
+
|
|
6
|
+
# import os
|
|
7
|
+
# os.environ["ANONYMIZED_TELEMETRY"] = "false"
|
|
8
|
+
|
|
9
|
+
# from langchain_ollama import ChatOllama
|
|
10
|
+
# from browser_use import Agent
|
|
11
|
+
# import asyncio
|
|
12
|
+
# from rich.panel import Panel
|
|
13
|
+
# from rich import print as rprint
|
|
14
|
+
|
|
15
|
+
# BOX_WIDTH = 150 # width for box drawing
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# def _get_padding(text: str, padding_before: int = 2, padding_after: int = 1) -> str:
|
|
19
|
+
# """Calculate the padding needed to align the box correctly.
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
╰{'─' * 70}╯
|
|
31
|
-
""")
|
|
21
|
+
# Args:
|
|
22
|
+
# text: The text to pad
|
|
23
|
+
# padding_before: The space taken before the text (usually "║ ")
|
|
24
|
+
# padding_after: The space needed after the text (usually " ║")
|
|
32
25
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
26
|
+
# Returns:
|
|
27
|
+
# A string of spaces for padding
|
|
28
|
+
# """
|
|
29
|
+
# # Count visible characters (might not be perfect for all Unicode characters)
|
|
30
|
+
# text_length = len(text)
|
|
31
|
+
# padding_length = BOX_WIDTH - padding_before - text_length - padding_after
|
|
32
|
+
# return ' ' * max(0, padding_length)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# # Create agent with the model
|
|
36
|
+
# async def main():
|
|
37
|
+
# # header for browser automation agent
|
|
38
|
+
# title = "🌐 Browser Automation Agent"
|
|
39
|
+
# rprint(Panel(title, title="Status", width=BOX_WIDTH))
|
|
40
|
+
|
|
41
|
+
# rprint("🔄 Initializing LLM model (llama3.1:8b)...")
|
|
42
|
+
# llm = ChatOllama(model="llama3.1:8b")
|
|
43
|
+
# rprint("✅ LLM model initialized")
|
|
44
|
+
|
|
45
|
+
# task_line1 = "🤖 Task: Open https://chat.openai.com/ and ask how many r's in"
|
|
46
|
+
# task_line2 = "rrraaararewey, use Thinking Button and type the answer"
|
|
47
|
+
# task_content = f"{task_line1}\n{task_line2}"
|
|
48
|
+
# rprint(Panel(task_content, title="Task", width=BOX_WIDTH))
|
|
49
|
+
|
|
50
|
+
# rprint("🚀 Creating and launching browser agent...")
|
|
51
|
+
# agent = Agent(
|
|
52
|
+
# task="open https://chat.openai.com/ and ask how many r's in rrraaararewey, use Thinking Button and type the answer",
|
|
53
|
+
# llm=llm
|
|
54
|
+
# )
|
|
55
|
+
|
|
56
|
+
# rprint("🏃♂️ Running agent task...")
|
|
57
|
+
# await agent.run()
|
|
41
58
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
╚{'═' * 70}╝
|
|
46
|
-
""")
|
|
59
|
+
# # footer success box
|
|
60
|
+
# title = "✅ Browser automation task completed"
|
|
61
|
+
# rprint(Panel(title, title="Status", width=BOX_WIDTH))
|
|
47
62
|
|
|
48
63
|
|
|
49
|
-
if __name__ == "__main__":
|
|
50
|
-
|
|
64
|
+
# if __name__ == "__main__":
|
|
65
|
+
# asyncio.run(main())
|
|
51
66
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import List, Optional, Union
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.panel import Panel
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
def generate_file_checklist(repo_root: Union[str, Path], exclude_dirs: Optional[List[str]] = None) -> Path:
|
|
@@ -9,7 +11,6 @@ def generate_file_checklist(repo_root: Union[str, Path], exclude_dirs: Optional[
|
|
|
9
11
|
actual_exclude_dirs: List[str] = ['.venv', '.git', '__pycache__', 'build', 'dist', '*.egg-info']
|
|
10
12
|
if exclude_dirs is not None:
|
|
11
13
|
actual_exclude_dirs = exclude_dirs
|
|
12
|
-
|
|
13
14
|
repo_root = Path(repo_root).expanduser().absolute()
|
|
14
15
|
output_path: Path = repo_root / ".ai" / "repo_task" / "file_checklist.md"
|
|
15
16
|
py_files: List[Path] = []
|
|
@@ -62,12 +63,8 @@ def main() -> None:
|
|
|
62
63
|
return
|
|
63
64
|
|
|
64
65
|
output_path = generate_file_checklist(args.repo, exclude_dirs)
|
|
65
|
-
|
|
66
|
-
{
|
|
67
|
-
✅ SUCCESS | Markdown checklist generated successfully!
|
|
68
|
-
📄 File Location: {output_path}
|
|
69
|
-
{'=' * 60}
|
|
70
|
-
""")
|
|
66
|
+
console = Console()
|
|
67
|
+
console.print(Panel(f"✅ SUCCESS | Markdown checklist generated successfully!\n📄 File Location: {output_path}", border_style="bold blue", expand=False))
|
|
71
68
|
|
|
72
69
|
|
|
73
70
|
if __name__ == "__main__":
|
machineconfig/utils/ai/url2md.py
CHANGED
|
@@ -18,17 +18,25 @@ depth = input("🔍 Enter the crawl depth (default: 4): ") or "4"
|
|
|
18
18
|
|
|
19
19
|
website_name_as_valid_filename = url.split("//")[-1].split("/")[0].replace(".", "_").replace(":", "_")
|
|
20
20
|
domain = url.split("//")[-1].split("/")[0]
|
|
21
|
-
op_dir = cwd.joinpath(".website", website_name_as_valid_filename)
|
|
21
|
+
op_dir = cwd.joinpath(".ai/website", website_name_as_valid_filename)
|
|
22
22
|
op_dir.mkdir(exist_ok=True, parents=True)
|
|
23
23
|
urls_file = op_dir.joinpath("urls", "urls.txt")
|
|
24
24
|
urls_file.parent.mkdir(exist_ok=True, parents=True)
|
|
25
|
-
if urls_file.exists():
|
|
26
|
-
|
|
25
|
+
# if urls_file.exists():
|
|
26
|
+
# urls_file.unlink()
|
|
27
27
|
|
|
28
28
|
print("🌐 Crawling the website to extract URLs...")
|
|
29
29
|
command = f"""xcrawl3r --url {url} --domain {domain} --depth {depth} --concurrency 20 --parallelism 4 --output {urls_file} """
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
print(f"Running command: {command}")
|
|
33
|
+
subprocess.run(command, shell=True, check=True)
|
|
34
|
+
except KeyboardInterrupt:
|
|
35
|
+
if urls_file.exists():
|
|
36
|
+
print("\n❌ Process interrupted by user, proceeding with existing URLs...")
|
|
37
|
+
else:
|
|
38
|
+
print("\n❌ Process interrupted by user, no URLs found.")
|
|
39
|
+
exit(1)
|
|
32
40
|
|
|
33
41
|
all_urls = urls_file.read_text().splitlines()
|
|
34
42
|
relevant_urls = list(set(all_urls)) # remove duplicates
|
|
@@ -46,13 +46,7 @@ def write_shell_script_to_default_program_path(program: str, desc: str, preserve
|
|
|
46
46
|
program = "$orig_path = $pwd\n" + program + "\ncd $orig_path"
|
|
47
47
|
else:
|
|
48
48
|
program = 'orig_path=$(cd -- "." && pwd)\n' + program + '\ncd "$orig_path" || exit'
|
|
49
|
-
if display:
|
|
50
|
-
print(f"""
|
|
51
|
-
{'=' * 60}
|
|
52
|
-
⚙️ SHELL SCRIPT | Executing at {PROGRAM_PATH}
|
|
53
|
-
{'=' * 60}
|
|
54
|
-
""")
|
|
55
|
-
print_code(code=program, lexer="shell", desc=desc)
|
|
49
|
+
if display: print_code(code=program, lexer="shell", desc=desc, subtitle=str(PROGRAM_PATH))
|
|
56
50
|
PROGRAM_PATH.create(parents_only=True).write_text(program)
|
|
57
51
|
if execute:
|
|
58
52
|
Terminal().run(f". {PROGRAM_PATH}", shell="powershell").capture().print_if_unsuccessful(desc="🛠️ EXECUTION | Shell script running", strict_err=True, strict_returncode=True)
|
|
@@ -65,18 +59,18 @@ code = r'''{python_script}'''
|
|
|
65
59
|
try:
|
|
66
60
|
from machineconfig.utils.utils import print_code
|
|
67
61
|
print_code(code=code, lexer="python", desc="Python Script")
|
|
68
|
-
except ImportError: print(f"
|
|
62
|
+
except ImportError: console.print(Panel(f"📜 PYTHON SCRIPT:\n\n{python_script}", title="Python Script", expand=False))
|
|
69
63
|
""" + python_script
|
|
70
64
|
python_file = P.tmp().joinpath("tmp_scripts", "python", randstr() + ".py").create(parents_only=True).write_text(python_script)
|
|
71
65
|
shell_script = get_shell_script_executing_python_file(python_file=python_file.to_str(), ve_name=ve_name)
|
|
72
66
|
shell_file = write_shell_script_to_file(shell_script)
|
|
73
67
|
return shell_file
|
|
74
68
|
|
|
75
|
-
def print_code(code: str, lexer: str, desc: str):
|
|
69
|
+
def print_code(code: str, lexer: str, desc: str, subtitle: str=""):
|
|
76
70
|
if lexer == "shell":
|
|
77
71
|
if platform.system() == "Windows": lexer = "powershell"
|
|
78
72
|
elif platform.system() == "Linux": lexer = "sh"
|
|
79
73
|
else: raise NotImplementedError(f"Platform {platform.system()} not supported for lexer {lexer}")
|
|
80
74
|
console = Console()
|
|
81
|
-
console.print(Panel(Syntax(code=code, lexer=lexer), title=f"📄 {desc}"), style="bold red")
|
|
75
|
+
console.print(Panel(Syntax(code=code, lexer=lexer), title=f"📄 {desc}", subtitle=subtitle), style="bold red")
|
|
82
76
|
|
machineconfig/utils/installer.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from machineconfig.utils.installer_utils.installer_abc import LINUX_INSTALL_PATH, CATEGORY
|
|
4
4
|
from machineconfig.utils.installer_utils.installer_class import Installer
|
|
5
5
|
from rich.console import Console
|
|
6
|
+
from rich.panel import Panel # Added import
|
|
6
7
|
|
|
7
8
|
from crocodile.file_management import P, Read
|
|
8
9
|
from crocodile.core import List as L
|
|
@@ -15,11 +16,8 @@ import platform
|
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
def check_latest():
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
║ 🔍 CHECKING FOR LATEST VERSIONS ║
|
|
21
|
-
╚{'═'*78}╝
|
|
22
|
-
""")
|
|
19
|
+
console = Console() # Added console initialization
|
|
20
|
+
console.print(Panel("🔍 CHECKING FOR LATEST VERSIONS", title="Status", expand=False)) # Replaced print with Panel
|
|
23
21
|
installers = get_installers(system=platform.system(), dev=False)
|
|
24
22
|
# installers += get_installers(system=platform.system(), dev=True)
|
|
25
23
|
installers_gitshub = []
|
|
@@ -49,11 +47,7 @@ def check_latest():
|
|
|
49
47
|
|
|
50
48
|
from crocodile.core import Display
|
|
51
49
|
Display.set_pandas_display()
|
|
52
|
-
print(
|
|
53
|
-
╔{'═'*78}╗
|
|
54
|
-
║ 📊 INSTALLATION STATUS SUMMARY ║
|
|
55
|
-
╚{'═'*78}╝
|
|
56
|
-
""")
|
|
50
|
+
console.print(Panel("📊 INSTALLATION STATUS SUMMARY", title="Status", expand=False)) # Replaced print with Panel
|
|
57
51
|
print(res_df)
|
|
58
52
|
print(f"{'═'*80}")
|
|
59
53
|
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
from crocodile.file_management import P, PLike
|
|
2
2
|
from crocodile.core_modules.core_1 import randstr
|
|
3
|
+
from rich.console import Console
|
|
4
|
+
from rich.panel import Panel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
console = Console()
|
|
3
8
|
|
|
4
9
|
|
|
5
10
|
def build_links(target_paths: list[tuple[PLike, str]], repo_root: PLike):
|
|
@@ -46,18 +51,10 @@ def symlink_func(this: P, to_this: P, prioritize_to_this: bool=True):
|
|
|
46
51
|
else: # this doesn't exist.
|
|
47
52
|
if not to_this.exists(): to_this.touch() # we have to touch it (file) or create it (folder)
|
|
48
53
|
try:
|
|
49
|
-
print(f"""
|
|
50
|
-
{'=' * 60}
|
|
51
|
-
🔗 LINKING | Creating symlink from {this} ➡️ {to_this}
|
|
52
|
-
{'=' * 60}
|
|
53
|
-
""")
|
|
54
|
+
console.print(Panel(f"🔗 LINKING | Creating symlink from {this} ➡️ {to_this}", title="Linking", expand=False))
|
|
54
55
|
P(this).symlink_to(target=to_this, verbose=True, overwrite=True)
|
|
55
56
|
except Exception as ex:
|
|
56
|
-
print(f"""
|
|
57
|
-
❌ ERROR | Failed at linking {this} ➡️ {to_this}.
|
|
58
|
-
Reason: {ex}
|
|
59
|
-
{'=' * 60}
|
|
60
|
-
""")
|
|
57
|
+
console.print(Panel(f"❌ ERROR | Failed at linking {this} ➡️ {to_this}. Reason: {ex}", title="Error", expand=False))
|
|
61
58
|
|
|
62
59
|
def symlink_copy(this: P, to_this: P, prioritize_to_this: bool=True):
|
|
63
60
|
this = P(this).expanduser().absolute()
|
|
@@ -74,15 +71,7 @@ def symlink_copy(this: P, to_this: P, prioritize_to_this: bool=True):
|
|
|
74
71
|
else: # this doesn't exist.
|
|
75
72
|
if not to_this.exists(): to_this.touch() # we have to touch it (file) or create it (folder)
|
|
76
73
|
try:
|
|
77
|
-
print(f"""
|
|
78
|
-
{'=' * 60}
|
|
79
|
-
📋 COPYING | Copying {to_this} to {this}
|
|
80
|
-
{'=' * 60}
|
|
81
|
-
""")
|
|
74
|
+
console.print(Panel(f"📋 COPYING | Copying {to_this} to {this}", title="Copying", expand=False))
|
|
82
75
|
to_this.copy(path=this, overwrite=True, verbose=True)
|
|
83
76
|
except Exception as ex:
|
|
84
|
-
print(f"""
|
|
85
|
-
❌ ERROR | Failed at copying {to_this} to {this}.
|
|
86
|
-
Reason: {ex}
|
|
87
|
-
{'=' * 60}
|
|
88
|
-
""")
|
|
77
|
+
console.print(Panel(f"❌ ERROR | Failed at copying {to_this} to {this}. Reason: {ex}", title="Error", expand=False))
|
|
@@ -15,7 +15,6 @@ T = TypeVar("T")
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def check_tool_exists(tool_name: str, install_script: Optional[str] = None) -> bool:
|
|
18
|
-
"""This is the CLI equivalent of `install_n_import` function of crocodile. """
|
|
19
18
|
if platform.system() == "Windows":
|
|
20
19
|
tool_name = tool_name.replace(".exe", "") + ".exe"
|
|
21
20
|
|
|
@@ -29,11 +28,8 @@ def check_tool_exists(tool_name: str, install_script: Optional[str] = None) -> b
|
|
|
29
28
|
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
30
29
|
res = False
|
|
31
30
|
if res is False and install_script is not None:
|
|
32
|
-
|
|
33
|
-
{
|
|
34
|
-
📥 INSTALLING TOOL | Installing {tool_name}...
|
|
35
|
-
{'=' * 60}
|
|
36
|
-
""")
|
|
31
|
+
console = Console()
|
|
32
|
+
console.print(Panel(f"📥 INSTALLING TOOL | Installing {tool_name}...", border_style="bold blue", expand=False))
|
|
37
33
|
Terminal().run(install_script, shell="powershell").print()
|
|
38
34
|
return check_tool_exists(tool_name=tool_name, install_script=None)
|
|
39
35
|
return res
|
|
@@ -63,6 +59,7 @@ def display_options(msg: str, options: Iterable[T], header: str="", tail: str=""
|
|
|
63
59
|
tool_name = "fzf"
|
|
64
60
|
options_strings: list[str] = [str(x) for x in options]
|
|
65
61
|
default_string = str(default) if default is not None else None
|
|
62
|
+
console = Console()
|
|
66
63
|
if fzf and check_tool_exists(tool_name):
|
|
67
64
|
from pyfzf.pyfzf import FzfPrompt
|
|
68
65
|
fzf_prompt = FzfPrompt()
|
|
@@ -81,7 +78,6 @@ def display_options(msg: str, options: Iterable[T], header: str="", tail: str=""
|
|
|
81
78
|
choice_idx_s = [options_strings.index(x) for x in choice_string_multi]
|
|
82
79
|
return [list(options)[x] for x in choice_idx_s]
|
|
83
80
|
else:
|
|
84
|
-
console = Console()
|
|
85
81
|
if default is not None:
|
|
86
82
|
assert default in options, f"Default `{default}` option not in options `{list(options)}`"
|
|
87
83
|
default_msg = Text(" <<<<-------- DEFAULT", style="bold red")
|
|
@@ -99,7 +95,7 @@ def display_options(msg: str, options: Iterable[T], header: str="", tail: str=""
|
|
|
99
95
|
|
|
100
96
|
if choice_string == "":
|
|
101
97
|
if default_string is None:
|
|
102
|
-
print("🧨 Default option not available!")
|
|
98
|
+
console.print(Panel("🧨 Default option not available!", title="Error", expand=False))
|
|
103
99
|
return display_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default, fzf=fzf, multi=multi, custom_input=custom_input)
|
|
104
100
|
choice_idx = options_strings.index(default_string)
|
|
105
101
|
assert default is not None, "🧨 Default option not available!"
|
|
@@ -116,7 +112,7 @@ def display_options(msg: str, options: Iterable[T], header: str="", tail: str=""
|
|
|
116
112
|
else:
|
|
117
113
|
_ = ie
|
|
118
114
|
# raise ValueError(f"Unknown choice. {choice_string}") from ie
|
|
119
|
-
print(f"❓ Unknown choice: '{choice_string}'")
|
|
115
|
+
console.print(Panel(f"❓ Unknown choice: '{choice_string}'", title="Error", expand=False))
|
|
120
116
|
return display_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default, fzf=fzf, multi=multi, custom_input=custom_input)
|
|
121
117
|
except TypeError as te: # int(choice_string) failed due to # either the number is invalid, or the input is custom.
|
|
122
118
|
if choice_string in options_strings: # string input
|
|
@@ -127,19 +123,16 @@ def display_options(msg: str, options: Iterable[T], header: str="", tail: str=""
|
|
|
127
123
|
else:
|
|
128
124
|
_ = te
|
|
129
125
|
# raise ValueError(f"Unknown choice. {choice_string}") from te
|
|
130
|
-
print(f"❓ Unknown choice: '{choice_string}'")
|
|
126
|
+
console.print(Panel(f"❓ Unknown choice: '{choice_string}'", title="Error", expand=False))
|
|
131
127
|
return display_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default, fzf=fzf, multi=multi, custom_input=custom_input)
|
|
132
|
-
print(f"✅ Selected option {choice_idx}: {choice_one}")
|
|
128
|
+
console.print(Panel(f"✅ Selected option {choice_idx}: {choice_one}", title="Selected", expand=False))
|
|
133
129
|
if multi: return [choice_one]
|
|
134
130
|
return choice_one
|
|
135
131
|
|
|
136
132
|
|
|
137
133
|
def choose_cloud_interactively() -> str:
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
🔍 LISTING CLOUD REMOTES | Fetching available cloud remotes...
|
|
141
|
-
{'=' * 60}
|
|
142
|
-
""")
|
|
134
|
+
console = Console()
|
|
135
|
+
console.print(Panel("🔍 LISTING CLOUD REMOTES | Fetching available cloud remotes...", border_style="bold blue", expand=False))
|
|
143
136
|
tmp = Terminal().run("rclone listremotes").op_if_successfull_or_default(strict_returcode=False)
|
|
144
137
|
# consider this: remotes = Read.ini(P.home().joinpath(".config/rclone/rclone.conf")).sections()
|
|
145
138
|
if isinstance(tmp, str):
|
|
@@ -149,10 +142,7 @@ def choose_cloud_interactively() -> str:
|
|
|
149
142
|
if len(remotes) == 0:
|
|
150
143
|
raise RuntimeError("You don't have remotes. Configure your rclone first to get cloud services access.")
|
|
151
144
|
cloud: str = choose_one_option(msg="WHICH CLOUD?", options=list(remotes), default=remotes[0], fzf=True)
|
|
152
|
-
print(f"""
|
|
153
|
-
✅ SELECTED CLOUD | {cloud}
|
|
154
|
-
{'=' * 60}
|
|
155
|
-
""")
|
|
145
|
+
console.print(Panel(f"✅ SELECTED CLOUD | {cloud}", border_style="bold blue", expand=False))
|
|
156
146
|
return cloud
|
|
157
147
|
|
|
158
148
|
def get_ssh_hosts() -> list[str]:
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
from crocodile.core import List as L
|
|
2
2
|
from crocodile.file_management import P
|
|
3
|
+
from machineconfig.utils.options import check_tool_exists, choose_one_option
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
from rich.panel import Panel
|
|
3
6
|
import platform
|
|
4
7
|
import subprocess
|
|
5
8
|
from typing import Optional, TypeVar
|
|
6
|
-
from machineconfig.utils.utils_options import check_tool_exists, choose_one_option
|
|
7
9
|
|
|
8
10
|
T = TypeVar("T")
|
|
11
|
+
console = Console()
|
|
9
12
|
|
|
10
13
|
def sanitize_path(a_path: P) -> P:
|
|
11
14
|
path = P(a_path)
|
|
@@ -13,71 +16,48 @@ def sanitize_path(a_path: P) -> P:
|
|
|
13
16
|
if platform.system() == "Windows": # path copied from Linux to Windows
|
|
14
17
|
path = P.home().joinpath(*path.parts[3:]) # exclude /home/username
|
|
15
18
|
assert path.exists(), f"File not found: {path}"
|
|
16
|
-
print(f"""
|
|
17
|
-
{'=' * 60}
|
|
18
|
-
🔗 PATH MAPPING | Linux → Windows: `{a_path}` ➡️ `{path}`
|
|
19
|
-
{'=' * 60}
|
|
20
|
-
""")
|
|
19
|
+
console.print(Panel(f"🔗 PATH MAPPING | Linux → Windows: `{a_path}` ➡️ `{path}`", title="Path Mapping", expand=False))
|
|
21
20
|
elif platform.system() == "Linux" and P.home().as_posix() not in path.as_posix(): # copied from Linux to Linux with different username
|
|
22
21
|
path = P.home().joinpath(*path.parts[3:]) # exclude /home/username (three parts: /, home, username)
|
|
23
22
|
assert path.exists(), f"File not found: {path}"
|
|
24
|
-
print(f"""
|
|
25
|
-
{'=' * 60}
|
|
26
|
-
🔗 PATH MAPPING | Linux → Linux: `{a_path}` ➡️ `{path}`
|
|
27
|
-
{'=' * 60}
|
|
28
|
-
""")
|
|
23
|
+
console.print(Panel(f"🔗 PATH MAPPING | Linux → Linux: `{a_path}` ➡️ `{path}`", title="Path Mapping", expand=False))
|
|
29
24
|
elif path.as_posix().startswith("C:"):
|
|
30
25
|
if platform.system() == "Linux": # path copied from Windows to Linux
|
|
31
|
-
xx = str(a_path).replace("
|
|
32
|
-
path = P.home().joinpath(*P(xx).parts[3:]) # exclude C
|
|
26
|
+
xx = str(a_path).replace("\\\\", "/")
|
|
27
|
+
path = P.home().joinpath(*P(xx).parts[3:]) # exclude C:\\Users\\username
|
|
33
28
|
assert path.exists(), f"File not found: {path}"
|
|
34
|
-
print(f"""
|
|
35
|
-
{'=' * 60}
|
|
36
|
-
🔗 PATH MAPPING | Windows → Linux: `{a_path}` ➡️ `{path}`
|
|
37
|
-
{'=' * 60}
|
|
38
|
-
""")
|
|
29
|
+
console.print(Panel(f"🔗 PATH MAPPING | Windows → Linux: `{a_path}` ➡️ `{path}`", title="Path Mapping", expand=False))
|
|
39
30
|
elif platform.system() == "Windows" and P.home().as_posix() not in path.as_posix(): # copied from Windows to Windows with different username
|
|
40
31
|
path = P.home().joinpath(*path.parts[2:])
|
|
41
32
|
assert path.exists(), f"File not found: {path}"
|
|
42
|
-
print(f"""
|
|
43
|
-
{'=' * 60}
|
|
44
|
-
🔗 PATH MAPPING | Windows → Windows: `{a_path}` ➡️ `{path}`
|
|
45
|
-
{'=' * 60}
|
|
46
|
-
""")
|
|
33
|
+
console.print(Panel(f"🔗 PATH MAPPING | Windows → Windows: `{a_path}` ➡️ `{path}`", title="Path Mapping", expand=False))
|
|
47
34
|
return path.expanduser().absolute()
|
|
48
35
|
|
|
49
36
|
def match_file_name(sub_string: str, search_root: Optional[P] = None) -> P:
|
|
50
37
|
"""Look up current directory for file name that matches the passed substring."""
|
|
51
38
|
search_root_obj = search_root if search_root is not None else P.cwd()
|
|
52
39
|
search_root_obj = search_root_obj.absolute()
|
|
53
|
-
print(f"""
|
|
54
|
-
{'=' * 60}
|
|
55
|
-
🔍 SEARCH | Looking for '{sub_string}' in {search_root_obj}
|
|
56
|
-
{'=' * 60}
|
|
57
|
-
""")
|
|
40
|
+
console.print(Panel(f"🔍 SEARCH | Looking for '{sub_string}' in {search_root_obj}", title="Search", expand=False))
|
|
58
41
|
|
|
59
42
|
search_root_objects = search_root_obj.search("*", not_in=["links", ".venv", ".git", ".idea", ".vscode", "node_modules", "__pycache__"])
|
|
60
|
-
search_results: L[P] = L([a_search_root_obj.search(f"*{sub_string}*", r=True) for a_search_root_obj in search_root_objects])
|
|
43
|
+
search_results: L[P] = L([a_search_root_obj.search(f"*{sub_string}*", r=True) for a_search_root_obj in search_root_objects])
|
|
44
|
+
if len(search_results) > 0:
|
|
45
|
+
search_results = search_results.reduce(lambda x, y: x + y) # type: ignore
|
|
46
|
+
else:
|
|
47
|
+
pass
|
|
61
48
|
search_results = search_results.filter(lambda x: x.suffix in (".py", ".sh", ".ps1"))
|
|
62
|
-
|
|
63
49
|
if len(search_results) == 1:
|
|
64
50
|
path_obj = search_results.list[0]
|
|
65
51
|
elif len(search_results) > 1:
|
|
66
52
|
msg = "Search results are ambiguous or non-existent, choose manually:"
|
|
67
|
-
print(f"""
|
|
68
|
-
⚠️ WARNING | {msg}
|
|
69
|
-
{'=' * 60}
|
|
70
|
-
""")
|
|
53
|
+
console.print(Panel(f"⚠️ WARNING | {msg}", title="Warning", expand=False))
|
|
71
54
|
choice = choose_one_option(msg=msg, options=search_results.list, fzf=True)
|
|
72
55
|
path_obj = P(choice)
|
|
73
56
|
else:
|
|
74
57
|
# let's do a final retry with sub_string.small()
|
|
75
58
|
sub_string_small = sub_string.lower()
|
|
76
59
|
if sub_string_small != sub_string:
|
|
77
|
-
print(
|
|
78
|
-
🔄 RETRY | Searching with lowercase letters
|
|
79
|
-
{'=' * 60}
|
|
80
|
-
""")
|
|
60
|
+
console.print(Panel("🔄 RETRY | Searching with lowercase letters", title="Retry", expand=False))
|
|
81
61
|
return match_file_name(sub_string=sub_string_small)
|
|
82
62
|
from git.repo import Repo
|
|
83
63
|
from git.exc import InvalidGitRepositoryError
|
|
@@ -85,10 +65,7 @@ def match_file_name(sub_string: str, search_root: Optional[P] = None) -> P:
|
|
|
85
65
|
repo = Repo(search_root_obj, search_parent_directories=True)
|
|
86
66
|
repo_root_dir = P(repo.working_dir)
|
|
87
67
|
if repo_root_dir != search_root_obj: # may be user is in a subdirectory of the repo root, try with root dir.
|
|
88
|
-
print(
|
|
89
|
-
🔄 RETRY | Searching from repository root instead of current directory
|
|
90
|
-
{'=' * 60}
|
|
91
|
-
""")
|
|
68
|
+
console.print(Panel("🔄 RETRY | Searching from repository root instead of current directory", title="Retry", expand=False))
|
|
92
69
|
return match_file_name(sub_string=sub_string, search_root=repo_root_dir)
|
|
93
70
|
else:
|
|
94
71
|
search_root_obj = repo_root_dir
|
|
@@ -97,55 +74,26 @@ def match_file_name(sub_string: str, search_root: Optional[P] = None) -> P:
|
|
|
97
74
|
|
|
98
75
|
if check_tool_exists(tool_name="fzf"):
|
|
99
76
|
try:
|
|
100
|
-
print(f"""
|
|
101
|
-
🔍 SEARCH STRATEGY | Using fd to search for '{sub_string}' in '{search_root_obj}' ...
|
|
102
|
-
{'=' * 60}
|
|
103
|
-
""")
|
|
77
|
+
console.print(Panel(f"🔍 SEARCH STRATEGY | Using fd to search for '{sub_string}' in '{search_root_obj}' ...", title="Search Strategy", expand=False))
|
|
104
78
|
fzf_cmd = f"cd '{search_root_obj}'; fd --type f --strip-cwd-prefix | fzf --filter={sub_string}"
|
|
105
|
-
search_res = subprocess.run(fzf_cmd, stdout=subprocess.PIPE, text=True, check=True, shell=True).stdout.split("
|
|
79
|
+
search_res = subprocess.run(fzf_cmd, stdout=subprocess.PIPE, text=True, check=True, shell=True).stdout.split("\\n")[:-1]
|
|
106
80
|
except subprocess.CalledProcessError as cpe:
|
|
107
|
-
print(f"""
|
|
108
|
-
|
|
109
|
-
{cpe}
|
|
110
|
-
{'=' * 60}
|
|
111
|
-
""")
|
|
112
|
-
msg = f"""
|
|
113
|
-
{'=' * 60}
|
|
114
|
-
💥 FILE NOT FOUND | Path {sub_string} does not exist. No search results
|
|
115
|
-
{'=' * 60}
|
|
116
|
-
"""
|
|
81
|
+
console.print(Panel(f"❌ ERROR | FZF search failed with '{sub_string}' in '{search_root_obj}'.\\n{cpe}", title="Error", expand=False))
|
|
82
|
+
msg = Panel(f"💥 FILE NOT FOUND | Path {sub_string} does not exist. No search results", title="File Not Found", expand=False)
|
|
117
83
|
raise FileNotFoundError(msg) from cpe
|
|
118
84
|
|
|
119
85
|
if len(search_res) == 1: return search_root_obj.joinpath(search_res[0])
|
|
120
86
|
else:
|
|
121
|
-
print(
|
|
122
|
-
🔍 SEARCH STRATEGY | Trying with raw fzf search ...
|
|
123
|
-
{'=' * 60}
|
|
124
|
-
""")
|
|
87
|
+
console.print(Panel("🔍 SEARCH STRATEGY | Trying with raw fzf search ...", title="Search Strategy", expand=False))
|
|
125
88
|
try:
|
|
126
89
|
res = subprocess.run(f"cd '{search_root_obj}'; fd | fzf --query={sub_string}", check=True, stdout=subprocess.PIPE, text=True, shell=True).stdout.strip()
|
|
127
90
|
except subprocess.CalledProcessError as cpe:
|
|
128
|
-
print(f"""
|
|
129
|
-
|
|
130
|
-
{'=' * 60}
|
|
131
|
-
""")
|
|
132
|
-
msg = f"""
|
|
133
|
-
{'=' * 60}
|
|
134
|
-
💥 FILE NOT FOUND | Path {sub_string} does not exist. No search results
|
|
135
|
-
{'=' * 60}
|
|
136
|
-
"""
|
|
91
|
+
console.print(Panel(f"❌ ERROR | FZF search failed with '{sub_string}' in '{search_root_obj}'. {cpe}", title="Error", expand=False))
|
|
92
|
+
msg = Panel(f"💥 FILE NOT FOUND | Path {sub_string} does not exist. No search results", title="File Not Found", expand=False)
|
|
137
93
|
raise FileNotFoundError(msg) from cpe
|
|
138
94
|
return search_root_obj.joinpath(res)
|
|
139
95
|
|
|
140
|
-
msg = f"""
|
|
141
|
-
{'=' * 60}
|
|
142
|
-
💥 FILE NOT FOUND | Path {sub_string} does not exist. No search results
|
|
143
|
-
{'=' * 60}
|
|
144
|
-
"""
|
|
96
|
+
msg = Panel(f"💥 FILE NOT FOUND | Path {sub_string} does not exist. No search results", title="File Not Found", expand=False)
|
|
145
97
|
raise FileNotFoundError(msg)
|
|
146
|
-
print(f"""
|
|
147
|
-
{'=' * 60}
|
|
148
|
-
✅ MATCH FOUND | `{sub_string}` ➡️ `{path_obj}`
|
|
149
|
-
{'=' * 60}
|
|
150
|
-
""")
|
|
98
|
+
console.print(Panel(f"✅ MATCH FOUND | `{sub_string}` ➡️ `{path_obj}`", title="Match Found", expand=False))
|
|
151
99
|
return path_obj
|