machineconfig 5.13__py3-none-any.whl → 5.15__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.

@@ -5,11 +5,11 @@ import typer
5
5
  def analyze_repo_development(repo_path: str = typer.Argument(..., help="Path to the git repository")):
6
6
  from machineconfig.scripts.python import count_lines
7
7
  from pathlib import Path
8
- count_lines_path = Path(count_lines.__file__).resolve().parent.joinpath("count_lines.py")
8
+ count_lines_path = Path(count_lines.__file__)
9
9
  # --project $HOME/code/machineconfig
10
- cmd = f"""uv run --python 3.13 --with machineconfig --group plot {count_lines_path} analyze-over-time {repo_path}"""
11
- from machineconfig.utils.code import run_script
12
- run_script(cmd)
10
+ cmd = f"""uv run --python 3.13 --with machineconfig[plot] {count_lines_path} analyze-over-time {repo_path}"""
11
+ from machineconfig.utils.code import run_shell_script
12
+ run_shell_script(cmd)
13
13
 
14
14
 
15
15
  if __name__ == "__main__":
@@ -40,8 +40,6 @@ except Exception: print(pycode)
40
40
 
41
41
 
42
42
  def get_read_data_pycode(path: str):
43
- # We need to be careful here since we're generating Python code as a string
44
- # that will use f-strings itself
45
43
  return f"""
46
44
  from rich.panel import Panel
47
45
  from rich.text import Text
@@ -49,7 +47,8 @@ from rich.console import Console
49
47
  console = Console()
50
48
  p = PathExtended(r'{path}').absolute()
51
49
  try:
52
- dat = p.readit()
50
+ from machineconfig.utils.files.read import Read
51
+ dat = Read.read(p)
53
52
  if isinstance(dat, dict):
54
53
  panel_title = f"📄 File Data: {{p.name}}"
55
54
  console.print(Panel(Text(str(dat), justify="left"), title=panel_title, expand=False))
@@ -63,53 +62,25 @@ except Exception as e:
63
62
  """
64
63
 
65
64
 
66
- def get_read_pyfile_pycode(path: PathExtended, as_module: bool, cmd: str = ""):
67
- if as_module:
68
- pycode = rf"""
69
- import sys
70
- sys.path.append(r'{path.parent}')
71
- from {path.stem} import *
72
- {cmd}
73
- """
74
- else:
75
- pycode = f"""
76
- __file__ = PathExtended(r'{path}')
77
- {path.read_text(encoding="utf-8")}
78
- """
79
- return pycode
80
-
81
65
 
82
66
  def main(
83
- module: Annotated[bool, typer.Option("--module", "-m", help="flag to run the file as a module as opposed to main.")] = False,
84
- newWindow: Annotated[bool, typer.Option("--newWindow", "-w", help="flag for running in new window.")] = False,
85
- nonInteratctive: Annotated[bool, typer.Option("--nonInteratctive", "-N", help="flag for a non-interactive session.")] = False,
86
67
  python: Annotated[bool, typer.Option("--python", "-p", help="flag to use python over IPython.")] = False,
87
68
  fzf: Annotated[bool, typer.Option("--fzf", "-F", help="search with fuzzy finder for python scripts and run them")] = False,
88
69
  ve: Annotated[Optional[str], typer.Option("--ve", "-v", help="virtual enviroment to use, defaults to activated ve, if existed, else ve.")] = None,
89
70
  profile: Annotated[Optional[str], typer.Option("--profile", "-P", help="ipython profile to use, defaults to default profile.")] = None,
90
71
  read: Annotated[str, typer.Option("--read", "-r", help="read a binary file.")] = "",
91
- file: Annotated[str, typer.Option("--file", "-f", help="python file path to interpret")] = "",
92
- cmd: Annotated[str, typer.Option("--cmd", "-c", help="python command to interpret")] = "",
93
- terminal: Annotated[str, typer.Option("--terminal", "-t", help="specify which terminal to be used. Default console host.")] = "",
94
- shell: Annotated[str, typer.Option("--shell", "-S", help="specify which shell to be used. Defaults to CMD.")] = "",
95
72
  jupyter: Annotated[bool, typer.Option("--jupyter", "-j", help="run in jupyter interactive console")] = False,
96
73
  streamlit_viewer: Annotated[bool, typer.Option("--stViewer", "-s", help="view in streamlit app")] = False,
74
+ visidata: Annotated[bool, typer.Option("--visidata", "-V", help="open data file in visidata")] = False,
97
75
  ) -> None:
98
76
  # ==================================================================================
99
77
  # flags processing
100
- interactivity = "" if nonInteratctive else "-i"
78
+ interactivity = "-i"
101
79
  interpreter = "python" if python else "ipython"
102
80
  ipython_profile: Optional[str] = profile
103
81
  file_obj = PathExtended.cwd() # initialization value, could be modified according to args.
104
82
 
105
- if cmd != "":
106
- text = "🖥️ Executing command from CLI argument"
107
- console.print(Panel(text, title="[bold blue]Info[/bold blue]"))
108
- import textwrap
109
-
110
- program = textwrap.dedent(cmd)
111
-
112
- elif fzf:
83
+ if fzf:
113
84
  text = "🔍 Searching for Python files..."
114
85
  console.print(Panel(text, title="[bold blue]Info[/bold blue]"))
115
86
  options = [str(item) for item in PathExtended.cwd().search("*.py", r=True)]
@@ -119,13 +90,6 @@ def main(
119
90
  text = f"📄 Selected file: {PathExtended(file_selected).name}"
120
91
  console.print(Panel(text, title="[bold blue]Info[/bold blue]"))
121
92
 
122
- elif file != "":
123
- file_obj = PathExtended(file.lstrip()).expanduser().absolute()
124
- program = get_read_pyfile_pycode(file_obj, as_module=module, cmd=cmd)
125
- text1 = f"📄 Loading file: {file_obj.name}"
126
- text2 = f"🔄 Mode: {'Module' if module else 'Script'}"
127
- console.print(Panel(f"{text1}\n{text2}", title="[bold blue]Info[/bold blue]"))
128
-
129
93
  elif read != "":
130
94
  if streamlit_viewer:
131
95
  # text = "📊 STARTING STREAMLIT VIEWER"
@@ -154,46 +118,35 @@ def main(
154
118
  preprogram = """
155
119
 
156
120
  #%%
157
- try:
158
- from crocodile.croshell import *
159
- print_header()
160
- print_logo(logo="crocodile")
161
- except ImportError:
162
- print("Crocodile not found, skipping import.")
121
+
122
+ from machineconfig.utils.files.headers import print_header, print_logo
123
+ print_header()
124
+ print_logo("CROCODILE")
163
125
  from pathlib import Path
164
- print(f"🐊 Crocodile Shell | Running @ {Path.cwd()}")
126
+
165
127
  """
166
128
 
167
129
  pyfile = PathExtended.tmp().joinpath(f"tmp_scripts/python/croshell/{randstr()}.py")
168
130
  pyfile.parent.mkdir(parents=True, exist_ok=True)
169
131
 
170
- if read != "":
171
- title = "Reading Data"
172
- elif file != "":
173
- title = "Running Python File"
174
- else:
175
- title = "Executed code"
132
+ title = "Reading Data"
176
133
  python_program = preprogram + add_print_header_pycode(str(pyfile), title=title) + program
177
134
  pyfile.write_text(python_program, encoding="utf-8")
178
135
  # ve_root_from_file, ipython_profile = get_ve_path_and_ipython_profile(PathExtended(file))
179
136
  ipython_profile = ipython_profile if ipython_profile is not None else "default"
180
137
  # ve_activateion_line = get_ve_activate_line(ve_name=args.ve or ve_profile_suggested, a_path=str(PathExtended.cwd()))
181
- shell_program = """
182
- #!/bin/bash
183
138
 
184
- """
185
- if jupyter:
139
+ if visidata:
140
+ fire_line = f"uv run --with visidata,pyarrow vd {str(file_obj)}"
141
+ elif jupyter:
186
142
  fire_line = f"code --new-window {str(pyfile)}"
187
143
  else:
188
- fire_line = f"uv run --project $HOME/code/machineconfig/.venv {interpreter} {interactivity} "
189
- if interpreter == "ipython": fire_line += f" --profile {ipython_profile} --no-banner"
190
- fire_line += " " + str(pyfile)
191
- shell_program += fire_line
192
- from rich.syntax import Syntax
193
- console.print(Syntax(shell_program, lexer="bash"))
194
- print()
195
- import subprocess
196
- subprocess.run(shell_program, shell=True, check=True)
144
+ if interpreter == "ipython": profile = f" --profile {ipython_profile} --no-banner"
145
+ else: profile = ""
146
+ fire_line = f"uv run --python 3.13 --with machineconfig[plot] {interpreter} {interactivity} {profile} {str(pyfile)}"
147
+
148
+ from machineconfig.utils.code import run_shell_script
149
+ run_shell_script(fire_line)
197
150
 
198
151
 
199
152
  def arg_parser() -> None:
@@ -221,8 +221,8 @@ python -m machineconfig.cluster.templates.cli_click --file {choice_file} """
221
221
  command = "$ErrorActionPreference = 'SilentlyContinue';\n" + command + "\nStart-Sleep -Seconds 0.5"
222
222
  else:
223
223
  raise NotImplementedError(f"Platform {platform.system()} not supported.")
224
- from machineconfig.utils.code import run_script
225
- run_script(command)
224
+ from machineconfig.utils.code import run_shell_script
225
+ run_shell_script(command)
226
226
 
227
227
 
228
228
  def main(
@@ -27,27 +27,23 @@ from questionary import Choice
27
27
  from rich.console import Console
28
28
  from rich.panel import Panel
29
29
  from rich.text import Text
30
- from machineconfig.utils.code import run_script as run_command
30
+ from machineconfig.utils.code import run_shell_script
31
31
 
32
32
  _ = cast
33
33
  console = Console()
34
34
 
35
35
 
36
36
  def display_header() -> None:
37
- """Display the script header."""
38
37
  header_text = Text("MACHINE CONFIGURATION", style="bold magenta")
39
38
  subtitle_text = Text("Interactive Installation Script", style="italic cyan")
40
39
  console.print(Panel(f"📦 {header_text}\n{subtitle_text}", border_style="blue", padding=(1, 2)))
41
40
  def display_completion_message() -> None:
42
- """Display completion message."""
43
41
  completion_text = Text("INSTALLATION COMPLETE", style="bold green")
44
42
  subtitle_text = Text("System setup finished successfully", style="italic green")
45
43
  console.print(Panel(f"✨ {completion_text}\n{subtitle_text}\n\n🎉 Your system has been configured successfully!\n🔄 You may need to reboot to apply all changes.", border_style="green", padding=(1, 2)))
46
44
  def display_dotfiles_instructions() -> None:
47
- """Display instructions for dotfiles migration."""
48
45
  header_text = Text("DOTFILES MIGRATION", style="bold yellow")
49
46
  subtitle_text = Text("Configuration transfer options", style="italic yellow")
50
-
51
47
  instructions = """
52
48
  🖱️ [bold blue]Method 1: USING MOUSE WITHOUT KB OR BROWSER SHARE[/bold blue]
53
49
  On original machine, run:
@@ -65,32 +61,9 @@ def display_dotfiles_instructions() -> None:
65
61
  [dim]cd ~
66
62
  cloud_copy SHARE_URL . --config ss[/dim]
67
63
  (requires symlinks to be created first)"""
68
-
69
64
  console.print(Panel(f"📂 {header_text}\n{subtitle_text}\n\n{instructions}", border_style="yellow", padding=(1, 2)))
70
65
 
71
66
 
72
- def install_windows_desktop_apps() -> bool:
73
- """Install Windows desktop applications using winget."""
74
- if system() != "Windows":
75
- console.print("❌ This function is only available on Windows systems.", style="bold red")
76
- return False
77
- console.print("🔧 Installing Nerd Fonts", style="bold cyan")
78
- try:
79
- from machineconfig.jobs.installer.custom_dev.nerfont_windows_helper import install_nerd_fonts
80
- install_nerd_fonts()
81
- console.print("✅ Nerd Fonts installed successfully", style="bold green")
82
- except Exception as e:
83
- console.print(f"❌ Error installing Nerd Fonts: {e}", style="bold red")
84
- console.print("🔧 Setting Windows Terminal settings", style="bold cyan")
85
- try:
86
- from machineconfig.setup_windows.wt_and_pwsh.set_wt_settings import main as set_wt_settings_main
87
- set_wt_settings_main()
88
- console.print("✅ Windows Terminal settings configured successfully", style="bold green")
89
- except Exception as e:
90
- console.print(f"❌ Error setting Windows Terminal settings: {e}", style="bold red")
91
- return True
92
-
93
-
94
67
  def get_installation_choices() -> list[str]:
95
68
  """Get user choices for installation options."""
96
69
  choices = [
@@ -114,11 +87,15 @@ def get_installation_choices() -> list[str]:
114
87
 
115
88
 
116
89
  def execute_installations(selected_options: list[str]) -> None:
117
- """Execute the selected installation options."""
118
90
  if system() == "Windows":
119
- run_command("$HOME/.local/bin/uv.exe self update")
91
+ from machineconfig import setup_windows as module
92
+ script_path = Path(module.__file__).parent / "ve.ps1"
93
+ run_shell_script(script_path.read_text(encoding="utf-8"))
120
94
  else:
121
- run_command("$HOME/.local/bin/uv self update")
95
+ from machineconfig import setup_linux as module
96
+ script_path = Path(module.__file__).parent / "ve.sh"
97
+ run_shell_script(script_path.read_text(encoding="utf-8"))
98
+
122
99
  for maybe_a_group in selected_options:
123
100
  if maybe_a_group in ("ESSENTIAL", "DEV", "ESSENTIAL_SYSTEM", "DEV_SYSTEM", "TerminalEyeCandy"):
124
101
  console.print(Panel("⚡ [bold bright_yellow]CLI APPLICATIONS[/bold bright_yellow]\n[italic]Command-line tools installation[/italic]", border_style="bright_yellow"))
@@ -129,21 +106,25 @@ def execute_installations(selected_options: list[str]) -> None:
129
106
  console.print("✅ CLI applications installed successfully", style="bold green")
130
107
  except Exception as e:
131
108
  console.print(f"❌ Error installing CLI applications: {e}", style="bold red")
132
- run_command(". $HOME/.bashrc")
109
+ run_shell_script(". $HOME/.bashrc")
133
110
 
134
111
  if "upgrade_system" in selected_options:
135
112
  if system() == "Windows":
136
113
  console.print("❌ System upgrade is not applicable on Windows via this script.", style="bold red")
137
114
  elif system() == "Linux":
138
115
  console.print(Panel("🔄 [bold magenta]SYSTEM UPDATE[/bold magenta]\n[italic]Package management[/italic]", border_style="magenta"))
139
- run_command("sudo nala upgrade -y")
116
+ run_shell_script("sudo nala upgrade -y")
140
117
  else:
141
118
  console.print(f"❌ System upgrade not supported on {system()}.", style="bold red")
142
119
  if "install_repos" in selected_options:
143
120
  console.print(Panel("🐍 [bold green]PYTHON ENVIRONMENT[/bold green]\n[italic]Virtual environment setup[/italic]", border_style="green"))
144
- from machineconfig import setup_linux as module
145
- script = Path(module.__file__).parent / "repos.sh"
146
- run_command(f"bash {script}")
121
+ if system() == "Windows":
122
+ from machineconfig import setup_windows as module
123
+ script_path = Path(module.__file__).parent / "repos.ps1"
124
+ else:
125
+ from machineconfig import setup_linux as module
126
+ script_path = Path(module.__file__).parent / "repos.sh"
127
+ run_shell_script(script_path.read_text(encoding="utf-8"))
147
128
 
148
129
  if "install_ssh_server" in selected_options:
149
130
  console.print(Panel("🔒 [bold red]SSH SERVER[/bold red]\n[italic]Remote access setup[/italic]", border_style="red"))
@@ -152,9 +133,9 @@ def execute_installations(selected_options: list[str]) -> None:
152
133
  Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
153
134
  Start-Service sshd
154
135
  Set-Service -Name sshd -StartupType 'Automatic'"""
155
- run_command(f'powershell -Command "{powershell_script}"')
136
+ run_shell_script(f'powershell -Command "{powershell_script}"')
156
137
  else:
157
- run_command("sudo nala install openssh-server -y")
138
+ run_shell_script("sudo nala install openssh-server -y")
158
139
 
159
140
  if "install_shell_profile" in selected_options:
160
141
  console.print(Panel("🐚 [bold green]SHELL PROFILE[/bold green]\n[italic]Shell configuration setup[/italic]", border_style="green"))
@@ -179,8 +160,8 @@ Set-Service -Name sshd -StartupType 'Automatic'"""
179
160
  console.print("✅ Symlinks created successfully", style="bold green")
180
161
  except Exception as e:
181
162
  console.print(f"❌ Error creating symlinks: {e}", style="bold red")
182
- run_command("sudo chmod 600 $HOME/.ssh/*")
183
- run_command("sudo chmod 700 $HOME/.ssh")
163
+ run_shell_script("sudo chmod 600 $HOME/.ssh/*")
164
+ run_shell_script("sudo chmod 700 $HOME/.ssh")
184
165
  else:
185
166
  console.print("⏭️ Skipping symlink creation - finish dotfiles transfer first", style="yellow")
186
167
 
@@ -200,7 +181,10 @@ Set-Service -Name sshd -StartupType 'Automatic'"""
200
181
  console.print(f"❌ Error retrieving backup data: {e}", style="bold red")
201
182
 
202
183
  if "install_windows_desktop" in selected_options:
203
- install_windows_desktop_apps()
184
+ from machineconfig.jobs.installer.custom_dev.nerfont_windows_helper import install_nerd_fonts
185
+ install_nerd_fonts()
186
+ from machineconfig.setup_windows.wt_and_pwsh.set_wt_settings import main as set_wt_settings_main
187
+ set_wt_settings_main()
204
188
 
205
189
 
206
190
  def main() -> None:
@@ -210,7 +194,7 @@ def main() -> None:
210
194
  if not selected_options:
211
195
  console.print("❌ No options selected. Exiting...", style="bold red")
212
196
  sys.exit(0)
213
- console.print(f"\n✅ Selected options: {', '.join(selected_options)}", style="bold green")
197
+ console.print(f"\n✅ Selected options: {'\n'.join(selected_options)}", style="bold green")
214
198
  proceed = questionary.confirm("🚀 Proceed with installation?", default=True).ask()
215
199
  if not proceed:
216
200
  console.print("❌ Installation cancelled.", style="bold red")
@@ -132,8 +132,8 @@ def main(
132
132
  #!/bin/bash
133
133
  ttyd --writable -t enableSixel=true {ssl_args} --port {port} --credential "{username}:{password}" -t 'theme={{"background": "black"}}' {start_command}
134
134
  """
135
- from machineconfig.utils.code import run_script
136
- run_script(code)
135
+ from machineconfig.utils.code import run_shell_script
136
+ run_shell_script(code)
137
137
 
138
138
 
139
139
  def main_with_parser():
@@ -10,3 +10,4 @@ Invoke-WebRequest -Uri "https://raw.githubusercontent.com/thisismygitrepo/machin
10
10
  rm ve.ps1
11
11
 
12
12
  uv run --python 3.13 --with machineconfig devops interactive
13
+ # uv run --python 3.13 --with machineconfig https://raw.githubusercontent.com/thisismygitrepo/machineconfig/ee4f69e838e1acbb275bfb5a3d3faee23345f2a8/src/machineconfig/scripts/python/devops.py
@@ -98,7 +98,7 @@ def print_code(code: str, lexer: str, desc: str, subtitle: str = ""):
98
98
  console.print(Panel(Syntax(code=code, lexer=lexer), title=f"📄 {desc}", subtitle=subtitle), style="bold red")
99
99
 
100
100
 
101
- def run_script(program: str):
101
+ def run_shell_script(program: str):
102
102
  import tempfile
103
103
  if platform.system() == "Windows":
104
104
  suffix = ".ps1"
@@ -0,0 +1,118 @@
1
+ """Ascii art
2
+ """
3
+
4
+ import os
5
+ import random
6
+ import textwrap
7
+ import subprocess
8
+ from pathlib import Path
9
+ import tempfile
10
+ import platform
11
+ from typing import Optional, Literal
12
+
13
+ # https://github.com/sepandhaghighi/art
14
+
15
+
16
+ BOX_OR_CHAR = Literal['boxes', 'cowsay']
17
+
18
+
19
+ class ArtLib:
20
+ @staticmethod
21
+ def cowsay(text: str):
22
+ import cowsay
23
+ char = random.choice(cowsay.char_names)
24
+ return cowsay.get_output_string(char, text=text)
25
+
26
+
27
+ class BoxStyles:
28
+ language = ['ada-box', 'caml', 'boxquote', 'stone', 'tex-box', 'shell', 'simple', 'c', 'cc', 'html']
29
+ scene = ['whirly', 'xes', 'columns', 'parchment', 'scroll', 'scroll-akn', 'diamonds', 'headline', 'nuke', 'spring', 'stark1'] # , 'important3'
30
+ character = ['capgirl', 'cat', 'boy', 'girl', 'dog', 'mouse', 'santa', 'face', 'ian_jones', 'peek', 'unicornsay']
31
+
32
+
33
+ class CowStyles:
34
+ eyes = ['-b', '-d', '-g', '-h', '-l', '-L', '-n', '-N', '-p', '-s', '-t', '-w', '-y']
35
+ # this one for the package installed with sudo apt install cowsay and is located at /usr/games/cowsay. See cowsay -l
36
+ figures = ['apt', 'bunny', 'cheese', 'cock', 'cower', 'daemon', 'default', 'dragon',
37
+ 'dragon-and-cow', 'duck', 'elephant', 'elephant-in-snake', 'eyes', 'fox', 'ghostbusters',
38
+ 'gnu', 'kangaroo', 'kiss', 'milk',
39
+ 'moose', 'pony', 'pony-smaller', 'sheep', 'skeleton', 'snowman', 'stegosaurus', # 'suse',
40
+ 'three-eyes', 'turkey', 'turtle', 'tux', 'unipony', 'unipony-smaller', 'vader', 'vader'] # 'hellokitty' 'mech-and-cow' # 'moofasa', 'stimpy', 'calvin', , 'ren', 'koala', 'flaming-sheep' , 'bud-frogs' , 'kosh' , 'luke-koala'
41
+
42
+
43
+ FIGLET_FONTS = ['banner', 'big', 'standard']
44
+
45
+ FIGJS_FONTS = ['3D Diagonal', '3D-ASCII', '4Max', '5 Line Oblique', 'Acrobatic', 'ANSI Regular', 'ANSI Shadow',
46
+ 'Avatar', 'Banner', 'Banner3-D', 'Banner4',
47
+ 'Basic', 'Big Money-ne', 'Big Money-nw', 'Big Money-se', 'Big Money-sw', 'Big', 'Bloody', 'Bolger', 'Braced', 'Bright',
48
+ 'DOS Rebel',
49
+ 'Elite', 'Epic', 'Flower Power',
50
+ 'Fraktur', # 'Isometric4'. 'AMC Tubes', 'Banner3', Alligator2
51
+ 'Star Wars',
52
+ 'Sub-Zero', 'The Edge', 'USA Flag', 'Varsity', "Doom"
53
+ ] # too large Crazy 'Sweet', 'Electronic', 'Swamp Land', Crawford, Alligator
54
+
55
+
56
+ def get_art(comment: Optional[str] = None, artlib: Optional[BOX_OR_CHAR] = None, style: Optional[str] = None, super_style: str = 'scene', prefix: str = ' ', file: Optional[str] = None, verbose: bool = True):
57
+ """ takes in a comment and does the following wrangling:
58
+ * text => figlet font => boxes => lolcat
59
+ * text => cowsay => lolcat
60
+ """
61
+ if comment is None:
62
+ try:
63
+ comment = subprocess.run("fortune", shell=True, capture_output=True, text=True, check=True).stdout
64
+ except Exception:
65
+ comment = "crocodile"
66
+ if artlib is None: artlib = random.choice(['boxes', 'cowsay'])
67
+ to_file = '' if not file else f'> {file}'
68
+ if artlib == 'boxes':
69
+ if style is None: style = random.choice(BoxStyles.__dict__[super_style or random.choice(['language', 'scene', 'character'])])
70
+ fonting = f'figlet -f {random.choice(FIGLET_FONTS)}'
71
+ cmd = f"""echo "{comment}" | {fonting} | boxes -d {style} {to_file}"""
72
+ else:
73
+ if style is None: style = random.choice(CowStyles.figures)
74
+ cmd = f"""echo "{comment}" | /usr/games/cowsay -f {style} {to_file}"""
75
+ try:
76
+ res = subprocess.run(cmd, text=True, capture_output=True, shell=True, check=True).stdout
77
+ except subprocess.CalledProcessError as ex:
78
+ print(ex)
79
+ return ""
80
+ res = textwrap.indent(res, prefix=prefix)
81
+ if verbose:
82
+ print(f'Using style: {style} from {artlib}', '\n' * 3)
83
+ print(f'{cmd=}')
84
+ print('Results:\n', res)
85
+ return res
86
+
87
+
88
+ def font_box_color(logo: str):
89
+ font = random.choice(FIGJS_FONTS)
90
+ # print(f"{font}\n")
91
+ box_style = random.choice(['whirly', 'xes', 'columns', 'parchment', 'scroll', 'scroll-akn', 'diamonds', 'headline', 'nuke', 'spring', 'stark1'])
92
+ _cmd = f'figlet -f "{font}" "{logo}" | boxes -d "{box_style}" | lolcatjs'
93
+ # print(_cmd)
94
+ os.system(_cmd) # | lolcat
95
+ # print("after")
96
+
97
+
98
+ def character_color(logo: str):
99
+ assert platform.system() == 'Windows', 'This function is only for Windows.'
100
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
101
+ f.write(ArtLib.cowsay(logo))
102
+ _new_art = f.name
103
+ os.system(f'type {_new_art} | lolcatjs') # | lolcat
104
+
105
+
106
+ def character_or_box_color(logo: str):
107
+ assert platform.system() in {'Linux', 'Darwin'}, 'This function is only for Linux and macOS.'
108
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
109
+ _new_art = f.name
110
+ get_art(logo, artlib=None, file=_new_art, verbose=False)
111
+ # Prefer bat on mac if available, fallback to cat
112
+ pager = "bat" if (platform.system() == "Darwin" and any((Path(p).joinpath("bat").exists() for p in os.environ.get("PATH", "").split(os.pathsep)))) else "cat"
113
+ command = f"{pager} {_new_art} | lolcat"
114
+ os.system(command)
115
+
116
+
117
+ if __name__ == '__main__':
118
+ pass
@@ -0,0 +1,71 @@
1
+
2
+ import glob
3
+ import os
4
+ import platform
5
+ import random
6
+ from pathlib import Path
7
+ from rich import pretty
8
+ from rich.console import Console
9
+ from typing import Optional
10
+
11
+
12
+ def print_header():
13
+ console = Console()
14
+ pretty.install()
15
+
16
+ # Environment Information Panel
17
+ from rich.panel import Panel
18
+ from rich.table import Table
19
+
20
+ table = Table(show_header=False, show_edge=False, pad_edge=False)
21
+ table.add_column("Label", style="cyan", no_wrap=True)
22
+ table.add_column("Value", style="white")
23
+
24
+ table.add_row("Python Version", platform.python_version())
25
+ table.add_row("Operating System", platform.system())
26
+ table.add_row("Virtual Environment", os.getenv('VIRTUAL_ENV', 'None'))
27
+ table.add_row("Running @", str(Path.cwd()))
28
+
29
+
30
+ console.print(Panel(table, title="[bold blue]✨ 🐊 Crocodile Shell 14.5 ✨ Made with 🐍 | Built with ❤️[/bold blue]", border_style="blue"))
31
+ def print_logo(logo: str):
32
+ from machineconfig.utils.files.ascii_art import font_box_color, character_color, character_or_box_color
33
+ if platform.system() == "Windows":
34
+ _1x = Path.home().joinpath(r"AppData/Roaming/npm/figlet").exists()
35
+ _2x = Path.home().joinpath(r"AppData/Roaming/npm/lolcatjs").exists()
36
+ _3x = Path.home().joinpath(r"AppData/Local/Microsoft/WindowsApps/boxes.exe").exists()
37
+ if _1x and _2x and _3x:
38
+ if random.choice([True, True, False]): font_box_color(logo)
39
+ else: character_color(logo)
40
+ else:
41
+ print("\n" + "🚫 " + "-" * 70 + " 🚫")
42
+ print("🔍 Missing ASCII art dependencies. Install with: iwr bit.ly/cfgasciiartwindows | iex")
43
+ print("🚫 " + "-" * 70 + " 🚫\n")
44
+ _default_art = Path(random.choice(glob.glob(str(Path(__file__).parent.joinpath("art", "*")))))
45
+ print(_default_art.read_text())
46
+ elif platform.system() in ["Linux", "Darwin"]: # Explicitly handle both Linux and macOS
47
+ def is_executable_in_path(executable_name: str) -> Optional[str]:
48
+ path_dirs = os.environ['PATH'].split(os.pathsep)
49
+ for path_dir in path_dirs:
50
+ path_to_executable = os.path.join(path_dir, executable_name)
51
+ if os.path.isfile(path_to_executable) and os.access(path_to_executable, os.X_OK): return path_to_executable
52
+ return None
53
+ avail_cowsay = is_executable_in_path("cowsay")
54
+ avail_lolcat = is_executable_in_path("lolcat")
55
+ avail_boxes = is_executable_in_path("boxes")
56
+ avail_figlet = is_executable_in_path("figlet")
57
+ if avail_cowsay and avail_lolcat and avail_boxes and avail_figlet:
58
+ _dynamic_art = random.choice([True, True, True, True, False])
59
+ if _dynamic_art: character_or_box_color(logo=logo)
60
+ else: print(Path(random.choice(glob.glob(str(Path(__file__).parent.joinpath("art", "*"))))).read_text())
61
+ else:
62
+ print("\n" + "🚫 " + "-" * 70 + " 🚫")
63
+ install_cmd = "devops install --group TerminalEyeCandy" if platform.system() == "Linux" else "brew install cowsay lolcat boxes figlet"
64
+ print(f"🔍 Missing ASCII art dependencies. Install with: {install_cmd}")
65
+ print("🚫 " + "-" * 70 + " 🚫\n")
66
+ _default_art = Path(random.choice(glob.glob(str(Path(__file__).parent.joinpath("art", "*")))))
67
+ print(_default_art.read_text())
68
+ else:
69
+ print(f"⚠️ Platform {platform.system()} not supported for ASCII art. Using default art.")
70
+ _default_art = Path(random.choice(glob.glob(str(Path(__file__).parent.joinpath("art", "*")))))
71
+ print(_default_art.read_text())
@@ -0,0 +1,103 @@
1
+
2
+
3
+
4
+ from pathlib import Path
5
+ from typing import Any, Optional
6
+
7
+
8
+ class Read:
9
+ @staticmethod
10
+ def read(path: 'Path', **kwargs: Any) -> Any:
11
+ if Path(path).is_dir(): raise IsADirectoryError(f"Path is a directory, not a file: {path}")
12
+ suffix = Path(path).suffix[1:]
13
+ if suffix == "": raise ValueError(f"File type could not be inferred from suffix. Suffix is empty. Path: {path}")
14
+ if suffix in ("sqlite", "sqlite3", "db", "duckdb"):
15
+ # from crocodile.database import DBMS
16
+ # if suffix == "duckdb": pass
17
+ # res = DBMS.from_local_db(path=path)
18
+ # print(res.describe_db())
19
+ # return res
20
+ raise NotImplementedError("Reading database files is not implemented yet. Use `crocodile.database.DBMS` to connect to the database file.")
21
+ try: return getattr(Read, suffix)(str(path), **kwargs)
22
+ except AttributeError as err:
23
+ if "type object 'Read' has no attribute" not in str(err): raise AttributeError(err) from err
24
+ if suffix in ('eps', 'jpg', 'jpeg', 'pdf', 'pgf', 'png', 'ps', 'raw', 'rgba', 'svg', 'svgz', 'tif', 'tiff'):
25
+ import matplotlib.pyplot as pyplot
26
+ return pyplot.imread(path, **kwargs) # from: plt.gcf().canvas.get_supported_filetypes().keys():
27
+ if suffix == "parquet":
28
+ import polars as pl
29
+ return pl.read_parquet(path, **kwargs)
30
+ elif suffix == "csv":
31
+ import polars as pl
32
+ return pl.read_csv(path, **kwargs)
33
+ try:
34
+ # guess = install_n_import('magic', 'python-magic').from_file(path)
35
+ guess = "IDKm"
36
+ raise AttributeError(f"Unknown file type. failed to recognize the suffix `{suffix}`. According to libmagic1, the file seems to be: {guess}") from err
37
+ except ImportError as err2:
38
+ print(f"💥 Unknown file type. failed to recognize the suffix `{suffix}` of file {path} ")
39
+ raise ImportError(err) from err2
40
+ @staticmethod
41
+ def json(path: 'Path', r: bool = False, **kwargs: Any) -> Any: # return could be list or dict etc
42
+ import json
43
+ try:
44
+ mydict = json.loads(Path(path).read_text(encoding='utf-8'), **kwargs)
45
+ except Exception:
46
+ import pyjson5
47
+ mydict = pyjson5.loads(Path(path).read_text(encoding='utf-8'), **kwargs) # file has C-style comments.
48
+ _ = r
49
+ return mydict
50
+ @staticmethod
51
+ def yaml(path: 'Path', r: bool = False) -> Any: # return could be list or dict etc
52
+ import yaml # type: ignore
53
+ with open(str(path), "r", encoding="utf-8") as file:
54
+ mydict = yaml.load(file, Loader=yaml.FullLoader)
55
+ _ = r
56
+ return mydict
57
+ @staticmethod
58
+ def ini(path: 'Path', encoding: Optional[str] = None):
59
+ if not Path(path).exists() or Path(path).is_dir(): raise FileNotFoundError(f"File not found or is a directory: {path}")
60
+ import configparser
61
+ res = configparser.ConfigParser()
62
+ res.read(filenames=[str(path)], encoding=encoding)
63
+ return res
64
+ @staticmethod
65
+ def toml(path: 'Path'):
66
+ import toml
67
+ return toml.loads(Path(path).read_text(encoding='utf-8'))
68
+ @staticmethod
69
+ def npy(path: 'Path', **kwargs: Any):
70
+ import numpy as np
71
+ data = np.load(str(path), allow_pickle=True, **kwargs)
72
+ # data = data.item() if data.dtype == np.object else data
73
+ return data
74
+ @staticmethod
75
+ def pickle(path: 'Path', **kwargs: Any):
76
+ import pickle
77
+ try: return pickle.loads(Path(path).read_bytes(), **kwargs)
78
+ except BaseException as ex:
79
+ print(f"💥 Failed to load pickle file `{path}` with error:\n{ex}")
80
+ raise ex
81
+ @staticmethod
82
+ def pkl(path: 'Path', **kwargs: Any): return Read.pickle(path, **kwargs)
83
+ # @staticmethod
84
+ # def dill(path: 'Path', **kwargs: Any) -> Any:
85
+ # """handles imports automatically provided that saved object was from an imported class (not in defined in __main__)"""
86
+ # import dill
87
+ # obj = dill.loads(str=Path(path).read_bytes(), **kwargs)
88
+ # return obj
89
+ @staticmethod
90
+ def py(path: 'Path', init_globals: Optional[dict[str, Any]] = None, run_name: Optional[str] = None):
91
+ import runpy
92
+ return runpy.run_path(str(path), init_globals=init_globals, run_name=run_name)
93
+ @staticmethod
94
+ def txt(path: 'Path', encoding: str = 'utf-8') -> str: return Path(path).read_text(encoding=encoding)
95
+ @staticmethod
96
+ def parquet(path: 'Path', **kwargs: Any):
97
+ import polars as pl
98
+ return pl.read_parquet(path, **kwargs)
99
+
100
+
101
+
102
+ if __name__ == '__main__':
103
+ pass
@@ -125,12 +125,12 @@ def install_group(package_group: PACKAGE_GROUPS):
125
125
  else:
126
126
  options_system = get_installers_system_groups()
127
127
  from machineconfig.utils.schemas.installer.installer_types import get_normalized_arch, get_os_name
128
- from machineconfig.utils.code import run_script
128
+ from machineconfig.utils.code import run_shell_script
129
129
  for an_item in options_system:
130
130
  if an_item["appName"] == package_group:
131
131
  program = an_item["fileNamePattern"][get_normalized_arch()][get_os_name()]
132
132
  if program is not None:
133
- run_script(program)
133
+ run_shell_script(program)
134
134
  break
135
135
 
136
136
 
@@ -124,6 +124,13 @@ def check_tool_exists(tool_name: str) -> bool:
124
124
  return any([Path("/usr/local/bin").joinpath(tool_name).is_file(), Path("/usr/bin").joinpath(tool_name).is_file(), root_path.joinpath(tool_name).is_file()])
125
125
  else:
126
126
  raise NotImplementedError(f"platform {platform.system()} not implemented")
127
+ def is_executable_in_path(executable_name: str) -> bool:
128
+ import os
129
+ path_dirs = os.environ['PATH'].split(os.pathsep)
130
+ for path_dir in path_dirs:
131
+ path_to_executable = os.path.join(path_dir, executable_name)
132
+ if os.path.isfile(path_to_executable) and os.access(path_to_executable, os.X_OK): return True
133
+ return False
127
134
 
128
135
 
129
136
  def check_if_installed_already(exe_name: str, version: Optional[str], use_cache: bool) -> tuple[str, str, str]:
@@ -6,31 +6,6 @@ from rich.console import Console
6
6
  import subprocess
7
7
  from typing import Optional, Union, Iterable, overload, Literal
8
8
 
9
-
10
- # _ = cmd
11
- # cmd = "where.exe"
12
- # cmd = "which"
13
- # try: # talking to terminal is too slow.
14
- # _tmp = subprocess.check_output([cmd, tool_name], stderr=subprocess.DEVNULL)
15
- # res: bool = True
16
- # except (subprocess.CalledProcessError, FileNotFoundError):
17
- # res = False
18
- # return res
19
- # return root_path.joinpath(tool_name).is_file()
20
-
21
-
22
- # def choose_from_options[T](options: Iterable[T], header: str = "", tail: str = "", prompt: str = "", msg: str = "", default: Optional[T] = None, fzf: bool = False, custom_input: bool = False) -> T:
23
- # choice_key = choose_from_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default, fzf=fzf, multi=False, custom_input=custom_input)
24
- # assert not isinstance(choice_key, list)
25
- # return choice_key
26
-
27
-
28
- # def choose_from_options[T](options: Iterable[T], header: str = "", tail: str = "", prompt: str = "", msg: str = "", default: Optional[T] = None, custom_input: bool = False) -> list[T]:
29
- # choice_key = choose_from_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default, fzf=True, multi=True, custom_input=custom_input)
30
- # if isinstance(choice_key, list):
31
- # return choice_key
32
- # return [choice_key]
33
-
34
9
  @overload
35
10
  def choose_from_options[T](msg: str, options: Iterable[T], multi: Literal[False], custom_input: bool = False, header: str = "", tail: str = "", prompt: str = "", default: Optional[T] = None, fzf: bool = False) -> T: ...
36
11
  @overload
@@ -147,7 +147,7 @@ class Terminal:
147
147
  return os.getuid() == 0 # Check for root on Posix
148
148
  '''
149
149
 
150
- # def run_script(self, script: str, shell: SHELLS = "default", verbose: bool = False):
150
+ # def run_shell_script(self, script: str, shell: SHELLS = "default", verbose: bool = False):
151
151
  # if self.machine == "Linux":
152
152
  # script = "#!/bin/bash" + "\n" + script # `source` is only available in bash.
153
153
  # script_file = PathExtended.tmpfile(name="tmp_shell_script", suffix=".ps1" if self.machine == "Windows" else ".sh", folder="tmp_scripts")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: machineconfig
3
- Version: 5.13
3
+ Version: 5.15
4
4
  Summary: Dotfiles management package
5
5
  Author-email: Alex Al-Saffar <programmer@usa.com>
6
6
  License: Apache 2.0
@@ -143,8 +143,8 @@ machineconfig/scripts/python/cloud_mount.py,sha256=GwcXbd5ohoHGESfX5edtCEl2-umDD
143
143
  machineconfig/scripts/python/cloud_repo_sync.py,sha256=8dnlHbQqRymPRU0v01pNIuaIvFeY4fReP7ewNSSCt34,9765
144
144
  machineconfig/scripts/python/cloud_sync.py,sha256=RWGpAfJ9fnN18yNBSgN44dzA38Hmd4879JL5r2pcyrM,3514
145
145
  machineconfig/scripts/python/count_lines.py,sha256=ZexMRsV70pe9fhLbGuens9EP5gCf078EwTDRHRZo5A0,15960
146
- machineconfig/scripts/python/count_lines_frontend.py,sha256=SCFCCYgGy96uVFAo8tcnAv-P_4ytqJOpWe0nzoPi8H8,572
147
- machineconfig/scripts/python/croshell.py,sha256=parFHSL859H00ExDpDBPHBFe_E_DrfVq6P8CpCGVK9A,8571
146
+ machineconfig/scripts/python/count_lines_frontend.py,sha256=bIha5lKjWxKiO1OJAbt9gKzVyECXFbWKWIy69bdyaJg,533
147
+ machineconfig/scripts/python/croshell.py,sha256=zHUhOqWG81AOTeawZoDkpURnV1fAisY2lyZ0apvlmVY,6547
148
148
  machineconfig/scripts/python/devops.py,sha256=JB4_M6S-nO3yqas8wtAlU2r6jsmHu_nlq7aoEOH-54Y,3486
149
149
  machineconfig/scripts/python/devops_add_identity.py,sha256=wvjNgqsLmqD2SxbNCW_usqfp0LI-TDvcJJKGOWt2oFw,3775
150
150
  machineconfig/scripts/python/devops_add_ssh_key.py,sha256=BXB-9RvuSZO0YTbnM2azeABW2ngLW4SKhhAGAieMzfw,6873
@@ -155,14 +155,14 @@ machineconfig/scripts/python/fire_agents_help_launch.py,sha256=1ymWiszfjCyPv3ofi
155
155
  machineconfig/scripts/python/fire_agents_help_search.py,sha256=qIfSS_su2YJ1Gb0_lu4cbjlJlYMBw0v52NTGiSrGjk8,2991
156
156
  machineconfig/scripts/python/fire_agents_helper_types.py,sha256=zKu8Vr6iucaGSkCm_Tkt_WrYU7-6Nript3coYyzTXzY,295
157
157
  machineconfig/scripts/python/fire_agents_load_balancer.py,sha256=mpqx3uaQdBXYieuvhdK-qsvLepf9oIMo3pwPj9mSEDI,1079
158
- machineconfig/scripts/python/fire_jobs.py,sha256=Mg7M6pm3PvyJlnMGYas8hEVYLIJYiyy-pBiRWCGLFjQ,15895
158
+ machineconfig/scripts/python/fire_jobs.py,sha256=VIZZOjnE0u1g7U1jmYN3YUTFsLt8MM4_z67U951oEm4,15907
159
159
  machineconfig/scripts/python/fire_jobs_args_helper.py,sha256=-gl5I-26Op12nToIpAA-YEpvn8MMkNlI5XjhUbj50I0,4273
160
160
  machineconfig/scripts/python/fire_jobs_route_helper.py,sha256=EFWsg6F9TeSAtYQec57WtPopUbm2euGZTUZv6J4RhNE,3026
161
161
  machineconfig/scripts/python/fire_jobs_streamlit_helper.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
162
162
  machineconfig/scripts/python/ftpx.py,sha256=QfQTp-6jQP6yxfbLc5sKxiMtTgAgc8sjN7d17_uLiZc,9400
163
163
  machineconfig/scripts/python/get_zellij_cmd.py,sha256=e35-18hoXM9N3PFbvbizfkNY_-63iMicieWE3TbGcCQ,576
164
164
  machineconfig/scripts/python/gh_models.py,sha256=3BLfW25mBRiPO5VKtVm-nMlKLv-PaZDw7mObajq6F6M,5538
165
- machineconfig/scripts/python/interactive.py,sha256=wjxwxU5KtCh8MgujCQjEQctZPpKfPc71lMVFLhODQFE,11769
165
+ machineconfig/scripts/python/interactive.py,sha256=gxAaVasW37TbSPswiyli-ImNQLU8jQbCb6Csnk5Igdg,11188
166
166
  machineconfig/scripts/python/mount_nfs.py,sha256=aECrL64j9g-9rF49sVJAjGmzaoGgcMnl3g9v17kQF4c,3239
167
167
  machineconfig/scripts/python/mount_nw_drive.py,sha256=iru6AtnTyvyuk6WxlK5R4lDkuliVpPV5_uBTVVhXtjQ,1550
168
168
  machineconfig/scripts/python/mount_ssh.py,sha256=k2fKq3f5dKq_7anrFOlqvJoI_3U4EWNHLRZ1o3Lsy6M,2268
@@ -176,7 +176,7 @@ machineconfig/scripts/python/repos_helper_record.py,sha256=dtnnInQPn00u1cyr0oOgJ
176
176
  machineconfig/scripts/python/repos_helper_update.py,sha256=AYyKIB7eQ48yoYmFjydIhRI1lV39TBv_S4_LCa-oKuQ,11042
177
177
  machineconfig/scripts/python/scheduler.py,sha256=rKhssuxkD697EY6qaV6CSdNhxpAQLDWO4fE8GMCQ9FA,3061
178
178
  machineconfig/scripts/python/sessions.py,sha256=e8gL0fVWOZ5WcJsA3ZWfqJBc5c7g-rMlVf0SF63rIaU,8547
179
- machineconfig/scripts/python/share_terminal.py,sha256=pqKnly6QRtcPmw0lLyRN6NRuK2bntM1hOdqQfw5jJnc,5324
179
+ machineconfig/scripts/python/share_terminal.py,sha256=D9zwPZk4cV2ix5f-fHDfp0awtMsI5C5ANlfv1vW-VKE,5336
180
180
  machineconfig/scripts/python/snapshot.py,sha256=aDvKeoniZaeTSNv9zWBUajaj2yagAxVdfuvO1_tgq5Y,1026
181
181
  machineconfig/scripts/python/start_slidev.py,sha256=FAJ1_WkAQ7KcbRZ3cSN_72NDgV_flRrwxmXv1imyulI,4897
182
182
  machineconfig/scripts/python/start_terminals.py,sha256=DRWbMZumhPmL0DvvsCsbRNFL5AVQn1SgaziafTio3YQ,6149
@@ -370,18 +370,18 @@ machineconfig/setup_windows/others/obs.ps1,sha256=2andchcXpxS3rqZjGaMpY5VShxTAKW
370
370
  machineconfig/setup_windows/web_shortcuts/all.ps1,sha256=L03JJ4Jua_bzgtF3kuDOkuQ-Nqaj_ZcV3CFEkCHD1WI,908
371
371
  machineconfig/setup_windows/web_shortcuts/ascii_art.ps1,sha256=pUVTtgKHOdgaK3hxz7JoMZzTyQ7vm2RfE_OJgB7e4cw,1270
372
372
  machineconfig/setup_windows/web_shortcuts/croshell.ps1,sha256=cTQnegGLGYhuFY3YuuAj2ortN__adA2dznk2E737h4A,644
373
- machineconfig/setup_windows/web_shortcuts/interactive.ps1,sha256=-76toOluRnxtgo6NuAHgHWMnZQT3zroeCBBLkMTd13g,522
373
+ machineconfig/setup_windows/web_shortcuts/interactive.ps1,sha256=RMUq_GNf0FCD_o4g4BEbBRg098VOyUEh9ezL2rRNEOI,714
374
374
  machineconfig/setup_windows/web_shortcuts/ssh.ps1,sha256=Tj9axEugJE7I3AQ0w1eUGLPb8ufME5jvU5S7VUjlLJE,424
375
375
  machineconfig/setup_windows/wt_and_pwsh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
376
376
  machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py,sha256=ogxJnwpdcpH7N6dFJu95UCNoGYirZKQho_3X0F_hmXs,6791
377
377
  machineconfig/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
378
378
  machineconfig/utils/accessories.py,sha256=W_9dLzjwNTW5JQk_pe3B2ijQ1nA2-8Kdg2r7VBtzgQs,4340
379
- machineconfig/utils/code.py,sha256=S7uY5kLPxLcLlR7B2KHeYkenlysAYSPcxFiUYHXSxX8,5646
379
+ machineconfig/utils/code.py,sha256=Q44GVBgI5wEphGAKsMmXE2wEtzjJngy5pfJV9NCJ8EA,5652
380
380
  machineconfig/utils/installer.py,sha256=xYM6tyctqLmr2lLXUKWgobTRufGIua31uspMXP4HGjY,9945
381
381
  machineconfig/utils/io.py,sha256=ZXB3aataS1IZ_0WMcCRSmoN1nbkvEO-bWYcs-TpngqU,2872
382
382
  machineconfig/utils/links.py,sha256=S0XICdbcFESUqm5RINDrOf3O8G1b7QEADncXXcC8IQc,15520
383
383
  machineconfig/utils/notifications.py,sha256=vvdsY5IX6XEiILTnt5lNyHxhCi0ljdGX2T_67VRfrG4,9009
384
- machineconfig/utils/options.py,sha256=8pG-apcc28xxJ5BQiACsGNTKwWtkQyH3hCtzBEhokK8,8366
384
+ machineconfig/utils/options.py,sha256=vUO4Kej-vDOv64wHr2HNDyu6PATURpjd7xp6N8OOoJg,7083
385
385
  machineconfig/utils/path_extended.py,sha256=Xjdn2AVnB8p1jfNMNe2kJutVa5zGnFFJVGZbw-Bp_hg,53200
386
386
  machineconfig/utils/path_helper.py,sha256=0e3Xh3BAEv27oqcezNeVLHJllGmLEgLH4T1l90m-650,8014
387
387
  machineconfig/utils/procs.py,sha256=Bm-yopmj19yiBO9tywJHEcs9rZmeRyJqbgTSe216LTU,11349
@@ -389,24 +389,27 @@ machineconfig/utils/scheduler.py,sha256=pOzpOowapfC6Fl_k82JbESmLS8eh-zk4FyjJyUX1
389
389
  machineconfig/utils/scheduling.py,sha256=RF1iXJpqf4Dg18jdZWtBixz97KAHC6VKYqTFSpdLWuc,11188
390
390
  machineconfig/utils/source_of_truth.py,sha256=GnjcVkKm11RyZFHGnPbne5YDEBYoZ5yryBNkpfGC7O4,854
391
391
  machineconfig/utils/ssh.py,sha256=KTUp42nT4Vuh350_EvArQoR2N5iVXrc2BFld93fRUX4,20919
392
- machineconfig/utils/terminal.py,sha256=Jqojb1xta_SLftUIXmWK7Mn87e1NJXavC5Hbf3fRT-I,11795
392
+ machineconfig/utils/terminal.py,sha256=IlmOByfQG-vjhaFFxxzU5rWzP5_qUzmalRfuey3PAmc,11801
393
393
  machineconfig/utils/upgrade_packages.py,sha256=H96zVJEWXJW07nh5vhjuSCrPtXGqoUb7xeJsFYYdmCI,3330
394
394
  machineconfig/utils/ve.py,sha256=L-6PBXnQGXThiwWgheJMQoisAZOZA6SVCbGw2J-GFnI,2414
395
395
  machineconfig/utils/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
396
396
  machineconfig/utils/ai/generate_file_checklist.py,sha256=ajbmhcBToRugl75c_KZRq2XJumxKgIqQhyf7_YtF5q4,2729
397
397
  machineconfig/utils/cloud/onedrive/setup_oauth.py,sha256=ZTVkqgrwbV_EoPvyT8dyOTUE0ur3BW4sa9o6QYtt5Bo,2341
398
398
  machineconfig/utils/cloud/onedrive/transaction.py,sha256=m-aNcnWj_gfZVvJOSpkdIqjZxU_3nXx2CA-qKbQgP3I,26232
399
+ machineconfig/utils/files/ascii_art.py,sha256=cNJaJC07vx94fS44-tzgfbfBeCwXVrgpnWGBLUnfC38,5212
400
+ machineconfig/utils/files/headers.py,sha256=L54G11DfLadyZGyQXSQ7y8UI_tNvlld7zqP4qEAWL88,3647
401
+ machineconfig/utils/files/read.py,sha256=dyf-DDkLnCKgwmRH0Af4UtBIZh6iMUaYmjgJtdSGRFg,4744
399
402
  machineconfig/utils/installer_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
400
403
  machineconfig/utils/installer_utils/github_release_bulk.py,sha256=WJf_qZlF02SmIc6C7o1h4Gy4gAaJAfeAS8O9s2Itj-k,6535
401
- machineconfig/utils/installer_utils/installer.py,sha256=_XcatwArhwRepMYfaGYpjd-lqNGfijnjeZB8l4uKd-c,9266
402
- machineconfig/utils/installer_utils/installer_abc.py,sha256=9qtFt0_gz_VgaDCCVoXNiOgR42dRF1zU9054o135vs4,10797
404
+ machineconfig/utils/installer_utils/installer.py,sha256=H9wukQBSZDLlpB6Xn4Sa2hSV8iCUr9UQChcgOa3u-L8,9278
405
+ machineconfig/utils/installer_utils/installer_abc.py,sha256=VTHe5O3jA6k6rnUnXhgnEf6mVvkVQlEuXjzYLEDgEAs,11140
403
406
  machineconfig/utils/installer_utils/installer_class.py,sha256=fN4Nfqn4tlSfQGW52A_Ipi6GT6utC30ZuSj5WM_yxIY,20252
404
407
  machineconfig/utils/schemas/fire_agents/fire_agents_input.py,sha256=pTxvLzIpD5RF508lUUBBkWcc4V1B10J4ylvVgVGkcM0,2037
405
408
  machineconfig/utils/schemas/installer/installer_types.py,sha256=QClRY61QaduBPJoSpdmTIdgS9LS-RvE-QZ-D260tD3o,1214
406
409
  machineconfig/utils/schemas/layouts/layout_types.py,sha256=TcqlZdGVoH8htG5fHn1KWXhRdPueAcoyApppZsPAPto,2020
407
410
  machineconfig/utils/schemas/repos/repos_types.py,sha256=ECVr-3IVIo8yjmYmVXX2mnDDN1SLSwvQIhx4KDDQHBQ,405
408
- machineconfig-5.13.dist-info/METADATA,sha256=a6BFT3NbESfTyf5oY3DJv-eiv3Nn24gYHgrIRydpaN8,8030
409
- machineconfig-5.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
410
- machineconfig-5.13.dist-info/entry_points.txt,sha256=2afE1mw-o4MUlfxyX73SV02XaQI4SV_LdL2r6_CzhPU,1074
411
- machineconfig-5.13.dist-info/top_level.txt,sha256=porRtB8qms8fOIUJgK-tO83_FeH6Bpe12oUVC670teA,14
412
- machineconfig-5.13.dist-info/RECORD,,
411
+ machineconfig-5.15.dist-info/METADATA,sha256=8JyyiMszEzLFyVI_-3rScZA_eBYO8Jd8dPOj3FyGHjQ,8030
412
+ machineconfig-5.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
413
+ machineconfig-5.15.dist-info/entry_points.txt,sha256=2afE1mw-o4MUlfxyX73SV02XaQI4SV_LdL2r6_CzhPU,1074
414
+ machineconfig-5.15.dist-info/top_level.txt,sha256=porRtB8qms8fOIUJgK-tO83_FeH6Bpe12oUVC670teA,14
415
+ machineconfig-5.15.dist-info/RECORD,,