facter

package module
v0.0.0-...-3487296 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 9, 2026 License: BSD-3-Clause Imports: 8 Imported by: 0

README

go-ruby-facter

go-ruby-facter

ci coverage Go Reference

A pure-Go (CGO-free) implementation of the Ruby Facter API semantics, layered as an importable adapter over the go-facter system-inventory engine.

go-facter discovers the built-in structured facts (os, kernel, networking, processors, memory, filesystems, virtualisation, uptime, identity) and resolves simple custom and external facts. This package adds the parts of Ruby Facter that a generic inventory engine does not model:

  • the module surface — Value/[], Fact, List, ToHash, Each;
  • Add with full resolution semantics — several resolutions per fact, :weight/has_weight ordering, :confine predicates (fact, env and block confines), :timeout, and aggregate facts (chunks + an aggregate/merge step);
  • Facter::Core::Execution-style Execute/Which behind an injectable Executor seam;
  • clear/reset/flush cache semantics;
  • external- and custom-fact search-path loading, delegated to the engine.

Resolution follows Ruby Facter 4: for a fact, the highest-weight resolution whose confines all match and whose code returns a value wins; ties break by declaration order. A fact with no matching custom resolution falls back to the engine's built-in value.

Ruby → Go API map

Ruby Go
Facter.value(:x) / Facter[:x] (*Facter).Value("x")
Facter.fact(:x) (*Facter).Fact("x")
Facter.add(:x) { … } (*Facter).Add("x", Options{…}, ResolveFunc)
Facter.add(:x, :type => :aggregate) (*Facter).AddAggregate("x", Options{…}, Aggregate{…})
Facter.to_hash (*Facter).ToHash() (alias of ResolveAll)
Facter.list / Facter.each (*Facter).List() / (*Facter).Each(fn)
Facter.flush / Facter.reset / Facter.clear (*Facter).Flush() / Reset() / Clear()
Facter::Core::Execution.execute / .which (*Facter).Execute / Which
confine :x => v / confine(:x){…} / confine{…} ConfineFact / ConfineFactFunc / ConfineBlock

Usage

f := facter.New() // backed by a real go-facter engine

f.Add("role", facter.Options{
    Confine: []facter.Confine{facter.ConfineFact("os.family", "Debian")},
}, func(rc *facter.ResolutionContext) (any, bool) {
    return "web", true
})

v, _ := f.Value("os.name")   // built-in fact
role, _ := f.Value("role")   // custom fact
all := f.ResolveAll()        // nested map[string]any, ready to marshal

Relationship to rbgo

This package has no dependency on any Ruby runtime. Custom resolvers are Go-typed (ResolveFunc + Confine predicates). A consumer such as go-embedded-ruby (rbgo) adapts a Ruby Facter.add … do … end block into those Go values, marshals results, and wires a Ruby Facter constant onto this adapter. ResolveAll is the documented integration point.

License

BSD-3-Clause — see LICENSE.

Documentation

Overview

Package facter is a pure-Go (no cgo) implementation of the Ruby Facter API semantics, layered as an importable adapter over the system-inventory engine github.com/go-facter/facter.

The go-facter engine discovers the built-in structured facts (os, kernel, networking, processors, memory, filesystems, virtualisation, uptime, identity) and resolves simple custom facts and external facts. This package adds the parts of Ruby's Facter that a generic inventory engine does not model:

  • the module surface — Value/[] , Fact, List, ToHash, Each;
  • Add with full resolution semantics — several resolutions per fact, :weight / has_weight ordering, :confine predicates (fact, env and block confines) that gate a resolution, :timeout, and aggregate facts (chunks plus an aggregate/merge step);
  • Facter::Core::Execution-style Execute / Which helpers behind an injectable Executor seam;
  • clear / reset / flush cache semantics;
  • external- and custom-fact search-path loading, delegated to the engine.

Resolution order follows Ruby Facter 4: for a given fact the resolution with the highest weight whose confines all match and whose code returns a value wins; ties break by declaration order. A fact with no matching custom resolution falls back to the engine's built-in value, so custom resolutions override built-ins exactly when their weight lets them.

The package has no dependency on any Ruby runtime. Custom resolvers are Go-typed (a ResolveFunc plus Confine predicates); a consumer such as go-embedded-ruby (rbgo) adapts a Ruby "Facter.add ... do ... end" block into those Go values and marshals results, then wires a Ruby Facter constant onto this adapter. ResolveAll is the documented integration point: it returns the fully resolved fact set as a nested map[string]any ready for marshalling.

Index

Constants

View Source
const Version = "4.0.0"

Version is the Ruby Facter major line whose semantics this adapter matches.

Variables

This section is empty.

Functions

This section is empty.

Types

type Aggregate

type Aggregate struct {
	// Chunks maps a chunk name to the function that computes it.
	Chunks map[string]ChunkFunc
	// Requires maps a chunk name to the chunk names that must run before it. It is
	// the Go analogue of a chunk's :require option and only affects ordering.
	Requires map[string][]string
	// Merge combines the resolved chunk results into the fact's value. When nil,
	// the results are deep-merged. It is the Go analogue of the aggregate block;
	// returning ok=false means the aggregate produced no value.
	Merge func(chunks map[string]any) (any, bool)
}

Aggregate describes an aggregate fact: named chunks, optional inter-chunk ordering, and a merge step. It is the Go analogue of Ruby's Facter::Core::Aggregate (chunk / aggregate blocks).

type ChunkFunc

type ChunkFunc func(ctx *ResolutionContext) (any, bool)

ChunkFunc computes one chunk of an aggregate fact. It returns (value, true) when the chunk produces data and (nil, false) when it has nothing to contribute. It is the Go analogue of a Ruby aggregate "chunk" block.

type Confine

type Confine func(f *Facter) bool

Confine gates a resolution: it is consulted against the owning Facter and must return true for the resolution to be eligible. It is the Go analogue of a Ruby "confine" declaration.

func ConfineBlock

func ConfineBlock(pred func(f *Facter) bool) Confine

ConfineBlock confines on an arbitrary predicate over the Facter, the Go analogue of Ruby's confine { ... } block form.

func ConfineEnv

func ConfineEnv(key string, allowed ...string) Confine

ConfineEnv confines on an environment variable's value being one of allowed (case-insensitively). With no allowed values it confines to the variable being set and non-empty.

func ConfineFact

func ConfineFact(name string, allowed ...any) Confine

ConfineFact confines a resolution to hosts where fact name resolves to one of allowed. It is the Go analogue of Ruby's confine :name => value (or an array of values). With no allowed values it confines to name merely being present.

func ConfineFactFunc

func ConfineFactFunc(name string, pred func(v any) bool) Confine

ConfineFactFunc confines on an arbitrary predicate over fact name's value. It is the Go analogue of Ruby's confine(:name) { |val| ... }. The resolution is gated out when the fact is absent.

type Engine

type Engine interface {
	// Value resolves a fact by dotted path (Facter.value / Facter[]).
	Value(path string) (any, bool)
	// ToHash resolves every built-in fact into one nested map.
	ToHash() map[string]any
	// Names lists the registered built-in fact names.
	Names() []string
	// LoadExternalFacts loads external (out-of-process) facts from dirs.
	LoadExternalFacts(dirs ...string) error
}

Engine is the system-inventory back end the adapter resolves built-in facts against. *github.com/go-facter/facter.Collection satisfies it; tests inject a fake. It is the seam between the Ruby-Facter semantics implemented here and the generic fact engine underneath.

type Executor

type Executor interface {
	// Execute runs command and returns its trimmed stdout, or ("", false) on any
	// failure (empty command, launch error, non-zero exit).
	Execute(command string) (string, bool)
	// Which returns the resolved path of binary on PATH, or ("", false) when it is
	// not found.
	Which(binary string) (string, bool)
}

Executor is the Facter::Core::Execution back end: it runs a command and locates a binary. It is an injectable seam so custom facts that shell out stay testable without invoking real binaries. SetExecutor replaces it.

type Fact

type Fact struct {
	// contains filtered or unexported fields
}

Fact is a handle to a named fact, the Go analogue of Ruby's Facter::Util::Fact. It resolves through the owning Facter, so it always reflects the current registry and cache.

func (*Fact) Add

func (ft *Fact) Add(opts Options, resolve ResolveFunc) *Fact

Add appends another resolution to this fact and returns the handle for chaining, mirroring repeated Facter.add blocks for the same fact.

func (*Fact) Name

func (ft *Fact) Name() string

Name returns the fact's name.

func (*Fact) Resolutions

func (ft *Fact) Resolutions() int

Resolutions reports how many custom resolutions are registered for the fact.

func (*Fact) Value

func (ft *Fact) Value() (any, bool)

Value resolves the fact and returns its value and presence.

type Facter

type Facter struct {
	// contains filtered or unexported fields
}

Facter is the Ruby Facter module surface. It owns an Engine for built-in facts, a registry of custom resolutions, one per-run value cache and one execution seam. It is the object a Ruby binding wraps to expose Facter.value, Facter.add, Facter.to_hash and friends. All methods are safe for concurrent use.

func New

func New() *Facter

New returns a Facter backed by a fresh go-facter engine with every built-in fact group registered against the real operating system. It is the entry point for production use and the object rbgo binds a Ruby Facter constant onto.

func NewWithEngine

func NewWithEngine(newEngine func() Engine) *Facter

NewWithEngine returns a Facter backed by the engine produced by newEngine. The factory (rather than a single instance) is stored so Reset can rebuild a clean engine. It is the seam tests use to drive the adapter against a fake engine.

func (*Facter) Add

func (f *Facter) Add(name string, opts Options, resolve ResolveFunc) *Fact

Add registers a resolution for name resolved by resolve, honouring opts (weight, confines, timeout). It is the Go surface behind Ruby's Facter.add(name) { ... }. Calling Add again for the same name adds another resolution; the highest-weight matching one wins. It returns a Fact handle for chaining further resolutions.

func (*Facter) AddAggregate

func (f *Facter) AddAggregate(name string, opts Options, spec Aggregate) *Fact

AddAggregate registers an aggregate fact: a set of chunks whose results are combined by spec.Merge (or deep-merged when Merge is nil). It is the surface behind Ruby's Facter.add(:x, :type => :aggregate) with chunk / aggregate blocks.

func (*Facter) AddValue

func (f *Facter) AddValue(name string, value any) *Fact

AddValue registers a fact with a constant value — the degenerate custom fact (Facter.add(:x) { setcode { v } } with no logic).

func (*Facter) Clear

func (f *Facter) Clear()

Clear is Ruby's Facter.clear: it resets the collection and flushes cached values. Here it is equivalent to Reset.

func (*Facter) Each

func (f *Facter) Each(fn func(name string, value any))

Each resolves every fact and calls fn with each name and value, in sorted name order. It is the surface behind Ruby's Facter.each.

func (*Facter) Execute

func (f *Facter) Execute(command string) (string, bool)

Execute runs command through the execution seam and returns its trimmed stdout, or ("", false) on failure. It is the surface behind Facter::Core::Execution.execute.

func (*Facter) Fact

func (f *Facter) Fact(name string) *Fact

Fact returns a handle for name, or nil when neither a custom resolution nor a built-in fact provides it. It mirrors Ruby's Facter.fact / Facter[] (which return nil for an unknown fact).

func (*Facter) Flush

func (f *Facter) Flush()

Flush clears the per-run value cache so the next query re-resolves. It is the surface behind Ruby's Facter.flush. Custom resolutions stay registered.

func (*Facter) List

func (f *Facter) List() []string

List returns every known fact name — built-in and custom — sorted and de-duplicated. It is the surface behind Ruby's Facter.list.

func (*Facter) LoadExternalFacts

func (f *Facter) LoadExternalFacts(dirs ...string) error

LoadExternalFacts loads external facts from dirs, delegating file discovery and parsing to the engine. It is the surface behind Facter's external-fact search path.

func (*Facter) Reset

func (f *Facter) Reset()

Reset forgets every custom resolution, clears the cache and rebuilds a clean engine. It is the surface behind Ruby's Facter.reset.

func (*Facter) ResolveAll

func (f *Facter) ResolveAll() map[string]any

ResolveAll resolves every known fact — built-ins from the engine plus every custom fact — into one nested map. It is the documented integration point a consumer (rbgo) marshals; ToHash is its Ruby-named alias.

func (*Facter) SetExecutor

func (f *Facter) SetExecutor(e Executor)

SetExecutor replaces the Facter::Core::Execution back end, so a caller (or a test) can supply command results without touching real binaries.

func (*Facter) ToHash

func (f *Facter) ToHash() map[string]any

ToHash is the Ruby Facter.to_hash surface; it returns the same map as ResolveAll.

func (*Facter) ToJSON

func (f *Facter) ToJSON() (string, error)

ToJSON marshals the fully resolved fact set as JSON, reusing the engine's encoder.

func (*Facter) ToYAML

func (f *Facter) ToYAML() string

ToYAML marshals the fully resolved fact set as YAML, reusing the engine's encoder.

func (*Facter) Value

func (f *Facter) Value(path string) (any, bool)

Value resolves a fact by dotted path: the first segment names a fact and any further segments descend into a structured fact's nested maps, so Value("os.name") works. It is the surface behind Ruby's Facter.value / Facter[].

func (*Facter) ValueString

func (f *Facter) ValueString(path string) (string, bool)

ValueString is Value coerced to a string, the common case for a Ruby caller. The bool reports presence, not emptiness.

func (*Facter) Which

func (f *Facter) Which(binary string) (string, bool)

Which resolves a binary on PATH, or ("", false) when absent. It is the surface behind Facter::Core::Execution.which.

type Options

type Options struct {
	// Weight sets an explicit resolution weight; it only takes effect when
	// HasWeight is true, mirroring Ruby's has_weight. Higher wins.
	Weight int
	// HasWeight marks Weight as explicit. When false, the resolution's weight is
	// the number of its confines, exactly as Ruby Facter defaults it.
	HasWeight bool
	// Timeout bounds how long the resolver may run; zero means no bound. A
	// resolution that times out contributes no value and the next one is tried.
	Timeout time.Duration
	// Confine lists predicates that must all pass for the resolution to be
	// considered.
	Confine []Confine
}

Options carries the per-resolution knobs of a Ruby Facter.add block.

type ResolutionContext

type ResolutionContext struct {
	// contains filtered or unexported fields
}

ResolutionContext is handed to a resolver and to chunk functions. It is the Go analogue of the block self in a Ruby setcode block: it can read other facts and run commands through the same Facter.

func (*ResolutionContext) Execute

func (rc *ResolutionContext) Execute(command string) (string, bool)

Execute runs a command through the Facter's execution seam.

func (*ResolutionContext) Value

func (rc *ResolutionContext) Value(path string) (any, bool)

Value reads another fact, so one resolution can depend on another.

func (*ResolutionContext) ValueString

func (rc *ResolutionContext) ValueString(path string) (string, bool)

ValueString reads another fact as a string.

func (*ResolutionContext) Which

func (rc *ResolutionContext) Which(binary string) (string, bool)

Which resolves a binary on PATH through the Facter's execution seam.

type ResolveFunc

type ResolveFunc func(ctx *ResolutionContext) (any, bool)

ResolveFunc produces a fact's value. It returns (value, true) when the fact resolves and (nil, false) when it does not on this host. It is the Go analogue of a Ruby resolution's setcode block; rbgo adapts a Ruby block into one of these.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL