lifecycle

package
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Feb 19, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package lifecycle provides the lifecycle management system for markata-go.

The lifecycle system orchestrates the build process through 9 stages:

  • configure: Load configuration and initialize plugins
  • validate: Validate configuration before processing
  • glob: Discover content files
  • load: Parse files into posts
  • transform: Pre-render processing (jinja-md, etc.)
  • render: Convert markdown to HTML
  • collect: Build feeds, navigation, and aggregated content
  • write: Write output files
  • cleanup: Release resources

Plugin System

Plugins implement optional interfaces corresponding to each stage:

type MyPlugin struct{}

func (p *MyPlugin) Name() string { return "my-plugin" }

func (p *MyPlugin) Load(m *Manager) error {
    // Process files into posts
    return nil
}

func (p *MyPlugin) Render(m *Manager) error {
    // Render posts to HTML
    return nil
}

Priority Ordering

Plugins can implement PriorityPlugin to control execution order:

func (p *MyPlugin) Priority(stage Stage) int {
    if stage == StageRender {
        return PriorityLast // Run after other render plugins
    }
    return PriorityDefault
}

Usage

Basic usage:

m := lifecycle.NewManager()
m.RegisterPlugin(&MyGlobPlugin{})
m.RegisterPlugin(&MyLoadPlugin{})
m.RegisterPlugin(&MyRenderPlugin{})

if err := m.Run(); err != nil {
    log.Fatal(err)
}

Running up to a specific stage:

// Run only up to load stage (useful for preview/watch mode)
if err := m.RunTo(lifecycle.StageLoad); err != nil {
    log.Fatal(err)
}

// Later, continue from where we left off
if err := m.Run(); err != nil {
    log.Fatal(err)
}

Filtering and mapping posts:

// Get published posts
posts, _ := m.Filter("published==true")

// Get all titles of posts with tag "golang", sorted by date
titles, _ := m.Map("title", "tags contains golang", "date", true)

Index

Constants

View Source
const (
	// PriorityFirst ensures a plugin runs before most others.
	PriorityFirst = -1000

	// PriorityEarly ensures a plugin runs early in the stage.
	PriorityEarly = -100

	// PriorityDefault is the default priority.
	PriorityDefault = 0

	// PriorityLate ensures a plugin runs late in the stage.
	PriorityLate = 100

	// PriorityLast ensures a plugin runs after most others.
	PriorityLast = 1000
)

Priority constants for common ordering scenarios.

Variables

StageOrder defines the execution order of all lifecycle stages.

Functions

func IsValidStage

func IsValidStage(s Stage) bool

IsValidStage checks if the given stage is a valid lifecycle stage.

func StageIndex

func StageIndex(s Stage) int

StageIndex returns the index of a stage in the execution order. Returns -1 if the stage is not found.

Types

type Cache

type Cache interface {
	Get(key string) (interface{}, bool)
	Set(key string, value interface{})
	Delete(key string)
	Clear()
}

Cache is an interface for caching data between stages. Implementations must be thread-safe for concurrent access.

type CleanupPlugin

type CleanupPlugin interface {
	Plugin
	Cleanup(m *Manager) error
}

CleanupPlugin is implemented by plugins that participate in the cleanup stage. This stage is used to release resources and perform cleanup tasks.

type CollectPlugin

type CollectPlugin interface {
	Plugin
	Collect(m *Manager) error
}

CollectPlugin is implemented by plugins that participate in the collect stage. This stage is used to build feeds, navigation, and other aggregated content.

type Config

type Config struct {
	// ContentDir is the directory containing content files.
	ContentDir string

	// OutputDir is the directory for generated output.
	OutputDir string

	// GlobPatterns are patterns to match content files.
	GlobPatterns []string

	// Extra holds additional configuration options.
	Extra map[string]interface{}
}

Config holds markata configuration.

func NewConfig

func NewConfig() *Config

NewConfig creates a new Config with default values.

type ConfigurePlugin

type ConfigurePlugin interface {
	Plugin
	Configure(m *Manager) error
}

ConfigurePlugin is implemented by plugins that participate in the configure stage. This stage is used to load configuration and initialize plugin state.

type CriticalError added in v0.6.0

type CriticalError interface {
	error
	IsCritical() bool
}

CriticalError is an interface that errors can implement to indicate they should be treated as critical errors that halt the build, regardless of which stage they occur in.

type Feed

type Feed struct {
	// Name is the feed identifier.
	Name string

	// Title is the feed title.
	Title string

	// Posts are the posts included in the feed.
	Posts []*models.Post

	// Content is the generated feed content.
	Content string

	// Path is the output path for the feed.
	Path string
}

Feed represents a generated feed (RSS, Atom, etc.).

type GlobPlugin

type GlobPlugin interface {
	Plugin
	Glob(m *Manager) error
}

GlobPlugin is implemented by plugins that participate in the glob stage. This stage is used to discover content files.

type HookError

type HookError struct {
	Stage    Stage
	Plugin   string
	Err      error
	Critical bool
}

HookError represents an error that occurred during hook execution.

func (*HookError) Error

func (e *HookError) Error() string

func (*HookError) Unwrap

func (e *HookError) Unwrap() error

type HookErrors

type HookErrors struct {
	Errors []*HookError
}

HookErrors is a collection of errors from hook execution.

func (*HookErrors) Add

func (e *HookErrors) Add(stage Stage, plugin string, err error, critical bool)

Add adds an error to the collection.

func (*HookErrors) Error

func (e *HookErrors) Error() string

func (*HookErrors) HasCritical

func (e *HookErrors) HasCritical() bool

HasCritical returns true if any error is marked as critical.

type LoadPlugin

type LoadPlugin interface {
	Plugin
	Load(m *Manager) error
}

LoadPlugin is implemented by plugins that participate in the load stage. This stage is used to parse files into posts.

type Manager

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

Manager orchestrates the lifecycle stages and plugin execution.

func NewManager

func NewManager() *Manager

NewManager creates a new lifecycle Manager with default settings. Concurrency is auto-detected from CPU cores, capped at 16.

func (*Manager) AddFeed

func (m *Manager) AddFeed(feed *Feed)

AddFeed adds a feed to the feeds slice.

func (*Manager) AddFile

func (m *Manager) AddFile(file string)

AddFile adds a file path to the files slice.

func (*Manager) AddPost

func (m *Manager) AddPost(post *models.Post)

AddPost adds a post to the posts slice. This invalidates the post index, which will be rebuilt on next access.

func (*Manager) AssetHashes added in v0.7.0

func (m *Manager) AssetHashes() map[string]string

AssetHashes returns a copy of all registered asset hashes.

func (*Manager) Cache

func (m *Manager) Cache() Cache

Cache returns the cache instance.

func (*Manager) Concurrency

func (m *Manager) Concurrency() int

Concurrency returns the concurrency level.

func (*Manager) Config

func (m *Manager) Config() *Config

Config returns the current configuration.

func (*Manager) CurrentStage

func (m *Manager) CurrentStage() Stage

CurrentStage returns the currently executing stage.

func (*Manager) Feeds

func (m *Manager) Feeds() []*Feed

Feeds returns a copy of the feeds slice.

func (*Manager) Files

func (m *Manager) Files() []string

Files returns a copy of the discovered file paths.

func (*Manager) Filter

func (m *Manager) Filter(expr string) ([]*models.Post, error)

Filter returns posts matching the given expression. The expression supports the AST-based filter syntax:

  • "published == True" - field equals value
  • "draft != True" - field not equals value
  • "'go' in tags" - value in slice (or "tags contains go" for legacy syntax)
  • "date <= today" - date comparisons with special values
  • Multiple conditions can be combined with "and" or "or"
  • Supports "not" for negation

func (*Manager) FilterPosts added in v0.6.0

func (m *Manager) FilterPosts(predicate func(*models.Post) bool) []*models.Post

FilterPosts returns a new slice containing only posts that match the predicate. This is useful for pre-filtering posts before processing:

changed := m.FilterPosts(func(p *models.Post) bool {
    return cache.ShouldRebuild(p.Path, p.InputHash, p.Template)
})
return m.ProcessPostsSliceConcurrently(changed, processFunc)

func (*Manager) GetAssetHash added in v0.7.0

func (m *Manager) GetAssetHash(path string) string

GetAssetHash retrieves the content hash for an asset path. Returns empty string if no hash is registered.

func (*Manager) HasRun

func (m *Manager) HasRun(stage Stage) bool

HasRun returns true if the given stage has completed.

func (*Manager) Map

func (m *Manager) Map(field, filterExpr, sortField string, reverse bool) ([]interface{}, error)

Map extracts field values from posts, with optional filtering and sorting. Parameters:

  • field: the field to extract (supports dot notation for nested fields)
  • filterExpr: optional filter expression (same syntax as Filter)
  • sortField: field to sort by (empty for no sorting)
  • reverse: if true, sort in descending order

func (*Manager) Plugins

func (m *Manager) Plugins() []Plugin

Plugins returns a copy of the registered plugins.

func (*Manager) PostIndex added in v0.6.0

func (m *Manager) PostIndex() *PostIndex

PostIndex returns the shared post lookup index. The index is built lazily on first access and cached. It is automatically invalidated when posts are modified via SetPosts/AddPost.

func (*Manager) Posts

func (m *Manager) Posts() []*models.Post

Posts returns a copy of the posts slice.

func (*Manager) ProcessPostsConcurrently

func (m *Manager) ProcessPostsConcurrently(fn func(*models.Post) error) error

ProcessPostsConcurrently processes posts concurrently using a bounded worker pool. The worker pool is sized to Concurrency(), ensuring that regardless of post count, only a fixed number of goroutines are spawned. This eliminates scheduler overhead and memory churn for large builds.

Error handling: If any post fails to process, the function continues processing remaining posts and returns an aggregated error containing the count of failures and the first error encountered.

func (*Manager) ProcessPostsSliceConcurrently added in v0.6.0

func (m *Manager) ProcessPostsSliceConcurrently(posts []*models.Post, fn func(*models.Post) error) error

ProcessPostsSliceConcurrently processes the provided posts slice concurrently. This is useful when you have pre-filtered posts (e.g., only posts needing rebuild) and want to avoid iterating all posts.

Use this for incremental processing where you know only a subset of posts need work:

changedPosts := m.FilterPosts(func(p *models.Post) bool { return needsRebuild(p) })
return m.ProcessPostsSliceConcurrently(changedPosts, processFunc)

func (*Manager) RegisterPlugin

func (m *Manager) RegisterPlugin(p Plugin)

RegisterPlugin adds a plugin to the manager. Plugins are executed in registration order within the same priority level.

func (*Manager) RegisterPlugins

func (m *Manager) RegisterPlugins(plugins ...Plugin)

RegisterPlugins adds multiple plugins to the manager.

func (*Manager) Reset

func (m *Manager) Reset()

Reset clears the manager state, allowing stages to be run again.

func (*Manager) Run

func (m *Manager) Run() error

Run executes all lifecycle stages in order.

func (*Manager) RunTo

func (m *Manager) RunTo(stage Stage) error

RunTo executes lifecycle stages up to and including the specified stage. Already completed stages are skipped.

func (*Manager) SetAssetHash added in v0.7.0

func (m *Manager) SetAssetHash(path, hash string)

SetAssetHash stores a content hash for an asset path (for cache busting). This is called by the static_assets plugin during the Write stage.

func (*Manager) SetCache

func (m *Manager) SetCache(cache Cache)

SetCache sets a custom cache implementation.

func (*Manager) SetConcurrency

func (m *Manager) SetConcurrency(n int)

SetConcurrency sets the concurrency level for parallel processing.

func (*Manager) SetConfig

func (m *Manager) SetConfig(config *Config)

SetConfig sets the configuration.

func (*Manager) SetFeeds

func (m *Manager) SetFeeds(feeds []*Feed)

SetFeeds sets the feeds slice.

func (*Manager) SetFiles

func (m *Manager) SetFiles(files []string)

SetFiles sets the discovered file paths.

func (*Manager) SetPosts

func (m *Manager) SetPosts(posts []*models.Post)

SetPosts sets the posts slice. This invalidates the post index, which will be rebuilt on next access.

func (*Manager) Warnings

func (m *Manager) Warnings() []*HookError

Warnings returns collected non-critical errors.

type Plugin

type Plugin interface {
	// Name returns the unique name of the plugin.
	Name() string
}

Plugin is the base interface that all plugins must implement.

type PostIndex added in v0.6.0

type PostIndex struct {
	// BySlug maps lowercase slug to post
	BySlug map[string]*models.Post
	// BySlugified maps slugified versions (spaces->hyphens, lowercase) to post
	BySlugified map[string]*models.Post
	// ByHref maps href path to post
	ByHref map[string]*models.Post
	// ByPath maps file path to post
	ByPath map[string]*models.Post
}

PostIndex provides efficient lookups for posts by various keys. This is built once after the Load stage and shared across all plugins to avoid each plugin building its own lookup maps.

func (*PostIndex) LookupBySlug added in v0.6.0

func (idx *PostIndex) LookupBySlug(slug string) *models.Post

LookupBySlug finds a post by slug, trying exact match first then slugified. Returns nil if not found.

func (*PostIndex) Refresh added in v0.6.0

func (idx *PostIndex) Refresh(m *Manager)

Refresh rebuilds the index from the manager's current posts. Safe to call multiple times; replaces all lookup maps.

type PriorityPlugin

type PriorityPlugin interface {
	Plugin
	// Priority returns the plugin's priority for a given stage.
	// Lower values run first. Default priority is 0.
	// Use negative values for "tryfirst" behavior.
	// Use positive values for "trylast" behavior.
	Priority(stage Stage) int
}

PriorityPlugin can be implemented by plugins to control execution order within a stage. Plugins with lower priority values run first.

type RenderPlugin

type RenderPlugin interface {
	Plugin
	Render(m *Manager) error
}

RenderPlugin is implemented by plugins that participate in the render stage. This stage is used to convert markdown to HTML.

type Stage

type Stage string

Stage represents a lifecycle stage in the markata build process.

const (
	// StageConfigure loads config and initializes plugins.
	StageConfigure Stage = "configure"

	// StageValidate validates the configuration.
	StageValidate Stage = "validate"

	// StageGlob discovers content files.
	StageGlob Stage = "glob"

	// StageLoad parses files into posts.
	StageLoad Stage = "load"

	// StageTransform performs pre-render processing (jinja-md, etc.).
	StageTransform Stage = "transform"

	// StageRender converts markdown to HTML.
	StageRender Stage = "render"

	// StageCollect builds feeds and navigation.
	StageCollect Stage = "collect"

	// StageWrite writes output files.
	StageWrite Stage = "write"

	// StageCleanup releases resources.
	StageCleanup Stage = "cleanup"
)

func StagesBefore

func StagesBefore(s Stage) []Stage

StagesBefore returns all stages that come before the given stage.

func StagesUpTo

func StagesUpTo(s Stage) []Stage

StagesUpTo returns all stages up to and including the given stage.

type TransformPlugin

type TransformPlugin interface {
	Plugin
	Transform(m *Manager) error
}

TransformPlugin is implemented by plugins that participate in the transform stage. This stage is used for pre-render processing (jinja-md, etc.).

type ValidatePlugin

type ValidatePlugin interface {
	Plugin
	Validate(m *Manager) error
}

ValidatePlugin is implemented by plugins that participate in the validate stage. This stage is used to validate configuration before processing begins.

type WritePlugin

type WritePlugin interface {
	Plugin
	Write(m *Manager) error
}

WritePlugin is implemented by plugins that participate in the write stage. This stage is used to write output files.

Jump to

Keyboard shortcuts

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