Documentation
¶
Overview ¶
Package app implements siphon's verbs over the domain layer. CLI and TUI both call into this package; neither cares about the other.
Index ¶
- func Backup(parent context.Context, d Deps, opt BackupOpts) (<-chan jobs.Event, string, error)
- func CDCStateDir() string
- func Inspect(ctx context.Context, d Deps, profile string) (*driver.Schema, error)
- func RequireCapability(d Deps, profileName string, requiredCap Capability) error
- func Restore(parent context.Context, d Deps, opt RestoreOpts) (<-chan jobs.Event, string, error)
- func RunCDC(parent context.Context, d Deps, opt SyncOpts) (<-chan jobs.Event, string, error)
- func Sync(parent context.Context, d Deps, opt SyncOpts) (<-chan jobs.Event, string, error)
- func Verify(ctx context.Context, d Deps, dumpID string) (*driver.VerifyReport, error)
- type BackupOpts
- type CDCState
- type Capability
- type ChainOutcome
- type Deps
- type DriverGetter
- type Gate
- type PruneOpts
- type PruneResult
- type RestoreOpts
- type SyncOpts
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Backup ¶
Backup dumps the source profile to a new entry in the catalog. Returns the running job's Event channel and ID.
func CDCStateDir ¶
func CDCStateDir() string
CDCStateDir returns the per-user directory holding CDC resume state. It honors SIPHON_STATE_HOME, then XDG_STATE_HOME, then $HOME/.local/state — mirroring how internal/config resolves its config path, so tests can redirect it without writing to the real home.
func RequireCapability ¶
func RequireCapability(d Deps, profileName string, requiredCap Capability) error
RequireCapability resolves profileName to its driver and checks that the driver supports requiredCap. It returns nil when supported, or a CodeUser errs.Error wrapping ErrDriverUnsupported (with an actionable hint) when not.
Callers in the presentation layer (CLI/TUI) use this for verb pre-flight so an unsupported affordance fails fast with a clear message rather than crashing partway through. It takes a profile name (not a driver.Driver) so the CLI never has to import the driver package (depguard boundary).
func Restore ¶
Restore resolves the dump's chain (base + incrementals) and applies it in order into the target profile. For a plain (non-incremental) dump the chain is a single element. --up-to stops the chain early at the named dump.
func RunCDC ¶
RunCDC starts (or resumes) a continuous, unbounded sync: it tails the source's logical change stream and applies each engine-neutral CanonicalChange to the target. It works same-engine and cross-engine alike because CanonicalChange is engine-neutral and ApplyChange replays it natively on the target.
Both drivers must advertise CapCDC. On a first run (no prior state) it captures a consistent start position, takes an initial schema+data snapshot, then streams changes committed after that position. On a restart it resumes from the saved position with no snapshot.
Resume granularity is "since the last clean exit": RunCDC persists the streamer's returned final position when the stream stops (the position is tied to what was actually delivered, never ahead of it). Re-applying the tail after a crash is safe because ApplyChange is idempotent (INSERT upserts; UPDATE and DELETE target by primary key).
ctx cancellation is the normal stop signal (matching the bounded-stream convention): on cancel RunCDC persists final state and returns nil; only a non-cancel StreamChanges error is surfaced.
func Sync ¶
Sync backs up From and restores into To in a single pass. The native (homogeneous) path streams the dump through a bounded jobs.Stream — no temp file, no catalog entry — so backpressure is observable via FillPercent while a backup failure still propagates to Restore as a read error (via CloseErr), preventing a truncated dump from being committed as if clean.
When opt.CrossEngine is set the work routes through runCrossEngineSync, which is capability-gated and uses driver.SchemaInspector + driver.CanonicalTransfer for typed cross-engine snapshot transfer.
func Verify ¶
Verify checks the integrity of a dump entry by recomputing the sha256 of the dump file and comparing it against the checksum recorded in the meta sidecar. It is stateless — no DB connection is required (Phase B checksums only; Phase F adds envelope-header validation via the driver's Verify method).
Types ¶
type BackupOpts ¶
type BackupOpts struct {
Profile string
IncludeTables []string
ExcludeTables []string
ExcludeDataFrom []string
SchemaOnly bool
DataOnly bool
CompressionLevel int
Parallel int
Incremental bool
BaseID string
}
BackupOpts configures the Backup verb.
type CDCState ¶
type CDCState struct {
JobID string `json:"job_id"`
Source string `json:"source_profile"`
Target string `json:"target_profile"`
LastAppliedLSN string `json:"last_applied_lsn,omitempty"`
LastBinlogFile string `json:"last_binlog_file,omitempty"`
LastBinlogPos uint64 `json:"last_binlog_pos,omitempty"`
UpdatedAt time.Time `json:"updated_at"`
}
CDCState is persisted between runs so a long-running continuous sync can resume from the last applied position after a restart.
type Capability ¶
type Capability string
Capability identifies a specific feature flag a verb requires. The string values mirror the driver.Capabilities field semantics and appear in the user-facing hint when a driver lacks the capability.
const ( CapIncremental Capability = "incremental" CapNativeStream Capability = "native-stream" CapPerTable Capability = "per-table" CapSchemaOnly Capability = "schema-only" CapDataOnly Capability = "data-only" CapParallel Capability = "parallel" CapCompression Capability = "compression" CapBinaryFormat Capability = "binary-format" CapCrossEngineSource Capability = "cross-engine-source" CapCrossEngineTarget Capability = "cross-engine-target" CapCDC Capability = "cdc" CapNativeBackpressure Capability = "native-backpressure" CapCrossVersionIncremental Capability = "cross-version-incremental" )
type ChainOutcome ¶
type ChainOutcome struct {
Root string
DumpIDs []string
SizeBytes int64
Pruned bool // true = scheduled for (or performed) deletion
Deleted []string // dump IDs actually deleted (Apply only)
Errors []string // per-dump deletion failures (Apply only)
}
ChainOutcome is one chain's place in the plan, flattened for reporting.
type Deps ¶
type Deps struct {
Profiles *profile.Store
Dumps *dumps.Catalog
Runner *jobs.Runner
Drivers DriverGetter
// Auditor records destructive operations; nil is a no-op. It is also the
// interception seam for 2FA gating (a pre-check before the verb) and
// telemetry (timing/outcome), so those reuse these call sites.
Auditor audit.Auditor
// Gate, if set, is consulted before a destructive verb runs and can block it
// (e.g. require 2FA / destructive confirmation for a profile's group).
Gate Gate
// Actor is the OS user attributed in audit records.
Actor string
}
Deps bundles every dependency the app verbs need. CLI and TUI build one Deps at startup and pass it to every verb. Makes mocking trivial.
type DriverGetter ¶
DriverGetter is satisfied by internal/driver.Get. Wrapped to allow mocking.
func DefaultDrivers ¶
func DefaultDrivers() DriverGetter
DefaultDrivers returns a DriverGetter backed by the global driver registry. Presentation layers (CLI, TUI) use this so they never import internal/driver directly — dependency flows through the application layer.
type Gate ¶
Gate authorizes a destructive operation before it runs. A nil Gate allows everything. Returning a non-nil error blocks the verb.
type PruneOpts ¶
type PruneOpts struct {
Profile string
Policy dumps.RetentionPolicy
Apply bool
}
PruneOpts configures a prune run. Policy is resolved by the caller (the CLI maps config + flags into it), so this layer stays config-agnostic. Profile scopes the catalog to one profile's dumps ("" = all profiles). Apply performs deletions; otherwise the run is a dry-run that only computes the plan.
type PruneResult ¶
type PruneResult struct {
Profile string
Apply bool
Outcomes []ChainOutcome
Reclaimed int64 // bytes freed (sum of successfully deleted dumps; Apply only)
Failed int // count of dumps that failed to delete
}
PruneResult is the structured outcome the CLI renders.
func Prune ¶
Prune groups the catalog into chains, plans retention over them, and (when Apply) deletes the pruned chains. It is synchronous (like Verify): prune is a list + a few deletes, not a long stream, so it returns a structured result directly rather than over the job channel.
Deletion is chain-aware and leaf-inward: within a pruned chain, incrementals are removed before the base, so an interrupted prune leaves at worst a complete shorter chain — never a base missing under a surviving incremental.
type RestoreOpts ¶
type RestoreOpts struct {
Profile string
DumpID string
TargetTables []string
SchemaOnly bool
DataOnly bool
Clean bool
UpTo string // optional: stop applying the chain after this dump ID
}
RestoreOpts configures the Restore verb.
type SyncOpts ¶
type SyncOpts struct {
From string
To string
Stream bool
Tables []string
// CrossEngine routes through the canonical-schema path (e.g. postgres→mysql)
// instead of the native homogeneous stream. Gated on driver capability.
CrossEngine bool
// Continuous requests CDC follow mode: routes to RunCDC, which tails the
// source change stream and applies each change to the target (same-engine
// and cross-engine), resumable via the CDC state file.
Continuous bool
}
SyncOpts configures the Sync verb.