7
7
from rich .box import ROUNDED
8
8
from rich .panel import Panel
9
9
10
+ from codegen .cli .commands .start .docker_session import CODEGEN_RUNNER_IMAGE , DockerSession , DockerSessions
10
11
from codegen .configs .models .secrets import SecretsConfig
11
12
from codegen .git .repo_operator .local_git_repo import LocalGitRepo
12
13
from codegen .git .schemas .repo_config import RepoConfig
13
14
from codegen .shared .network .port import get_free_port
14
15
16
+ _default_host = "0.0.0.0"
17
+
15
18
16
19
@click .command (name = "start" )
17
20
@click .option ("--platform" , "-t" , type = click .Choice (["linux/amd64" , "linux/arm64" , "linux/amd64,linux/arm64" ]), default = "linux/amd64,linux/arm64" , help = "Target platform(s) for the Docker image" )
18
21
@click .option ("--port" , "-p" , type = int , default = None , help = "Port to run the server on" )
19
- @click .option ("--detached" , "-d" , is_flag = True , default = False , help = "Starts up the server as detached background process" )
20
- def start_command (port : int | None , platform : str , detached : bool ):
22
+ def start_command (port : int | None , platform : str ):
21
23
"""Starts a local codegen server"""
24
+ repo_path = Path .cwd ().resolve ()
25
+ repo_config = RepoConfig .from_repo_path (str (repo_path ))
26
+ docker_sessions = DockerSessions .load ()
27
+ if (existing_session := docker_sessions .get (repo_config .name )) is not None :
28
+ return _handle_existing_session (repo_config , existing_session )
29
+
22
30
codegen_version = version ("codegen" )
23
31
rich .print (f"[bold green]Codegen version:[/bold green] { codegen_version } " )
24
32
codegen_root = Path (__file__ ).parent .parent .parent .parent .parent .parent
@@ -29,8 +37,9 @@ def start_command(port: int | None, platform: str, detached: bool):
29
37
rich .print ("[bold blue]Building Docker image...[/bold blue]" )
30
38
_build_docker_image (codegen_root , platform )
31
39
rich .print ("[bold blue]Starting Docker container...[/bold blue]" )
32
- _run_docker_container (port , detached )
33
- rich .print (Panel (f"[green]Server started successfully![/green]\n Access the server at: [bold]http://0.0.0.0:{ port } [/bold]" , box = ROUNDED , title = "Codegen Server" ))
40
+ _run_docker_container (repo_config , port )
41
+ rich .print (Panel (f"[green]Server started successfully![/green]\n Access the server at: [bold]http://{ _default_host } :{ port } [/bold]" , box = ROUNDED , title = "Codegen Server" ))
42
+ # TODO: memory snapshot here
34
43
except subprocess .CalledProcessError as e :
35
44
rich .print (f"[bold red]Error:[/bold red] Failed to { e .cmd [0 ]} Docker container" )
36
45
raise click .Abort ()
@@ -39,7 +48,26 @@ def start_command(port: int | None, platform: str, detached: bool):
39
48
raise click .Abort ()
40
49
41
50
42
- def _build_docker_image (codegen_root : Path , platform : str ):
51
+ def _handle_existing_session (repo_config : RepoConfig , docker_session : DockerSession ) -> None :
52
+ if docker_session .is_running ():
53
+ rich .print (
54
+ Panel (
55
+ f"[green]Codegen server for { repo_config .name } is already running at: [bold]http://{ docker_session .host } :{ docker_session .port } [/bold][/green]" ,
56
+ box = ROUNDED ,
57
+ title = "Codegen Server" ,
58
+ )
59
+ )
60
+ return
61
+
62
+ if docker_session .start ():
63
+ rich .print (Panel (f"[yellow]Docker session for { repo_config .name } is not running. Restarting...[/yellow]" , box = ROUNDED , title = "Docker Session" ))
64
+ return
65
+
66
+ rich .print (Panel (f"[red]Failed to restart container for { repo_config .name } [/red]" , box = ROUNDED , title = "Docker Session" ))
67
+ click .Abort ()
68
+
69
+
70
+ def _build_docker_image (codegen_root : Path , platform : str ) -> None :
43
71
build_cmd = [
44
72
"docker" ,
45
73
"buildx" ,
@@ -57,21 +85,19 @@ def _build_docker_image(codegen_root: Path, platform: str):
57
85
subprocess .run (build_cmd , check = True )
58
86
59
87
60
- def _run_docker_container (port : int , detached : bool ):
61
- repo_path = Path .cwd ().resolve ()
62
- repo_config = RepoConfig .from_repo_path (repo_path )
88
+ def _run_docker_container (repo_config : RepoConfig , port : int ) -> None :
63
89
container_repo_path = f"/app/git/{ repo_config .name } "
90
+ name_args = ["--name" , f"{ repo_config .name } " ]
64
91
envvars = {
65
92
"REPOSITORY_LANGUAGE" : repo_config .language .value ,
66
- "REPOSITORY_OWNER" : LocalGitRepo (repo_path ).owner ,
93
+ "REPOSITORY_OWNER" : LocalGitRepo (repo_config . repo_path ).owner ,
67
94
"REPOSITORY_PATH" : container_repo_path ,
68
95
"GITHUB_TOKEN" : SecretsConfig ().github_token ,
69
96
}
70
97
envvars_args = [arg for k , v in envvars .items () for arg in ("--env" , f"{ k } ={ v } " )]
71
- mount_args = ["-v" , f"{ repo_path } :{ container_repo_path } " ]
72
- run_mode = "-d" if detached else "-it"
73
- entry_point = f"uv run --frozen uvicorn codegen.runner.sandbox.server:app --host 0.0.0.0 --port { port } "
74
- run_cmd = ["docker" , "run" , run_mode , "-p" , f"{ port } :{ port } " , * mount_args , * envvars_args , "codegen-runner" , entry_point ]
98
+ mount_args = ["-v" , f"{ repo_config .repo_path } :{ container_repo_path } " ]
99
+ entry_point = f"uv run --frozen uvicorn codegen.runner.sandbox.server:app --host { _default_host } --port { port } "
100
+ run_cmd = ["docker" , "run" , "-d" , "-p" , f"{ port } :{ port } " , * name_args , * mount_args , * envvars_args , CODEGEN_RUNNER_IMAGE , entry_point ]
75
101
76
102
rich .print (f"run_cmd: { str .join (' ' , run_cmd )} " )
77
103
subprocess .run (run_cmd , check = True )
0 commit comments