wiring

package
v0.0.0-...-9a5c20e Latest Latest
Warning

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

Go to latest
Published: May 2, 2024 License: BSD-3-Clause Imports: 9 Imported by: 35

README

wiring

import "github.com/blueprint-uservices/blueprint/blueprint/pkg/wiring"

Package wiring provides the entry point for a Blueprint application to create and configure a wiring spec; that wiring spec can be enriched and extended by plugins; ultimately it is used by applications to generate concrete application instances.

The starting point for a Blueprint application is the NewWiringSpec function.

spec := wiring.NewWiringSpec("my_application")

Subsequently, Blueprint applications should typically not need to directly invoke methods on the WiringSpec instance; instead the applications should invoke plugins, passing the WiringSpec instance to those plugins.

After doing so,invoke the [BuildIR] function to construct the Blueprint IR for specified nodes

applicationIR, err := spec.BuildIR("my_service")

Finally, artifacts can be generated by the IR by invoking GenerateArtifacts:

err = applicationIR.GenerateArtifacts("build")

For more information, consult the Blueprint User Manual.

Index

func BuildApplicationIR

func BuildApplicationIR(spec WiringSpec, name string, nodesToInstantiate ...string) (*ir.ApplicationNode, error)

Builds the IR of an application using the definitions of the provided spec. Returns an [ir.ApplicationNode] of the application.

Callers should typically provide nodesToInstantiate to specify which nodes should be instantiated in the application. This method will recursively instantiate any dependencies.

If nodesToInstantiate is empty, all nodes will be instantiated, but this might not result in an application with the desired topology. Hence the recommended approach is to explicitly specify which nodes to instantiate.

type BuildFunc

Creates an IR node within the provided namespace or within a new child namespace. Other named IR nodes can be fetched from the provided Namespace by invoking [Namespace.Get] or other Namespace methods.

type BuildFunc func(Namespace) (ir.IRNode, error)

type DeferOpts

Options for deferred functions provided with [Namespace.Defer]

type DeferOpts struct {
    // Defaults to false. If set to true, pushes the deferred function to the front of the queue instead of the back.
    Front bool
}

type Namespace

Namespace is a dependency injection container used by Blueprint plugins during Blueprint's IR construction process. Namespaces instantiate and store IRNodes. A root Blueprint application is itself a Namespace.

A Namespace argument is passed to the BuildFunc when an IRNode is being built. An IRNode can potentially be built multiple times, in different namespaces.

If an IRNode depends on other IRNodes, those others can be fetched by calling [Namespace.Get]. If those IRNodes haven't yet been built, then their BuildFuncs will also be invoked, recursively. Conversely, if those IRNodes are already built, then the built instance is re-used.

Namespaces are hierarchical and a namespace implementation can choose to only support a subset of IRNodes. In this case, [Namespace.Get] on an unsupported IRNode will recursively get the node on the parent namespace. Namespaces inspect the nodeType argument of [WiringSpec.Define] to make this decision.

type Namespace interface {
    // Returns the name of this namespace
    Name() string

    // Gets an IRNode with the specified name from this namespace, placing the result in the pointer dst.
    // dst should typically be a pointer to an IRNode type.
    // If the node has already been built, it returns the existing built node.
    // If the node hasn't yet been built, the node's [BuildFunc] will be called and the result will be
    // cached and returned.
    // This call might recursively call [Get] on a parent namespace depending on the [nodeType] registered
    // for name.
    Get(name string, dst any) error

    // The same as [Get] but without creating a depending (an edge) into the current namespace.  Most
    // plugins should use [Get] instead.
    Instantiate(name string, dst any) error

    // Gets a property from the wiring spec; dst should be a pointer to a value
    GetProperty(name string, key string, dst any) error

    // Gets a slice of properties from the wiring spec; dst should be a pointer to a slice
    GetProperties(name string, key string, dst any) error

    // Puts a node into this namespace
    Put(name string, node ir.IRNode) error

    // Creates and returns a child namespace within this namespaces.
    // handler will be used to determine what nodes can be built in the child namespace, and
    // handler's callbacks will be invoked when nodes get created within the child namespace.
    //
    // Subsequently, the namespace can be retrieved with GetNamespace
    //
    // Returns an error if the namespace has already been created
    DeriveNamespace(name string, handler NamespaceHandler) (Namespace, error)

    // Returns the child namespace with the given name.  The child namespace must have been created in this
    // namespace, using DeriveNamespace, otherwise an error will be returned.
    GetNamespace(name string) (Namespace, error)

    // Enqueue a function to be executed after all currently-queued functions have finished executing.
    // Most plugins should not need to use this.
    // [DeferOpts] can be optionally specified.
    Defer(f func() error, options ...DeferOpts)

    // Log an info-level message
    Info(message string, args ...any)

    // Log a warn-level message
    Warn(message string, args ...any)

    // Log an error-level message
    Error(message string, args ...any) error
}

type NamespaceHandler

NamespaceHandler is an interface intended for use by any Blueprint plugin that wants to provide a custom namespace.

type NamespaceHandler interface {
    // Reports true if this namespace can build nodes of the specified node type.
    //
    // For some node type T, if Accepts(T) returns false, then nodes of type T will
    // not be built in this namespace and instead the parent namespace will be called.
    Accepts(any) bool

    // After a node has been gotten from the parent namespace, AddEdge will be
    // called to inform the handler that the node should be passed to this namespace
    // as an argument.
    AddEdge(string, ir.IRNode) error

    // After a node has been built in this namespace, AddNode will be called
    // to enable the handler to save the built node.
    AddNode(string, ir.IRNode) error
}

type WiringDef

type WiringDef struct {
    Name       string
    NodeType   any
    Build      BuildFunc
    Properties map[string][]any
    Options    WiringOpts
}

func (*WiringDef) AddProperty
func (def *WiringDef) AddProperty(key string, value any)

func (*WiringDef) GetProperties
func (def *WiringDef) GetProperties(key string, dst any) error

func (*WiringDef) GetProperty
func (def *WiringDef) GetProperty(key string, dst any) error

func (*WiringDef) String
func (def *WiringDef) String() string

type WiringError

type WiringError struct {
    Errors []error
}

func (WiringError) Error
func (e WiringError) Error() string

type WiringOpts

Additional options that can be specified when defining a WiringSpec node.

type WiringOpts struct {
    // The type of node returned by the BuildFunc.  By default this is assumed to be the same
    // as nodeType.  Specifying this property does not currently have any effect.
    ReturnType any

    // Used by plugins to indicate whether the BuildFunc builds new nodes, or simply gets
    // and returns other nodes.  Defaults to false.  When set to true, the returned node of
    // a BuildFunc is not added as a node to the namespace or as an edge, since the node originated
    // from some other BuildFunc and therefore was already added as a node or edge.
    ProxyNode bool
}

type WiringSpec

type WiringSpec interface {
    // Provides a node definition for name.  The provided [BuildFunc] build will be used to build
    // the node.  nodeType indicates the type of node that gets built.  Additional [WiringOpts] can
    // be optionally provided to fine-tune the node's build behavior.
    Define(name string, nodeType any, build BuildFunc, options ...WiringOpts)

    GetDef(name string) *WiringDef // For use by plugins to access the defined build functions and metadata
    Defs() []string                // Returns names of all defined nodes

    Alias(name string, pointsto string)   // Defines an alias to another defined node; these can be recursive
    GetAlias(alias string) (string, bool) // Gets the value of the specified alias, if it exists

    SetProperty(name string, key string, value any)       // Sets a static property value in the wiring spec, replacing any existing value specified
    AddProperty(name string, key string, value any)       // Adds a static property value in the wiring spec
    GetProperty(name string, key string, dst any) error   // Gets a static property value from the wiring spec
    GetProperties(name string, key string, dst any) error // Gets all static property values from the wiring spec

    String() string // Returns a string representation of everything that has been defined

    // Errors while building a wiring spec are accumulated within the wiring spec, rather than as return values to calls
    AddError(err error) // Used by plugins to signify an error; the error will be returned by a call to Err or GetBlueprint
    Err() error         // Gets an error if there is currently one

    BuildIR(nodesToInstantiate ...string) (*ir.ApplicationNode, error) // After defining everything, this builds the IR for the specified named nodes (implicitly including dependencies of those nodes)
}

func NewWiringSpec
func NewWiringSpec(name string) WiringSpec

Generated by gomarkdoc

Documentation

Overview

Package wiring provides the entry point for a Blueprint application to create and configure a wiring spec; that wiring spec can be enriched and extended by plugins; ultimately it is used by applications to generate concrete application instances.

The starting point for a Blueprint application is the NewWiringSpec function.

spec := wiring.NewWiringSpec("my_application")

Subsequently, Blueprint applications should typically not need to directly invoke methods on the WiringSpec instance; instead the applications should invoke plugins, passing the WiringSpec instance to those plugins.

After doing so,invoke the [BuildIR] function to construct the Blueprint IR for specified nodes

applicationIR, err := spec.BuildIR("my_service")

Finally, artifacts can be generated by the IR by invoking GenerateArtifacts:

err = applicationIR.GenerateArtifacts("build")

For more information, consult the Blueprint User Manual.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildApplicationIR

func BuildApplicationIR(spec WiringSpec, name string, nodesToInstantiate ...string) (*ir.ApplicationNode, error)

Builds the IR of an application using the definitions of the provided spec. Returns an ir.ApplicationNode of the application.

Callers should typically provide nodesToInstantiate to specify which nodes should be instantiated in the application. This method will recursively instantiate any dependencies.

If nodesToInstantiate is empty, all nodes will be instantiated, but this might not result in an application with the desired topology. Hence the recommended approach is to explicitly specify which nodes to instantiate.

Types

type BuildFunc

type BuildFunc func(Namespace) (ir.IRNode, error)

Creates an IR node within the provided namespace or within a new child namespace. Other named IR nodes can be fetched from the provided Namespace by invoking [Namespace.Get] or other Namespace methods.

type DeferOpts

type DeferOpts struct {
	// Defaults to false. If set to true, pushes the deferred function to the front of the queue instead of the back.
	Front bool
}

Options for deferred functions provided with [Namespace.Defer]

type Namespace

type Namespace interface {
	// Returns the name of this namespace
	Name() string

	// Gets an IRNode with the specified name from this namespace, placing the result in the pointer dst.
	// dst should typically be a pointer to an IRNode type.
	// If the node has already been built, it returns the existing built node.
	// If the node hasn't yet been built, the node's [BuildFunc] will be called and the result will be
	// cached and returned.
	// This call might recursively call [Get] on a parent namespace depending on the [nodeType] registered
	// for name.
	Get(name string, dst any) error

	// The same as [Get] but without creating a depending (an edge) into the current namespace.  Most
	// plugins should use [Get] instead.
	Instantiate(name string, dst any) error

	// Gets a property from the wiring spec; dst should be a pointer to a value
	GetProperty(name string, key string, dst any) error

	// Gets a slice of properties from the wiring spec; dst should be a pointer to a slice
	GetProperties(name string, key string, dst any) error

	// Puts a node into this namespace
	Put(name string, node ir.IRNode) error

	// Creates and returns a child namespace within this namespaces.
	// handler will be used to determine what nodes can be built in the child namespace, and
	// handler's callbacks will be invoked when nodes get created within the child namespace.
	//
	// Subsequently, the namespace can be retrieved with GetNamespace
	//
	// Returns an error if the namespace has already been created
	DeriveNamespace(name string, handler NamespaceHandler) (Namespace, error)

	// Returns the child namespace with the given name.  The child namespace must have been created in this
	// namespace, using DeriveNamespace, otherwise an error will be returned.
	GetNamespace(name string) (Namespace, error)

	// Enqueue a function to be executed after all currently-queued functions have finished executing.
	// Most plugins should not need to use this.
	// [DeferOpts] can be optionally specified.
	Defer(f func() error, options ...DeferOpts)

	// Log an info-level message
	Info(message string, args ...any)

	// Log a warn-level message
	Warn(message string, args ...any)

	// Log an error-level message
	Error(message string, args ...any) error
}

Namespace is a dependency injection container used by Blueprint plugins during Blueprint's IR construction process. Namespaces instantiate and store IRNodes. A root Blueprint application is itself a Namespace.

A Namespace argument is passed to the BuildFunc when an IRNode is being built. An IRNode can potentially be built multiple times, in different namespaces.

If an IRNode depends on other IRNodes, those others can be fetched by calling [Namespace.Get]. If those IRNodes haven't yet been built, then their BuildFuncs will also be invoked, recursively. Conversely, if those IRNodes are already built, then the built instance is re-used.

Namespaces are hierarchical and a namespace implementation can choose to only support a subset of IRNodes. In this case, [Namespace.Get] on an unsupported IRNode will recursively get the node on the parent namespace. Namespaces inspect the nodeType argument of [WiringSpec.Define] to make this decision.

type NamespaceHandler

type NamespaceHandler interface {
	// Reports true if this namespace can build nodes of the specified node type.
	//
	// For some node type T, if Accepts(T) returns false, then nodes of type T will
	// not be built in this namespace and instead the parent namespace will be called.
	Accepts(any) bool

	// After a node has been gotten from the parent namespace, AddEdge will be
	// called to inform the handler that the node should be passed to this namespace
	// as an argument.
	AddEdge(string, ir.IRNode) error

	// After a node has been built in this namespace, AddNode will be called
	// to enable the handler to save the built node.
	AddNode(string, ir.IRNode) error
}

NamespaceHandler is an interface intended for use by any Blueprint plugin that wants to provide a custom namespace.

type WiringDef

type WiringDef struct {
	Name       string
	NodeType   any
	Build      BuildFunc
	Properties map[string][]any
	Options    WiringOpts
}

func (*WiringDef) AddProperty

func (def *WiringDef) AddProperty(key string, value any)

func (*WiringDef) GetProperties

func (def *WiringDef) GetProperties(key string, dst any) error

func (*WiringDef) GetProperty

func (def *WiringDef) GetProperty(key string, dst any) error

func (*WiringDef) String

func (def *WiringDef) String() string

type WiringError

type WiringError struct {
	Errors []error
}

func (WiringError) Error

func (e WiringError) Error() string

type WiringOpts

type WiringOpts struct {
	// The type of node returned by the BuildFunc.  By default this is assumed to be the same
	// as nodeType.  Specifying this property does not currently have any effect.
	ReturnType any

	// Used by plugins to indicate whether the BuildFunc builds new nodes, or simply gets
	// and returns other nodes.  Defaults to false.  When set to true, the returned node of
	// a BuildFunc is not added as a node to the namespace or as an edge, since the node originated
	// from some other BuildFunc and therefore was already added as a node or edge.
	ProxyNode bool
}

Additional options that can be specified when defining a WiringSpec node.

type WiringSpec

type WiringSpec interface {
	// Provides a node definition for name.  The provided [BuildFunc] build will be used to build
	// the node.  nodeType indicates the type of node that gets built.  Additional [WiringOpts] can
	// be optionally provided to fine-tune the node's build behavior.
	Define(name string, nodeType any, build BuildFunc, options ...WiringOpts)

	GetDef(name string) *WiringDef // For use by plugins to access the defined build functions and metadata
	Defs() []string                // Returns names of all defined nodes

	Alias(name string, pointsto string)   // Defines an alias to another defined node; these can be recursive
	GetAlias(alias string) (string, bool) // Gets the value of the specified alias, if it exists

	SetProperty(name string, key string, value any)       // Sets a static property value in the wiring spec, replacing any existing value specified
	AddProperty(name string, key string, value any)       // Adds a static property value in the wiring spec
	GetProperty(name string, key string, dst any) error   // Gets a static property value from the wiring spec
	GetProperties(name string, key string, dst any) error // Gets all static property values from the wiring spec

	String() string // Returns a string representation of everything that has been defined

	// Errors while building a wiring spec are accumulated within the wiring spec, rather than as return values to calls
	AddError(err error) // Used by plugins to signify an error; the error will be returned by a call to Err or GetBlueprint
	Err() error         // Gets an error if there is currently one

	BuildIR(nodesToInstantiate ...string) (*ir.ApplicationNode, error) // After defining everything, this builds the IR for the specified named nodes (implicitly including dependencies of those nodes)
}

func NewWiringSpec

func NewWiringSpec(name string) WiringSpec

Jump to

Keyboard shortcuts

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