Files
BrowserOS/packages/browseros/tools/bdev/internal/engine/sync.go
Nikhil 39a7d49c25 feat: add workspace-centric bdev cli (#585)
* fix: clean-up bdev

* feat: add workspace-centric bdev cli

* fix: address review comments for 0326-bdev_cli_redesign

* fix: address review feedback for PR #585

* fix: address review feedback for PR #585
2026-03-27 08:48:23 -07:00

131 lines
3.5 KiB
Go

package engine
import (
"context"
"fmt"
"time"
"github.com/browseros-ai/BrowserOS/packages/browseros/tools/bdev/internal/git"
"github.com/browseros-ai/BrowserOS/packages/browseros/tools/bdev/internal/repo"
"github.com/browseros-ai/BrowserOS/packages/browseros/tools/bdev/internal/workspace"
)
type SyncOptions struct {
Workspace workspace.Entry
Repo *repo.Info
Remote string
Rebase bool
}
type SyncResult struct {
Workspace string `json:"workspace"`
Remote string `json:"remote"`
RepoHead string `json:"repo_head"`
StashRef string `json:"stash_ref,omitempty"`
Rebased bool `json:"rebased"`
Fallback bool `json:"fallback"`
Applied []string `json:"applied,omitempty"`
Conflicts []string `json:"conflicts,omitempty"`
}
func Sync(ctx context.Context, opts SyncOptions) (*SyncResult, error) {
if opts.Remote == "" {
opts.Remote = "origin"
}
dirty, err := git.IsDirty(ctx, opts.Repo.Root)
if err != nil {
return nil, err
}
if dirty {
return nil, fmt.Errorf("patches repo has uncommitted changes; commit or stash them before syncing")
}
branch, err := git.CurrentBranch(ctx, opts.Repo.Root)
if err != nil {
return nil, err
}
if err := git.PullRebase(ctx, opts.Repo.Root, opts.Remote, branch); err != nil {
return nil, err
}
head, err := git.HeadRev(ctx, opts.Repo.Root)
if err != nil {
return nil, err
}
state, err := workspace.LoadState(opts.Workspace.Path)
if err != nil {
return nil, err
}
result := &SyncResult{
Workspace: opts.Workspace.Name,
Remote: opts.Remote,
RepoHead: head,
Rebased: opts.Rebase,
}
status, err := InspectWorkspace(ctx, opts.Workspace, opts.Repo)
if err != nil {
return nil, err
}
divergent := append([]string{}, status.NeedsUpdate...)
divergent = append(divergent, status.Orphaned...)
if len(divergent) > 0 {
stashRef, err := git.StashPush(ctx, opts.Workspace.Path, "bdev sync stash", true, divergent)
if err != nil {
return nil, err
}
result.StashRef = stashRef
state.PendingStash = stashRef
if err := workspace.SaveState(opts.Workspace.Path, state); err != nil {
return nil, err
}
}
if state.LastSyncRev == "" || state.BaseCommit != "" && state.BaseCommit != opts.Repo.BaseCommit {
result.Fallback = true
applyResult, err := Apply(ctx, ApplyOptions{
Workspace: opts.Workspace,
Repo: opts.Repo,
Reset: true,
Mode: "sync-reset",
})
if err != nil {
return nil, err
}
result.Applied = applyResult.Applied
if len(applyResult.Conflicts) > 0 {
for _, conflict := range applyResult.Conflicts {
result.Conflicts = append(result.Conflicts, conflict.ChromiumPath)
}
return result, nil
}
} else {
applyResult, err := Apply(ctx, ApplyOptions{
Workspace: opts.Workspace,
Repo: opts.Repo,
ChangedRef: state.LastSyncRev,
RangeEnd: head,
Mode: "sync",
})
if err != nil {
return nil, err
}
result.Applied = applyResult.Applied
if len(applyResult.Conflicts) > 0 {
for _, conflict := range applyResult.Conflicts {
result.Conflicts = append(result.Conflicts, conflict.ChromiumPath)
}
return result, nil
}
}
if opts.Rebase && result.StashRef != "" {
if err := git.StashPop(ctx, opts.Workspace.Path, result.StashRef); err != nil {
return nil, err
}
}
state.PendingStash = ""
state.BaseCommit = opts.Repo.BaseCommit
state.LastSyncRev = head
state.LastSyncAt = time.Now().UTC()
if err := workspace.SaveState(opts.Workspace.Path, state); err != nil {
return nil, err
}
return result, nil
}