vssh 3.7.5__tar.gz → 4.1.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.
- vssh-4.1.0/PKG-INFO +224 -0
- vssh-4.1.0/README.md +207 -0
- vssh-4.1.0/pyproject.toml +30 -0
- vssh-4.1.0/vssh/__init__.py +51 -0
- vssh-4.1.0/vssh.egg-info/PKG-INFO +224 -0
- {vssh-3.7.5 → vssh-4.1.0}/vssh.egg-info/SOURCES.txt +1 -0
- vssh-4.1.0/vssh.egg-info/entry_points.txt +2 -0
- vssh-4.1.0/vssh.egg-info/top_level.txt +1 -0
- {vssh-3.7.5 → vssh-4.1.0}/vssh.py +0 -0
- vssh-3.7.5/PKG-INFO +0 -478
- vssh-3.7.5/README.md +0 -455
- vssh-3.7.5/pyproject.toml +0 -41
- vssh-3.7.5/vssh.egg-info/PKG-INFO +0 -478
- vssh-3.7.5/vssh.egg-info/entry_points.txt +0 -6
- vssh-3.7.5/vssh.egg-info/top_level.txt +0 -2
- {vssh-3.7.5 → vssh-4.1.0}/LICENSE +0 -0
- {vssh-3.7.5 → vssh-4.1.0}/setup.cfg +0 -0
- {vssh-3.7.5 → vssh-4.1.0}/vssh.egg-info/dependency_links.txt +0 -0
- {vssh-3.7.5 → vssh-4.1.0}/vssh_mcp_server.py +0 -0
vssh-4.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vssh
|
|
3
|
+
Version: 4.1.0
|
|
4
|
+
Summary: vssh - installs Go binary
|
|
5
|
+
Author-email: MeshPOP <mpop@mpop.dev>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/meshpop/vssh
|
|
8
|
+
Keywords: ssh,scp,remote
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
12
|
+
Classifier: Operating System :: MacOS
|
|
13
|
+
Requires-Python: >=3.8
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# vssh
|
|
19
|
+
|
|
20
|
+
[](https://pypi.org/project/vssh/)
|
|
21
|
+
|
|
22
|
+
**SSH/SCP CLI - Go binary installer**
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install vssh
|
|
26
|
+
vssh # Auto-downloads Go binary on first run
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This package automatically downloads and installs the native Go binary for your platform.
|
|
30
|
+
[](https://pypi.org/project/vssh/)
|
|
31
|
+
[](LICENSE)
|
|
32
|
+
|
|
33
|
+
**Fast SSH alternative for server fleets. One shared secret. No key management.**
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install vssh
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Pure Python standard library. No external packages. Linux and macOS.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Why vssh?
|
|
44
|
+
|
|
45
|
+
| | SSH | vssh |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| Authentication | Per-server public keys | One shared HMAC secret |
|
|
48
|
+
| Add a new server | Generate + copy key | Just set the same secret |
|
|
49
|
+
| Revoke access | Remove key from every server | Rotate secret once |
|
|
50
|
+
| Connection setup | Full handshake (~200–400ms) | Token check (~1ms) |
|
|
51
|
+
| Server discovery | IPs / DNS | wire mesh auto-discovery |
|
|
52
|
+
| Fleet health | None | `vssh status` — all nodes |
|
|
53
|
+
| AI management | ✗ | ✓ MCP integration |
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## How it works
|
|
58
|
+
|
|
59
|
+
Each server runs a persistent daemon on TCP port 48291. Every request includes an HMAC-SHA256 time-based token derived from the shared secret — no public key cryptography, no handshake overhead.
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
┌──────────────────────────────────────┐
|
|
63
|
+
│ Fleet │
|
|
64
|
+
│ ┌──────┐ ┌──────┐ ┌──────┐ │
|
|
65
|
+
│ │ web1 │ │ web2 │ │ db1 │ ... │
|
|
66
|
+
│ │:48291│ │:48291│ │:48291│ │
|
|
67
|
+
│ └──┬───┘ └──┬───┘ └──┬───┘ │
|
|
68
|
+
│ └─────────┴─────────┘ │
|
|
69
|
+
│ wire / VPN │
|
|
70
|
+
└─────────────────┬────────────────────┘
|
|
71
|
+
│ TCP :48291
|
|
72
|
+
┌──────┴──────┐
|
|
73
|
+
│ vssh client │
|
|
74
|
+
└─────────────┘
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Setup
|
|
80
|
+
|
|
81
|
+
### 1. Install and start the daemon on each server
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
export VSSH_SECRET=your-shared-secret
|
|
85
|
+
vssh server
|
|
86
|
+
|
|
87
|
+
# Or install as a systemd service:
|
|
88
|
+
vssh install
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Generate a strong secret:
|
|
92
|
+
```bash
|
|
93
|
+
python3 -c "import secrets; print(secrets.token_hex(32))"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 2. Configure the client
|
|
97
|
+
|
|
98
|
+
With [wire](https://github.com/meshpop/wire) mesh VPN, vssh auto-discovers all nodes — no client config needed.
|
|
99
|
+
|
|
100
|
+
For standalone use, create `~/.vssh/config`:
|
|
101
|
+
|
|
102
|
+
```ini
|
|
103
|
+
web1=192.168.1.10
|
|
104
|
+
web2=192.168.1.11
|
|
105
|
+
db1=192.168.1.20
|
|
106
|
+
SECRET=your-shared-secret
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## CLI Reference
|
|
112
|
+
|
|
113
|
+
### Fleet status
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
vssh status # All nodes — online/offline, latency
|
|
117
|
+
vssh status --full # Status + disk, memory, load
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Remote execution
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
vssh web1 "df -h" # Run command
|
|
124
|
+
vssh web1 # Interactive shell
|
|
125
|
+
vssh web1 "df -h && free -h" # Chained commands
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### File transfer
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
vssh put ./nginx.conf web1:/etc/nginx/ # Upload
|
|
132
|
+
vssh get web1:/var/log/app.log ./ # Download
|
|
133
|
+
vssh sync ./config/ web1:/etc/app/ # Sync directory
|
|
134
|
+
vssh rsync <local> <host>:<remote> # Delta sync (changed blocks only)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Auto-compresses text files. Skips upload if remote file is identical (MD5 check).
|
|
138
|
+
|
|
139
|
+
### RPC — typed JSON data
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
vssh rpc web1 get_disk
|
|
143
|
+
vssh rpc web1 get_processes '{"n": 5, "sort": "mem"}'
|
|
144
|
+
vssh rpc-list web1 # List all available methods
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
| Method | Returns |
|
|
148
|
+
|---|---|
|
|
149
|
+
| `get_disk` | Disk usage |
|
|
150
|
+
| `get_memory` | Memory stats |
|
|
151
|
+
| `get_load` | Load averages |
|
|
152
|
+
| `get_processes` | Top processes |
|
|
153
|
+
| `get_gpu` | GPU VRAM, utilization, temp |
|
|
154
|
+
| `get_logs` | Log file or journalctl |
|
|
155
|
+
| `list_services` | Running systemd services |
|
|
156
|
+
| `restart_service` | Restart nginx / docker / postgresql / redis |
|
|
157
|
+
| `docker_containers` | Docker container list |
|
|
158
|
+
| `file_read` / `file_write` | File operations |
|
|
159
|
+
|
|
160
|
+
### Other
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
vssh speed-test web1 # Measure transfer speed
|
|
164
|
+
vssh history [count] [filter] # Command history
|
|
165
|
+
vssh stats [days] # Transfer stats
|
|
166
|
+
vssh pipe-up web1:/path # Pipe stdin to remote file
|
|
167
|
+
vssh pipe-down web1:"cmd" # Pipe remote output to stdout
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Tailscale Failover
|
|
173
|
+
|
|
174
|
+
If a node's primary VPN IP is unreachable, vssh automatically tries the Tailscale IP:
|
|
175
|
+
|
|
176
|
+
1. Try wire VPN IP (1.5s timeout)
|
|
177
|
+
2. Fall back to Tailscale IP, cache for 60s
|
|
178
|
+
3. After 60s: retry wire — if recovered, clear failover
|
|
179
|
+
|
|
180
|
+
The failover map is built automatically by cross-referencing `tailscale status` with wire peers.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## AI Management via MCP
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{
|
|
188
|
+
"mcpServers": {
|
|
189
|
+
"vssh": { "command": "vssh-mcp" }
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
> "Check which servers are online and show me disk usage"
|
|
195
|
+
> "Deploy the new config to all web servers and reload nginx"
|
|
196
|
+
> "What's using the most memory on db1?"
|
|
197
|
+
|
|
198
|
+
### MCP Tools
|
|
199
|
+
|
|
200
|
+
| Tool | Description |
|
|
201
|
+
|---|---|
|
|
202
|
+
| `vssh_status` | Fleet status — all nodes, latency |
|
|
203
|
+
| `vssh_exec` | Run command on remote server |
|
|
204
|
+
| `vssh_put` / `vssh_get` | Upload / download file |
|
|
205
|
+
| `vssh_sync` | Sync directory |
|
|
206
|
+
| `vssh_speed_test` | Transfer speed |
|
|
207
|
+
| `vssh_tunnel` | Port-forward tunnel |
|
|
208
|
+
| `vssh_keys` | Show secret and server list |
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## MeshPOP Stack
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
mpop Fleet orchestration — monitor, manage, automate
|
|
216
|
+
vssh Authenticated transport — remote exec, file transfer ← this
|
|
217
|
+
wire Encrypted mesh VPN — connects all nodes
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
MIT — [MeshPOP](https://github.com/meshpop)
|
vssh-4.1.0/README.md
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# vssh
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/vssh/)
|
|
4
|
+
|
|
5
|
+
**SSH/SCP CLI - Go binary installer**
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install vssh
|
|
9
|
+
vssh # Auto-downloads Go binary on first run
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
This package automatically downloads and installs the native Go binary for your platform.
|
|
13
|
+
[](https://pypi.org/project/vssh/)
|
|
14
|
+
[](LICENSE)
|
|
15
|
+
|
|
16
|
+
**Fast SSH alternative for server fleets. One shared secret. No key management.**
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install vssh
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Pure Python standard library. No external packages. Linux and macOS.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Why vssh?
|
|
27
|
+
|
|
28
|
+
| | SSH | vssh |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| Authentication | Per-server public keys | One shared HMAC secret |
|
|
31
|
+
| Add a new server | Generate + copy key | Just set the same secret |
|
|
32
|
+
| Revoke access | Remove key from every server | Rotate secret once |
|
|
33
|
+
| Connection setup | Full handshake (~200–400ms) | Token check (~1ms) |
|
|
34
|
+
| Server discovery | IPs / DNS | wire mesh auto-discovery |
|
|
35
|
+
| Fleet health | None | `vssh status` — all nodes |
|
|
36
|
+
| AI management | ✗ | ✓ MCP integration |
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## How it works
|
|
41
|
+
|
|
42
|
+
Each server runs a persistent daemon on TCP port 48291. Every request includes an HMAC-SHA256 time-based token derived from the shared secret — no public key cryptography, no handshake overhead.
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
┌──────────────────────────────────────┐
|
|
46
|
+
│ Fleet │
|
|
47
|
+
│ ┌──────┐ ┌──────┐ ┌──────┐ │
|
|
48
|
+
│ │ web1 │ │ web2 │ │ db1 │ ... │
|
|
49
|
+
│ │:48291│ │:48291│ │:48291│ │
|
|
50
|
+
│ └──┬───┘ └──┬───┘ └──┬───┘ │
|
|
51
|
+
│ └─────────┴─────────┘ │
|
|
52
|
+
│ wire / VPN │
|
|
53
|
+
└─────────────────┬────────────────────┘
|
|
54
|
+
│ TCP :48291
|
|
55
|
+
┌──────┴──────┐
|
|
56
|
+
│ vssh client │
|
|
57
|
+
└─────────────┘
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Setup
|
|
63
|
+
|
|
64
|
+
### 1. Install and start the daemon on each server
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
export VSSH_SECRET=your-shared-secret
|
|
68
|
+
vssh server
|
|
69
|
+
|
|
70
|
+
# Or install as a systemd service:
|
|
71
|
+
vssh install
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Generate a strong secret:
|
|
75
|
+
```bash
|
|
76
|
+
python3 -c "import secrets; print(secrets.token_hex(32))"
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 2. Configure the client
|
|
80
|
+
|
|
81
|
+
With [wire](https://github.com/meshpop/wire) mesh VPN, vssh auto-discovers all nodes — no client config needed.
|
|
82
|
+
|
|
83
|
+
For standalone use, create `~/.vssh/config`:
|
|
84
|
+
|
|
85
|
+
```ini
|
|
86
|
+
web1=192.168.1.10
|
|
87
|
+
web2=192.168.1.11
|
|
88
|
+
db1=192.168.1.20
|
|
89
|
+
SECRET=your-shared-secret
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## CLI Reference
|
|
95
|
+
|
|
96
|
+
### Fleet status
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
vssh status # All nodes — online/offline, latency
|
|
100
|
+
vssh status --full # Status + disk, memory, load
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Remote execution
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
vssh web1 "df -h" # Run command
|
|
107
|
+
vssh web1 # Interactive shell
|
|
108
|
+
vssh web1 "df -h && free -h" # Chained commands
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### File transfer
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
vssh put ./nginx.conf web1:/etc/nginx/ # Upload
|
|
115
|
+
vssh get web1:/var/log/app.log ./ # Download
|
|
116
|
+
vssh sync ./config/ web1:/etc/app/ # Sync directory
|
|
117
|
+
vssh rsync <local> <host>:<remote> # Delta sync (changed blocks only)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Auto-compresses text files. Skips upload if remote file is identical (MD5 check).
|
|
121
|
+
|
|
122
|
+
### RPC — typed JSON data
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
vssh rpc web1 get_disk
|
|
126
|
+
vssh rpc web1 get_processes '{"n": 5, "sort": "mem"}'
|
|
127
|
+
vssh rpc-list web1 # List all available methods
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
| Method | Returns |
|
|
131
|
+
|---|---|
|
|
132
|
+
| `get_disk` | Disk usage |
|
|
133
|
+
| `get_memory` | Memory stats |
|
|
134
|
+
| `get_load` | Load averages |
|
|
135
|
+
| `get_processes` | Top processes |
|
|
136
|
+
| `get_gpu` | GPU VRAM, utilization, temp |
|
|
137
|
+
| `get_logs` | Log file or journalctl |
|
|
138
|
+
| `list_services` | Running systemd services |
|
|
139
|
+
| `restart_service` | Restart nginx / docker / postgresql / redis |
|
|
140
|
+
| `docker_containers` | Docker container list |
|
|
141
|
+
| `file_read` / `file_write` | File operations |
|
|
142
|
+
|
|
143
|
+
### Other
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
vssh speed-test web1 # Measure transfer speed
|
|
147
|
+
vssh history [count] [filter] # Command history
|
|
148
|
+
vssh stats [days] # Transfer stats
|
|
149
|
+
vssh pipe-up web1:/path # Pipe stdin to remote file
|
|
150
|
+
vssh pipe-down web1:"cmd" # Pipe remote output to stdout
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Tailscale Failover
|
|
156
|
+
|
|
157
|
+
If a node's primary VPN IP is unreachable, vssh automatically tries the Tailscale IP:
|
|
158
|
+
|
|
159
|
+
1. Try wire VPN IP (1.5s timeout)
|
|
160
|
+
2. Fall back to Tailscale IP, cache for 60s
|
|
161
|
+
3. After 60s: retry wire — if recovered, clear failover
|
|
162
|
+
|
|
163
|
+
The failover map is built automatically by cross-referencing `tailscale status` with wire peers.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## AI Management via MCP
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"mcpServers": {
|
|
172
|
+
"vssh": { "command": "vssh-mcp" }
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
> "Check which servers are online and show me disk usage"
|
|
178
|
+
> "Deploy the new config to all web servers and reload nginx"
|
|
179
|
+
> "What's using the most memory on db1?"
|
|
180
|
+
|
|
181
|
+
### MCP Tools
|
|
182
|
+
|
|
183
|
+
| Tool | Description |
|
|
184
|
+
|---|---|
|
|
185
|
+
| `vssh_status` | Fleet status — all nodes, latency |
|
|
186
|
+
| `vssh_exec` | Run command on remote server |
|
|
187
|
+
| `vssh_put` / `vssh_get` | Upload / download file |
|
|
188
|
+
| `vssh_sync` | Sync directory |
|
|
189
|
+
| `vssh_speed_test` | Transfer speed |
|
|
190
|
+
| `vssh_tunnel` | Port-forward tunnel |
|
|
191
|
+
| `vssh_keys` | Show secret and server list |
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## MeshPOP Stack
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
mpop Fleet orchestration — monitor, manage, automate
|
|
199
|
+
vssh Authenticated transport — remote exec, file transfer ← this
|
|
200
|
+
wire Encrypted mesh VPN — connects all nodes
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## License
|
|
206
|
+
|
|
207
|
+
MIT — [MeshPOP](https://github.com/meshpop)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vssh"
|
|
7
|
+
version = "4.1.0"
|
|
8
|
+
description = "vssh - installs Go binary"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.8"
|
|
12
|
+
authors = [{name = "MeshPOP", email = "mpop@mpop.dev"}]
|
|
13
|
+
keywords = ["ssh", "scp", "remote"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Operating System :: POSIX :: Linux",
|
|
18
|
+
"Operating System :: MacOS",
|
|
19
|
+
]
|
|
20
|
+
dependencies = []
|
|
21
|
+
|
|
22
|
+
[project.scripts]
|
|
23
|
+
vssh = "vssh:main"
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Homepage = "https://github.com/meshpop/vssh"
|
|
27
|
+
|
|
28
|
+
[tool.setuptools.packages.find]
|
|
29
|
+
where = ["."]
|
|
30
|
+
include = ["vssh*"]
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""vssh - Go binary wrapper for pip install"""
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
import subprocess
|
|
5
|
+
import platform
|
|
6
|
+
import urllib.request
|
|
7
|
+
import stat
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
__version__ = "4.1.0"
|
|
11
|
+
|
|
12
|
+
def get_binary_path():
|
|
13
|
+
local_bin = Path.home() / ".local" / "bin"
|
|
14
|
+
if local_bin.exists():
|
|
15
|
+
return local_bin / "vssh"
|
|
16
|
+
return Path(__file__).parent / "bin" / "vssh"
|
|
17
|
+
|
|
18
|
+
def get_download_url():
|
|
19
|
+
system = platform.system().lower()
|
|
20
|
+
machine = platform.machine().lower()
|
|
21
|
+
|
|
22
|
+
os_name = "darwin" if system == "darwin" else "linux"
|
|
23
|
+
arch = "arm64" if machine in ("arm64", "aarch64") else "amd64"
|
|
24
|
+
|
|
25
|
+
return f"https://github.com/meshpop/vssh/releases/latest/download/vssh-{os_name}-{arch}"
|
|
26
|
+
|
|
27
|
+
def ensure_binary():
|
|
28
|
+
binary_path = get_binary_path()
|
|
29
|
+
if binary_path.exists():
|
|
30
|
+
return binary_path
|
|
31
|
+
|
|
32
|
+
binary_path.parent.mkdir(parents=True, exist_ok=True)
|
|
33
|
+
url = get_download_url()
|
|
34
|
+
print(f"Downloading vssh from {url}...")
|
|
35
|
+
urllib.request.urlretrieve(url, binary_path)
|
|
36
|
+
binary_path.chmod(binary_path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
|
37
|
+
print(f"Installed vssh to {binary_path}")
|
|
38
|
+
return binary_path
|
|
39
|
+
|
|
40
|
+
def main():
|
|
41
|
+
try:
|
|
42
|
+
binary_path = ensure_binary()
|
|
43
|
+
result = subprocess.run([str(binary_path)] + sys.argv[1:])
|
|
44
|
+
sys.exit(result.returncode)
|
|
45
|
+
except Exception as e:
|
|
46
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
47
|
+
print("Install manually: https://github.com/meshpop/vssh", file=sys.stderr)
|
|
48
|
+
sys.exit(1)
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
main()
|