88from rich .panel import Panel
99
1010from codegen .cli .commands .start .docker_container import DockerContainer
11- from codegen .cli .commands .start .docker_fleet import CODEGEN_RUNNER_IMAGE , DockerFleet
11+ from codegen .cli .commands .start .docker_fleet import CODEGEN_RUNNER_IMAGE
1212from codegen .configs .models .secrets import SecretsConfig
1313from codegen .git .repo_operator .local_git_repo import LocalGitRepo
1414from codegen .git .schemas .repo_config import RepoConfig
2020@click .command (name = "start" )
2121@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" )
2222@click .option ("--port" , "-p" , type = int , default = None , help = "Port to run the server on" )
23- def start_command (port : int | None , platform : str ):
23+ @click .option ("--detached" , "-d" , is_flag = True , help = "Run the server in detached mode" )
24+ @click .option ("--skip-build" , is_flag = True , help = "Skip building the Docker image" )
25+ @click .option ("--force" , "-f" , is_flag = True , help = "Force start the server even if it is already running" )
26+ def start_command (port : int | None , platform : str , detached : bool = False , skip_build : bool = False , force : bool = False ) -> None :
2427 """Starts a local codegen server"""
2528 repo_path = Path .cwd ().resolve ()
2629 repo_config = RepoConfig .from_repo_path (str (repo_path ))
27- fleet = DockerFleet .load ()
28- if (container := fleet .get (repo_config .name )) is not None :
29- return _handle_existing_container (repo_config , container )
30+ if (container := DockerContainer .get (repo_config .name )) is not None :
31+ if force :
32+ rich .print (f"[yellow]Removing existing runner { repo_config .name } to force restart[/yellow]" )
33+ container .remove ()
34+ else :
35+ return _handle_existing_container (repo_config , container , force )
3036
3137 codegen_version = version ("codegen" )
3238 rich .print (f"[bold green]Codegen version:[/bold green] { codegen_version } " )
@@ -35,10 +41,11 @@ def start_command(port: int | None, platform: str):
3541 port = get_free_port ()
3642
3743 try :
38- rich .print ("[bold blue]Building Docker image...[/bold blue]" )
39- _build_docker_image (codegen_root , platform )
44+ if not skip_build :
45+ rich .print ("[bold blue]Building Docker image...[/bold blue]" )
46+ _build_docker_image (codegen_root , platform )
4047 rich .print ("[bold blue]Starting Docker container...[/bold blue]" )
41- _run_docker_container (repo_config , port )
48+ _run_docker_container (repo_config , port , detached )
4249 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" ))
4350 # TODO: memory snapshot here
4451 except subprocess .CalledProcessError as e :
@@ -49,7 +56,7 @@ def start_command(port: int | None, platform: str):
4956 raise click .Abort ()
5057
5158
52- def _handle_existing_container (repo_config : RepoConfig , container : DockerContainer ) -> None :
59+ def _handle_existing_container (repo_config : RepoConfig , container : DockerContainer , force : bool ) -> None :
5360 if container .is_running ():
5461 rich .print (
5562 Panel (
@@ -86,19 +93,26 @@ def _build_docker_image(codegen_root: Path, platform: str) -> None:
8693 subprocess .run (build_cmd , check = True )
8794
8895
89- def _run_docker_container (repo_config : RepoConfig , port : int ) -> None :
96+ def _run_docker_container (repo_config : RepoConfig , port : int , detached : bool ) -> None :
9097 container_repo_path = f"/app/git/{ repo_config .name } "
9198 name_args = ["--name" , f"{ repo_config .name } " ]
9299 envvars = {
93100 "REPOSITORY_LANGUAGE" : repo_config .language .value ,
94101 "REPOSITORY_OWNER" : LocalGitRepo (repo_config .repo_path ).owner ,
95102 "REPOSITORY_PATH" : container_repo_path ,
96103 "GITHUB_TOKEN" : SecretsConfig ().github_token ,
104+ "PYTHONUNBUFFERED" : "1" , # Ensure Python output is unbuffered
97105 }
98106 envvars_args = [arg for k , v in envvars .items () for arg in ("--env" , f"{ k } ={ v } " )]
99107 mount_args = ["-v" , f"{ repo_config .repo_path } :{ container_repo_path } " ]
100- entry_point = f"uv run --frozen uvicorn codegen.runner.sandbox.server:app --host { _default_host } --port { port } "
101- run_cmd = ["docker" , "run" , "-d" , "-p" , f"{ port } :{ port } " , * name_args , * mount_args , * envvars_args , CODEGEN_RUNNER_IMAGE , entry_point ]
108+ entry_point = f"uv run --frozen uvicorn codegen.runner.servers.local_daemon:app --host { _default_host } --port { port } "
109+ port_args = ["-p" , f"{ port } :{ port } " ]
110+ detached_args = ["-d" ] if detached else []
111+ run_cmd = ["docker" , "run" , * detached_args , * port_args , * name_args , * mount_args , * envvars_args , CODEGEN_RUNNER_IMAGE , entry_point ]
102112
103113 rich .print (f"run_cmd: { str .join (' ' , run_cmd )} " )
104114 subprocess .run (run_cmd , check = True )
115+
116+ if detached :
117+ rich .print ("[yellow]Container started in detached mode. To view logs, run:[/yellow]" )
118+ rich .print (f"[bold]docker logs -f { repo_config .name } [/bold]" )
0 commit comments