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

@@ -1,22 +1,18 @@
1
1
  """devops with emojis"""
2
2
 
3
- from machineconfig.utils.options import choose_from_options
3
+ from machineconfig.scripts.python.share_terminal import main as share_terminal_main
4
+ import machineconfig.scripts.python.devops_devapps_install as installer_entry_point
4
5
 
5
6
  from platform import system
6
- from typing import Optional, Literal, TypeAlias
7
7
  from rich.console import Console
8
8
  from rich.panel import Panel
9
9
  import typer
10
10
 
11
11
  console = Console()
12
- app = typer.Typer(help="🛠️ DevOps operations with emojis", invoke_without_command=True, no_args_is_help=True)
12
+ app = typer.Typer(help="🛠️ DevOps operations with emojis", no_args_is_help=True)
13
13
 
14
- BOX_WIDTH = 150 # width for box drawing
15
-
16
-
17
- COMMANDS: TypeAlias = Literal["🔄 UPDATE essential repos", "⚙️ DEVAPPS install", "🔗 SYMLINKS, SHELL PROFILE, FONT, TERMINAL SETTINGS.", "🆕 SYMLINKS new", "🔑 SSH add pub key to this machine", "🗝️ SSH add identity (private key) to this machine", "🔐 SSH use key pair to connect two machines", "📡 SSH setup", "🐧 SSH setup wsl", "💾 BACKUP", "📥 RETRIEVE", "⏰ SCHEDULER"]
18
14
 
19
- options_list = list(COMMANDS.__args__)
15
+ BOX_WIDTH = 150 # width for box drawing
20
16
 
21
17
 
22
18
  @app.command()
@@ -27,12 +23,9 @@ def update():
27
23
  helper.main()
28
24
 
29
25
 
30
- @app.command()
31
- def install():
32
- """⚙️ DEVAPPS install"""
33
- console.print(Panel("⚙️ Installing development applications...", width=BOX_WIDTH, border_style="blue"))
34
- import machineconfig.scripts.python.devops_devapps_install as helper
35
- helper.main(which=None)
26
+ app.command(name="install", help="📦 Install essential packages")(installer_entry_point.main)
27
+ app.command(name="share-terminal", help="📡 Share terminal via web browser")(share_terminal_main)
28
+
36
29
 
37
30
 
38
31
  @app.command()
@@ -123,55 +116,12 @@ def scheduler():
123
116
  # from machineconfig.scripts.python.scheduler import main as helper
124
117
  # helper()
125
118
 
126
-
127
- def args_parser():
128
- app()
129
-
130
-
131
- @app.command()
132
- def interactive(which: Optional[COMMANDS] = None):
133
- """🛠️ Interactive menu mode (legacy)"""
134
- console.print(Panel("🚀 Initializing DevOps operation...", width=BOX_WIDTH, border_style="blue"))
135
- options = options_list
136
- if which is None:
137
- try:
138
- choice_key = choose_from_options(msg="", options=options, header="🛠️ DEVOPS", default=options[0], multi=False, fzf=False)
139
- except KeyboardInterrupt:
140
- console.print(Panel("❌ Operation cancelled by user", title_align="left", border_style="red", width=BOX_WIDTH))
141
- return
142
- else:
143
- choice_key = which
144
-
145
- console.print(Panel(f"🔧 SELECTED OPERATION\n{choice_key}", title_align="left", border_style="green", width=BOX_WIDTH))
146
-
147
- if choice_key == "🔄 UPDATE essential repos":
148
- update()
149
- elif choice_key == "⚙️ DEVAPPS install":
150
- install()
151
- elif choice_key == "🆕 SYMLINKS new":
152
- symlinks_new()
153
- elif choice_key == "🔗 SYMLINKS, SHELL PROFILE, FONT, TERMINAL SETTINGS.":
154
- symlinks()
155
- elif choice_key == "🔑 SSH add pub key to this machine":
156
- ssh_add_key()
157
- elif choice_key == "🔐 SSH use key pair to connect two machines":
158
- ssh_connect()
159
- elif choice_key == "🗝️ SSH add identity (private key) to this machine":
160
- ssh_add_identity()
161
- elif choice_key == "📡 SSH setup":
162
- ssh_setup()
163
- elif choice_key == "🐧 SSH setup wsl":
164
- ssh_setup_wsl()
165
- elif choice_key == "💾 BACKUP":
166
- backup()
167
- elif choice_key == "📥 RETRIEVE":
168
- retrieve()
169
- elif choice_key == "⏰ SCHEDULER":
170
- scheduler()
171
- else:
172
- console.print(Panel("❌ ERROR: Invalid choice", title_align="left", border_style="red", width=BOX_WIDTH))
173
- raise ValueError(f"Unimplemented choice: {choice_key}")
119
+ @app.command("ia")
120
+ def interactive():
121
+ """🤖 INTERACTIVE configuration of machine."""
122
+ from machineconfig.scripts.python.interactive import main
123
+ main()
174
124
 
175
125
 
176
126
  if __name__ == "__main__":
177
- args_parser()
127
+ pass
@@ -1,16 +1,11 @@
1
1
  """Devops Devapps Install"""
2
2
 
3
- # import subprocess
4
3
  import typer
5
4
  from rich.progress import Progress, SpinnerColumn, TextColumn
6
- from machineconfig.utils.source_of_truth import LIBRARY_ROOT
7
- from machineconfig.utils.options import choose_from_options
8
- from machineconfig.utils.installer import get_installers, install_all
9
- from machineconfig.utils.schemas.installer.installer_types import get_normalized_arch, get_os_name
10
5
  from platform import system
11
- from typing import Any, Optional, Literal, TypeAlias, get_args, Annotated
6
+ from typing import Optional, Literal, TypeAlias, cast, get_args, Annotated
12
7
 
13
- WHICH_CAT: TypeAlias = Literal["essentials", "essentialsDev", "systymPackages", "precheckedPackages"]
8
+ WHICH_CAT: TypeAlias = Literal["essentials", "essentialsDev", "systymPackages", "precheckedPackages", "ia"]
14
9
 
15
10
 
16
11
  def main_with_parser():
@@ -20,11 +15,12 @@ def main_with_parser():
20
15
  app()
21
16
 
22
17
 
23
- def main(which: Annotated[Optional[str], typer.Argument(help=f"Choose a category or program to install, {list(get_args(WHICH_CAT))} or <program_name>")]) -> None:
24
- if which is not None and which in get_args(WHICH_CAT): # install by category
18
+ def main(which: Annotated[Optional[str], typer.Argument(help=f"Choose a category or program to install, {list(get_args(WHICH_CAT))} or <program_name> or list of programs names separated by comma.")]) -> None:
19
+ if which in get_args(WHICH_CAT): # install by category
25
20
  return get_programs_by_category(program_name=which) # type: ignore
26
-
27
- if which is not None: # install by name
21
+ from machineconfig.utils.schemas.installer.installer_types import get_normalized_arch, get_os_name
22
+ from machineconfig.utils.installer import get_installers
23
+ if which != "ia" and which is not None: # install by name
28
24
  total_messages: list[str] = []
29
25
  for a_which in which.split(",") if type(which) == str else which:
30
26
  all_installers = get_installers(os=get_os_name(), arch=get_normalized_arch(), which_cats=["GITHUB_ESSENTIAL", "CUSTOM_ESSENTIAL", "GITHUB_DEV", "CUSTOM_DEV"])
@@ -53,6 +49,12 @@ def main(which: Annotated[Optional[str], typer.Argument(help=f"Choose a category
53
49
  print(a_message)
54
50
  return None
55
51
 
52
+
53
+
54
+ def install_interactively():
55
+ from machineconfig.utils.options import choose_from_options
56
+ from machineconfig.utils.schemas.installer.installer_types import get_normalized_arch, get_os_name
57
+ from machineconfig.utils.installer import get_installers
56
58
  installers = get_installers(os=get_os_name(), arch=get_normalized_arch(), which_cats=["GITHUB_ESSENTIAL", "CUSTOM_ESSENTIAL", "GITHUB_DEV", "CUSTOM_DEV"])
57
59
  # Check installed programs with progress indicator
58
60
  with Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}")) as progress:
@@ -84,8 +86,7 @@ def main(which: Annotated[Optional[str], typer.Argument(help=f"Choose a category
84
86
  if a_program_name.startswith("📦 "):
85
87
  category_name = a_program_name[2:] # Remove "📦 " prefix
86
88
  if category_name in get_args(WHICH_CAT):
87
- shell_commands = get_programs_by_category(program_name=category_name) # type: ignore
88
- total_commands += "\n" + shell_commands
89
+ get_programs_by_category(program_name=cast(WHICH_CAT, category_name))
89
90
  else:
90
91
  # Handle individual installer options
91
92
  installer_idx = installer_options.index(a_program_name)
@@ -112,15 +113,18 @@ def get_programs_by_category(program_name: WHICH_CAT):
112
113
  ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
113
114
  ┃ 📦 Installing Category: {program_name}
114
115
  ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━""")
116
+ from machineconfig.utils.source_of_truth import LIBRARY_ROOT
117
+ from machineconfig.utils.installer import get_installers, install_all
118
+ from machineconfig.utils.installer_utils.installer_abc import parse_apps_installer_linux, parse_apps_installer_windows
119
+ from machineconfig.utils.schemas.installer.installer_types import get_normalized_arch, get_os_name
120
+ from machineconfig.utils.options import choose_from_options
115
121
  match program_name:
116
122
  case "essentials":
117
123
  installers_ = get_installers(os=get_os_name(), arch=get_normalized_arch(), which_cats=["GITHUB_ESSENTIAL", "CUSTOM_ESSENTIAL"])
118
124
  install_all(installers=installers_)
119
- program = ""
120
125
  case "essentialsDev":
121
126
  installers_ = get_installers(os=get_os_name(), arch=get_normalized_arch(), which_cats=["GITHUB_DEV", "CUSTOM_DEV", "GITHUB_ESSENTIAL", "CUSTOM_ESSENTIAL"])
122
127
  install_all(installers=installers_)
123
- program = ""
124
128
  case "systymPackages":
125
129
  if system() == "Windows":
126
130
  options_system = parse_apps_installer_windows(LIBRARY_ROOT.joinpath("setup_windows/apps.ps1").read_text(encoding="utf-8"))
@@ -141,79 +145,14 @@ def get_programs_by_category(program_name: WHICH_CAT):
141
145
  if sub_program.startswith("#winget"):
142
146
  sub_program = sub_program[1:]
143
147
  program += "\n" + sub_program
144
- # case "CHOOSE": raise NotImplementedError("CHOOSE is not implemented yet.")
145
- # case "OtherDevApps":
146
- # installers = get_installers(dev=True, system=system())
147
- # options__: list[str] = [x.get_description() for x in tqdm(installers, desc="Checking installed programs")]
148
- # program_names = choose_from_options(multi=True, msg="", options=sorted(options__) + ["all"], header="CHOOSE DEV APP")
149
- # if "all" in program_names: program_names = options__
150
- # program = ""
151
- # print("Installing:")
152
- # L(program_names).print()
153
- # for name in program_names:
154
- # try:
155
- # idx = options__.index(name)
156
- # except ValueError as ve:
157
- # print(f"{name=}")
158
- # print(f"{options__=}")
159
- # raise ve
160
- # print(f"Installing {name}")
161
- # sub_program = installers[idx].install_robust(version=None) # finish the task
162
-
148
+ case "ia":
149
+ install_interactively()
163
150
  case "precheckedPackages":
164
151
  # from machineconfig.jobs.python.check_installations import precheckedPackages
165
152
  # ci = precheckedPackages()
166
153
  # ci.download_safe_apps(name="essentials")
167
154
  # program = ""
168
155
  raise NotImplementedError("precheckedPackages is not implemented yet.")
169
- return program
170
-
171
-
172
- def parse_apps_installer_linux(txt: str) -> dict[str, Any]:
173
- txts = txt.split("""yes '' | sed 3q; echo "----------------------------- installing """)
174
- res = {}
175
- for chunk in txts[1:]:
176
- try:
177
- k = chunk.split("----")[0].rstrip().lstrip()
178
- v = "\n".join(chunk.split("\n")[1:])
179
- res[k] = v
180
- except IndexError as e:
181
- print(f"""
182
- ❌ Error parsing chunk:
183
- {"-" * 50}
184
- {chunk}
185
- {"-" * 50}""")
186
- raise e
187
- return res
188
-
189
-
190
- def parse_apps_installer_windows(txt: str) -> dict[str, Any]:
191
- chunks: list[str] = []
192
- for idx, item in enumerate(txt.split(sep="winget install")):
193
- if idx == 0:
194
- continue
195
- if idx == 1:
196
- chunks.append(item)
197
- else:
198
- chunks.append("winget install" + item)
199
- # progs = L(txt.splitlines()).filter(lambda x: x.startswith("winget ") or x.startswith("#winget"))
200
- res: dict[str, str] = {}
201
- for a_chunk in chunks:
202
- try:
203
- name = a_chunk.split("--name ")[1]
204
- if "--Id" not in name:
205
- print(f"⚠️ Warning: {name} does not have an Id, skipping")
206
- continue
207
- name = name.split(" --Id ", maxsplit=1)[0].strip('"').strip('"')
208
- res[name] = a_chunk
209
- except IndexError as e:
210
- print(f"""
211
- ❌ Error parsing chunk:
212
- {"-" * 50}
213
- {a_chunk}
214
- {"-" * 50}""")
215
- raise e
216
- return res
217
156
 
218
157
 
219
158
  if __name__ == "__main__":
@@ -19,6 +19,8 @@ for better user experience with checkbox selections.
19
19
 
20
20
  import subprocess
21
21
  import sys
22
+ from pathlib import Path
23
+ from platform import system
22
24
 
23
25
  import questionary
24
26
  from questionary import Choice
@@ -39,36 +41,23 @@ def run_command(command: str, description: str) -> bool:
39
41
  except subprocess.CalledProcessError as e:
40
42
  console.print(f"❌ Error executing command: {e}", style="bold red")
41
43
  return False
42
-
43
-
44
44
  def display_header() -> None:
45
45
  """Display the script header."""
46
46
  header_text = Text("MACHINE CONFIGURATION", style="bold magenta")
47
47
  subtitle_text = Text("Interactive Installation Script", style="italic cyan")
48
- console.print(Panel(
49
- f"📦 {header_text}\n{subtitle_text}",
50
- border_style="blue",
51
- padding=(1, 2)
52
- ))
53
-
54
-
48
+ console.print(Panel(f"📦 {header_text}\n{subtitle_text}", border_style="blue", padding=(1, 2)))
55
49
  def display_completion_message() -> None:
56
50
  """Display completion message."""
57
51
  completion_text = Text("INSTALLATION COMPLETE", style="bold green")
58
52
  subtitle_text = Text("System setup finished successfully", style="italic green")
59
- console.print(Panel(
60
- f"✨ {completion_text}\n{subtitle_text}\n\n🎉 Your system has been configured successfully!\n🔄 You may need to reboot to apply all changes.",
61
- border_style="green",
62
- padding=(1, 2)
63
- ))
64
-
65
-
53
+ 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)))
66
54
  def display_dotfiles_instructions() -> None:
67
55
  """Display instructions for dotfiles migration."""
68
56
  header_text = Text("DOTFILES MIGRATION", style="bold yellow")
69
57
  subtitle_text = Text("Configuration transfer options", style="italic yellow")
70
-
71
- instructions = """🖱️ [bold blue]Method 1: USING MOUSE WITHOUT KB OR BROWSER SHARE[/bold blue]
58
+
59
+ instructions = """
60
+ 🖱️ [bold blue]Method 1: USING MOUSE WITHOUT KB OR BROWSER SHARE[/bold blue]
72
61
  On original machine, run:
73
62
  [dim]cd ~/dotfiles/creds/msc
74
63
  easy-sharing . --password rew --username al[/dim]
@@ -84,172 +73,194 @@ def display_dotfiles_instructions() -> None:
84
73
  [dim]cd ~
85
74
  cloud_copy SHARE_URL . --config ss[/dim]
86
75
  (requires symlinks to be created first)"""
76
+
77
+ console.print(Panel(f"📂 {header_text}\n{subtitle_text}\n\n{instructions}", border_style="yellow", padding=(1, 2)))
78
+
79
+
80
+ def install_windows_desktop_apps() -> bool:
81
+ """Install Windows desktop applications using winget."""
82
+ if system() != "Windows":
83
+ console.print("❌ This function is only available on Windows systems.", style="bold red")
84
+ return False
87
85
 
88
- console.print(Panel(
89
- f"📂 {header_text}\n{subtitle_text}\n\n{instructions}",
90
- border_style="yellow",
91
- padding=(1, 2)
92
- ))
86
+ console.print(Panel("💻 [bold cyan]WINDOWS DESKTOP APPS[/bold cyan]\n[italic]Installing Brave, Windows Terminal, PowerShell, and VSCode[/italic]", border_style="cyan"))
87
+
88
+ # Install winget applications
89
+ winget_commands = [
90
+ ('winget install --no-upgrade --name "Windows Terminal" --Id "Microsoft.WindowsTerminal" --source winget --scope user --accept-package-agreements --accept-source-agreements', "Installing Windows Terminal"),
91
+ ('winget install --no-upgrade --name "Powershell" --Id "Microsoft.PowerShell" --source winget --scope user --accept-package-agreements --accept-source-agreements', "Installing PowerShell"),
92
+ ('winget install --no-upgrade --name "Brave" --Id "Brave.Brave" --source winget --scope user --accept-package-agreements --accept-source-agreements', "Installing Brave Browser"),
93
+ ('winget install --no-upgrade --name "Microsoft Visual Studio Code" --Id "Microsoft.VisualStudioCode" --source winget --scope user --accept-package-agreements --accept-source-agreements', "Installing Visual Studio Code"),
94
+ ]
95
+
96
+ success = True
97
+ for command, description in winget_commands:
98
+ if not run_command(command, description):
99
+ success = False
100
+
101
+ # Install Nerd Fonts via Python
102
+ console.print("🔧 Installing Nerd Fonts", style="bold cyan")
103
+ try:
104
+ from machineconfig.jobs.installer.custom_dev.nerfont_windows_helper import install_nerd_fonts
105
+ install_nerd_fonts()
106
+ console.print("✅ Nerd Fonts installed successfully", style="bold green")
107
+ except Exception as e:
108
+ console.print(f"❌ Error installing Nerd Fonts: {e}", style="bold red")
109
+ success = False
110
+
111
+ # Set Windows Terminal settings via Python
112
+ console.print("🔧 Setting Windows Terminal settings", style="bold cyan")
113
+ try:
114
+ from machineconfig.setup_windows.wt_and_pwsh.set_wt_settings import main as set_wt_settings_main
115
+ set_wt_settings_main()
116
+ console.print("✅ Windows Terminal settings configured successfully", style="bold green")
117
+ except Exception as e:
118
+ console.print(f"❌ Error setting Windows Terminal settings: {e}", style="bold red")
119
+ success = False
120
+
121
+ return success
93
122
 
94
123
 
95
124
  def get_installation_choices() -> list[str]:
96
125
  """Get user choices for installation options."""
97
126
  choices = [
98
- Choice(value="install_apps", title="📥 Install Apps - Install base system applications", checked=False),
99
- Choice(value="upgrade_system", title="🔄 Upgrade System Packages - Update all system packages", checked=False),
100
- Choice(value="install_uv_repos", title="🐍 Install UV and Repos - Set up Python environment and repositories", checked=False),
101
- Choice(value="install_ssh_server", title="🔒 Install SSH Server - Set up remote access", checked=False),
102
- Choice(value="create_symlinks", title="🔗 Create Symlinks - Set up configuration symlinks (finish dotfiles transfer first)", checked=False),
103
- Choice(value="install_cli_apps", title="⚡ Install CLI Apps - Command-line tools installation", checked=False),
104
- Choice(value="install_dev_tools", title="🛠️ Install Development Tools - rust, libssl-dev, ffmpeg, wezterm, brave, code", checked=False),
127
+ Choice(value="install_apps", title="📥 Install Apps - Install base system applications", checked=False),
128
+ Choice(value="upgrade_system", title="🔄 Upgrade System Packages - Update all system packages", checked=False),
129
+ Choice(value="install_uv_repos", title="🐍 Install Repos - Set up Python environment and repositories permanently.", checked=False),
130
+ Choice(value="install_ssh_server", title="🔒 Install SSH Server - Set up remote access", checked=False),
131
+ Choice(value="create_symlinks", title="🔗 Create Symlinks - Set up configuration symlinks (finish dotfiles transfer first)", checked=False),
132
+ Choice(value="install_cli_apps", title="⚡ Install CLI Apps - Command-line tools installation", checked=False),
133
+ Choice(value="install_dev_tools", title="🛠️ Install Development Tools - rust, libssl-dev, ffmpeg, wezterm, brave, code", checked=False),
105
134
  Choice(value="retrieve_repositories", title="📚 Retrieve Repositories - Clone repositories to ~/code", checked=False),
106
- Choice(value="retrieve_data", title="💾 Retrieve Data - Backup restoration", checked=False),
107
- Choice(value="install_ascii_art", title="🎨 Install ASCII Art Libraries - Terminal visualization tools", checked=False),
135
+ Choice(value="retrieve_data", title="💾 Retrieve Data - Backup restoration", checked=False),
136
+ Choice(value="install_ascii_art", title="🎨 Install ASCII Art Libraries - Terminal visualization tools", checked=False),
108
137
  ]
109
-
110
- selected = questionary.checkbox(
111
- "Select the installation options you want to execute:",
112
- choices=choices,
113
- show_description=True,
114
- ).ask()
115
-
138
+ # Add Windows-specific options
139
+ if system() == "Windows":
140
+ choices.append(Choice(value="install_windows_desktop", title="💻 Install Windows Desktop Apps - Brave, Windows Terminal, PowerShell, VSCode (Windows only)", checked=False))
141
+ selected = questionary.checkbox("Select the installation options you want to execute:", choices=choices, show_description=True).ask()
116
142
  return selected or []
117
143
 
118
144
 
119
145
  def execute_installations(selected_options: list[str]) -> None:
120
146
  """Execute the selected installation options."""
121
147
  # Always start with VE setup
122
- console.print(Panel(
123
- "🐍 [bold green]PYTHON ENVIRONMENT[/bold green]\n[italic]Setting up base virtual environment[/italic]",
124
- border_style="green"
125
- ))
126
- run_command(
127
- "curl https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_linux/ve.sh | bash",
128
- "Setting up base virtual environment"
129
- )
130
-
148
+ console.print(Panel("🐍 [bold green]PYTHON ENVIRONMENT[/bold green]\n[italic]Setting up base virtual environment[/italic]", border_style="green"))
149
+ run_command("curl https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_linux/ve.sh | bash", "Setting up base virtual environment")
150
+
131
151
  if "install_apps" in selected_options:
132
- console.print(Panel(
133
- "📦 [bold blue]APPLICATIONS[/bold blue]\n[italic]Installing base system applications[/italic]",
134
- border_style="blue"
135
- ))
136
- run_command(
137
- "curl https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_linux/apps.sh | bash",
138
- "Installing base system applications"
139
- )
140
-
152
+ console.print(Panel("📦 [bold blue]APPLICATIONS[/bold blue]\n[italic]Installing base system applications[/italic]", border_style="blue"))
153
+ if system() == "Windows":
154
+ # Windows: Use PowerShell to execute local apps.ps1 script
155
+ from machineconfig import setup_windows as module
156
+ script = Path(module.__file__).parent / "apps.ps1"
157
+ run_command(f'powershell -ExecutionPolicy Bypass -File "{script}"', "Installing Windows applications")
158
+ else:
159
+ # Linux: Use existing bash script approach
160
+ from machineconfig import setup_linux as module
161
+ script = Path(module.__file__).parent / "apps.sh"
162
+ run_command(f"bash {script}", "Installing Linux base system applications")
163
+
141
164
  if "upgrade_system" in selected_options:
142
- console.print(Panel(
143
- "🔄 [bold magenta]SYSTEM UPDATE[/bold magenta]\n[italic]Package management[/italic]",
144
- border_style="magenta"
145
- ))
165
+ console.print(Panel("🔄 [bold magenta]SYSTEM UPDATE[/bold magenta]\n[italic]Package management[/italic]", border_style="magenta"))
146
166
  run_command("sudo nala upgrade -y", "Upgrading system packages")
147
-
167
+
148
168
  if "install_uv_repos" in selected_options:
149
- console.print(Panel(
150
- "🐍 [bold green]PYTHON ENVIRONMENT[/bold green]\n[italic]Virtual environment setup[/italic]",
151
- border_style="green"
152
- ))
153
- run_command(
154
- "curl https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_linux/repos.sh | bash",
155
- "Setting up Python environment and repositories"
156
- )
157
-
169
+ console.print(Panel("🐍 [bold green]PYTHON ENVIRONMENT[/bold green]\n[italic]Virtual environment setup[/italic]", border_style="green"))
170
+ from machineconfig import setup_linux as module
171
+ script = Path(module.__file__).parent / "repos.sh"
172
+ run_command(f"bash {script}", "Setting up Python environment and repositories")
173
+
158
174
  if "install_ssh_server" in selected_options:
159
- console.print(Panel(
160
- "🔒 [bold red]SSH SERVER[/bold red]\n[italic]Remote access setup[/italic]",
161
- border_style="red"
162
- ))
163
- run_command("sudo nala install openssh-server -y", "Installing SSH server")
164
-
165
- # Always display dotfiles instructions if symlinks are selected
175
+ console.print(Panel("🔒 [bold red]SSH SERVER[/bold red]\n[italic]Remote access setup[/italic]", border_style="red"))
176
+ if system() == "Windows":
177
+ powershell_script = """Write-Host "🔧 Installing and configuring SSH server..."
178
+ Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
179
+ Start-Service sshd
180
+ Set-Service -Name sshd -StartupType 'Automatic'"""
181
+ run_command(f'powershell -Command "{powershell_script}"', "Installing and configuring SSH server")
182
+ else:
183
+ run_command("sudo nala install openssh-server -y", "Installing SSH server")
184
+
166
185
  if "create_symlinks" in selected_options:
167
186
  display_dotfiles_instructions()
168
-
169
- dotfiles_ready = questionary.confirm(
170
- "📂 Have you finished copying dotfiles?",
171
- default=True
172
- ).ask()
173
-
187
+ dotfiles_ready = questionary.confirm("📂 Have you finished copying dotfiles?", default=True).ask()
174
188
  if dotfiles_ready:
175
- console.print(Panel(
176
- "🔗 [bold cyan]SYMLINK CREATION[/bold cyan]\n[italic]Configuration setup[/italic]",
177
- border_style="cyan"
178
- ))
179
- run_command(
180
- "uv run --python 3.13 --with machineconfig python -m fire machineconfig.profile.create main_symlinks --choice=all",
181
- "Creating symlinks"
182
- )
189
+ console.print(Panel("🔗 [bold cyan]SYMLINK CREATION[/bold cyan]\n[italic]Configuration setup[/italic]", border_style="cyan"))
190
+ console.print("🔧 Creating symlinks", style="bold cyan")
191
+ try:
192
+ from machineconfig.profile.create import main_symlinks
193
+ main_symlinks()
194
+ console.print(" Symlinks created successfully", style="bold green")
195
+ except Exception as e:
196
+ console.print(f"❌ Error creating symlinks: {e}", style="bold red")
183
197
  run_command("sudo chmod 600 $HOME/.ssh/*", "Setting SSH key permissions")
184
198
  run_command("sudo chmod 700 $HOME/.ssh", "Setting SSH directory permissions")
185
199
  else:
186
200
  console.print("⏭️ Skipping symlink creation - finish dotfiles transfer first", style="yellow")
187
-
201
+
188
202
  if "install_cli_apps" in selected_options:
189
- console.print(Panel(
190
- " [bold bright_yellow]CLI APPLICATIONS[/bold bright_yellow]\n[italic]Command-line tools installation[/italic]",
191
- border_style="bright_yellow"
192
- ))
193
- run_command(
194
- "uv run --python 3.13 --with machineconfig python -m fire machineconfig.scripts.python.devops_devapps_install main --which=essentials",
195
- "Installing CLI applications"
196
- )
203
+ console.print(Panel("⚡ [bold bright_yellow]CLI APPLICATIONS[/bold bright_yellow]\n[italic]Command-line tools installation[/italic]", border_style="bright_yellow"))
204
+ console.print("🔧 Installing CLI applications", style="bold cyan")
205
+ try:
206
+ from machineconfig.scripts.python.devops_devapps_install import main as devops_devapps_install_main
207
+ devops_devapps_install_main(which="essentials")
208
+ console.print(" CLI applications installed successfully", style="bold green")
209
+ except Exception as e:
210
+ console.print(f"❌ Error installing CLI applications: {e}", style="bold red")
197
211
  run_command(". $HOME/.bashrc", "Reloading bash configuration")
198
-
212
+
199
213
  if "install_dev_tools" in selected_options:
200
- console.print(Panel(
201
- "🛠️ [bold bright_blue]DEVELOPMENT TOOLS[/bold bright_blue]\n[italic]Software development packages[/italic]",
202
- border_style="bright_blue"
203
- ))
204
- run_command(
205
- "(curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh) || true",
206
- "Installing Rust toolchain"
207
- )
214
+ console.print(Panel("🛠️ [bold bright_blue]DEVELOPMENT TOOLS[/bold bright_blue]\n[italic]Software development packages[/italic]", border_style="bright_blue"))
215
+ run_command("(curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh) || true", "Installing Rust toolchain")
208
216
  run_command("sudo nala install libssl-dev -y", "Installing libssl-dev")
209
217
  run_command("sudo nala install ffmpeg -y", "Installing ffmpeg")
210
- run_command(
211
- "uv run --python 3.13 --with machineconfig python -m fire machineconfig.scripts.python.devops_devapps_install main --which=wezterm,brave,code",
212
- "Installing development applications"
213
- )
214
-
218
+ console.print("🔧 Installing development applications", style="bold cyan")
219
+ try:
220
+ from machineconfig.scripts.python.devops_devapps_install import main as devops_devapps_install_main
221
+ devops_devapps_install_main(which="wezterm,brave,code")
222
+ console.print("✅ Development applications installed successfully", style="bold green")
223
+ except Exception as e:
224
+ console.print(f"❌ Error installing development applications: {e}", style="bold red")
225
+
215
226
  if "retrieve_repositories" in selected_options:
216
- console.print(Panel(
217
- "📚 [bold bright_magenta]REPOSITORIES[/bold bright_magenta]\n[italic]Project code retrieval[/italic]",
218
- border_style="bright_magenta"
219
- ))
220
- run_command("repos ~/code --clone --cloud odg1", "Cloning repositories")
221
-
227
+ console.print(Panel("📚 [bold bright_magenta]REPOSITORIES[/bold bright_magenta]\n[italic]Project code retrieval[/italic]", border_style="bright_magenta"))
228
+ from machineconfig.scripts.python import repos as module
229
+ module.main(directory=str(Path.home() / "code"), clone=True, cloud="odg1")
230
+
222
231
  if "retrieve_data" in selected_options:
223
- console.print(Panel(
224
- "💾 [bold bright_cyan]DATA RETRIEVAL[/bold bright_cyan]\n[italic]Backup restoration[/italic]",
225
- border_style="bright_cyan"
226
- ))
227
- run_command(
228
- "uv run --python 3.13 --with machineconfig python -m fire machineconfig.scripts.python.devops_backup_retrieve main --direction=RETRIEVE",
229
- "Retrieving backup data"
230
- )
231
-
232
+ console.print(Panel("💾 [bold bright_cyan]DATA RETRIEVAL[/bold bright_cyan]\n[italic]Backup restoration[/italic]", border_style="bright_cyan"))
233
+ console.print("🔧 Retrieving backup data", style="bold cyan")
234
+ try:
235
+ from machineconfig.scripts.python.devops_backup_retrieve import main_backup_retrieve
236
+ main_backup_retrieve(direction="RETRIEVE")
237
+ console.print(" Backup data retrieved successfully", style="bold green")
238
+ except Exception as e:
239
+ console.print(f"❌ Error retrieving backup data: {e}", style="bold red")
240
+
232
241
  if "install_ascii_art" in selected_options:
233
- console.print(Panel(
234
- "🎨 [bold bright_green]ASCII ART[/bold bright_green]\n[italic]Terminal visualization tools[/italic]",
235
- border_style="bright_green"
236
- ))
237
- run_command("curl bit.ly/cfgasciiartlinux -L | sudo bash", "Installing ASCII art libraries")
242
+ console.print(Panel("🎨 [bold bright_green]ASCII ART[/bold bright_green]\n[italic]Terminal visualization tools[/italic]", border_style="bright_green"))
243
+ from machineconfig import setup_linux as module
244
+ script = Path(module.__file__).parent / "web_shortcuts" / "ascii_art.sh"
245
+ run_command(f"bash {script}", "Installing ASCII art libraries")
246
+
247
+ if "install_windows_desktop" in selected_options:
248
+ install_windows_desktop_apps()
238
249
 
239
250
 
240
251
  def main() -> None:
241
252
  """Main function to run the interactive installation."""
242
253
  display_header()
243
- selected_options = get_installation_choices()
254
+ selected_options = get_installation_choices()
244
255
  if not selected_options:
245
256
  console.print("❌ No options selected. Exiting...", style="bold red")
246
257
  sys.exit(0)
247
258
  console.print(f"\n✅ Selected options: {', '.join(selected_options)}", style="bold green")
248
- proceed = questionary.confirm("🚀 Proceed with installation?", default=True).ask()
259
+ proceed = questionary.confirm("🚀 Proceed with installation?", default=True).ask()
249
260
  if not proceed:
250
261
  console.print("❌ Installation cancelled.", style="bold red")
251
262
  sys.exit(0)
252
- execute_installations(selected_options)
263
+ execute_installations(selected_options)
253
264
  display_completion_message()
254
265
 
255
266
 
@@ -60,7 +60,6 @@ def main(
60
60
  clone_repos(spec_path=repos_root, preferred_remote=None, checkout_branch_flag=checkout_to_branch, checkout_commit_flag=checkout)
61
61
 
62
62
  elif all or commit or pull or push:
63
- # Use the new helper function for git operations
64
63
  perform_git_operations(
65
64
  repos_root=repos_root,
66
65
  pull=pull or all,