Skip to content

Commit d32ba2d

Browse files
authored
fix: set git config + misc daemon improvements (#677)
1 parent 3a8a2cd commit d32ba2d

File tree

8 files changed

+94
-50
lines changed

8 files changed

+94
-50
lines changed

src/codegen/cli/commands/run/run_daemon.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def run_daemon(session: CodegenSession, function, diff_preview: int | None = Non
4646
limited_diff = "\n".join(diff_lines[:diff_preview])
4747

4848
if truncated:
49-
limited_diff += "\n\n...\n\n[yellow]diff truncated to {diff_preview} lines, view the full change set on your local file system after using run with `--apply-local`[/yellow]"
49+
limited_diff += f"\n\n...\n\n[yellow]diff truncated to {diff_preview} lines[/yellow]"
5050

5151
panel = Panel(limited_diff, title="[bold]Diff Preview[/bold]", border_style="blue", padding=(1, 2), expand=False)
5252
rich.print(panel)

src/codegen/cli/commands/start/main.py

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import platform as py_platform
12
import subprocess
23
from importlib.metadata import version
34
from pathlib import Path
@@ -18,12 +19,11 @@
1819

1920

2021
@click.command(name="start")
21-
@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")
2323
@click.option("--detached", "-d", is_flag=True, help="Run the server in detached mode")
2424
@click.option("--skip-build", is_flag=True, help="Skip building the Docker image")
2525
@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:
26+
def start_command(port: int | None, detached: bool = False, skip_build: bool = False, force: bool = False) -> None:
2727
"""Starts a local codegen server"""
2828
repo_path = Path.cwd().resolve()
2929
repo_config = RepoConfig.from_repo_path(str(repo_path))
@@ -42,15 +42,10 @@ def start_command(port: int | None, platform: str, detached: bool = False, skip_
4242

4343
try:
4444
if not skip_build:
45-
rich.print("[bold blue]Building Docker image...[/bold blue]")
46-
_build_docker_image(codegen_root, platform)
47-
rich.print("[bold blue]Starting Docker container...[/bold blue]")
45+
_build_docker_image(codegen_root)
4846
_run_docker_container(repo_config, port, detached)
4947
rich.print(Panel(f"[green]Server started successfully![/green]\nAccess the server at: [bold]http://{_default_host}:{port}[/bold]", box=ROUNDED, title="Codegen Server"))
5048
# TODO: memory snapshot here
51-
except subprocess.CalledProcessError as e:
52-
rich.print(f"[bold red]Error:[/bold red] Failed to {e.cmd[0]} Docker container")
53-
raise click.Abort()
5449
except Exception as e:
5550
rich.print(f"[bold red]Error:[/bold red] {e!s}")
5651
raise click.Abort()
@@ -75,7 +70,8 @@ def _handle_existing_container(repo_config: RepoConfig, container: DockerContain
7570
click.Abort()
7671

7772

78-
def _build_docker_image(codegen_root: Path, platform: str) -> None:
73+
def _build_docker_image(codegen_root: Path) -> None:
74+
platform = _get_platform()
7975
build_cmd = [
8076
"docker",
8177
"buildx",
@@ -89,11 +85,31 @@ def _build_docker_image(codegen_root: Path, platform: str) -> None:
8985
"--load",
9086
str(codegen_root),
9187
]
92-
rich.print(f"build_cmd: {str.join(' ', build_cmd)}")
88+
rich.print(
89+
Panel(
90+
f"{str.join(' ', build_cmd)}",
91+
box=ROUNDED,
92+
title="Running Build Command",
93+
style="blue",
94+
padding=(1, 1),
95+
)
96+
)
9397
subprocess.run(build_cmd, check=True)
9498

9599

100+
def _get_platform() -> str:
101+
machine = py_platform.machine().lower()
102+
if machine in ("x86_64", "amd64"):
103+
return "linux/amd64"
104+
elif machine in ("arm64", "aarch64"):
105+
return "linux/arm64"
106+
else:
107+
rich.print(f"[yellow]Warning: Unknown architecture {machine}, defaulting to linux/amd64[/yellow]")
108+
return "linux/amd64"
109+
110+
96111
def _run_docker_container(repo_config: RepoConfig, port: int, detached: bool) -> None:
112+
rich.print("[bold blue]Starting Docker container...[/bold blue]")
97113
container_repo_path = f"/app/git/{repo_config.name}"
98114
name_args = ["--name", f"{repo_config.name}"]
99115
envvars = {
@@ -108,9 +124,17 @@ def _run_docker_container(repo_config: RepoConfig, port: int, detached: bool) ->
108124
entry_point = f"uv run --frozen uvicorn codegen.runner.servers.local_daemon:app --host {_default_host} --port {port}"
109125
port_args = ["-p", f"{port}:{port}"]
110126
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]
112-
113-
rich.print(f"run_cmd: {str.join(' ', run_cmd)}")
127+
run_cmd = ["docker", "run", "--rm", *detached_args, *port_args, *name_args, *mount_args, *envvars_args, CODEGEN_RUNNER_IMAGE, entry_point]
128+
129+
rich.print(
130+
Panel(
131+
f"{str.join(' ', run_cmd)}",
132+
box=ROUNDED,
133+
title="Running Run Command",
134+
style="blue",
135+
padding=(1, 1),
136+
)
137+
)
114138
subprocess.run(run_cmd, check=True)
115139

116140
if detached:

src/codegen/git/repo_operator/repo_operator.py

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -145,31 +145,25 @@ def git_cli(self) -> GitCLI:
145145
for level in levels:
146146
with git_cli.config_reader(level) as reader:
147147
if reader.has_option("user", "name") and not username:
148-
username = reader.get("user", "name")
149-
user_level = level
148+
username = username or reader.get("user", "name")
149+
user_level = user_level or level
150150
if reader.has_option("user", "email") and not email:
151-
email = reader.get("user", "email")
152-
email_level = level
153-
if self.bot_commit:
154-
self._set_bot_email(git_cli)
151+
email = email or reader.get("user", "email")
152+
email_level = email_level or level
153+
154+
# We need a username and email to commit, so if they're not set, set them to the bot's
155+
if not username or self.bot_commit:
155156
self._set_bot_username(git_cli)
156-
else:
157-
# we need a username and email to commit, so if they're not set, set them to the bot's
158-
# Case 1: username is not set: set it to the bot's
159-
if not username:
160-
self._set_bot_username(git_cli)
161-
# Case 2: username is set to the bot's at the repo level, but something else is set at the user level: unset it
162-
elif username != CODEGEN_BOT_NAME and user_level != "repository":
163-
self._unset_bot_username(git_cli)
164-
# 3: Caseusername is only set at the repo level: do nothing
165-
else:
166-
pass # no-op to make the logic clearer
167-
# Repeat for email
168-
if not email:
169-
self._set_bot_email(git_cli)
157+
if not email or self.bot_commit:
158+
self._set_bot_email(git_cli)
170159

171-
elif email != CODEGEN_BOT_EMAIL and email_level != "repository":
160+
# If user config is set at a level above the repo level: unset it
161+
if not self.bot_commit:
162+
if username and username != CODEGEN_BOT_NAME and user_level != "repository":
163+
self._unset_bot_username(git_cli)
164+
if email and email != CODEGEN_BOT_EMAIL and email_level != "repository":
172165
self._unset_bot_email(git_cli)
166+
173167
return git_cli
174168

175169
@property

src/codegen/runner/sandbox/runner.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ class SandboxRunner:
2828
codebase: CodebaseType
2929
executor: SandboxExecutor
3030

31-
def __init__(self, repo_config: RepoConfig) -> None:
31+
def __init__(self, repo_config: RepoConfig, op: RepoOperator | None = None) -> None:
3232
self.repo = repo_config
33-
self.op = RepoOperator(repo_config=self.repo, setup_option=SetupOption.PULL_OR_CLONE, bot_commit=True)
33+
self.op = op or RepoOperator(repo_config=self.repo, setup_option=SetupOption.PULL_OR_CLONE, bot_commit=True)
3434
self.commit = self.op.git_cli.head.commit
3535

3636
async def warmup(self) -> None:

src/codegen/runner/servers/local_daemon.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from fastapi import FastAPI
55

66
from codegen.git.configs.constants import CODEGEN_BOT_EMAIL, CODEGEN_BOT_NAME
7+
from codegen.git.repo_operator.repo_operator import RepoOperator
8+
from codegen.git.schemas.enums import SetupOption
79
from codegen.git.schemas.repo_config import RepoConfig
810
from codegen.runner.enums.warmup_state import WarmupState
911
from codegen.runner.models.apis import (
@@ -14,14 +16,15 @@
1416
)
1517
from codegen.runner.models.codemod import Codemod, CodemodRunResult
1618
from codegen.runner.sandbox.runner import SandboxRunner
19+
from codegen.shared.logging.get_logger import get_logger
1720

1821
# Configure logging at module level
1922
logging.basicConfig(
2023
level=logging.INFO,
2124
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
2225
force=True,
2326
)
24-
logger = logging.getLogger(__name__)
27+
logger = get_logger(__name__)
2528

2629
server_info: ServerInfo
2730
runner: SandboxRunner
@@ -37,13 +40,14 @@ async def lifespan(server: FastAPI):
3740
server_info = ServerInfo(repo_name=repo_config.full_name or repo_config.name)
3841

3942
# Set the bot email and username
43+
op = RepoOperator(repo_config=repo_config, setup_option=SetupOption.SKIP, bot_commit=True)
44+
runner = SandboxRunner(repo_config=repo_config, op=op)
4045
logger.info(f"Configuring git user config to {CODEGEN_BOT_EMAIL} and {CODEGEN_BOT_NAME}")
41-
runner = SandboxRunner(repo_config=repo_config)
4246
runner.op.git_cli.git.config("user.email", CODEGEN_BOT_EMAIL)
4347
runner.op.git_cli.git.config("user.name", CODEGEN_BOT_NAME)
4448

4549
# Parse the codebase
46-
logger.info(f"Starting up sandbox fastapi server for repo_name={repo_config.name}")
50+
logger.info(f"Starting up fastapi server for repo_name={repo_config.name}")
4751
server_info.warmup_state = WarmupState.PENDING
4852
await runner.warmup()
4953
server_info.synced_commit = runner.commit.hexsha

src/codegen/sdk/codebase/codebase_context.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from codegen.sdk.typescript.external.ts_declassify.ts_declassify import TSDeclassify
3232
from codegen.shared.enums.programming_language import ProgrammingLanguage
3333
from codegen.shared.exceptions.control_flow import StopCodemodException
34+
from codegen.shared.logging.get_logger import get_logger
3435
from codegen.shared.performance.stopwatch_utils import stopwatch, stopwatch_with_sentry
3536

3637
if TYPE_CHECKING:
@@ -51,9 +52,7 @@
5152
from codegen.sdk.core.node_id_factory import NodeId
5253
from codegen.sdk.core.parser import Parser
5354

54-
import logging
55-
56-
logger = logging.getLogger(__name__)
55+
logger = get_logger(__name__)
5756

5857

5958
# src/vs/platform/contextview/browser/contextMenuService.ts is ignored as there is a parsing error with tree-sitter

src/codegen/shared/logging/get_logger.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
import colorlog
44

5-
handler = colorlog.StreamHandler()
6-
handler.setFormatter(
7-
colorlog.ColoredFormatter(
5+
6+
def get_logger(name: str, level: int = logging.INFO) -> logging.Logger:
7+
# Force configure the root logger with a NullHandler to prevent duplicate logs
8+
logging.basicConfig(handlers=[logging.NullHandler()], force=True)
9+
10+
formatter = colorlog.ColoredFormatter(
811
"%(white)s%(asctime)s - %(name)s - %(log_color)s%(levelname)s%(reset)s%(white)s - %(message_log_color)s%(message)s",
912
log_colors={
1013
"DEBUG": "cyan",
@@ -23,11 +26,16 @@
2326
}
2427
},
2528
)
26-
)
27-
28-
29-
def get_logger(name: str, level: int = logging.INFO) -> logging.Logger:
3029
logger = logging.getLogger(name)
30+
if logger.hasHandlers():
31+
for h in logger.handlers:
32+
logger.removeHandler(h)
33+
34+
handler = colorlog.StreamHandler()
35+
handler.setFormatter(formatter)
3136
logger.addHandler(handler)
37+
# Ensure the logger propagates to the root logger
38+
logger.propagate = False
39+
# Set the level on the logger itself
3240
logger.setLevel(level)
3341
return logger

uv.lock

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)