projectdevsetup 1.0.0__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.
- projectdevsetup/__init__.py +11 -0
- projectdevsetup/__main__.py +31 -0
- projectdevsetup/detector.py +102 -0
- projectdevsetup/installer.py +447 -0
- projectdevsetup/network.py +80 -0
- projectdevsetup/path_manager.py +149 -0
- projectdevsetup/permissions.py +95 -0
- projectdevsetup/templates/Hello.java +8 -0
- projectdevsetup/templates/__init__.py +5 -0
- projectdevsetup/templates/hello.c +9 -0
- projectdevsetup/templates/hello.cpp +9 -0
- projectdevsetup/templates/hello.go +10 -0
- projectdevsetup/templates/hello.html +25 -0
- projectdevsetup/templates/hello.js +4 -0
- projectdevsetup/templates/hello.py +4 -0
- projectdevsetup/templates/hello.rs +6 -0
- projectdevsetup/utils/__init__.py +5 -0
- projectdevsetup/utils/logger.py +69 -0
- projectdevsetup/utils/os_detect.py +142 -0
- projectdevsetup/utils/venv_helper.py +95 -0
- projectdevsetup/vscode.py +386 -0
- projectdevsetup/wizard.py +262 -0
- projectdevsetup-1.0.0.dist-info/METADATA +83 -0
- projectdevsetup-1.0.0.dist-info/RECORD +27 -0
- projectdevsetup-1.0.0.dist-info/WHEEL +5 -0
- projectdevsetup-1.0.0.dist-info/licenses/LICENSE +22 -0
- projectdevsetup-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
"""
|
|
2
|
+
@project projectdevsetup
|
|
3
|
+
@org Zenith Open Source Projects
|
|
4
|
+
@license MIT License
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import subprocess
|
|
8
|
+
import platform
|
|
9
|
+
import webbrowser
|
|
10
|
+
import os
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from projectdevsetup.detector import check_vscode
|
|
13
|
+
from projectdevsetup.network import download_file, get_temp_dir
|
|
14
|
+
from projectdevsetup.utils.logger import (
|
|
15
|
+
info,
|
|
16
|
+
success,
|
|
17
|
+
error,
|
|
18
|
+
warning,
|
|
19
|
+
already_installed,
|
|
20
|
+
)
|
|
21
|
+
from projectdevsetup.utils.os_detect import detect_system
|
|
22
|
+
|
|
23
|
+
VSCODE_DOWNLOAD_PAGE = "https://code.visualstudio.com/Download"
|
|
24
|
+
|
|
25
|
+
VSCODE_WINDOWS_URL = (
|
|
26
|
+
"https://code.visualstudio.com/sha/download?build=stable&os=win32-x64-user"
|
|
27
|
+
)
|
|
28
|
+
VSCODE_LINUX_DEB_URL = (
|
|
29
|
+
"https://code.visualstudio.com/sha/download?build=stable&os=linux-deb-x64"
|
|
30
|
+
)
|
|
31
|
+
VSCODE_LINUX_RPM_URL = (
|
|
32
|
+
"https://code.visualstudio.com/sha/download?build=stable&os=linux-rpm-x64"
|
|
33
|
+
)
|
|
34
|
+
VSCODE_MAC_URL = (
|
|
35
|
+
"https://code.visualstudio.com/sha/download?build=stable&os=darwin-universal"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
EXTENSIONS = {
|
|
39
|
+
"python": ["ms-python.python", "ms-python.pylance"],
|
|
40
|
+
"c": ["ms-vscode.cpptools"],
|
|
41
|
+
"cpp": ["ms-vscode.cpptools"],
|
|
42
|
+
"java": ["vscjava.vscode-java-pack"],
|
|
43
|
+
"html": ["ritwickdey.liveserver", "esbenp.prettier-vscode"],
|
|
44
|
+
"javascript": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"],
|
|
45
|
+
"rust": ["rust-lang.rust-analyzer"],
|
|
46
|
+
"go": ["golang.go"],
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def ensure_vscode_installed(sys_info) -> bool:
|
|
51
|
+
"""
|
|
52
|
+
Make sure VSCode is installed.
|
|
53
|
+
Returns True if VSCode is available after this function runs.
|
|
54
|
+
"""
|
|
55
|
+
if check_vscode():
|
|
56
|
+
already_installed("Visual Studio Code")
|
|
57
|
+
return True
|
|
58
|
+
|
|
59
|
+
info("Visual Studio Code is not installed. Attempting to install...")
|
|
60
|
+
|
|
61
|
+
if sys_info.os_name == "windows":
|
|
62
|
+
return _install_vscode_windows(sys_info)
|
|
63
|
+
elif sys_info.os_name == "linux":
|
|
64
|
+
return _install_vscode_linux(sys_info)
|
|
65
|
+
elif sys_info.os_name == "mac":
|
|
66
|
+
return _install_vscode_mac(sys_info)
|
|
67
|
+
else:
|
|
68
|
+
_open_download_page()
|
|
69
|
+
return False
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _install_vscode_windows(sys_info) -> bool:
|
|
73
|
+
"""Try winget first, then direct download, then browser fallback."""
|
|
74
|
+
if sys_info.package_manager == "winget":
|
|
75
|
+
info("Installing VSCode via winget...")
|
|
76
|
+
try:
|
|
77
|
+
result = subprocess.run(
|
|
78
|
+
[
|
|
79
|
+
"winget",
|
|
80
|
+
"install",
|
|
81
|
+
"--id",
|
|
82
|
+
"Microsoft.VisualStudioCode",
|
|
83
|
+
"--silent",
|
|
84
|
+
"--accept-package-agreements",
|
|
85
|
+
"--accept-source-agreements",
|
|
86
|
+
],
|
|
87
|
+
capture_output=True,
|
|
88
|
+
text=True,
|
|
89
|
+
timeout=300,
|
|
90
|
+
)
|
|
91
|
+
if result.returncode == 0 and check_vscode():
|
|
92
|
+
success("Visual Studio Code installed successfully!")
|
|
93
|
+
return True
|
|
94
|
+
except Exception:
|
|
95
|
+
pass
|
|
96
|
+
|
|
97
|
+
if sys_info.package_manager == "choco":
|
|
98
|
+
info("Installing VSCode via Chocolatey...")
|
|
99
|
+
try:
|
|
100
|
+
result = subprocess.run(
|
|
101
|
+
["choco", "install", "vscode", "-y"],
|
|
102
|
+
capture_output=True,
|
|
103
|
+
text=True,
|
|
104
|
+
timeout=300,
|
|
105
|
+
)
|
|
106
|
+
if result.returncode == 0 and check_vscode():
|
|
107
|
+
success("Visual Studio Code installed successfully!")
|
|
108
|
+
return True
|
|
109
|
+
except Exception:
|
|
110
|
+
pass
|
|
111
|
+
|
|
112
|
+
info("Downloading VSCode installer directly...")
|
|
113
|
+
tmp = get_temp_dir()
|
|
114
|
+
installer = tmp / "vscode_installer.exe"
|
|
115
|
+
if download_file(VSCODE_WINDOWS_URL, installer, "Visual Studio Code"):
|
|
116
|
+
try:
|
|
117
|
+
info("Running VSCode installer silently...")
|
|
118
|
+
subprocess.run(
|
|
119
|
+
[str(installer), "/VERYSILENT", "/MERGETASKS=!runcode"], timeout=300
|
|
120
|
+
)
|
|
121
|
+
if check_vscode():
|
|
122
|
+
success("Visual Studio Code installed successfully!")
|
|
123
|
+
return True
|
|
124
|
+
except Exception:
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
_open_download_page()
|
|
128
|
+
return False
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _install_vscode_linux(sys_info) -> bool:
|
|
132
|
+
"""Try snap, then apt/rpm repo, then browser fallback."""
|
|
133
|
+
if sys_info.package_manager != "none" and _try_snap_install():
|
|
134
|
+
return True
|
|
135
|
+
|
|
136
|
+
if sys_info.package_manager == "apt":
|
|
137
|
+
if _try_apt_vscode():
|
|
138
|
+
return True
|
|
139
|
+
|
|
140
|
+
if sys_info.package_manager in ("dnf", "yum"):
|
|
141
|
+
if _try_rpm_vscode(sys_info.package_manager):
|
|
142
|
+
return True
|
|
143
|
+
|
|
144
|
+
if sys_info.package_manager == "apt":
|
|
145
|
+
tmp = get_temp_dir()
|
|
146
|
+
pkg = tmp / "vscode.deb"
|
|
147
|
+
if download_file(VSCODE_LINUX_DEB_URL, pkg, "Visual Studio Code"):
|
|
148
|
+
try:
|
|
149
|
+
subprocess.run(["sudo", "dpkg", "-i", str(pkg)], timeout=120)
|
|
150
|
+
subprocess.run(["sudo", "apt-get", "install", "-f", "-y"], timeout=120)
|
|
151
|
+
if check_vscode():
|
|
152
|
+
success("Visual Studio Code installed successfully!")
|
|
153
|
+
return True
|
|
154
|
+
except Exception:
|
|
155
|
+
pass
|
|
156
|
+
|
|
157
|
+
if not sys_info.has_display:
|
|
158
|
+
warning(
|
|
159
|
+
"No display detected. This appears to be a server. "
|
|
160
|
+
"VSCode cannot be installed on a headless server. "
|
|
161
|
+
"Skipping VSCode installation."
|
|
162
|
+
)
|
|
163
|
+
return False
|
|
164
|
+
|
|
165
|
+
_open_download_page()
|
|
166
|
+
return False
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _try_snap_install() -> bool:
|
|
170
|
+
"""Try installing VSCode via snap."""
|
|
171
|
+
try:
|
|
172
|
+
subprocess.run(
|
|
173
|
+
["sudo", "systemctl", "start", "snapd"], capture_output=True, timeout=30
|
|
174
|
+
)
|
|
175
|
+
result = subprocess.run(
|
|
176
|
+
["sudo", "snap", "install", "code", "--classic"],
|
|
177
|
+
capture_output=True,
|
|
178
|
+
text=True,
|
|
179
|
+
timeout=300,
|
|
180
|
+
)
|
|
181
|
+
if result.returncode == 0 and check_vscode():
|
|
182
|
+
success("Visual Studio Code installed successfully via snap!")
|
|
183
|
+
return True
|
|
184
|
+
except Exception:
|
|
185
|
+
pass
|
|
186
|
+
return False
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _try_apt_vscode() -> bool:
|
|
190
|
+
"""Add Microsoft apt repo and install VSCode."""
|
|
191
|
+
try:
|
|
192
|
+
commands = [
|
|
193
|
+
["sudo", "apt-get", "install", "-y", "wget", "gpg", "apt-transport-https"],
|
|
194
|
+
[
|
|
195
|
+
"bash",
|
|
196
|
+
"-c",
|
|
197
|
+
"wget -qO- https://packages.microsoft.com/keys/microsoft.asc"
|
|
198
|
+
" | gpg --dearmor > /tmp/microsoft.gpg",
|
|
199
|
+
],
|
|
200
|
+
[
|
|
201
|
+
"sudo",
|
|
202
|
+
"install",
|
|
203
|
+
"-D",
|
|
204
|
+
"-o",
|
|
205
|
+
"root",
|
|
206
|
+
"-g",
|
|
207
|
+
"root",
|
|
208
|
+
"-m",
|
|
209
|
+
"644",
|
|
210
|
+
"/tmp/microsoft.gpg",
|
|
211
|
+
"/etc/apt/keyrings/packages.microsoft.gpg",
|
|
212
|
+
],
|
|
213
|
+
[
|
|
214
|
+
"bash",
|
|
215
|
+
"-c",
|
|
216
|
+
'echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/'
|
|
217
|
+
"packages.microsoft.gpg] https://packages.microsoft.com/"
|
|
218
|
+
'repos/code stable main" | sudo tee '
|
|
219
|
+
"/etc/apt/sources.list.d/vscode.list",
|
|
220
|
+
],
|
|
221
|
+
["sudo", "apt-get", "update"],
|
|
222
|
+
["sudo", "apt-get", "install", "-y", "code"],
|
|
223
|
+
]
|
|
224
|
+
for cmd in commands:
|
|
225
|
+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
|
|
226
|
+
if result.returncode != 0:
|
|
227
|
+
return False
|
|
228
|
+
if check_vscode():
|
|
229
|
+
success("Visual Studio Code installed successfully!")
|
|
230
|
+
return True
|
|
231
|
+
except Exception:
|
|
232
|
+
pass
|
|
233
|
+
return False
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def _try_rpm_vscode(pkg_manager: str) -> bool:
|
|
237
|
+
"""Install VSCode on Fedora/CentOS via rpm repo."""
|
|
238
|
+
try:
|
|
239
|
+
commands = [
|
|
240
|
+
[
|
|
241
|
+
"sudo",
|
|
242
|
+
"rpm",
|
|
243
|
+
"--import",
|
|
244
|
+
"https://packages.microsoft.com/keys/microsoft.asc",
|
|
245
|
+
],
|
|
246
|
+
[
|
|
247
|
+
"bash",
|
|
248
|
+
"-c",
|
|
249
|
+
'echo -e "[code]\nname=Visual Studio Code\n'
|
|
250
|
+
"baseurl=https://packages.microsoft.com/yumrepos/vscode\n"
|
|
251
|
+
"enabled=1\ngpgcheck=1\ngpgkey=https://packages.microsoft.com"
|
|
252
|
+
'/keys/microsoft.asc" | sudo tee /etc/yum.repos.d/vscode.repo',
|
|
253
|
+
],
|
|
254
|
+
["sudo", pkg_manager, "install", "-y", "code"],
|
|
255
|
+
]
|
|
256
|
+
for cmd in commands:
|
|
257
|
+
subprocess.run(cmd, capture_output=True, text=True, timeout=120)
|
|
258
|
+
if check_vscode():
|
|
259
|
+
success("Visual Studio Code installed successfully!")
|
|
260
|
+
return True
|
|
261
|
+
except Exception:
|
|
262
|
+
pass
|
|
263
|
+
return False
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _install_vscode_mac(sys_info) -> bool:
|
|
267
|
+
"""Try homebrew, then direct download, then browser fallback."""
|
|
268
|
+
from projectdevsetup.detector import check_brew
|
|
269
|
+
|
|
270
|
+
if check_brew():
|
|
271
|
+
info("Installing VSCode via Homebrew...")
|
|
272
|
+
try:
|
|
273
|
+
result = subprocess.run(
|
|
274
|
+
["brew", "install", "--cask", "visual-studio-code"],
|
|
275
|
+
capture_output=True,
|
|
276
|
+
text=True,
|
|
277
|
+
timeout=300,
|
|
278
|
+
)
|
|
279
|
+
if result.returncode == 0 and check_vscode():
|
|
280
|
+
success("Visual Studio Code installed successfully!")
|
|
281
|
+
return True
|
|
282
|
+
except Exception:
|
|
283
|
+
pass
|
|
284
|
+
|
|
285
|
+
info("Homebrew not found. Installing Homebrew first...")
|
|
286
|
+
try:
|
|
287
|
+
brew_install = subprocess.run(
|
|
288
|
+
[
|
|
289
|
+
"/bin/bash",
|
|
290
|
+
"-c",
|
|
291
|
+
"$(curl -fsSL https://raw.githubusercontent.com/"
|
|
292
|
+
"Homebrew/install/HEAD/install.sh)",
|
|
293
|
+
],
|
|
294
|
+
timeout=600,
|
|
295
|
+
)
|
|
296
|
+
if brew_install.returncode == 0:
|
|
297
|
+
subprocess.run(
|
|
298
|
+
["brew", "install", "--cask", "visual-studio-code"], timeout=300
|
|
299
|
+
)
|
|
300
|
+
if check_vscode():
|
|
301
|
+
success("Visual Studio Code installed successfully!")
|
|
302
|
+
return True
|
|
303
|
+
except Exception:
|
|
304
|
+
pass
|
|
305
|
+
|
|
306
|
+
_open_download_page()
|
|
307
|
+
return False
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def _open_download_page():
|
|
311
|
+
"""Open the VSCode download page in the user's browser."""
|
|
312
|
+
warning(
|
|
313
|
+
"Could not install VSCode automatically. "
|
|
314
|
+
"Opening the download page in your browser..."
|
|
315
|
+
)
|
|
316
|
+
print(
|
|
317
|
+
"\n Please download and install VSCode from:\n"
|
|
318
|
+
f" {VSCODE_DOWNLOAD_PAGE}\n"
|
|
319
|
+
"\n After installing, run this command again.\n"
|
|
320
|
+
)
|
|
321
|
+
try:
|
|
322
|
+
webbrowser.open(VSCODE_DOWNLOAD_PAGE)
|
|
323
|
+
except Exception:
|
|
324
|
+
pass
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def install_extensions(language: str) -> bool:
|
|
328
|
+
"""
|
|
329
|
+
Install VSCode extensions for a given language.
|
|
330
|
+
Returns True if all installed successfully.
|
|
331
|
+
"""
|
|
332
|
+
if not check_vscode():
|
|
333
|
+
warning("VSCode is not installed. Skipping extension installation.")
|
|
334
|
+
return False
|
|
335
|
+
|
|
336
|
+
exts = EXTENSIONS.get(language.lower(), [])
|
|
337
|
+
if not exts:
|
|
338
|
+
return True
|
|
339
|
+
|
|
340
|
+
all_success = True
|
|
341
|
+
for ext in exts:
|
|
342
|
+
info(f"Installing VSCode extension: {ext}")
|
|
343
|
+
for attempt in range(1, 4):
|
|
344
|
+
try:
|
|
345
|
+
result = subprocess.run(
|
|
346
|
+
["code", "--install-extension", ext, "--force"],
|
|
347
|
+
capture_output=True,
|
|
348
|
+
text=True,
|
|
349
|
+
timeout=120,
|
|
350
|
+
)
|
|
351
|
+
if result.returncode == 0:
|
|
352
|
+
success(f"Extension {ext} installed.")
|
|
353
|
+
break
|
|
354
|
+
else:
|
|
355
|
+
if attempt == 3:
|
|
356
|
+
warning(
|
|
357
|
+
f"Could not install extension {ext} "
|
|
358
|
+
"automatically.\n"
|
|
359
|
+
f" Please install it manually in VSCode:\n"
|
|
360
|
+
f" 1. Open VSCode\n"
|
|
361
|
+
f" 2. Press Ctrl+Shift+X\n"
|
|
362
|
+
f" 3. Search for: {ext}\n"
|
|
363
|
+
f" 4. Click Install\n"
|
|
364
|
+
)
|
|
365
|
+
all_success = False
|
|
366
|
+
except Exception:
|
|
367
|
+
if attempt == 3:
|
|
368
|
+
all_success = False
|
|
369
|
+
return all_success
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def open_in_vscode(file_path: Path):
|
|
373
|
+
"""Open a specific file in VSCode."""
|
|
374
|
+
if not check_vscode():
|
|
375
|
+
warning("VSCode is not available. Please open your file manually.")
|
|
376
|
+
return
|
|
377
|
+
try:
|
|
378
|
+
info(f"Opening {file_path.name} in VSCode...")
|
|
379
|
+
subprocess.Popen(["code", str(file_path)])
|
|
380
|
+
success(f"VSCode opened with {file_path.name}!")
|
|
381
|
+
except Exception:
|
|
382
|
+
warning(
|
|
383
|
+
f"Could not open VSCode automatically. "
|
|
384
|
+
f"Please open this file manually:\n"
|
|
385
|
+
f" {file_path}"
|
|
386
|
+
)
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"""
|
|
2
|
+
@project projectdevsetup
|
|
3
|
+
@org Zenith Open Source Projects
|
|
4
|
+
@license MIT License
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import re
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from projectdevsetup.utils.logger import (
|
|
11
|
+
header,
|
|
12
|
+
info,
|
|
13
|
+
success,
|
|
14
|
+
error,
|
|
15
|
+
warning,
|
|
16
|
+
divider,
|
|
17
|
+
step,
|
|
18
|
+
ask,
|
|
19
|
+
)
|
|
20
|
+
from projectdevsetup.utils.os_detect import detect_system
|
|
21
|
+
from projectdevsetup.network import check_internet
|
|
22
|
+
from projectdevsetup.permissions import (
|
|
23
|
+
check_disk_space,
|
|
24
|
+
assert_not_root,
|
|
25
|
+
handle_no_admin_windows,
|
|
26
|
+
)
|
|
27
|
+
from projectdevsetup.detector import get_installed_summary
|
|
28
|
+
from projectdevsetup.installer import Installer
|
|
29
|
+
from projectdevsetup.vscode import (
|
|
30
|
+
ensure_vscode_installed,
|
|
31
|
+
install_extensions,
|
|
32
|
+
open_in_vscode,
|
|
33
|
+
)
|
|
34
|
+
from projectdevsetup.utils.venv_helper import create_venv
|
|
35
|
+
|
|
36
|
+
LANGUAGES = {
|
|
37
|
+
"1": ("Python", "python", ".py"),
|
|
38
|
+
"2": ("C", "c", ".c"),
|
|
39
|
+
"3": ("C++", "cpp", ".cpp"),
|
|
40
|
+
"4": ("Java", "java", ".java"),
|
|
41
|
+
"5": ("HTML / CSS", "html", ".html"),
|
|
42
|
+
"6": ("JavaScript", "javascript", ".js"),
|
|
43
|
+
"7": ("Rust", "rust", ".rs"),
|
|
44
|
+
"8": ("Go", "go", ".go"),
|
|
45
|
+
"9": ("All Languages", "all", ""),
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
TEMPLATE_MAP = {
|
|
49
|
+
"python": "hello.py",
|
|
50
|
+
"c": "hello.c",
|
|
51
|
+
"cpp": "hello.cpp",
|
|
52
|
+
"java": "Hello.java",
|
|
53
|
+
"html": "hello.html",
|
|
54
|
+
"javascript": "hello.js",
|
|
55
|
+
"rust": "hello.rs",
|
|
56
|
+
"go": "hello.go",
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def run():
|
|
61
|
+
"""Main entry point for the wizard."""
|
|
62
|
+
header()
|
|
63
|
+
|
|
64
|
+
_preflight_checks()
|
|
65
|
+
|
|
66
|
+
language_name, language_key = _select_language()
|
|
67
|
+
|
|
68
|
+
file_name = _get_file_name(language_key)
|
|
69
|
+
|
|
70
|
+
output_dir = _get_output_dir(file_name)
|
|
71
|
+
|
|
72
|
+
divider()
|
|
73
|
+
info(f"Setting up {language_name} environment...")
|
|
74
|
+
divider()
|
|
75
|
+
|
|
76
|
+
installer = Installer()
|
|
77
|
+
sys_info = installer.sys_info
|
|
78
|
+
|
|
79
|
+
total_steps = 4
|
|
80
|
+
current_step = 1
|
|
81
|
+
|
|
82
|
+
if language_key == "all":
|
|
83
|
+
for key, (name, lang_key, _) in LANGUAGES.items():
|
|
84
|
+
if lang_key != "all":
|
|
85
|
+
step(current_step, total_steps, f"Installing {name}")
|
|
86
|
+
installer.install_for_language(lang_key)
|
|
87
|
+
current_step += 1
|
|
88
|
+
else:
|
|
89
|
+
step(current_step, total_steps, f"Installing {language_name} tools")
|
|
90
|
+
installer.install_for_language(language_key)
|
|
91
|
+
current_step += 1
|
|
92
|
+
|
|
93
|
+
step(current_step, total_steps, "Setting up Visual Studio Code")
|
|
94
|
+
vscode_ok = ensure_vscode_installed(sys_info)
|
|
95
|
+
current_step += 1
|
|
96
|
+
|
|
97
|
+
step(current_step, total_steps, "Installing VSCode extensions")
|
|
98
|
+
if vscode_ok:
|
|
99
|
+
if language_key == "all":
|
|
100
|
+
for key, (name, lang_key, _) in LANGUAGES.items():
|
|
101
|
+
if lang_key != "all":
|
|
102
|
+
install_extensions(lang_key)
|
|
103
|
+
else:
|
|
104
|
+
install_extensions(language_key)
|
|
105
|
+
current_step += 1
|
|
106
|
+
|
|
107
|
+
step(current_step, total_steps, "Creating your starter file")
|
|
108
|
+
created_files = []
|
|
109
|
+
if language_key == "all":
|
|
110
|
+
for key, (name, lang_key, ext) in LANGUAGES.items():
|
|
111
|
+
if lang_key != "all":
|
|
112
|
+
f = _create_starter_file(lang_key, "hello", output_dir)
|
|
113
|
+
if f:
|
|
114
|
+
created_files.append(f)
|
|
115
|
+
else:
|
|
116
|
+
f = _create_starter_file(language_key, file_name, output_dir)
|
|
117
|
+
if f:
|
|
118
|
+
created_files.append(f)
|
|
119
|
+
|
|
120
|
+
if language_key in ("python", "all"):
|
|
121
|
+
create_venv(output_dir)
|
|
122
|
+
|
|
123
|
+
if vscode_ok and created_files:
|
|
124
|
+
open_in_vscode(created_files[0])
|
|
125
|
+
|
|
126
|
+
divider()
|
|
127
|
+
success("Everything is set up! Happy coding!")
|
|
128
|
+
success(f"Your files are in: {output_dir}")
|
|
129
|
+
print(
|
|
130
|
+
f"\n Made with love by Zenith Open Source Projects\n"
|
|
131
|
+
f" https://zenithopensourceprojects.vercel.app\n"
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _preflight_checks():
|
|
136
|
+
"""Run all pre-flight checks before doing anything."""
|
|
137
|
+
info("Running checks before we start...")
|
|
138
|
+
|
|
139
|
+
info("Checking internet connection...")
|
|
140
|
+
if not check_internet():
|
|
141
|
+
error(
|
|
142
|
+
"No internet connection detected. "
|
|
143
|
+
"Please connect to the internet and run this again."
|
|
144
|
+
)
|
|
145
|
+
sys.exit(1)
|
|
146
|
+
success("Internet connection OK.")
|
|
147
|
+
|
|
148
|
+
if not check_disk_space(required_gb=2.0):
|
|
149
|
+
sys.exit(1)
|
|
150
|
+
|
|
151
|
+
assert_not_root()
|
|
152
|
+
|
|
153
|
+
import platform
|
|
154
|
+
|
|
155
|
+
if platform.system() == "Windows":
|
|
156
|
+
from projectdevsetup.permissions import check_admin_windows
|
|
157
|
+
|
|
158
|
+
if not check_admin_windows():
|
|
159
|
+
warning(
|
|
160
|
+
"You are not running as administrator. "
|
|
161
|
+
"Some installations may fail. "
|
|
162
|
+
"If needed, restart as administrator."
|
|
163
|
+
)
|
|
164
|
+
else:
|
|
165
|
+
success("Administrator rights detected.")
|
|
166
|
+
|
|
167
|
+
success("All checks passed. Starting setup...")
|
|
168
|
+
divider()
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _select_language() -> tuple:
|
|
172
|
+
"""Show language menu and get user selection."""
|
|
173
|
+
print(" Which programming language do you want to set up?\n")
|
|
174
|
+
for num, (name, _, _) in LANGUAGES.items():
|
|
175
|
+
print(f" {num}. {name}")
|
|
176
|
+
print()
|
|
177
|
+
|
|
178
|
+
while True:
|
|
179
|
+
choice = ask("Enter a number (1-9):").strip()
|
|
180
|
+
if choice in LANGUAGES:
|
|
181
|
+
name, key, _ = LANGUAGES[choice]
|
|
182
|
+
success(f"You selected: {name}")
|
|
183
|
+
return name, key
|
|
184
|
+
else:
|
|
185
|
+
warning("Please enter a number between 1 and 9.")
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _get_file_name(language_key: str) -> str:
|
|
189
|
+
"""Ask the user for their starter file name."""
|
|
190
|
+
if language_key == "all":
|
|
191
|
+
return "hello"
|
|
192
|
+
|
|
193
|
+
lang_ext = ""
|
|
194
|
+
for num, (name, key, ext) in LANGUAGES.items():
|
|
195
|
+
if key == language_key:
|
|
196
|
+
lang_ext = ext
|
|
197
|
+
break
|
|
198
|
+
|
|
199
|
+
print()
|
|
200
|
+
info(f"What do you want to name your file? (without extension)")
|
|
201
|
+
info(f"Example: if you type 'hello', your file will be 'hello{lang_ext}'")
|
|
202
|
+
print()
|
|
203
|
+
|
|
204
|
+
while True:
|
|
205
|
+
name = ask("File name:").strip()
|
|
206
|
+
if not name:
|
|
207
|
+
warning("Please enter a file name.")
|
|
208
|
+
continue
|
|
209
|
+
clean = re.sub(r"[^\w\-]", "_", name)
|
|
210
|
+
if clean != name:
|
|
211
|
+
warning(
|
|
212
|
+
f"Special characters removed. "
|
|
213
|
+
f"Your file will be named: {clean}{lang_ext}"
|
|
214
|
+
)
|
|
215
|
+
if clean:
|
|
216
|
+
return clean
|
|
217
|
+
warning("Please enter a valid file name.")
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _get_output_dir(file_name: str) -> Path:
|
|
221
|
+
"""Create and return the output directory for the project."""
|
|
222
|
+
output = Path.home() / "projectdevsetup_projects" / file_name
|
|
223
|
+
output.mkdir(parents=True, exist_ok=True)
|
|
224
|
+
return output
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _create_starter_file(
|
|
228
|
+
language_key: str, file_name: str, output_dir: Path
|
|
229
|
+
) -> Path | None:
|
|
230
|
+
"""
|
|
231
|
+
Copy the correct template to the output directory
|
|
232
|
+
with the user's chosen file name.
|
|
233
|
+
"""
|
|
234
|
+
template_name = TEMPLATE_MAP.get(language_key)
|
|
235
|
+
if not template_name:
|
|
236
|
+
return None
|
|
237
|
+
|
|
238
|
+
suffix = Path(template_name).suffix
|
|
239
|
+
|
|
240
|
+
if language_key == "java":
|
|
241
|
+
class_name = file_name.capitalize()
|
|
242
|
+
out_file = output_dir / f"{class_name}{suffix}"
|
|
243
|
+
template_content = (
|
|
244
|
+
f"// Hello, World! — Java\n"
|
|
245
|
+
f"// projectdevsetup by Zenith Open Source Projects\n\n"
|
|
246
|
+
f"public class {class_name} {{\n"
|
|
247
|
+
f" public static void main(String[] args) {{\n"
|
|
248
|
+
f' System.out.println("Hello, World!");\n'
|
|
249
|
+
f" }}\n"
|
|
250
|
+
f"}}\n"
|
|
251
|
+
)
|
|
252
|
+
out_file.write_text(template_content)
|
|
253
|
+
else:
|
|
254
|
+
out_file = output_dir / f"{file_name}{suffix}"
|
|
255
|
+
try:
|
|
256
|
+
template_path = Path(__file__).parent / "templates" / template_name
|
|
257
|
+
out_file.write_text(template_path.read_text())
|
|
258
|
+
except Exception:
|
|
259
|
+
out_file.write_text(f"// Your {language_key} starter file\n")
|
|
260
|
+
|
|
261
|
+
success(f"Created: {out_file}")
|
|
262
|
+
return out_file
|