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.
@@ -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