devs-cli 4.0.4__py3-none-any.whl → 4.0.7__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.
devs/core/integration.py CHANGED
@@ -1,6 +1,7 @@
1
1
  """VS Code and external tool integrations."""
2
2
 
3
3
  import json
4
+ import shlex
4
5
  import subprocess
5
6
  import time
6
7
  from pathlib import Path
@@ -8,7 +9,7 @@ from typing import List, Optional
8
9
 
9
10
  from rich.console import Console
10
11
 
11
- from ..exceptions import VSCodeError, DependencyError
12
+ from ..exceptions import VSCodeError
12
13
  from devs_common.core.project import Project
13
14
  from devs_common.utils.devcontainer import prepare_devcontainer_environment
14
15
 
@@ -25,13 +26,19 @@ class VSCodeIntegration:
25
26
  project: Project instance
26
27
  """
27
28
  self.project = project
28
- self._check_vscode_cli()
29
-
30
- def _check_vscode_cli(self) -> None:
31
- """Check if VS Code CLI is available.
32
-
33
- Raises:
34
- DependencyError: If code command is not found
29
+ self.code_available = self._check_vscode_cli()
30
+
31
+ def _check_vscode_cli(self) -> bool:
32
+ """Check if the VS Code 'code' CLI is available.
33
+
34
+ This is intentionally non-fatal: on a remote/headless dev box (e.g. one you
35
+ only ever reach over SSH) there may be no local 'code' command, but it is still
36
+ useful to start the container and print the URI / command you'd run from a
37
+ machine that does have VS Code. Callers consult ``self.code_available`` and fall
38
+ back to printing the command instead of launching.
39
+
40
+ Returns:
41
+ True if the 'code' command is available, False otherwise.
35
42
  """
36
43
  try:
37
44
  result = subprocess.run(
@@ -40,16 +47,9 @@ class VSCodeIntegration:
40
47
  text=True,
41
48
  check=False
42
49
  )
43
- if result.returncode != 0:
44
- raise DependencyError(
45
- "VS Code 'code' command not found. Make sure VS Code is installed "
46
- "and the 'code' command is available in your PATH."
47
- )
50
+ return result.returncode == 0
48
51
  except FileNotFoundError:
49
- raise DependencyError(
50
- "VS Code 'code' command not found. Make sure VS Code is installed "
51
- "and the 'code' command is available in your PATH."
52
- )
52
+ return False
53
53
 
54
54
  def generate_devcontainer_uri(
55
55
  self,
@@ -98,7 +98,51 @@ class VSCodeIntegration:
98
98
  vscode_uri = f"vscode-remote://dev-container+{workspace_hex}/workspaces/{workspace_name}"
99
99
 
100
100
  return vscode_uri
101
-
101
+
102
+ def _format_code_command(
103
+ self,
104
+ workspace_dir: Path,
105
+ dev_name: str,
106
+ live: bool,
107
+ new_window: bool,
108
+ ssh_host: Optional[str],
109
+ ) -> str:
110
+ """Build the 'code' command string for opening a container.
111
+
112
+ Returned as a copy/paste-ready, shell-quoted string so it can be printed and
113
+ run from another machine that has VS Code installed.
114
+ """
115
+ vscode_uri = self.generate_devcontainer_uri(
116
+ workspace_dir, dev_name, live, attach_to_existing=True, ssh_host=ssh_host
117
+ )
118
+ cmd = ["code"]
119
+ if new_window:
120
+ cmd.append("--new-window")
121
+ cmd.extend(["--folder-uri", vscode_uri])
122
+ return " ".join(shlex.quote(part) for part in cmd)
123
+
124
+ def _print_code_commands(
125
+ self,
126
+ workspace_dir: Path,
127
+ dev_name: str,
128
+ live: bool,
129
+ new_window: bool,
130
+ ssh_host: Optional[str],
131
+ ) -> None:
132
+ """Print the 'code' command(s) for this container.
133
+
134
+ Always prints the plain (non-SSH) command. When an SSH host is set, the SSH
135
+ form is printed too, so you can copy whichever matches where you're running it.
136
+ """
137
+ if ssh_host:
138
+ ssh_cmd = self._format_code_command(workspace_dir, dev_name, live, new_window, ssh_host)
139
+ console.print(f" 📋 VS Code command (via SSH: {ssh_host}):")
140
+ console.print(f" {ssh_cmd}")
141
+
142
+ plain_cmd = self._format_code_command(workspace_dir, dev_name, live, new_window, None)
143
+ console.print(f" 📋 VS Code command:")
144
+ console.print(f" {plain_cmd}")
145
+
102
146
  def launch_devcontainer(
103
147
  self,
104
148
  workspace_dir: Path,
@@ -127,11 +171,6 @@ class VSCodeIntegration:
127
171
  workspace_dir, dev_name, live, attach_to_existing=True, ssh_host=ssh_host
128
172
  )
129
173
 
130
- if ssh_host:
131
- console.print(f" 🚀 Opening VS Code for: {dev_name} (via SSH: {ssh_host})")
132
- else:
133
- console.print(f" 🚀 Opening VS Code for: {dev_name}")
134
-
135
174
  cmd = ["code"]
136
175
 
137
176
  if new_window:
@@ -139,6 +178,25 @@ class VSCodeIntegration:
139
178
 
140
179
  cmd.extend(["--folder-uri", vscode_uri])
141
180
 
181
+ # Always print the command(s) so they can be copied and run elsewhere.
182
+ self._print_code_commands(workspace_dir, dev_name, live, new_window, ssh_host)
183
+
184
+ # No local 'code' command (e.g. a headless remote dev box reached over SSH):
185
+ # don't fail — the container is already prepared, so just point to the
186
+ # command printed above and stop here.
187
+ if not self.code_available:
188
+ console.print(
189
+ f" ⚠️ VS Code 'code' command not found here — container is ready, "
190
+ "but VS Code can't be launched from this machine. "
191
+ "Run the command above from a machine with VS Code installed."
192
+ )
193
+ return True
194
+
195
+ if ssh_host:
196
+ console.print(f" 🚀 Opening VS Code for: {dev_name} (via SSH: {ssh_host})")
197
+ else:
198
+ console.print(f" 🚀 Opening VS Code for: {dev_name}")
199
+
142
200
  # Set environment variables using shared function
143
201
  container_workspace_name = self.project.get_workspace_name(dev_name)
144
202
  env = prepare_devcontainer_environment(
@@ -217,7 +275,7 @@ class VSCodeIntegration:
217
275
  console.print(f" ❌ Failed to launch {dev_name}: {e}")
218
276
  continue
219
277
 
220
- if success_count > 0:
278
+ if success_count > 0 and self.code_available:
221
279
  console.print("")
222
280
  console.print(f"💡 VS Code windows should open shortly with titles: '<dev-name> - {self.project.info.directory.name}'")
223
281
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devs-cli
3
- Version: 4.0.4
3
+ Version: 4.0.7
4
4
  Summary: DevContainer Management Tool - Manage multiple named devcontainers for any project
5
5
  Author: Dan Lester
6
6
  License-Expression: MIT
@@ -3,11 +3,11 @@ devs/cli.py,sha256=wRqKwdyGYAqemrabrH7NhMpBYX4iFJpowWxwDqptYmk,44125
3
3
  devs/config.py,sha256=DaS2_1x0h63cHn34RmWbEhUx_1u3-sAo16tM3AXMKfQ,1561
4
4
  devs/exceptions.py,sha256=7xO7ihJu_U6CupZPMv89B4N5EBSUcdj2OdA6GPAFPEE,490
5
5
  devs/core/__init__.py,sha256=TPy3eZi-AEztci_QZ37YAAl2zvUQlwBALpyiQx2ED7Q,363
6
- devs/core/integration.py,sha256=1x-6gbFRqR95dykdLyt0RmrhUxeFzlIq_yBitDGd1qI,11471
6
+ devs/core/integration.py,sha256=cM3bIok06Z4faIkTyF8h35FeKdHpnx3_h2mXnJ1SaW0,13935
7
7
  devs/utils/__init__.py,sha256=f-sEWETPfW2Xkaxgd-l6FS-jIQAorLlQZOicIZvp-W0,638
8
- devs_cli-4.0.4.dist-info/licenses/LICENSE,sha256=bi2EUiv-lmC_quQVkNqzTYXJpjVarkPsVKfqhJl7ccQ,1067
9
- devs_cli-4.0.4.dist-info/METADATA,sha256=pbkj80f2KAnueazHgj0bE2JcISS2k6xr_TvWUudR2ho,5282
10
- devs_cli-4.0.4.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
11
- devs_cli-4.0.4.dist-info/entry_points.txt,sha256=s8-pgqZ1QvzPJgHP9vNxwBYdezmGsFdRUHacJPZ4WOs,39
12
- devs_cli-4.0.4.dist-info/top_level.txt,sha256=9RIVUPVGuOdO84qkBh_9XcKoTV7773o3py78wz2-IZk,5
13
- devs_cli-4.0.4.dist-info/RECORD,,
8
+ devs_cli-4.0.7.dist-info/licenses/LICENSE,sha256=bi2EUiv-lmC_quQVkNqzTYXJpjVarkPsVKfqhJl7ccQ,1067
9
+ devs_cli-4.0.7.dist-info/METADATA,sha256=kak8KcJlQeXQGLObaeobYBGZWS9CsCFOOaRYMu9j6B0,5282
10
+ devs_cli-4.0.7.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
11
+ devs_cli-4.0.7.dist-info/entry_points.txt,sha256=s8-pgqZ1QvzPJgHP9vNxwBYdezmGsFdRUHacJPZ4WOs,39
12
+ devs_cli-4.0.7.dist-info/top_level.txt,sha256=9RIVUPVGuOdO84qkBh_9XcKoTV7773o3py78wz2-IZk,5
13
+ devs_cli-4.0.7.dist-info/RECORD,,