helper-cli 0.1.16__py3-none-any.whl → 0.1.21__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.
- helper/__init__.py +7 -0
- helper/commands/arch.py +8 -2
- helper/commands/docker.py +345 -181
- helper/commands/file.py +202 -0
- helper/commands/internal_ip.py +10 -2
- helper/commands/nixos.py +57 -31
- helper/commands/public_ip.py +11 -2
- helper/commands/speed.py +4 -5
- helper/commands/system_info.py +161 -111
- helper/commands/venv.py +130 -0
- helper/main.py +57 -31
- helper/table.py +29 -0
- {helper_cli-0.1.16.dist-info → helper_cli-0.1.21.dist-info}/METADATA +2 -2
- helper_cli-0.1.21.dist-info/RECORD +19 -0
- helper_cli-0.1.16.dist-info/RECORD +0 -15
- {helper_cli-0.1.16.dist-info → helper_cli-0.1.21.dist-info}/WHEEL +0 -0
- {helper_cli-0.1.16.dist-info → helper_cli-0.1.21.dist-info}/entry_points.txt +0 -0
- {helper_cli-0.1.16.dist-info → helper_cli-0.1.21.dist-info}/top_level.txt +0 -0
helper/commands/system_info.py
CHANGED
|
@@ -4,14 +4,18 @@ import subprocess
|
|
|
4
4
|
import sys
|
|
5
5
|
from datetime import datetime
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
def run_command(cmd):
|
|
8
9
|
"""Run a shell command and return its output"""
|
|
9
10
|
try:
|
|
10
|
-
result = subprocess.check_output(
|
|
11
|
+
result = subprocess.check_output(
|
|
12
|
+
cmd, shell=True, text=True, stderr=subprocess.STDOUT
|
|
13
|
+
).strip()
|
|
11
14
|
return result if result else "N/A"
|
|
12
15
|
except subprocess.CalledProcessError as e:
|
|
13
16
|
return f"Error: {e.output}" if e.output else "Command failed"
|
|
14
17
|
|
|
18
|
+
|
|
15
19
|
def format_bytes(size_bytes):
|
|
16
20
|
"""Convert bytes to human readable format"""
|
|
17
21
|
if not isinstance(size_bytes, (int, float)):
|
|
@@ -19,53 +23,54 @@ def format_bytes(size_bytes):
|
|
|
19
23
|
size_bytes = float(size_bytes)
|
|
20
24
|
except (ValueError, TypeError):
|
|
21
25
|
return str(size_bytes)
|
|
22
|
-
|
|
23
|
-
for unit in [
|
|
24
|
-
if size_bytes < 1024.0 or unit ==
|
|
26
|
+
|
|
27
|
+
for unit in ["B", "KB", "MB", "GB", "TB", "PB"]:
|
|
28
|
+
if size_bytes < 1024.0 or unit == "PB":
|
|
25
29
|
return f"{size_bytes:.1f} {unit}"
|
|
26
30
|
size_bytes /= 1024.0
|
|
27
31
|
return f"{size_bytes:.1f} PB"
|
|
28
32
|
|
|
33
|
+
|
|
29
34
|
def parse_vm_stat(output):
|
|
30
35
|
"""Parse macOS vm_stat output and return human readable memory info"""
|
|
31
|
-
if not output or
|
|
36
|
+
if not output or "Mach Virtual Memory Statistics" not in output:
|
|
32
37
|
return "Memory information not available"
|
|
33
|
-
|
|
38
|
+
|
|
34
39
|
# Get physical memory using sysctl
|
|
35
40
|
try:
|
|
36
|
-
total_memory = int(run_command(
|
|
41
|
+
total_memory = int(run_command("sysctl -n hw.memsize"))
|
|
37
42
|
except (ValueError, subprocess.CalledProcessError):
|
|
38
43
|
return "Error: Could not determine total physical memory"
|
|
39
|
-
|
|
40
|
-
lines = output.split(
|
|
44
|
+
|
|
45
|
+
lines = output.split("\n")
|
|
41
46
|
mem_info = {}
|
|
42
|
-
|
|
47
|
+
|
|
43
48
|
for line in lines[1:]: # Skip header
|
|
44
|
-
if
|
|
45
|
-
key, value = line.split(
|
|
46
|
-
key = key.strip().strip(
|
|
49
|
+
if ":" in line:
|
|
50
|
+
key, value = line.split(":", 1)
|
|
51
|
+
key = key.strip().strip(".")
|
|
47
52
|
try:
|
|
48
53
|
# Convert pages to bytes (1 page = 4KB on macOS)
|
|
49
|
-
pages = int(value.strip().strip(
|
|
54
|
+
pages = int(value.strip().strip("."))
|
|
50
55
|
mem_info[key] = pages * 4096 # 4KB per page
|
|
51
56
|
except (ValueError, AttributeError):
|
|
52
57
|
mem_info[key] = value.strip()
|
|
53
|
-
|
|
58
|
+
|
|
54
59
|
# Calculate memory usage
|
|
55
|
-
wired_memory = mem_info.get(
|
|
56
|
-
active_memory = mem_info.get(
|
|
57
|
-
inactive_memory = mem_info.get(
|
|
58
|
-
free_memory = mem_info.get(
|
|
59
|
-
|
|
60
|
+
wired_memory = mem_info.get("Pages wired down", 0)
|
|
61
|
+
active_memory = mem_info.get("Pages active", 0)
|
|
62
|
+
inactive_memory = mem_info.get("Pages inactive", 0)
|
|
63
|
+
free_memory = mem_info.get("Pages free", 0)
|
|
64
|
+
|
|
60
65
|
# Calculate used memory (wired + active)
|
|
61
66
|
used_memory = wired_memory + active_memory
|
|
62
|
-
|
|
67
|
+
|
|
63
68
|
# Calculate app memory (active + inactive)
|
|
64
69
|
app_memory = active_memory + inactive_memory
|
|
65
|
-
|
|
70
|
+
|
|
66
71
|
# Calculate cached files (inactive memory can be purged by the OS)
|
|
67
72
|
cached_files = inactive_memory
|
|
68
|
-
|
|
73
|
+
|
|
69
74
|
return (
|
|
70
75
|
f"Total: {format_bytes(total_memory)}\n"
|
|
71
76
|
f"Used: {format_bytes(used_memory)} (Apps: {format_bytes(app_memory)}, Wired: {format_bytes(wired_memory)})\n"
|
|
@@ -74,137 +79,167 @@ def parse_vm_stat(output):
|
|
|
74
79
|
f"Usage: {used_memory/total_memory*100:.1f}%"
|
|
75
80
|
)
|
|
76
81
|
|
|
82
|
+
|
|
77
83
|
def parse_df_output(output):
|
|
78
84
|
"""Parse df output and format sizes"""
|
|
79
85
|
if not output:
|
|
80
86
|
return "Disk information not available"
|
|
81
|
-
|
|
82
|
-
lines = output.split(
|
|
87
|
+
|
|
88
|
+
lines = output.split("\n")
|
|
83
89
|
if not lines:
|
|
84
90
|
return output
|
|
85
|
-
|
|
91
|
+
|
|
86
92
|
# Keep the header
|
|
87
93
|
result = [lines[0]]
|
|
88
|
-
|
|
94
|
+
|
|
89
95
|
# Process each line
|
|
90
96
|
for line in lines[1:]:
|
|
91
97
|
if not line.strip():
|
|
92
98
|
continue
|
|
93
|
-
|
|
99
|
+
|
|
94
100
|
parts = line.split()
|
|
95
101
|
if len(parts) >= 5:
|
|
96
102
|
# Format size columns (assuming standard df -h output)
|
|
97
|
-
parts[1] = format_bytes(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
parts[1] = format_bytes(
|
|
104
|
+
parts[1]
|
|
105
|
+
.upper()
|
|
106
|
+
.replace("G", "GB")
|
|
107
|
+
.replace("M", "MB")
|
|
108
|
+
.replace("K", "KB")
|
|
109
|
+
.replace("B", "")
|
|
110
|
+
.replace("I", "")
|
|
111
|
+
.strip()
|
|
112
|
+
)
|
|
113
|
+
parts[2] = format_bytes(
|
|
114
|
+
parts[2]
|
|
115
|
+
.upper()
|
|
116
|
+
.replace("G", "GB")
|
|
117
|
+
.replace("M", "MB")
|
|
118
|
+
.replace("K", "KB")
|
|
119
|
+
.replace("B", "")
|
|
120
|
+
.replace("I", "")
|
|
121
|
+
.strip()
|
|
122
|
+
)
|
|
123
|
+
parts[3] = format_bytes(
|
|
124
|
+
parts[3]
|
|
125
|
+
.upper()
|
|
126
|
+
.replace("G", "GB")
|
|
127
|
+
.replace("M", "MB")
|
|
128
|
+
.replace("K", "KB")
|
|
129
|
+
.replace("B", "")
|
|
130
|
+
.replace("I", "")
|
|
131
|
+
.strip()
|
|
132
|
+
)
|
|
133
|
+
|
|
104
134
|
# Reconstruct the line with formatted sizes
|
|
105
|
-
result.append(
|
|
135
|
+
result.append(" ".join(parts))
|
|
106
136
|
else:
|
|
107
137
|
result.append(line)
|
|
108
|
-
|
|
109
|
-
return
|
|
138
|
+
|
|
139
|
+
return "\n".join(result)
|
|
140
|
+
|
|
110
141
|
|
|
111
142
|
def get_os_specific_info():
|
|
112
143
|
"""Get OS-specific system information"""
|
|
113
144
|
system = platform.system().lower()
|
|
114
|
-
|
|
115
|
-
if system ==
|
|
145
|
+
|
|
146
|
+
if system == "darwin": # macOS
|
|
116
147
|
return {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
148
|
+
"cpu": "sysctl -n machdep.cpu.brand_string",
|
|
149
|
+
"cpu_cores": "sysctl -n hw.ncpu",
|
|
150
|
+
"memory": "vm_stat",
|
|
151
|
+
"disks": "df -h",
|
|
152
|
+
"os_version": "sw_vers",
|
|
153
|
+
"hostname": "hostname",
|
|
154
|
+
"uptime": "uptime",
|
|
124
155
|
}
|
|
125
|
-
elif system ==
|
|
156
|
+
elif system == "linux":
|
|
126
157
|
return {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
158
|
+
"cpu": 'cat /proc/cpuinfo | grep "model name" | head -n 1 | cut -d":" -f2',
|
|
159
|
+
"cpu_cores": "nproc",
|
|
160
|
+
"memory": "free -h",
|
|
161
|
+
"disks": "df -h",
|
|
162
|
+
"os_version": "cat /etc/os-release",
|
|
163
|
+
"hostname": "hostname",
|
|
164
|
+
"uptime": "uptime",
|
|
134
165
|
}
|
|
135
|
-
elif system ==
|
|
166
|
+
elif system == "windows":
|
|
136
167
|
return {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
168
|
+
"cpu": "wmic cpu get name",
|
|
169
|
+
"cpu_cores": "wmic cpu get NumberOfCores",
|
|
170
|
+
"memory": "wmic OS get TotalVisibleMemorySize,FreePhysicalMemory /Value",
|
|
171
|
+
"disks": "wmic logicaldisk get size,freespace,caption",
|
|
172
|
+
"os_version": 'systeminfo | findstr /B /C:"OS Name" /C:"OS Version"',
|
|
173
|
+
"hostname": "hostname",
|
|
174
|
+
"uptime": "wmic os get lastbootuptime",
|
|
144
175
|
}
|
|
145
176
|
else:
|
|
146
177
|
return None
|
|
147
178
|
|
|
179
|
+
|
|
148
180
|
def format_uptime(uptime_str, system):
|
|
149
181
|
"""Format uptime string based on OS"""
|
|
150
|
-
if system ==
|
|
182
|
+
if system == "darwin" or system == "linux":
|
|
151
183
|
# Example: ' 8:53 up 1 day, 3:45, 2 users, load averages: 2.22 2.41 2.35'
|
|
152
|
-
parts = uptime_str.split(
|
|
153
|
-
if
|
|
154
|
-
return
|
|
184
|
+
parts = uptime_str.split(",")
|
|
185
|
+
if "up" in parts[0]:
|
|
186
|
+
return "Uptime: " + parts[0].split("up", 1)[1].strip()
|
|
155
187
|
return uptime_str
|
|
156
188
|
|
|
189
|
+
|
|
157
190
|
@click.command()
|
|
158
191
|
def system_info():
|
|
159
192
|
"""Display system information including CPU, RAM, and disk usage"""
|
|
160
193
|
system = platform.system().lower()
|
|
161
194
|
commands = get_os_specific_info()
|
|
162
|
-
|
|
195
|
+
|
|
163
196
|
if not commands:
|
|
164
197
|
click.echo("Unsupported operating system")
|
|
165
198
|
return
|
|
166
|
-
|
|
199
|
+
|
|
167
200
|
# System Information
|
|
168
|
-
click.echo("="*40 + " System Information " + "="*40)
|
|
201
|
+
click.echo("=" * 40 + " System Information " + "=" * 40)
|
|
169
202
|
click.echo(f"System: {platform.system()} {platform.release()}")
|
|
170
203
|
click.echo(f"Node Name: {run_command(commands['hostname'])}")
|
|
171
204
|
click.echo(f"Machine: {platform.machine()}")
|
|
172
|
-
click.echo(
|
|
173
|
-
|
|
205
|
+
click.echo(
|
|
206
|
+
f"Processor: {platform.processor() or run_command(commands['cpu']).strip()}"
|
|
207
|
+
)
|
|
208
|
+
|
|
174
209
|
# OS Version
|
|
175
|
-
click.echo("\n" + "="*40 + " OS Version " + "="*40)
|
|
176
|
-
click.echo(run_command(commands[
|
|
177
|
-
|
|
210
|
+
click.echo("\n" + "=" * 40 + " OS Version " + "=" * 40)
|
|
211
|
+
click.echo(run_command(commands["os_version"]))
|
|
212
|
+
|
|
178
213
|
# Uptime
|
|
179
|
-
click.echo("\n" + "="*40 + " Uptime " + "="*40)
|
|
180
|
-
uptime = run_command(commands[
|
|
214
|
+
click.echo("\n" + "=" * 40 + " Uptime " + "=" * 40)
|
|
215
|
+
uptime = run_command(commands["uptime"])
|
|
181
216
|
click.echo(format_uptime(uptime, system))
|
|
182
|
-
|
|
217
|
+
|
|
183
218
|
# CPU Information
|
|
184
|
-
click.echo("\n" + "="*40 + " CPU Info " + "="*40)
|
|
185
|
-
cpu_cores = run_command(commands[
|
|
219
|
+
click.echo("\n" + "=" * 40 + " CPU Info " + "=" * 40)
|
|
220
|
+
cpu_cores = run_command(commands["cpu_cores"]).strip()
|
|
186
221
|
click.echo(f"CPU Cores: {cpu_cores}")
|
|
187
|
-
|
|
188
|
-
if system ==
|
|
189
|
-
cpu_info = run_command(commands[
|
|
222
|
+
|
|
223
|
+
if system == "darwin" or system == "linux":
|
|
224
|
+
cpu_info = run_command(commands["cpu"]).strip()
|
|
190
225
|
click.echo(f"CPU: {cpu_info}")
|
|
191
|
-
|
|
226
|
+
|
|
192
227
|
# CPU Usage (simplified for cross-platform)
|
|
193
|
-
if system ==
|
|
194
|
-
load_avg = run_command(
|
|
228
|
+
if system == "darwin":
|
|
229
|
+
load_avg = run_command("sysctl -n vm.loadavg").strip()
|
|
195
230
|
click.echo(f"Load Average: {load_avg}")
|
|
196
|
-
elif system ==
|
|
197
|
-
load_avg = run_command(
|
|
231
|
+
elif system == "linux":
|
|
232
|
+
load_avg = run_command("cat /proc/loadavg").strip()
|
|
198
233
|
click.echo(f"Load Average: {load_avg}")
|
|
199
|
-
|
|
234
|
+
|
|
200
235
|
# Memory Information
|
|
201
|
-
click.echo("\n" + "="*40 + " Memory Information " + "="*40)
|
|
202
|
-
if system ==
|
|
203
|
-
mem_info = run_command(
|
|
236
|
+
click.echo("\n" + "=" * 40 + " Memory Information " + "=" * 40)
|
|
237
|
+
if system == "darwin":
|
|
238
|
+
mem_info = run_command("vm_stat")
|
|
204
239
|
click.echo(parse_vm_stat(mem_info))
|
|
205
|
-
elif system ==
|
|
206
|
-
mem_info = run_command(
|
|
207
|
-
lines = mem_info.split(
|
|
240
|
+
elif system == "linux":
|
|
241
|
+
mem_info = run_command("free -b") # Get bytes for consistent formatting
|
|
242
|
+
lines = mem_info.split("\n")
|
|
208
243
|
if len(lines) > 1:
|
|
209
244
|
headers = lines[0].split()
|
|
210
245
|
values = lines[1].split()
|
|
@@ -218,12 +253,19 @@ def system_info():
|
|
|
218
253
|
f"Free: {format_bytes(free)}\n"
|
|
219
254
|
f"Usage: {used/total*100:.1f}%"
|
|
220
255
|
)
|
|
221
|
-
elif system ==
|
|
222
|
-
mem_info = run_command(
|
|
223
|
-
|
|
256
|
+
elif system == "windows":
|
|
257
|
+
mem_info = run_command(
|
|
258
|
+
"wmic OS get TotalVisibleMemorySize,FreePhysicalMemory /Value"
|
|
259
|
+
)
|
|
260
|
+
if "TotalVisibleMemorySize" in mem_info and "FreePhysicalMemory" in mem_info:
|
|
224
261
|
try:
|
|
225
|
-
total =
|
|
226
|
-
|
|
262
|
+
total = (
|
|
263
|
+
int(mem_info.split("TotalVisibleMemorySize=")[1].split("\n")[0])
|
|
264
|
+
* 1024
|
|
265
|
+
) # KB to bytes
|
|
266
|
+
free = (
|
|
267
|
+
int(mem_info.split("FreePhysicalMemory=")[1].split("\n")[0]) * 1024
|
|
268
|
+
) # KB to bytes
|
|
227
269
|
used = total - free
|
|
228
270
|
click.echo(
|
|
229
271
|
f"Total: {format_bytes(total)}\n"
|
|
@@ -235,15 +277,18 @@ def system_info():
|
|
|
235
277
|
click.echo(mem_info)
|
|
236
278
|
else:
|
|
237
279
|
click.echo(mem_info)
|
|
238
|
-
|
|
280
|
+
|
|
239
281
|
# Disk Information
|
|
240
|
-
click.echo("\n" + "="*40 + " Disk Information " + "="*40)
|
|
241
|
-
if system ==
|
|
242
|
-
disks = run_command(
|
|
243
|
-
if
|
|
244
|
-
lines = disks.split(
|
|
245
|
-
result = [
|
|
246
|
-
"
|
|
282
|
+
click.echo("\n" + "=" * 40 + " Disk Information " + "=" * 40)
|
|
283
|
+
if system == "windows":
|
|
284
|
+
disks = run_command("wmic logicaldisk get size,freespace,caption")
|
|
285
|
+
if "Caption" in disks:
|
|
286
|
+
lines = disks.split("\n")
|
|
287
|
+
result = [
|
|
288
|
+
"{:<5} {:<15} {:<15} {:<15} {:<10}".format(
|
|
289
|
+
"Drive", "Total Space", "Free Space", "Used Space", "% Used"
|
|
290
|
+
)
|
|
291
|
+
]
|
|
247
292
|
for line in lines[1:]:
|
|
248
293
|
parts = line.strip().split()
|
|
249
294
|
if len(parts) >= 3:
|
|
@@ -259,18 +304,23 @@ def system_info():
|
|
|
259
304
|
format_bytes(size),
|
|
260
305
|
format_bytes(free),
|
|
261
306
|
format_bytes(used),
|
|
262
|
-
pct_used
|
|
307
|
+
pct_used,
|
|
263
308
|
)
|
|
264
309
|
)
|
|
265
310
|
except (ValueError, IndexError):
|
|
266
311
|
continue
|
|
267
|
-
click.echo(
|
|
312
|
+
click.echo("\n".join(result))
|
|
268
313
|
else:
|
|
269
314
|
click.echo(disks)
|
|
270
315
|
else:
|
|
271
|
-
disks = run_command(
|
|
316
|
+
disks = run_command(
|
|
317
|
+
"df -h"
|
|
318
|
+
if system != "windows"
|
|
319
|
+
else "wmic logicaldisk get size,freespace,caption"
|
|
320
|
+
)
|
|
272
321
|
click.echo(parse_df_output(disks))
|
|
273
322
|
|
|
323
|
+
|
|
274
324
|
# Add aliases for the command
|
|
275
325
|
sysinfo = system_info
|
|
276
326
|
si = system_info
|
helper/commands/venv.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Virtual environment management commands for the helper CLI.
|
|
3
|
+
|
|
4
|
+
This module provides commands to manage Python virtual environments,
|
|
5
|
+
including activating and deactivating them from the command line.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def find_virtualenv(path=None):
|
|
15
|
+
"""Find virtual environment in the given path or current directory.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
path (str, optional): Path to search for virtual environment.
|
|
19
|
+
Defaults to current directory.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
str: Path to the activate script if found, None otherwise.
|
|
23
|
+
"""
|
|
24
|
+
if path is None:
|
|
25
|
+
path = os.getcwd()
|
|
26
|
+
|
|
27
|
+
# Check common virtual environment directories
|
|
28
|
+
venv_dirs = ["venv", ".venv"]
|
|
29
|
+
for venv_dir in venv_dirs:
|
|
30
|
+
activate_script = os.path.join(path, venv_dir, "bin", "activate")
|
|
31
|
+
if os.path.exists(activate_script):
|
|
32
|
+
return activate_script
|
|
33
|
+
|
|
34
|
+
# If not found in current directory, try parent directories
|
|
35
|
+
parent = os.path.dirname(path)
|
|
36
|
+
if parent != path: # Prevent infinite recursion
|
|
37
|
+
return find_virtualenv(parent)
|
|
38
|
+
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def source_virtualenv(venv_path=None):
|
|
43
|
+
"""Source a virtual environment.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
venv_path (str, optional): Path to the virtual environment.
|
|
47
|
+
If None, search in current and parent directories.
|
|
48
|
+
"""
|
|
49
|
+
if venv_path is None:
|
|
50
|
+
activate_script = find_virtualenv()
|
|
51
|
+
if not activate_script:
|
|
52
|
+
click.echo(
|
|
53
|
+
"Error: No virtual environment found in current or parent directories.",
|
|
54
|
+
err=True,
|
|
55
|
+
)
|
|
56
|
+
click.echo(
|
|
57
|
+
"Please specify the path to the virtual environment or "
|
|
58
|
+
"create one with 'python -m venv venv'"
|
|
59
|
+
)
|
|
60
|
+
sys.exit(1)
|
|
61
|
+
else:
|
|
62
|
+
# If path is provided, check if it's a directory or activate script
|
|
63
|
+
if os.path.isdir(venv_path):
|
|
64
|
+
# If it's a directory, look for bin/activate
|
|
65
|
+
activate_script = os.path.join(venv_path, "bin", "activate")
|
|
66
|
+
if not os.path.exists(activate_script):
|
|
67
|
+
click.echo(f"Error: No activate script found in {venv_path}", err=True)
|
|
68
|
+
sys.exit(1)
|
|
69
|
+
elif os.path.isfile(venv_path):
|
|
70
|
+
# If it's a file, use it directly
|
|
71
|
+
activate_script = venv_path
|
|
72
|
+
else:
|
|
73
|
+
click.echo(f"Error: {venv_path} is not a valid file or directory", err=True)
|
|
74
|
+
sys.exit(1)
|
|
75
|
+
|
|
76
|
+
# Get the absolute path to the activate script
|
|
77
|
+
activate_script = os.path.abspath(activate_script)
|
|
78
|
+
|
|
79
|
+
# Print the command to source the virtual environment
|
|
80
|
+
# The user needs to run this with 'eval $(h venv source [path])' or
|
|
81
|
+
# 'source <(h venv source [path])'
|
|
82
|
+
click.echo(f'source "{activate_script}"')
|
|
83
|
+
venv_dir = os.path.dirname(os.path.dirname(activate_script))
|
|
84
|
+
click.echo(f"# Virtual environment activated: {venv_dir}", err=True)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def deactivate_virtualenv():
|
|
88
|
+
"""Print the command to deactivate the current virtual environment."""
|
|
89
|
+
click.echo("deactivate")
|
|
90
|
+
click.echo("# Virtual environment deactivated", err=True)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@click.group()
|
|
94
|
+
def venv():
|
|
95
|
+
"""Manage Python virtual environments (v0.1.19)."""
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@venv.command()
|
|
99
|
+
@click.argument("path", required=False)
|
|
100
|
+
def source(path):
|
|
101
|
+
"""Source a Python virtual environment.
|
|
102
|
+
|
|
103
|
+
If no path is provided, searches for a virtual environment in the current or parent directories.
|
|
104
|
+
Looks for 'venv' first, then '.venv'.
|
|
105
|
+
|
|
106
|
+
Usage:
|
|
107
|
+
h venv source [PATH] # Source the specified virtual environment or auto-detect
|
|
108
|
+
eval $(h venv source) # In bash/zsh to activate the virtual environment
|
|
109
|
+
source <(h venv source) # Alternative syntax for bash/zsh
|
|
110
|
+
"""
|
|
111
|
+
source_virtualenv(path)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@venv.command()
|
|
115
|
+
def deactivate():
|
|
116
|
+
"""Deactivate the current virtual environment.
|
|
117
|
+
|
|
118
|
+
Usage:
|
|
119
|
+
h venv deactivate # Show the deactivate command
|
|
120
|
+
eval $(h venv deactivate) # In bash/zsh to deactivate the virtual environment
|
|
121
|
+
"""
|
|
122
|
+
deactivate_virtualenv()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# Add short aliases
|
|
126
|
+
s = source
|
|
127
|
+
d = deactivate
|
|
128
|
+
|
|
129
|
+
# Add the commands to the module
|
|
130
|
+
__all__ = ["venv", "source", "deactivate", "s", "d"]
|