devs-common 2.0.3__tar.gz → 2.0.5__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.
- {devs_common-2.0.3 → devs_common-2.0.5}/PKG-INFO +1 -1
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/core/container.py +83 -42
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/Dockerfile +2 -2
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/devcontainer.json +2 -1
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common.egg-info/PKG-INFO +1 -1
- {devs_common-2.0.3 → devs_common-2.0.5}/pyproject.toml +1 -1
- {devs_common-2.0.3 → devs_common-2.0.5}/LICENSE +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/README.md +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/__init__.py +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/config.py +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/core/__init__.py +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/core/project.py +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/core/workspace.py +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/devs_config.py +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/exceptions.py +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/scripts/copy-ssh.sh +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/scripts/post-create-wrapper.sh +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/scripts/python-venv-integration.sh +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/scripts/screenshot-webapp.sh +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/scripts/setup-workspace.sh +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/scripts/start-tunnel.sh +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/scripts/tunnel-status.sh +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/scripts/webapp-screenshot.py +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/sudo-scripts/init-firewall.sh +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/sudo-scripts/setup-devs-env.sh +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/sudo-scripts/setup-vscode-cache.sh +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/sudo-scripts/start-services.sh +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/vscode-settings-reference.md +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/utils/__init__.py +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/utils/config_hash.py +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/utils/console.py +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/utils/devcontainer.py +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/utils/devcontainer_template.py +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/utils/docker_client.py +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/utils/file_utils.py +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common/utils/git_utils.py +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common.egg-info/SOURCES.txt +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common.egg-info/dependency_links.txt +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common.egg-info/requires.txt +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/devs_common.egg-info/top_level.txt +0 -0
- {devs_common-2.0.3 → devs_common-2.0.5}/setup.cfg +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
import re
|
|
5
|
+
import time
|
|
5
6
|
from datetime import datetime, timezone
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from typing import Dict, List, Optional, Tuple
|
|
@@ -817,14 +818,34 @@ class ContainerManager:
|
|
|
817
818
|
extra_env=extra_env
|
|
818
819
|
)
|
|
819
820
|
|
|
820
|
-
def
|
|
821
|
-
"""
|
|
821
|
+
def _get_tunnel_name(self, dev_name: str) -> str:
|
|
822
|
+
"""Generate a VS Code tunnel name, truncated to 20 chars.
|
|
823
|
+
|
|
824
|
+
VS Code tunnel names have a 20 character limit. We keep the dev name
|
|
825
|
+
suffix and shorten the project portion if needed.
|
|
826
|
+
"""
|
|
827
|
+
project_prefix = self.config.project_prefix if self.config else "dev"
|
|
828
|
+
tunnel_name = f"{project_prefix}-{self.project.info.name}-{dev_name}"
|
|
829
|
+
# Sanitize: tunnel names can only contain alphanumeric, dash, underscore
|
|
830
|
+
tunnel_name = tunnel_name.replace(".", "-").replace("_", "-")
|
|
831
|
+
|
|
832
|
+
if len(tunnel_name) > 20:
|
|
833
|
+
suffix = f"-{dev_name}"
|
|
834
|
+
prefix_budget = 20 - len(suffix)
|
|
835
|
+
if prefix_budget >= 3:
|
|
836
|
+
project_part = f"{project_prefix}-{self.project.info.name}"
|
|
837
|
+
project_part = project_part[:prefix_budget].rstrip("-")
|
|
838
|
+
tunnel_name = f"{project_part}{suffix}"
|
|
839
|
+
else:
|
|
840
|
+
tunnel_name = tunnel_name[:20]
|
|
822
841
|
|
|
823
|
-
|
|
824
|
-
to the container without SSH. The tunnel process will run in the foreground
|
|
825
|
-
and can be stopped with Ctrl+C.
|
|
842
|
+
return tunnel_name
|
|
826
843
|
|
|
827
|
-
|
|
844
|
+
def start_tunnel(self, dev_name: str, workspace_dir: Path, debug: bool = False, live: bool = False, extra_env: Optional[Dict[str, str]] = None) -> None:
|
|
845
|
+
"""Start a VS Code tunnel in the background.
|
|
846
|
+
|
|
847
|
+
Requires prior authentication via tunnel_auth(). The tunnel runs
|
|
848
|
+
detached inside the container.
|
|
828
849
|
|
|
829
850
|
Args:
|
|
830
851
|
dev_name: Development environment name
|
|
@@ -837,59 +858,79 @@ class ContainerManager:
|
|
|
837
858
|
ContainerError: If tunnel startup fails
|
|
838
859
|
"""
|
|
839
860
|
try:
|
|
840
|
-
# Prepare container for execution
|
|
841
861
|
container_name, container_workspace_dir = self._prepare_container_exec(
|
|
842
862
|
dev_name, workspace_dir, debug=debug, live=live, extra_env=extra_env
|
|
843
863
|
)
|
|
844
864
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
tunnel_name = f"{project_prefix}-{self.project.info.name}-{dev_name}"
|
|
850
|
-
# Sanitize: tunnel names can only contain alphanumeric, dash, underscore
|
|
851
|
-
tunnel_name = tunnel_name.replace(".", "-").replace("_", "-")
|
|
852
|
-
|
|
853
|
-
# Truncate to 20 chars if needed (VS Code tunnel limit)
|
|
854
|
-
if len(tunnel_name) > 20:
|
|
855
|
-
# Keep the dev name suffix, shorten the project part
|
|
856
|
-
suffix = f"-{dev_name}"
|
|
857
|
-
prefix_budget = 20 - len(suffix)
|
|
858
|
-
if prefix_budget >= 3:
|
|
859
|
-
project_part = f"{project_prefix}-{self.project.info.name}"
|
|
860
|
-
project_part = project_part[:prefix_budget].rstrip("-")
|
|
861
|
-
tunnel_name = f"{project_part}{suffix}"
|
|
862
|
-
else:
|
|
863
|
-
# Dev name itself is very long, just truncate the whole thing
|
|
864
|
-
tunnel_name = tunnel_name[:20]
|
|
865
|
+
tunnel_name = self._get_tunnel_name(dev_name)
|
|
866
|
+
log_file = '/tmp/vscode-tunnel.log'
|
|
867
|
+
tunnel_cmd = f'/usr/local/bin/code tunnel --accept-server-license-terms --name {tunnel_name}'
|
|
868
|
+
vscode_cmd = f"code --remote tunnel+{tunnel_name} {container_workspace_dir}"
|
|
865
869
|
|
|
866
870
|
console.print(f"[bold cyan]Starting VS Code tunnel for: {dev_name}[/bold cyan]")
|
|
867
871
|
console.print(f" Container: {container_name}")
|
|
868
872
|
console.print(f" Tunnel name: {tunnel_name}")
|
|
869
873
|
console.print("")
|
|
870
|
-
console.print("[yellow]First-time usage requires authentication:[/yellow]")
|
|
871
|
-
console.print(" 1. A URL and code will be displayed")
|
|
872
|
-
console.print(" 2. Open the URL in your browser")
|
|
873
|
-
console.print(" 3. Enter the code to authenticate with GitHub/Microsoft")
|
|
874
|
-
console.print("")
|
|
875
|
-
console.print("[dim]Press Ctrl+C to stop the tunnel[/dim]")
|
|
876
|
-
console.print("")
|
|
877
874
|
|
|
878
|
-
# Start
|
|
879
|
-
# The code CLI binary is installed at /usr/local/bin/code in the container
|
|
875
|
+
# Start detached
|
|
880
876
|
cmd = [
|
|
881
|
-
'docker', 'exec', '-
|
|
877
|
+
'docker', 'exec', '-d',
|
|
882
878
|
container_name,
|
|
883
|
-
'/
|
|
884
|
-
'
|
|
885
|
-
'--name', tunnel_name
|
|
879
|
+
'/bin/sh', '-c',
|
|
880
|
+
f'{tunnel_cmd} > {log_file} 2>&1'
|
|
886
881
|
]
|
|
887
882
|
|
|
888
883
|
if debug:
|
|
889
884
|
console.print(f"[dim]Running: {' '.join(cmd)}[/dim]")
|
|
890
885
|
|
|
891
|
-
|
|
892
|
-
|
|
886
|
+
subprocess.run(cmd, check=True)
|
|
887
|
+
|
|
888
|
+
# Poll the log to confirm startup and show the URL
|
|
889
|
+
console.print("[dim]Waiting for tunnel to start...[/dim]")
|
|
890
|
+
for i in range(15):
|
|
891
|
+
time.sleep(1)
|
|
892
|
+
result = subprocess.run(
|
|
893
|
+
['docker', 'exec', container_name, 'cat', log_file],
|
|
894
|
+
capture_output=True, text=True
|
|
895
|
+
)
|
|
896
|
+
output = result.stdout
|
|
897
|
+
|
|
898
|
+
if 'Open this link' in output or 'vscode.dev/tunnel' in output:
|
|
899
|
+
console.print(f"[bold green]Tunnel running![/bold green]")
|
|
900
|
+
console.print("")
|
|
901
|
+
console.print("[bold]Connect from your local machine:[/bold]")
|
|
902
|
+
console.print(f" {vscode_cmd}")
|
|
903
|
+
console.print("")
|
|
904
|
+
for line in output.split('\n'):
|
|
905
|
+
if 'vscode.dev/tunnel' in line:
|
|
906
|
+
console.print(f"[dim]Or open in browser: {line.strip()}[/dim]")
|
|
907
|
+
console.print(f"[dim]Use 'devs tunnel {dev_name} --status' to check status[/dim]")
|
|
908
|
+
console.print(f"[dim]Use 'devs tunnel {dev_name} --kill' to stop[/dim]")
|
|
909
|
+
return
|
|
910
|
+
|
|
911
|
+
if 'log in' in output.lower() or 'device' in output.lower() or 'invalid' in output.lower():
|
|
912
|
+
console.print("[yellow]Authentication required.[/yellow]")
|
|
913
|
+
console.print(f" Run: devs tunnel {dev_name} --auth")
|
|
914
|
+
subprocess.run(
|
|
915
|
+
['docker', 'exec', container_name, '/usr/local/bin/code', 'tunnel', 'kill'],
|
|
916
|
+
capture_output=True
|
|
917
|
+
)
|
|
918
|
+
return
|
|
919
|
+
|
|
920
|
+
if debug and output.strip():
|
|
921
|
+
console.print(f"[dim]Log ({i+1}s): {output.strip()[-100:]}[/dim]")
|
|
922
|
+
|
|
923
|
+
# Timeout - show what we have
|
|
924
|
+
result = subprocess.run(
|
|
925
|
+
['docker', 'exec', container_name, 'cat', log_file],
|
|
926
|
+
capture_output=True, text=True
|
|
927
|
+
)
|
|
928
|
+
if result.stdout.strip():
|
|
929
|
+
console.print("[yellow]Tunnel may still be starting. Log output:[/yellow]")
|
|
930
|
+
console.print(result.stdout.strip())
|
|
931
|
+
else:
|
|
932
|
+
console.print("[yellow]Tunnel started but no output yet. Check status with:[/yellow]")
|
|
933
|
+
console.print(f" devs tunnel {dev_name} --status")
|
|
893
934
|
|
|
894
935
|
except (DockerError, subprocess.SubprocessError) as e:
|
|
895
936
|
raise ContainerError(f"Failed to start tunnel in {dev_name}: {e}")
|
|
@@ -87,9 +87,9 @@ RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhisto
|
|
|
87
87
|
ENV DEVCONTAINER=true
|
|
88
88
|
|
|
89
89
|
# Create workspace and config directories and set permissions
|
|
90
|
-
RUN mkdir -p /workspaces /home/node/claudeconfig /home/node/codexconfig /home/node/.vscode-server/extensions && \
|
|
90
|
+
RUN mkdir -p /workspaces /home/node/claudeconfig /home/node/codexconfig /home/node/.vscode-server/extensions /home/node/.vscode/cli && \
|
|
91
91
|
echo '[]' > /home/node/.vscode-server/extensions/extensions.json && \
|
|
92
|
-
chown -R node:node /workspaces /home/node /home/node/.vscode-server && \
|
|
92
|
+
chown -R node:node /workspaces /home/node /home/node/.vscode-server /home/node/.vscode && \
|
|
93
93
|
chmod 755 /workspaces
|
|
94
94
|
|
|
95
95
|
WORKDIR /workspaces
|
|
@@ -83,7 +83,8 @@
|
|
|
83
83
|
// "source=${localEnv:WORKSPACE_FOLDER_NAME}-vscode-extensions,target=/home/node/.vscode-server/extensions,type=volume",
|
|
84
84
|
// .vscode-server includes extension state which we don't want to keep
|
|
85
85
|
// "source=${localEnv:WORKSPACE_FOLDER_NAME}-vscode-data,target=/home/node/.vscode-server,type=volume",
|
|
86
|
-
"source=${localEnv:WORKSPACE_FOLDER_NAME}-vscode-downloads,target=/home/node/.vscode-extensions-cache-volume,type=volume"
|
|
86
|
+
"source=${localEnv:WORKSPACE_FOLDER_NAME}-vscode-downloads,target=/home/node/.vscode-extensions-cache-volume,type=volume",
|
|
87
|
+
"source=${localEnv:HOME}/.devs/vscode-cli,target=/home/node/.vscode/cli,type=bind"
|
|
87
88
|
],
|
|
88
89
|
"remoteEnv": {
|
|
89
90
|
"NODE_OPTIONS": "--max-old-space-size=4096",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/scripts/post-create-wrapper.sh
RENAMED
|
File without changes
|
{devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/scripts/python-venv-integration.sh
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/sudo-scripts/setup-devs-env.sh
RENAMED
|
File without changes
|
{devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/sudo-scripts/setup-vscode-cache.sh
RENAMED
|
File without changes
|
{devs_common-2.0.3 → devs_common-2.0.5}/devs_common/templates/sudo-scripts/start-services.sh
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|