ssh-to-code 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.
- config_manager.py +141 -0
- host_selector.py +237 -0
- save_config.py +340 -0
- ssh_dir_browser.py +362 -0
- ssh_handler.py +233 -0
- ssh_to_code-1.0.0.dist-info/METADATA +384 -0
- ssh_to_code-1.0.0.dist-info/RECORD +12 -0
- ssh_to_code-1.0.0.dist-info/WHEEL +5 -0
- ssh_to_code-1.0.0.dist-info/entry_points.txt +2 -0
- ssh_to_code-1.0.0.dist-info/licenses/LICENSE +21 -0
- ssh_to_code-1.0.0.dist-info/top_level.txt +6 -0
- vscode_integration.py +185 -0
vscode_integration.py
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
VS Code Remote Integration
|
|
4
|
+
Helper functions for opening directories in VS Code via Remote-SSH
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import subprocess
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
from typing import Optional, Tuple
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class VSCodeRemote:
|
|
14
|
+
"""Handle VS Code Remote-SSH integration"""
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def is_vscode_installed() -> bool:
|
|
18
|
+
"""Check if VS Code CLI is available"""
|
|
19
|
+
try:
|
|
20
|
+
result = subprocess.run(['code', '--version'],
|
|
21
|
+
capture_output=True,
|
|
22
|
+
timeout=5)
|
|
23
|
+
return result.returncode == 0
|
|
24
|
+
except (FileNotFoundError, subprocess.TimeoutExpired):
|
|
25
|
+
return False
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def is_remote_ssh_installed() -> bool:
|
|
29
|
+
"""Check if Remote-SSH extension is installed"""
|
|
30
|
+
try:
|
|
31
|
+
result = subprocess.run(['code', '--list-extensions'],
|
|
32
|
+
capture_output=True,
|
|
33
|
+
text=True,
|
|
34
|
+
timeout=10)
|
|
35
|
+
if result.returncode == 0:
|
|
36
|
+
extensions = result.stdout.lower()
|
|
37
|
+
return 'ms-vscode-remote.remote-ssh' in extensions
|
|
38
|
+
return False
|
|
39
|
+
except (FileNotFoundError, subprocess.TimeoutExpired):
|
|
40
|
+
return False
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def get_ssh_config_hosts() -> list:
|
|
44
|
+
"""Get configured SSH hosts from ~/.ssh/config"""
|
|
45
|
+
ssh_config_path = os.path.expanduser('~/.ssh/config')
|
|
46
|
+
hosts = []
|
|
47
|
+
|
|
48
|
+
if not os.path.exists(ssh_config_path):
|
|
49
|
+
return hosts
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
with open(ssh_config_path, 'r') as f:
|
|
53
|
+
for line in f:
|
|
54
|
+
line = line.strip()
|
|
55
|
+
if line.startswith('Host ') and not '*' in line:
|
|
56
|
+
host = line.split('Host ')[1].strip()
|
|
57
|
+
hosts.append(host)
|
|
58
|
+
except Exception:
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
return hosts
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def open_remote_directory(hostname: str, username: str, port: int,
|
|
65
|
+
remote_path: str, new_window: bool = False) -> Tuple[bool, str]:
|
|
66
|
+
"""
|
|
67
|
+
Open a remote directory in VS Code
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
hostname: SSH hostname
|
|
71
|
+
username: SSH username
|
|
72
|
+
port: SSH port
|
|
73
|
+
remote_path: Remote directory path
|
|
74
|
+
new_window: Open in new window
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Tuple of (success, message)
|
|
78
|
+
"""
|
|
79
|
+
if not VSCodeRemote.is_vscode_installed():
|
|
80
|
+
return False, "VS Code CLI not found. Make sure 'code' is in your PATH."
|
|
81
|
+
|
|
82
|
+
if not VSCodeRemote.is_remote_ssh_installed():
|
|
83
|
+
return False, "Remote-SSH extension not installed. Install it from VS Code marketplace."
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
# Format: ssh-remote+user@host:port
|
|
87
|
+
ssh_target = f"{username}@{hostname}"
|
|
88
|
+
if port != 22:
|
|
89
|
+
ssh_target += f":{port}"
|
|
90
|
+
|
|
91
|
+
# Build command
|
|
92
|
+
cmd = ['code']
|
|
93
|
+
if new_window:
|
|
94
|
+
cmd.append('--new-window')
|
|
95
|
+
cmd.extend(['--remote', f'ssh-remote+{ssh_target}', remote_path])
|
|
96
|
+
|
|
97
|
+
# Execute command
|
|
98
|
+
subprocess.Popen(cmd,
|
|
99
|
+
stdout=subprocess.DEVNULL,
|
|
100
|
+
stderr=subprocess.DEVNULL,
|
|
101
|
+
start_new_session=True)
|
|
102
|
+
|
|
103
|
+
return True, f"Opening {remote_path} on {ssh_target} in VS Code..."
|
|
104
|
+
|
|
105
|
+
except Exception as e:
|
|
106
|
+
return False, f"Failed to open VS Code: {str(e)}"
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
def add_ssh_host_to_config(hostname: str, username: str, port: int = 22,
|
|
110
|
+
key_file: Optional[str] = None,
|
|
111
|
+
alias: Optional[str] = None) -> Tuple[bool, str]:
|
|
112
|
+
"""
|
|
113
|
+
Add SSH host configuration to ~/.ssh/config
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
hostname: SSH hostname
|
|
117
|
+
username: SSH username
|
|
118
|
+
port: SSH port
|
|
119
|
+
key_file: Path to private key file
|
|
120
|
+
alias: Host alias (optional)
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Tuple of (success, message)
|
|
124
|
+
"""
|
|
125
|
+
ssh_config_path = os.path.expanduser('~/.ssh/config')
|
|
126
|
+
ssh_dir = os.path.dirname(ssh_config_path)
|
|
127
|
+
|
|
128
|
+
# Create .ssh directory if it doesn't exist
|
|
129
|
+
if not os.path.exists(ssh_dir):
|
|
130
|
+
try:
|
|
131
|
+
os.makedirs(ssh_dir, mode=0o700)
|
|
132
|
+
except Exception as e:
|
|
133
|
+
return False, f"Failed to create .ssh directory: {str(e)}"
|
|
134
|
+
|
|
135
|
+
# Determine host alias
|
|
136
|
+
host_alias = alias or f"{username}@{hostname}"
|
|
137
|
+
|
|
138
|
+
# Build configuration entry
|
|
139
|
+
config_entry = f"\n# Added by ssh-dir-browser\n"
|
|
140
|
+
config_entry += f"Host {host_alias}\n"
|
|
141
|
+
config_entry += f" HostName {hostname}\n"
|
|
142
|
+
config_entry += f" User {username}\n"
|
|
143
|
+
if port != 22:
|
|
144
|
+
config_entry += f" Port {port}\n"
|
|
145
|
+
if key_file:
|
|
146
|
+
config_entry += f" IdentityFile {key_file}\n"
|
|
147
|
+
config_entry += "\n"
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
# Check if host already exists
|
|
151
|
+
if os.path.exists(ssh_config_path):
|
|
152
|
+
with open(ssh_config_path, 'r') as f:
|
|
153
|
+
content = f.read()
|
|
154
|
+
if f"Host {host_alias}" in content:
|
|
155
|
+
return False, f"Host '{host_alias}' already exists in SSH config"
|
|
156
|
+
|
|
157
|
+
# Append configuration
|
|
158
|
+
with open(ssh_config_path, 'a') as f:
|
|
159
|
+
f.write(config_entry)
|
|
160
|
+
|
|
161
|
+
return True, f"Added '{host_alias}' to SSH config"
|
|
162
|
+
|
|
163
|
+
except Exception as e:
|
|
164
|
+
return False, f"Failed to update SSH config: {str(e)}"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def main():
|
|
168
|
+
"""Test VS Code integration"""
|
|
169
|
+
print("VS Code Remote Integration Test")
|
|
170
|
+
print("=" * 50)
|
|
171
|
+
|
|
172
|
+
print(f"VS Code installed: {VSCodeRemote.is_vscode_installed()}")
|
|
173
|
+
print(f"Remote-SSH installed: {VSCodeRemote.is_remote_ssh_installed()}")
|
|
174
|
+
|
|
175
|
+
hosts = VSCodeRemote.get_ssh_config_hosts()
|
|
176
|
+
print(f"\nConfigured SSH hosts: {len(hosts)}")
|
|
177
|
+
for host in hosts[:5]: # Show first 5
|
|
178
|
+
print(f" - {host}")
|
|
179
|
+
|
|
180
|
+
if len(hosts) > 5:
|
|
181
|
+
print(f" ... and {len(hosts) - 5} more")
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
if __name__ == "__main__":
|
|
185
|
+
main()
|