Artifact b3bcf469680ee3ebbd6b345df277fc482e0e6e8fbf4e131c39f3d4dcb2e217a8:
- File
internal/merge/resolve.go
— part of check-in
[f5744359d3]
at
2026-04-19 16:30:54
on branch trunk
— Initial open source release
libfossil is a pure-Go implementation of the Fossil SCM, reading and writing the same .fossil SQLite repository format as upstream Fossil.
This is the first public release of code that previously lived in a private repository. The module path is github.com/danmestas/libfossil and the binary is named libfossil to avoid $PATH collisions with upstream fossil.
Included: - Repo lifecycle (create, clone), checkout/checkin, timeline, merge, diff, annotate, shun, tag, branch, bisect, stash, undo/redo - Sync-over-HTTP protocol (client and handler) - Two SQLite drivers: modernc (pure Go, default) and ncruces (wasm-capable) - Observer interfaces (SyncObserver, CheckoutObserver) with an optional OpenTelemetry implementation in observer/otel (separate submodule) - Deterministic simulation testing harness with BUGGIFY fault injection - Kong-based embeddable CLI under cli/ and a standalone binary under cmd/libfossil/ (user: [email protected], size: 2175) [annotate] [blame] [check-ins using]
package merge import ( "bufio" "path/filepath" "strings" libfossil "github.com/danmestas/libfossil/internal/fsltype" "github.com/danmestas/libfossil/internal/blob" "github.com/danmestas/libfossil/internal/content" "github.com/danmestas/libfossil/internal/manifest" "github.com/danmestas/libfossil/internal/repo" ) // PatternRule maps a glob pattern to a strategy name. type PatternRule struct { Glob string Strategy string } // Resolver picks the merge strategy for a given filename. type Resolver struct { patterns []PatternRule fallback string } // LoadResolver reads the .libfossil-merge file from the repo at the given // version, plus the merge-strategy config key as fallback. func LoadResolver(r *repo.Repo, tipRid libfossil.FslID) *Resolver { if r == nil { panic("merge.LoadResolver: r must not be nil") } res := &Resolver{fallback: "three-way"} var cfgDefault string if r.DB().QueryRow("SELECT value FROM config WHERE name='merge-strategy'").Scan(&cfgDefault) == nil && cfgDefault != "" { res.fallback = cfgDefault } if tipRid > 0 { files, err := manifest.ListFiles(r, tipRid) if err == nil { for _, f := range files { if f.Name == ".libfossil-merge" { rid, ok := blob.Exists(r.DB(), f.UUID) if ok { data, err := content.Expand(r.DB(), rid) if err == nil { res.patterns = parseMergeFile(data) } } break } } } } return res } // Resolve returns the strategy name for a filename. func (res *Resolver) Resolve(filename string) string { for _, p := range res.patterns { matched, matchErr := filepath.Match(p.Glob, filepath.Base(filename)) if matchErr != nil { continue } if matched { return p.Strategy } } return res.fallback } func parseMergeFile(data []byte) []PatternRule { var rules []PatternRule scanner := bufio.NewScanner(strings.NewReader(string(data))) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line == "" || strings.HasPrefix(line, "#") { continue } parts := strings.Fields(line) if len(parts) >= 2 { rules = append(rules, PatternRule{Glob: parts[0], Strategy: parts[1]}) } } return rules }