plugin

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Aug 15, 2023 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package plugin is the container for all things plugins. The top level package defines the interface for plugins. A plugin must, at the very least, provide an implementation of plugin.Interface. Then, that plugin is run by providing a main function that runs the plugin using the RunPlugin() function defined in "github.com/zostay/zedpm/plugin/metal".

From there, the plugin may:

* Define task implementations via the Implements, Prepare, Cancel, and Complete Prepare methods of the plugin.Interface.

* Define goals via the Goal method.

Plugins may be written in other languages than Golang. To do that, the plugin will need to implement the plugin interface defined by "github.com/hashicorp/go-plugin" to handle the startup of a gRPC server and then printing details regarding that gRPC server on stdout. The gRPC server implemented must implement the interface defined in the TaskExecution service found in task-interface.proto.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrUnsupportedTask is returned by Interface.Prepare when the named
	// task is not implemented by the plugin.
	ErrUnsupportedTask = fmt.Errorf("this plugin does not support that task")

	// ErrUnsupportedGoal is returned by Interface.Goal when the named goal
	// is not defined by the plugin.
	ErrUnsupportedGoal = fmt.Errorf("this plugin does not support that goal")

	// ErrBadTaskName is returned when a badly formatted task name is detected.
	ErrBadTaskName = fmt.Errorf("the task name is badly formatted")
)

Functions

func ApplyChanges

func ApplyChanges(ctx context.Context, changes map[string]string)

ApplyChanges will apply the given changes to the properties.

func AtomicProperties

func AtomicProperties(ctx context.Context, atomicOp func(storage.KV))

AtomicProperties executes the given function inside a write lock on the storage object. This allows non-idempotent, atomic modifications to be made to the storage without races.

For example, NEVER RUN:

// NEVER DO THIS! This contains a race condition and will work inconsistently.
v := plugin.GetInt(ctx, "foo")
plugin.Set(ctx, "foo", v+1)

Instead, you should follow this example:

plugin.AtomicProperties(ctx, func(p storage.KV) {
    v := p.GetInt("foo")
    p.Set("foo", v+1)
})

func ForCleanup

func ForCleanup(ctx context.Context, newCleaner SimpleTask)

ForCleanup adds the given task to be performed at cleanup time.

func Get

func Get(ctx context.Context, key string) any

Get returns the underlying value as is without attempt to coerce the value in any way.

func GetBool

func GetBool(ctx context.Context, key string) bool

GetBool returns the value for the given key as a boolean.

func GetDuration

func GetDuration(ctx context.Context, key string) time.Duration

GetDuration returns the value for the given key as a time.Duration.

func GetFloat64

func GetFloat64(ctx context.Context, key string) float64

GetFloat64 returns the value for the given key as a float64.

func GetInt

func GetInt(ctx context.Context, key string) int

GetInt returns the value for the given key as an int.

func GetInt32

func GetInt32(ctx context.Context, key string) int32

GetInt32 returns the value for the given key as an int32.

func GetInt64

func GetInt64(ctx context.Context, key string) int64

GetInt64 returns the value for the given key as an int64.

func GetIntSlice

func GetIntSlice(ctx context.Context, key string) []int

GetIntSlice returns the value for the given key as an []int.

func GetString

func GetString(ctx context.Context, key string) string

GetString returns the value for the given key as a string.

func GetStringMap

func GetStringMap(ctx context.Context, key string) map[string]any

GetStringMap returns the value for the given key as a map[string]any.

func GetStringMapString

func GetStringMapString(ctx context.Context, key string) map[string]string

GetStringMapString returns the value for the given key as a map[string]string.

func GetStringMapStringSlice

func GetStringMapStringSlice(ctx context.Context, key string) map[string][]string

GetStringMapStringSlice returns the value for the given key as a map[string][]string.

func GetStringSlice

func GetStringSlice(ctx context.Context, key string) []string

GetStringSlice returns the value for the given key as a []string.

func GetTime

func GetTime(ctx context.Context, key string) time.Time

GetTime returns the value for the given key as a time.Time.

func GetUint

func GetUint(ctx context.Context, key string) uint

GetUint returns the value for the given key as a uint.

func GetUint16

func GetUint16(ctx context.Context, key string) uint16

GetUint16 returns the value for the given key as a uint16.

func GetUint32

func GetUint32(ctx context.Context, key string) uint32

GetUint32 returns the value for the given key as a uint32.

func GetUint64

func GetUint64(ctx context.Context, key string) uint64

GetUint64 returns the value for the given key as a uint64.

func InitializeContext

func InitializeContext(ctx context.Context, pctx *Context) context.Context

InitializeContext attaches the plugin.Context to the context.Context.

func IsSet

func IsSet(ctx context.Context, key string) bool

IsSet returns whether or not the given key is set in the Context properties.

func KV

func KV(ctx context.Context) *storage.KVCon

KV returns the properties attached to the context.

func ListAdded

func ListAdded(ctx context.Context) []string

ListAdded returns all the files that have been created or added by the tooling since the Context was created.

func Logger

func Logger(ctx context.Context, withArgs ...interface{}) log.Interface

Logger returns the logger for the plugin to use. If any withArgs are passed, the returned logger will have had the hclog.Logger.With function called to set properties on the logger.

func OperationLess

func OperationLess(ops Operations) func(int, int) bool

OperationLess provides a sorting function for Operations.

func Set

func Set(ctx context.Context, key string, value any)

Set sets the given key/value pair on the Context properties.

func ToAdd

func ToAdd(ctx context.Context, newFile ...string)

ToAdd names a new file that has been created or added by the tooling, which allows it to be added to VC and other such tools.

Types

type Context

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

Context is a container providing the information accessed by the various context.Context accessors used by plugins.

This object is safe to use concurrently. Changes to properties are synchronized as are cleanup functions and add files. However, if your changes are not idempotent, special care must be taken to avoid race conditions. The AtomicProperties function is provided to allow for atomic operations to be safely performed without races.

func NewConfigContext

func NewConfigContext(
	logger *log.Logger,
	runtime storage.KV,
	taskName string,
	targetName string,
	pluginName string,
	cfg *config.Config,
) (*Context, error)

NewConfigContext constructs a new plugin Context, but with the given scopes defined for constructing properties to provide. This is ready to be used with InitializeContext to attach it to a context.Context.

This has the same limitations as NewContext regarding the properties that is mentioned in NewContext.

func NewContext

func NewContext(
	logger *log.Logger,
	properties storage.KV,
) *Context

NewContext constructs a new plugin Context, ready to be used with InitializeContext to attach it to a context.Context.

The properties object here will not be changed when any of the context setters, such as Set or ApplyChanges are used. These will be stored by wrapping the given properties in a storage.KVChanges object. The original caller can apply these changes by using UpdateStorage and StorageChanges together.

func (*Context) ListAdded added in v0.1.0

func (p *Context) ListAdded() []string

ListAdded returns the list of files added to the plugin context.

func (*Context) SetAdded added in v0.1.0

func (p *Context) SetAdded(addedFiles []string)

SetAdded replaces the added files with a new list.

func (*Context) StorageChanges

func (p *Context) StorageChanges() map[string]string

StorageChanges clears any changes that were made by callers to the mutator methods on the context.Context and returns them. These can be made permanent by calling UpdateStorage.

func (*Context) UpdateStorage

func (p *Context) UpdateStorage(store map[string]string)

UpdateStorage allows the owner of the Context to update the properties of the properties object given during construction. None of the mutator functions that work on context.Context are able to make changes to the original properties object as they only apply their changes to a storage.KVChanges wrapper applied during Context construction.

type GoalDescription

type GoalDescription interface {
	// Name is the top-level name of the task. This is preferable a single,
	// short verb. It must be all lowercase letters or may contain a hyphen.
	// This will be the default command-name to use to execute this task and
	// associated sub-tasks and also must match the first path element of a
	// SubTaskDescription Name.
	Name() string

	// Short is the short description of the task to show the user when showing
	// usage information for the task.
	Short() string

	// Aliases returns other names (possibly shortened names) to grant
	// implementations of this task.
	Aliases() []string
}

GoalDescription describes a top-level goal.

type Interface

type Interface interface {
	// Implements will list the tasks that this plugin implements. It may return
	// an empty list if no task is implemented. A task is only permitted to
	// implement a single task with a given name.
	Implements(ctx context.Context) (tasks []TaskDescription, err error)

	// Goal will return the GoalDefinition for the given goal name, which
	// provides documentation for the named top-level goal. This method should
	// return ErrUnsupportedGoal when no such top-level task is defined by this
	// plugin.
	Goal(ctx context.Context, name string) (def GoalDescription, err error)

	// Prepare should return an initialized Task object that is configured using
	// the given global configuration as well as the task configuration. The
	// object passed for task configuration is specific to the given taskName.
	//
	// The lifecycle of this method needs to be handled such that the return
	// value from this method must be handled similar to the following:
	//
	//  task, err := taskInterface.Prepare(ctx, taskName, globalCfg)
	//  if err != nil {
	//    if task != nil {
	//      cancelErr := taskInterface.Cancel(ctx, task)
	//      if cancelErr != nil {
	//        log.Print(cancelErr)
	//      }
	//    }
	//    return err
	//  }
	//
	// Once a task is returned from this method, you must either call Cancel
	// or Close on the Interface with the given task object or risk leaking
	// resources or having other unfinished working and unexpected results.
	//
	// This should return ErrUnsupportedTask if the given taskName does not
	// match a supported task.
	Prepare(
		ctx context.Context,
		taskName string,
	) (task Task, err error)

	// Cancel must be called when a task is not going to be completed in full.
	// The implementation will use this opportunity to call teardown and perform
	// any cleanup actions that have been queued up to try to undo the work done
	// so far.
	Cancel(ctx context.Context, task Task) (err error)

	// Complete must be called when a task has been run to completion. This
	// allows the task to perform any final teardown and cleanup resources.
	Complete(ctx context.Context, task Task) (err error)
}

Interface is the base interface that all plugins implement.

type Operation

type Operation struct {
	Order  Ordering
	Action OperationHandler
}

Operation is an object that is used to give Order to the Actions that get performed while executing a Stage of a Task.

type OperationFunc

type OperationFunc func(ctx context.Context) error

OperationFunc is an implementation of OperationHandler defined as a function.

func (OperationFunc) Call

func (op OperationFunc) Call(ctx context.Context) error

Call calls the OperationFunc.

type OperationHandler

type OperationHandler interface {
	// Call performs the operation. An error will typically result in
	// termination of the entire task with the given error.
	Call(ctx context.Context) error
}

OperationHandler defines the type interface for operations. An operation executes some part of a Task.

type Operations

type Operations []Operation

Operations is a list of zero or more Operation objects.

type Ordering

type Ordering int

Ordering is a scheme for prioritizing operations. An Ordering must be in the range of 0-100, inclusive. Lower Ordering values precede larger ones when it comes to determining the order of operations.

func (Ordering) String added in v0.1.0

func (o Ordering) String() string

type SimpleTask

type SimpleTask func()

SimpleTask is the type of function used for cleanup functions.

func ListCleanupTasks

func ListCleanupTasks(ctx context.Context) []SimpleTask

ListCleanupTasks returns all the cleanup tasks that have been setup so far since the start of this Context. The tasks are returned in the reverse order they were added.

type Task

type Task interface {
	// Setup should be used exclusively for initial setup of the Task, such as
	// acquiring resources, setting clients and connections, and other
	// housekeeping tasks. No operations related to performing the task should
	// be performed here.
	Setup(context.Context) error

	// Check should only execute initial validation and guard functions to
	// prevent the operation from continuing. No writes or modifications ought
	// to be performed here. This can also be a reasonable stage at which to
	// detect and setup property values for later use.
	Check(context.Context) error

	// Begin should be used to prepare early stage operations for the task.
	Begin(context.Context) (Operations, error)

	// Run should be used to prepare middle stage operations for the task.
	Run(context.Context) (Operations, error)

	// End should be used to prepare late stage operations for the task.
	End(context.Context) (Operations, error)

	// Finish should be used for any final checks to ensure the task has been
	// performed correctly and sanely. Modifications should not be performed
	// at this late stage.
	Finish(context.Context) error

	// Teardown should only be used to releasing resources, closing connections,
	// and internal cleanup. No operations realted to performing the task should
	// be performed here.
	Teardown(context.Context) error
}

Task provides some operations to help perform a task. The task is executed in a series of stages and if multiple plugins implement a given task, they may be run in parallel. The task operations are executed in the following order:

* Setup

* Check

* Begin (in ascending Order)

* Run (in ascending Order)

* End (in ascending Order)

* Finish

* Teardown

And that's it.

type TaskBoilerplate

type TaskBoilerplate struct{}

TaskBoilerplate is intended at simplifying the implementation of a Task by providing empty, noop implementations for all Task methods. That way a Task only needs to implement the stages and operations it needs to implement.

func (TaskBoilerplate) Begin

func (TaskBoilerplate) Check

func (TaskBoilerplate) End

func (TaskBoilerplate) Finish

func (TaskBoilerplate) Run

func (TaskBoilerplate) Setup

func (TaskBoilerplate) Teardown

type TaskDescription

type TaskDescription interface {
	// Name is a path starting with a leading slash naming the sub-task. The
	// first element of this path must match a TaskDescription defined by the
	// given Plugin (or a built-in task). The remaining path elements define a
	// sub-task of the level above. This is usually of the form of /verb/noun
	// where short words a preferred and the names must be lowercase and may
	// contain hyphens.
	//
	// The path elements here will become the names of the sub-commands on the
	// command-line if a user wants to execute a sub-step of a larger task.
	Name() string

	// Short is the short description of what this sub-task does. It will be
	// combined with all other like-named sub-tasks to from the description text
	// shown when usage help is requested. This description should be very
	// concise.
	Short() string

	// Requires names zero or more sub-task names on which this task depends.
	// Usually, these will be other sub-tasks that are defined by this plugin.
	//
	// Actual sub-task dependencies are calculated by calculating the
	// requirements of all like-named sub-tasks together. For example, if
	// /release/publish in plugin A depends on /release/mint and it dapends on
	// /release/wait in plugin B and both plugins will be executed, then this
	// task will not be executed until after both /release/wait and
	// /release/mint have been executed.
	Requires() []string
}

TaskDescription describes a sub-task.

type Tasks

type Tasks []Task

Tasks is a list of Task objects.

Directories

Path Synopsis
Package api defines the gRPC interface plugins use over the wire.
Package api defines the gRPC interface plugins use over the wire.
grpc
client
Package client implements the gRPC client used by the zedpm master process to communicate with all the plugins.
Package client implements the gRPC client used by the zedpm master process to communicate with all the plugins.
service
Package service implements the gRPC service for plugins so plugins can just implement the plugin.Interface and related interfaces.
Package service implements the gRPC service for plugins so plugins can just implement the plugin.Interface and related interfaces.
Package master implements the components for executing goals and sub-tasks across multiple plugins concurrently with proper interleaving and error handling.
Package master implements the components for executing goals and sub-tasks across multiple plugins concurrently with proper interleaving and error handling.
Package metal provides the entry point for implementing the plugin system in a process.
Package metal provides the entry point for implementing the plugin system in a process.
Package translate provides object translation to translate API objects into local plugin objects and vice versa.
Package translate provides object translation to translate API objects into local plugin objects and vice versa.

Jump to

Keyboard shortcuts

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