fix(build): add CGO build constraints for Dolt-dependent files

The dolthub/gozstd dependency requires CGO. Several files were importing
the dolt package without build constraints, causing CI failures when
building with CGO_ENABLED=0 for Linux, FreeBSD, and Android.

Changes:
- Add //go:build cgo to federation.go and doctor/federation.go
- Create dolt_server_cgo.go/nocgo.go to abstract dolt.Server usage
- Create federation_nocgo.go with stub command explaining CGO requirement
- Create doctor/federation_nocgo.go with stub health checks
- Update daemon.go to use the dolt server abstraction

Federation and Dolt-specific features are unavailable in non-CGO builds.
Users are directed to pre-built binaries from GitHub releases.

Fixes v0.49.0 CI failure.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
emma
2026-01-22 00:01:37 -08:00
committed by Steve Yegge
parent 9381190462
commit f91bbf3a03
7 changed files with 225 additions and 13 deletions

View File

@@ -17,7 +17,6 @@ import (
"github.com/steveyegge/beads/internal/configfile"
"github.com/steveyegge/beads/internal/daemon"
"github.com/steveyegge/beads/internal/rpc"
"github.com/steveyegge/beads/internal/storage/dolt"
"github.com/steveyegge/beads/internal/storage/factory"
"github.com/steveyegge/beads/internal/storage/sqlite"
"github.com/steveyegge/beads/internal/syncbranch"
@@ -421,13 +420,17 @@ func runDaemonLoop(interval time.Duration, autoCommit, autoPush, autoPull, local
}
// Start dolt sql-server if federation mode is enabled and backend is dolt
var doltServer *dolt.Server
var doltServer *DoltServerHandle
factoryOpts := factory.Options{}
if federation && backend != configfile.BackendDolt {
log.Warn("federation mode requires dolt backend, ignoring --federation flag")
federation = false
}
if federation && backend == configfile.BackendDolt {
if !DoltServerAvailable() {
log.Error("federation mode requires CGO; use pre-built binaries from GitHub releases")
return
}
log.Info("starting dolt sql-server for federation mode")
doltPath := filepath.Join(beadsDir, "dolt")
@@ -436,22 +439,16 @@ func runDaemonLoop(interval time.Duration, autoCommit, autoPush, autoPull, local
// Use provided ports or defaults
sqlPort := federationPort
if sqlPort == 0 {
sqlPort = dolt.DefaultSQLPort
sqlPort = DoltDefaultSQLPort
}
remotePort := remotesapiPort
if remotePort == 0 {
remotePort = dolt.DefaultRemotesAPIPort
remotePort = DoltDefaultRemotesAPIPort
}
doltServer = dolt.NewServer(dolt.ServerConfig{
DataDir: doltPath,
SQLPort: sqlPort,
RemotesAPIPort: remotePort,
Host: "127.0.0.1",
LogFile: serverLogFile,
})
if err := doltServer.Start(ctx); err != nil {
var err error
doltServer, err = StartDoltServer(ctx, doltPath, serverLogFile, sqlPort, remotePort)
if err != nil {
log.Error("failed to start dolt sql-server", "error", err)
return
}

View File

@@ -1,3 +1,5 @@
//go:build cgo
package doctor
import (

View File

@@ -0,0 +1,53 @@
//go:build !cgo
package doctor
// CheckFederationRemotesAPI returns N/A when CGO is not available.
func CheckFederationRemotesAPI(path string) DoctorCheck {
return DoctorCheck{
Name: "Federation remotesapi",
Status: StatusOK,
Message: "N/A (requires CGO)",
Category: CategoryFederation,
}
}
// CheckFederationPeerConnectivity returns N/A when CGO is not available.
func CheckFederationPeerConnectivity(path string) DoctorCheck {
return DoctorCheck{
Name: "Peer Connectivity",
Status: StatusOK,
Message: "N/A (requires CGO)",
Category: CategoryFederation,
}
}
// CheckFederationSyncStaleness returns N/A when CGO is not available.
func CheckFederationSyncStaleness(path string) DoctorCheck {
return DoctorCheck{
Name: "Sync Staleness",
Status: StatusOK,
Message: "N/A (requires CGO)",
Category: CategoryFederation,
}
}
// CheckFederationConflicts returns N/A when CGO is not available.
func CheckFederationConflicts(path string) DoctorCheck {
return DoctorCheck{
Name: "Federation Conflicts",
Status: StatusOK,
Message: "N/A (requires CGO)",
Category: CategoryFederation,
}
}
// CheckDoltServerModeMismatch returns N/A when CGO is not available.
func CheckDoltServerModeMismatch(path string) DoctorCheck {
return DoctorCheck{
Name: "Dolt Mode",
Status: StatusOK,
Message: "N/A (requires CGO)",
Category: CategoryFederation,
}
}

74
cmd/bd/dolt_server_cgo.go Normal file
View File

@@ -0,0 +1,74 @@
//go:build cgo
package main
import (
"context"
"github.com/steveyegge/beads/internal/storage/dolt"
)
// DoltServerHandle wraps a dolt.Server for CGO builds
type DoltServerHandle struct {
server *dolt.Server
}
// DoltDefaultSQLPort is the default SQL port for dolt server
const DoltDefaultSQLPort = dolt.DefaultSQLPort
// DoltDefaultRemotesAPIPort is the default remotesapi port for dolt server
const DoltDefaultRemotesAPIPort = dolt.DefaultRemotesAPIPort
// StartDoltServer starts a dolt sql-server for federation mode
func StartDoltServer(ctx context.Context, dataDir, logFile string, sqlPort, remotePort int) (*DoltServerHandle, error) {
server := dolt.NewServer(dolt.ServerConfig{
DataDir: dataDir,
SQLPort: sqlPort,
RemotesAPIPort: remotePort,
Host: "127.0.0.1",
LogFile: logFile,
})
if err := server.Start(ctx); err != nil {
return nil, err
}
return &DoltServerHandle{server: server}, nil
}
// Stop stops the dolt server
func (h *DoltServerHandle) Stop() error {
if h.server != nil {
return h.server.Stop()
}
return nil
}
// SQLPort returns the SQL port the server is listening on
func (h *DoltServerHandle) SQLPort() int {
if h.server != nil {
return h.server.SQLPort()
}
return 0
}
// RemotesAPIPort returns the remotesapi port the server is listening on
func (h *DoltServerHandle) RemotesAPIPort() int {
if h.server != nil {
return h.server.RemotesAPIPort()
}
return 0
}
// Host returns the host the server is listening on
func (h *DoltServerHandle) Host() string {
if h.server != nil {
return h.server.Host()
}
return ""
}
// DoltServerAvailable returns true when CGO is available
func DoltServerAvailable() bool {
return true
}

View File

@@ -0,0 +1,50 @@
//go:build !cgo
package main
import (
"context"
"errors"
)
// DoltServerHandle is a stub for non-CGO builds
type DoltServerHandle struct{}
// DoltDefaultSQLPort is the default SQL port for dolt server
const DoltDefaultSQLPort = 3306
// DoltDefaultRemotesAPIPort is the default remotesapi port for dolt server
const DoltDefaultRemotesAPIPort = 50051
// ErrDoltRequiresCGO is returned when dolt features are requested without CGO
var ErrDoltRequiresCGO = errors.New("dolt backend requires CGO; use pre-built binaries from GitHub releases or enable CGO")
// StartDoltServer returns an error in non-CGO builds
func StartDoltServer(ctx context.Context, dataDir, logFile string, sqlPort, remotePort int) (*DoltServerHandle, error) {
return nil, ErrDoltRequiresCGO
}
// Stop is a no-op stub
func (h *DoltServerHandle) Stop() error {
return nil
}
// SQLPort returns 0 in non-CGO builds
func (h *DoltServerHandle) SQLPort() int {
return 0
}
// RemotesAPIPort returns 0 in non-CGO builds
func (h *DoltServerHandle) RemotesAPIPort() int {
return 0
}
// Host returns empty string in non-CGO builds
func (h *DoltServerHandle) Host() string {
return ""
}
// DoltServerAvailable returns false when CGO is not available
func DoltServerAvailable() bool {
return false
}

View File

@@ -1,3 +1,5 @@
//go:build cgo
package main
import (

View File

@@ -0,0 +1,34 @@
//go:build !cgo
package main
import (
"fmt"
"github.com/spf13/cobra"
)
var federationCmd = &cobra.Command{
Use: "federation",
GroupID: "sync",
Short: "Manage peer-to-peer federation (requires CGO)",
Long: `Federation commands require CGO and the Dolt storage backend.
This binary was built without CGO support. To use federation features:
1. Use pre-built binaries from GitHub releases, or
2. Build from source with CGO enabled
Federation enables synchronized issue tracking across multiple Gas Towns,
each maintaining their own Dolt database while sharing updates via remotes.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Federation requires CGO and Dolt backend.")
fmt.Println("")
fmt.Println("This binary was built without CGO support. To use federation:")
fmt.Println(" 1. Download pre-built binaries from GitHub releases")
fmt.Println(" 2. Or build from source with CGO enabled")
},
}
func init() {
rootCmd.AddCommand(federationCmd)
}