Add orch control commands
This commit is contained in:
@@ -26,6 +26,31 @@ func newDispatchWorkspacePreparer(cmd *cobra.Command, opts dispatchOptions) stor
|
||||
}
|
||||
}
|
||||
|
||||
func newAttemptReuseWorkspacePreparer(cmd *cobra.Command, task store.Task, attempt *store.TaskAttempt) store.DispatchWorkspacePreparer {
|
||||
if attempt == nil || attempt.WorktreePath == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
workspaceRoot, ok := deriveWorkspaceRootFromAttempt(task.RunID, task.TaskID, attempt.WorktreePath)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
baseRef := attempt.BaseRef
|
||||
if strings.TrimSpace(baseRef) == "" {
|
||||
baseRef = attempt.BaseCommit
|
||||
}
|
||||
|
||||
opts := dispatchOptions{
|
||||
repoPath: attempt.WorktreePath,
|
||||
workspaceRoot: workspaceRoot,
|
||||
strictWorktree: true,
|
||||
baseRef: baseRef,
|
||||
}
|
||||
|
||||
return newDispatchWorkspacePreparer(cmd, opts)
|
||||
}
|
||||
|
||||
func dispatchUsesWorktree(opts dispatchOptions) bool {
|
||||
return strings.TrimSpace(opts.repoPath) != "" ||
|
||||
strings.TrimSpace(opts.workspaceRoot) != "" ||
|
||||
@@ -94,11 +119,15 @@ func resolveRepoRoot(ctx context.Context, repoPath string) (string, error) {
|
||||
return "", fmt.Errorf("resolve repo path: %w", err)
|
||||
}
|
||||
|
||||
stdout, _, err := runGit(ctx, absPath, "rev-parse", "--show-toplevel")
|
||||
if _, _, err := runGit(ctx, absPath, "rev-parse", "--show-toplevel"); err != nil {
|
||||
return "", protocol.InvalidInput("repo-path must point to a Git worktree", err)
|
||||
}
|
||||
|
||||
commonDir, err := resolveCommonGitDir(ctx, absPath)
|
||||
if err != nil {
|
||||
return "", protocol.InvalidInput("repo-path must point to a Git worktree", err)
|
||||
}
|
||||
return strings.TrimSpace(stdout), nil
|
||||
return filepath.Dir(commonDir), nil
|
||||
}
|
||||
|
||||
func resolveDispatchBase(ctx context.Context, repoRoot, workspaceRoot, requestedBaseRef string, strict bool) (string, string, error) {
|
||||
@@ -242,6 +271,27 @@ func buildAttemptWorktreePath(workspaceRoot, runID, taskID string, attemptNo int
|
||||
)
|
||||
}
|
||||
|
||||
func deriveWorkspaceRootFromAttempt(runID, taskID, worktreePath string) (string, bool) {
|
||||
suffix := filepath.Join(
|
||||
sanitizePathSegment(runID),
|
||||
sanitizePathSegment(taskID),
|
||||
filepath.Base(worktreePath),
|
||||
)
|
||||
parent := filepath.Dir(worktreePath)
|
||||
if filepath.Base(parent) != sanitizePathSegment(taskID) {
|
||||
return "", false
|
||||
}
|
||||
runDir := filepath.Dir(parent)
|
||||
if filepath.Base(runDir) != sanitizePathSegment(runID) {
|
||||
return "", false
|
||||
}
|
||||
root := filepath.Dir(runDir)
|
||||
if filepath.Clean(filepath.Join(root, suffix)) != filepath.Clean(worktreePath) {
|
||||
return "", false
|
||||
}
|
||||
return root, true
|
||||
}
|
||||
|
||||
func sanitizeGitSegment(value string) string {
|
||||
return sanitizeSegment(value)
|
||||
}
|
||||
@@ -301,3 +351,59 @@ func runGit(ctx context.Context, repoRoot string, args ...string) (string, strin
|
||||
}
|
||||
return "", message, fmt.Errorf("git %s: %s", strings.Join(args, " "), message)
|
||||
}
|
||||
|
||||
func cleanupAttemptWorktree(ctx context.Context, attempt store.TaskAttempt, force bool) error {
|
||||
if strings.TrimSpace(attempt.WorktreePath) == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := os.Stat(attempt.WorktreePath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("stat worktree path: %w", err)
|
||||
}
|
||||
|
||||
repoRoot, err := resolveRepoRootFromExistingWorktree(ctx, attempt.WorktreePath)
|
||||
if err != nil {
|
||||
if force {
|
||||
return os.RemoveAll(attempt.WorktreePath)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
args := []string{"worktree", "remove"}
|
||||
if force {
|
||||
args = append(args, "--force")
|
||||
}
|
||||
args = append(args, attempt.WorktreePath)
|
||||
if _, _, err := runGit(ctx, repoRoot, args...); err != nil {
|
||||
if force {
|
||||
return os.RemoveAll(attempt.WorktreePath)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolveRepoRootFromExistingWorktree(ctx context.Context, worktreePath string) (string, error) {
|
||||
commonDir, err := resolveCommonGitDir(ctx, worktreePath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Dir(commonDir), nil
|
||||
}
|
||||
|
||||
func resolveCommonGitDir(ctx context.Context, repoPath string) (string, error) {
|
||||
stdout, _, err := runGit(ctx, repoPath, "rev-parse", "--path-format=absolute", "--git-common-dir")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
commonDir := strings.TrimSpace(stdout)
|
||||
if !filepath.IsAbs(commonDir) {
|
||||
commonDir = filepath.Join(repoPath, commonDir)
|
||||
}
|
||||
return filepath.Clean(commonDir), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user