linwin 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. linwin-0.4.0/.gitignore +13 -0
  2. linwin-0.4.0/LICENSE +21 -0
  3. linwin-0.4.0/PKG-INFO +152 -0
  4. linwin-0.4.0/README.md +123 -0
  5. linwin-0.4.0/config.json +50 -0
  6. linwin-0.4.0/linwin/__init__.py +1 -0
  7. linwin-0.4.0/linwin/__main__.py +19 -0
  8. linwin-0.4.0/linwin/icons/linwin.ico +0 -0
  9. linwin-0.4.0/linwin/icons/linwin.png +0 -0
  10. linwin-0.4.0/linwin/linux/__init__.py +0 -0
  11. linwin-0.4.0/linwin/linux/__main__.py +195 -0
  12. linwin-0.4.0/linwin/linux/app.py +15 -0
  13. linwin-0.4.0/linwin/linux/screens/__init__.py +0 -0
  14. linwin-0.4.0/linwin/linux/screens/config_editor.py +91 -0
  15. linwin-0.4.0/linwin/linux/screens/setup.py +195 -0
  16. linwin-0.4.0/linwin/linux/screens/verify.py +105 -0
  17. linwin-0.4.0/linwin/linux/screens/welcome.py +166 -0
  18. linwin-0.4.0/linwin/linux/tasks/__init__.py +0 -0
  19. linwin-0.4.0/linwin/linux/tasks/apt.py +41 -0
  20. linwin-0.4.0/linwin/linux/tasks/snaps.py +51 -0
  21. linwin-0.4.0/linwin/linux/tasks/systemd.py +45 -0
  22. linwin-0.4.0/linwin/linux/tasks/wslg.py +45 -0
  23. linwin-0.4.0/linwin/linux/tasks/xrdp.py +324 -0
  24. linwin-0.4.0/linwin/shared/__init__.py +0 -0
  25. linwin-0.4.0/linwin/shared/base_app.py +67 -0
  26. linwin-0.4.0/linwin/shared/config.py +322 -0
  27. linwin-0.4.0/linwin/shared/headless_protocol.py +74 -0
  28. linwin-0.4.0/linwin/shared/launcher.py +104 -0
  29. linwin-0.4.0/linwin/shared/setup_logging.py +77 -0
  30. linwin-0.4.0/linwin/shared/subprocess_runner.py +164 -0
  31. linwin-0.4.0/linwin/shared/task_result.py +19 -0
  32. linwin-0.4.0/linwin/shared/theme.py +133 -0
  33. linwin-0.4.0/linwin/shared/verify_checks.py +83 -0
  34. linwin-0.4.0/linwin/shared/widgets.py +346 -0
  35. linwin-0.4.0/linwin/windows/__init__.py +0 -0
  36. linwin-0.4.0/linwin/windows/__main__.py +45 -0
  37. linwin-0.4.0/linwin/windows/app.py +168 -0
  38. linwin-0.4.0/linwin/windows/screens/__init__.py +0 -0
  39. linwin-0.4.0/linwin/windows/screens/config_editor.py +135 -0
  40. linwin-0.4.0/linwin/windows/screens/drive_picker.py +140 -0
  41. linwin-0.4.0/linwin/windows/screens/launcher.py +223 -0
  42. linwin-0.4.0/linwin/windows/screens/setup.py +423 -0
  43. linwin-0.4.0/linwin/windows/screens/setup_proposal.py +143 -0
  44. linwin-0.4.0/linwin/windows/screens/status.py +286 -0
  45. linwin-0.4.0/linwin/windows/screens/verify.py +146 -0
  46. linwin-0.4.0/linwin/windows/tasks/__init__.py +0 -0
  47. linwin-0.4.0/linwin/windows/tasks/auto_config.py +85 -0
  48. linwin-0.4.0/linwin/windows/tasks/drive_scan.py +139 -0
  49. linwin-0.4.0/linwin/windows/tasks/features.py +87 -0
  50. linwin-0.4.0/linwin/windows/tasks/full_verify.py +167 -0
  51. linwin-0.4.0/linwin/windows/tasks/health_check.py +54 -0
  52. linwin-0.4.0/linwin/windows/tasks/linux_invoke.py +29 -0
  53. linwin-0.4.0/linwin/windows/tasks/state.py +84 -0
  54. linwin-0.4.0/linwin/windows/tasks/validators.py +168 -0
  55. linwin-0.4.0/linwin/windows/tasks/wsl_config.py +72 -0
  56. linwin-0.4.0/linwin/windows/tasks/wsl_install.py +204 -0
  57. linwin-0.4.0/pyproject.toml +54 -0
  58. linwin-0.4.0/run.bat +12 -0
  59. linwin-0.4.0/scripts/prompts.md +13 -0
  60. linwin-0.4.0/scripts/publish.bat +49 -0
  61. linwin-0.4.0/scripts/run_claude.bat +4 -0
  62. linwin-0.4.0/scripts/setup_dev.bat +53 -0
  63. linwin-0.4.0/scripts/setup_wsl.bat +57 -0
  64. linwin-0.4.0/scripts/ship.bat +38 -0
  65. linwin-0.4.0/scripts/test.bat +8 -0
  66. linwin-0.4.0/tests/__init__.py +0 -0
  67. linwin-0.4.0/tests/conftest.py +54 -0
  68. linwin-0.4.0/tests/helpers.py +54 -0
  69. linwin-0.4.0/tests/test_config.py +187 -0
  70. linwin-0.4.0/tests/test_coverage_gaps.py +356 -0
  71. linwin-0.4.0/tests/test_drive_scan.py +110 -0
  72. linwin-0.4.0/tests/test_features.py +22 -0
  73. linwin-0.4.0/tests/test_final_gaps.py +362 -0
  74. linwin-0.4.0/tests/test_headless.py +141 -0
  75. linwin-0.4.0/tests/test_linux_tasks.py +660 -0
  76. linwin-0.4.0/tests/test_main_entry.py +124 -0
  77. linwin-0.4.0/tests/test_rdp_desktop.py +509 -0
  78. linwin-0.4.0/tests/test_rdp_lifecycle.py +469 -0
  79. linwin-0.4.0/tests/test_rdp_login.py +308 -0
  80. linwin-0.4.0/tests/test_rdp_session.py +245 -0
  81. linwin-0.4.0/tests/test_screens.py +465 -0
  82. linwin-0.4.0/tests/test_shared_modules.py +359 -0
  83. linwin-0.4.0/tests/test_state.py +74 -0
  84. linwin-0.4.0/tests/test_subprocess_runner.py +79 -0
  85. linwin-0.4.0/tests/test_validators.py +30 -0
  86. linwin-0.4.0/tests/test_windows_tasks.py +500 -0
  87. linwin-0.4.0/uv.lock +857 -0
  88. linwin-0.4.0/wsl_ubuntu_gnome.md +156 -0
@@ -0,0 +1,13 @@
1
+ .idea/
2
+ *.tar
3
+ *.vhdx
4
+ __pycache__/
5
+ *.pyc
6
+ .claude/settings.local.json
7
+ .coverage
8
+
9
+ # pyship build artifacts
10
+ app/
11
+ dist/
12
+ *.nsi
13
+ *.exe
linwin-0.4.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 James Abel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
linwin-0.4.0/PKG-INFO ADDED
@@ -0,0 +1,152 @@
1
+ Metadata-Version: 2.4
2
+ Name: linwin
3
+ Version: 0.4.0
4
+ Summary: Setup WSL2 and make it easily accessible from Windows desktop
5
+ Project-URL: Homepage, https://github.com/jamesabel/linwin
6
+ Project-URL: Repository, https://github.com/jamesabel/linwin
7
+ Project-URL: Issues, https://github.com/jamesabel/linwin/issues
8
+ Author: James Abel
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: TUI,Ubuntu,WSL,WSL2,WSLg,Windows,setup,xrdp
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: System Administrators
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: Microsoft :: Windows
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Topic :: System :: Installation/Setup
24
+ Classifier: Topic :: System :: Operating System
25
+ Requires-Python: >=3.11
26
+ Requires-Dist: pref>=0.3.1
27
+ Requires-Dist: textual>=0.79.0
28
+ Description-Content-Type: text/markdown
29
+
30
+ # linwin
31
+
32
+ Automated TUI (Text User Interface) to install Ubuntu on Windows 11 via WSL2, with the distro stored on a dedicated SSD drive. Includes WSLg for seamless Linux GUI apps on Windows and xrdp for full XFCE4 desktop access via Remote Desktop.
33
+
34
+ ## Prerequisites
35
+
36
+ - **Windows 11** (or Windows 10 build 19044+)
37
+ - **Hardware virtualization** enabled in BIOS/UEFI (Intel VT-x or AMD-V)
38
+ - **Administrator access** on Windows
39
+
40
+ ## Quick Start
41
+
42
+ ```powershell
43
+ scripts\setup_wsl.bat
44
+ ```
45
+
46
+ This launches an interactive terminal UI that:
47
+
48
+ - Auto-detects system hardware (RAM, CPUs, drives) and proposes an optimized configuration
49
+ - Scans drives and recommends the best one for WSL storage (NVMe > SSD > HDD)
50
+ - Runs startup verification and shows any issues before setup begins
51
+ - Lets you review and adjust all settings (distro, resources, packages)
52
+ - Enables WSL and Virtual Machine Platform features
53
+ - Installs Ubuntu, exports/imports to your chosen drive
54
+ - Writes `.wslconfig` with your resource limits
55
+ - Runs Linux-side setup (systemd, apt packages, snap packages, xrdp)
56
+ - Configures xrdp with XFCE4 desktop for Remote Desktop access
57
+ - Maintains a WSL keepalive process to prevent VM shutdown between sessions
58
+ - Verifies everything with a PASS/FAIL dashboard
59
+
60
+ The TUI handles admin elevation, the reboot boundary, and cross-WSL Linux setup automatically. After setup, a launcher screen lets you open apps, launch a terminal, or connect via Remote Desktop.
61
+
62
+ For quick reruns without dependency installation:
63
+
64
+ ```powershell
65
+ run.bat
66
+ ```
67
+
68
+ ### Linux TUI
69
+
70
+ A standalone Linux TUI is also available for running inside WSL Ubuntu directly:
71
+
72
+ ```bash
73
+ pip3 install textual
74
+ python3 -m linwin.linux
75
+ ```
76
+
77
+ A headless mode is available for non-interactive automation:
78
+
79
+ ```bash
80
+ python3 -m linwin.linux --headless --step enable-systemd
81
+ python3 -m linwin.linux --headless --step install-packages
82
+ ```
83
+
84
+ ### Keyboard Shortcuts
85
+
86
+ | Key | Action |
87
+ |-----|--------|
88
+ | 1-9 | Select numbered actions on any screen |
89
+ | Escape | Quit app / Cancel current screen |
90
+ | Ctrl+Q | Quit app |
91
+ | Click | Select action links and options |
92
+
93
+ ## Configuration
94
+
95
+ Edit `config.json` before running, or use the built-in Configure Settings screen. On first launch, the TUI auto-detects your system profile and proposes sensible defaults:
96
+
97
+ | Field | Default | Description |
98
+ |-------|---------|-------------|
99
+ | `distroName` | `Ubuntu-22.04` | Distro to install via `wsl --install` |
100
+ | `distroImportName` | `Ubuntu` | Name after export/import |
101
+ | `wslInstallPath` | auto-detected | Where to store the distro VHD |
102
+ | `wslDriveLetter` | auto-detected | Best available drive (NVMe > SSD > HDD) |
103
+ | `wslconfig.memory` | RAM ÷ 4 | RAM limit for WSL2 (min 4 GB) |
104
+ | `wslconfig.processors` | CPUs ÷ 2 | CPU cores for WSL2 (min 1) |
105
+ | `wslconfig.swap` | RAM ÷ 8 | Swap size (min 4 GB) |
106
+ | `wslconfig.defaultVhdSize` | `512GB` | Max VHD size |
107
+ | `snaps` | *(empty)* | Snap packages to install (configure via editor) |
108
+ | `aptPackages` | nautilus, x11-apps, xfce4, xfce4-terminal, xrdp, dbus-x11 | Apt packages to install |
109
+ | `xrdpPort` | `3390` | Port for xrdp (avoids conflict with Windows RDP on 3389) |
110
+
111
+ ## Project Structure
112
+
113
+ | Path | Description |
114
+ |------|-------------|
115
+ | `run.bat` | Quick launch -- runs the TUI without dependency installation |
116
+ | `scripts/setup_wsl.bat` | Full setup -- installs uv, Python, dependencies, then launches the TUI |
117
+ | `scripts/test.bat` | Run the test suite |
118
+ | `linwin/windows/` | Windows TUI package -- startup verification, auto-config, setup with live progress |
119
+ | `linwin/linux/` | Linux TUI package for WSL-side setup (also supports `--headless`) |
120
+ | `linwin/shared/` | Shared widgets, config, theme, and subprocess utilities |
121
+ | `tests/` | pytest test suite (106 tests) |
122
+ | `config.json` | Default configuration |
123
+
124
+ ## Setup Phases
125
+
126
+ **Startup:** Auto-detects system hardware, runs verification checks, and presents a setup proposal with recommended configuration for user approval.
127
+
128
+ **Phase 1 (Windows):** Validates prerequisites, enables WSL and Virtual Machine Platform features, prompts for reboot if needed.
129
+
130
+ **Phase 2 (Windows + Linux):** Updates WSL, installs Ubuntu, exports/imports distro to target drive, writes `.wslconfig`, enables systemd, installs apt and snap packages, configures xrdp with XFCE4 desktop.
131
+
132
+ **Verification:** Checks all Windows features, distro registration, WSL version, systemd, packages, WSLg display, xrdp service, and drive mounts.
133
+
134
+ ## Detailed Guide
135
+
136
+ See [wsl_ubuntu_gnome.md](wsl_ubuntu_gnome.md) for the full manual guide with GUI comparison (WSLg vs. external X servers), troubleshooting, security notes, and decision checklist.
137
+
138
+ ## Launching Apps
139
+
140
+ After setup, use the launcher screen to open apps directly, or connect via Remote Desktop:
141
+
142
+ ```powershell
143
+ mstsc /v:127.0.0.1:3390
144
+ ```
145
+
146
+ Individual apps can also be launched from an Ubuntu terminal:
147
+
148
+ ```bash
149
+ nautilus & # File Manager
150
+ ```
151
+
152
+ Apps appear as native Windows windows via WSLg. A background keepalive process ensures the WSL VM stays running between app launches.
linwin-0.4.0/README.md ADDED
@@ -0,0 +1,123 @@
1
+ # linwin
2
+
3
+ Automated TUI (Text User Interface) to install Ubuntu on Windows 11 via WSL2, with the distro stored on a dedicated SSD drive. Includes WSLg for seamless Linux GUI apps on Windows and xrdp for full XFCE4 desktop access via Remote Desktop.
4
+
5
+ ## Prerequisites
6
+
7
+ - **Windows 11** (or Windows 10 build 19044+)
8
+ - **Hardware virtualization** enabled in BIOS/UEFI (Intel VT-x or AMD-V)
9
+ - **Administrator access** on Windows
10
+
11
+ ## Quick Start
12
+
13
+ ```powershell
14
+ scripts\setup_wsl.bat
15
+ ```
16
+
17
+ This launches an interactive terminal UI that:
18
+
19
+ - Auto-detects system hardware (RAM, CPUs, drives) and proposes an optimized configuration
20
+ - Scans drives and recommends the best one for WSL storage (NVMe > SSD > HDD)
21
+ - Runs startup verification and shows any issues before setup begins
22
+ - Lets you review and adjust all settings (distro, resources, packages)
23
+ - Enables WSL and Virtual Machine Platform features
24
+ - Installs Ubuntu, exports/imports to your chosen drive
25
+ - Writes `.wslconfig` with your resource limits
26
+ - Runs Linux-side setup (systemd, apt packages, snap packages, xrdp)
27
+ - Configures xrdp with XFCE4 desktop for Remote Desktop access
28
+ - Maintains a WSL keepalive process to prevent VM shutdown between sessions
29
+ - Verifies everything with a PASS/FAIL dashboard
30
+
31
+ The TUI handles admin elevation, the reboot boundary, and cross-WSL Linux setup automatically. After setup, a launcher screen lets you open apps, launch a terminal, or connect via Remote Desktop.
32
+
33
+ For quick reruns without dependency installation:
34
+
35
+ ```powershell
36
+ run.bat
37
+ ```
38
+
39
+ ### Linux TUI
40
+
41
+ A standalone Linux TUI is also available for running inside WSL Ubuntu directly:
42
+
43
+ ```bash
44
+ pip3 install textual
45
+ python3 -m linwin.linux
46
+ ```
47
+
48
+ A headless mode is available for non-interactive automation:
49
+
50
+ ```bash
51
+ python3 -m linwin.linux --headless --step enable-systemd
52
+ python3 -m linwin.linux --headless --step install-packages
53
+ ```
54
+
55
+ ### Keyboard Shortcuts
56
+
57
+ | Key | Action |
58
+ |-----|--------|
59
+ | 1-9 | Select numbered actions on any screen |
60
+ | Escape | Quit app / Cancel current screen |
61
+ | Ctrl+Q | Quit app |
62
+ | Click | Select action links and options |
63
+
64
+ ## Configuration
65
+
66
+ Edit `config.json` before running, or use the built-in Configure Settings screen. On first launch, the TUI auto-detects your system profile and proposes sensible defaults:
67
+
68
+ | Field | Default | Description |
69
+ |-------|---------|-------------|
70
+ | `distroName` | `Ubuntu-22.04` | Distro to install via `wsl --install` |
71
+ | `distroImportName` | `Ubuntu` | Name after export/import |
72
+ | `wslInstallPath` | auto-detected | Where to store the distro VHD |
73
+ | `wslDriveLetter` | auto-detected | Best available drive (NVMe > SSD > HDD) |
74
+ | `wslconfig.memory` | RAM ÷ 4 | RAM limit for WSL2 (min 4 GB) |
75
+ | `wslconfig.processors` | CPUs ÷ 2 | CPU cores for WSL2 (min 1) |
76
+ | `wslconfig.swap` | RAM ÷ 8 | Swap size (min 4 GB) |
77
+ | `wslconfig.defaultVhdSize` | `512GB` | Max VHD size |
78
+ | `snaps` | *(empty)* | Snap packages to install (configure via editor) |
79
+ | `aptPackages` | nautilus, x11-apps, xfce4, xfce4-terminal, xrdp, dbus-x11 | Apt packages to install |
80
+ | `xrdpPort` | `3390` | Port for xrdp (avoids conflict with Windows RDP on 3389) |
81
+
82
+ ## Project Structure
83
+
84
+ | Path | Description |
85
+ |------|-------------|
86
+ | `run.bat` | Quick launch -- runs the TUI without dependency installation |
87
+ | `scripts/setup_wsl.bat` | Full setup -- installs uv, Python, dependencies, then launches the TUI |
88
+ | `scripts/test.bat` | Run the test suite |
89
+ | `linwin/windows/` | Windows TUI package -- startup verification, auto-config, setup with live progress |
90
+ | `linwin/linux/` | Linux TUI package for WSL-side setup (also supports `--headless`) |
91
+ | `linwin/shared/` | Shared widgets, config, theme, and subprocess utilities |
92
+ | `tests/` | pytest test suite (106 tests) |
93
+ | `config.json` | Default configuration |
94
+
95
+ ## Setup Phases
96
+
97
+ **Startup:** Auto-detects system hardware, runs verification checks, and presents a setup proposal with recommended configuration for user approval.
98
+
99
+ **Phase 1 (Windows):** Validates prerequisites, enables WSL and Virtual Machine Platform features, prompts for reboot if needed.
100
+
101
+ **Phase 2 (Windows + Linux):** Updates WSL, installs Ubuntu, exports/imports distro to target drive, writes `.wslconfig`, enables systemd, installs apt and snap packages, configures xrdp with XFCE4 desktop.
102
+
103
+ **Verification:** Checks all Windows features, distro registration, WSL version, systemd, packages, WSLg display, xrdp service, and drive mounts.
104
+
105
+ ## Detailed Guide
106
+
107
+ See [wsl_ubuntu_gnome.md](wsl_ubuntu_gnome.md) for the full manual guide with GUI comparison (WSLg vs. external X servers), troubleshooting, security notes, and decision checklist.
108
+
109
+ ## Launching Apps
110
+
111
+ After setup, use the launcher screen to open apps directly, or connect via Remote Desktop:
112
+
113
+ ```powershell
114
+ mstsc /v:127.0.0.1:3390
115
+ ```
116
+
117
+ Individual apps can also be launched from an Ubuntu terminal:
118
+
119
+ ```bash
120
+ nautilus & # File Manager
121
+ ```
122
+
123
+ Apps appear as native Windows windows via WSLg. A background keepalive process ensures the WSL VM stays running between app launches.
@@ -0,0 +1,50 @@
1
+ {
2
+ "distroName": "Ubuntu-22.04",
3
+ "distroImportName": "Ubuntu",
4
+ "wslInstallPath": "V:\\WSL\\Ubuntu",
5
+ "wslDriveLetter": "V",
6
+ "wslconfig": {
7
+ "memory": "15GB",
8
+ "processors": 10,
9
+ "swap": "7GB",
10
+ "swapFile": "V:\\WSL\\swap.vhdx",
11
+ "guiApplications": true,
12
+ "defaultVhdSize": "512GB"
13
+ },
14
+ "snaps": [
15
+ {
16
+ "name": "pycharm-community",
17
+ "classic": true
18
+ },
19
+ {
20
+ "name": "firefox",
21
+ "classic": false
22
+ }
23
+ ],
24
+ "optionalApps": [
25
+ {
26
+ "id": "pycharm-community",
27
+ "display_name": "PyCharm Community",
28
+ "command": "pycharm-community",
29
+ "install_method": "snap",
30
+ "classic": true
31
+ },
32
+ {
33
+ "id": "firefox",
34
+ "display_name": "Firefox",
35
+ "command": "firefox",
36
+ "install_method": "snap",
37
+ "classic": false
38
+ }
39
+ ],
40
+ "aptPackages": [
41
+ "nautilus",
42
+ "x11-apps",
43
+ "xfce4",
44
+ "xfce4-terminal",
45
+ "xrdp",
46
+ "dbus-x11"
47
+ ],
48
+ "enableSystemd": true,
49
+ "xrdpPort": 3390
50
+ }
@@ -0,0 +1 @@
1
+ """linwin — TUI setup tool for WSL2 Ubuntu with WSLg GUI and xrdp desktop."""
@@ -0,0 +1,19 @@
1
+ """Entry point for ``python -m linwin``.
2
+
3
+ Delegates to the Windows or Linux TUI based on the current platform.
4
+ """
5
+
6
+ import sys
7
+
8
+
9
+ def main() -> None:
10
+ if sys.platform == "win32":
11
+ from linwin.windows.__main__ import main as win_main
12
+ win_main()
13
+ else:
14
+ from linwin.linux.__main__ import main as linux_main
15
+ linux_main()
16
+
17
+
18
+ if __name__ == "__main__":
19
+ main()
Binary file
Binary file
File without changes
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env python3
2
+ """Linux-side TUI entry point for WSL Ubuntu setup.
3
+
4
+ Usage:
5
+ python3 -m linwin.linux # Interactive TUI
6
+ python3 -m linwin.linux --headless --step enable-systemd # Headless: enable systemd
7
+ python3 -m linwin.linux --headless --step install-packages # Headless: install packages
8
+ """
9
+
10
+ import argparse
11
+ import asyncio
12
+ import json
13
+ import sys
14
+ from pathlib import Path
15
+
16
+ from ..shared.headless_protocol import emit_error, emit_log, emit_task
17
+ from ..shared.setup_logging import setup_logging
18
+
19
+
20
+ def find_config() -> dict:
21
+ """Load config from the pref DB, or return defaults if unavailable.
22
+
23
+ Inside WSL the ``pref`` package may not be installed, so fall back
24
+ to defaults.
25
+ """
26
+ try:
27
+ from ..shared.config import load_config
28
+ return load_config().to_dict()
29
+ except ImportError:
30
+ # pref not installed (running inside WSL) — use defaults.
31
+ from ..shared.config import SetupConfig
32
+ return SetupConfig().to_dict()
33
+
34
+
35
+ def _run_task(task_id: str, coro, success_msg: str = "") -> bool:
36
+ """Run an async task with structured headless output. Returns True on success."""
37
+ emit_task(task_id, "running")
38
+ result = asyncio.run(coro)
39
+ if hasattr(result, "ok"):
40
+ if getattr(result, "skipped", False):
41
+ emit_task(task_id, "done")
42
+ emit_log(result.message)
43
+ elif result.ok:
44
+ emit_task(task_id, "done")
45
+ emit_log(success_msg or result.message)
46
+ else:
47
+ emit_task(task_id, "failed")
48
+ emit_error(result.message)
49
+ return False
50
+ else:
51
+ # Boolean or other non-TaskResult return value
52
+ emit_task(task_id, "done")
53
+ return True
54
+
55
+
56
+ def headless_enable_systemd(config: dict) -> int:
57
+ """Enable systemd in wsl.conf. Delegates to the async implementation in tasks.systemd."""
58
+ from .tasks.systemd import enable_systemd
59
+
60
+ if not _run_task("enable_systemd", enable_systemd()):
61
+ return 1
62
+ return 0
63
+
64
+
65
+ def headless_install_packages(config: dict) -> int:
66
+ """Install apt packages, snaps, verify WSLg. Delegates to async task modules."""
67
+ from .tasks import apt, snaps, wslg
68
+ from ..shared.config import SnapPackage
69
+
70
+ exit_code = 0
71
+
72
+ # apt update & upgrade
73
+ if not _run_task("apt_update", apt.apt_update()):
74
+ exit_code = 1
75
+ if not _run_task("apt_upgrade", apt.apt_upgrade()):
76
+ exit_code = 1
77
+
78
+ # apt packages
79
+ for pkg in config.get("aptPackages", []):
80
+ if not _run_task(f"apt_{pkg}", apt.install_apt_package(pkg)):
81
+ exit_code = 1
82
+
83
+ # Setup snapd
84
+ emit_task("setup_snapd", "running")
85
+ systemd_ok = asyncio.run(snaps.check_systemd_running())
86
+ if not systemd_ok:
87
+ emit_task("setup_snapd", "failed")
88
+ emit_error("systemd not running. Snaps require systemd + WSL restart.")
89
+ exit_code = 1
90
+ else:
91
+ result = asyncio.run(snaps.ensure_snapd())
92
+ if result.ok:
93
+ emit_task("setup_snapd", "done")
94
+ emit_log(result.message)
95
+ else:
96
+ emit_task("setup_snapd", "failed")
97
+ emit_error(result.message)
98
+ exit_code = 1
99
+
100
+ # Install optional apps (snap and apt; custom skipped)
101
+ for app_info in config.get("optionalApps", config.get("snaps", [])):
102
+ method = app_info.get("install_method", "snap")
103
+ app_id = app_info.get("id", app_info.get("name", ""))
104
+ if method == "snap":
105
+ snap = SnapPackage(
106
+ name=app_id,
107
+ classic=app_info.get("classic", True),
108
+ )
109
+ if not _run_task(f"snap_{snap.name}", snaps.install_snap(snap)):
110
+ exit_code = 1
111
+ elif method == "apt":
112
+ if not _run_task(f"apt_opt_{app_id}", apt.install_apt_package(app_id)):
113
+ exit_code = 1
114
+
115
+ # Verify WSLg
116
+ emit_task("verify_wslg", "running")
117
+ wslg_result = asyncio.run(wslg.verify_wslg())
118
+ emit_log(f"DISPLAY={wslg_result.display_value or '(not set)'}")
119
+ emit_log(f"/mnt/wslg: {'exists' if wslg_result.wslg_dir_exists else 'not found'}")
120
+ wslg_ok = wslg_result.display_set and wslg_result.wslg_dir_exists
121
+ emit_task("verify_wslg", "done" if wslg_ok else "failed")
122
+
123
+ return exit_code
124
+
125
+
126
+ def headless_configure_xrdp(config: dict) -> int:
127
+ """Install xrdp + xfce4, configure port/session, enable service.
128
+
129
+ Delegates to async task functions in tasks.xrdp. The enable_xrdp_service
130
+ call internally handles SSL permissions, systemd overrides, colord polkit,
131
+ logind delay, user linger, and GDM masking.
132
+ """
133
+ from .tasks import xrdp
134
+
135
+ exit_code = 0
136
+ port = config.get("xrdpPort", 3390)
137
+
138
+ if not _run_task("xrdp_install", xrdp.install_xrdp()):
139
+ exit_code = 1
140
+ if not _run_task("xrdp_port", xrdp.configure_xrdp_port(port)):
141
+ exit_code = 1
142
+ if not _run_task("xrdp_session", xrdp.configure_xrdp_session()):
143
+ exit_code = 1
144
+ if not _run_task("xrdp_service", xrdp.enable_xrdp_service()):
145
+ exit_code = 1
146
+
147
+ return exit_code
148
+
149
+
150
+ def main() -> None:
151
+ parser = argparse.ArgumentParser(description="WSL Ubuntu Setup TUI (Linux)")
152
+ parser.add_argument("--headless", action="store_true", help="Run without TUI (structured output)")
153
+ parser.add_argument("--step", choices=["enable-systemd", "install-packages", "configure-xrdp"],
154
+ help="Step to run (headless mode)")
155
+ args = parser.parse_args()
156
+
157
+ log = setup_logging()
158
+
159
+ config_data = find_config()
160
+
161
+ if args.headless:
162
+ log.info("Headless mode, step=%s", args.step)
163
+ try:
164
+ if args.step == "enable-systemd":
165
+ sys.exit(headless_enable_systemd(config_data))
166
+ elif args.step == "install-packages":
167
+ sys.exit(headless_install_packages(config_data))
168
+ elif args.step == "configure-xrdp":
169
+ sys.exit(headless_configure_xrdp(config_data))
170
+ else:
171
+ print("ERROR:--step required with --headless", flush=True)
172
+ sys.exit(1)
173
+ except SystemExit:
174
+ sys.stdout.flush()
175
+ raise
176
+ except Exception:
177
+ import traceback
178
+ tb = traceback.format_exc()
179
+ emit_error(tb)
180
+ log.error("Unhandled exception in headless mode:\n%s", tb)
181
+ sys.exit(1)
182
+ else:
183
+ # Interactive TUI mode
184
+ from ..shared.config import SetupConfig
185
+ from .app import LinuxSetupApp
186
+
187
+ log.info("Linux interactive TUI starting")
188
+ config = SetupConfig.from_dict(config_data)
189
+ app = LinuxSetupApp(config)
190
+ app.run()
191
+ log.info("Linux TUI exited")
192
+
193
+
194
+ if __name__ == "__main__":
195
+ main()
@@ -0,0 +1,15 @@
1
+ """Linux TUI Application — main Textual app for WSL Ubuntu setup."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from ..shared.base_app import BaseSetupApp
6
+ from .screens.welcome import WelcomeScreen
7
+
8
+
9
+ class LinuxSetupApp(BaseSetupApp):
10
+ """Textual TUI for Ubuntu package setup inside WSL."""
11
+
12
+ TITLE = "WSL Ubuntu Setup (Linux)"
13
+
14
+ def on_mount(self) -> None:
15
+ self.push_screen(WelcomeScreen(self._config))
File without changes