modulir

package module
v0.0.0-...-60f2093 Latest Latest
Warning

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

Go to latest
Published: Jul 16, 2024 License: MIT Imports: 19 Imported by: 8

README

Modulir Build Status

Modulir is an experimental mini-framework for static site generation that suggests that a site's main build recipe should be written in Go, both for type safety and to provide as much flexibility as possible.

The main features that the package provides are an entry point that takes a build loop, a job pool for enqueuing the set of parallel jobs that make up the build, and a set of modules that provide helpers for various features in Go's core and in other useful libraries that would otherwise be quite verbose.

The package is currently highly experimental and its APIs subject to change.

Development

Run tests:

cp .envrc.sample .envrc # set with bin locations
go test ./...

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Build

func Build(config *Config, f func(*Context) []error)

Build is one of the main entry points to the program. Call this to build only one time.

func BuildLoop

func BuildLoop(config *Config, f func(*Context) []error)

BuildLoop is one of the main entry points to the program. Call this to build in a perpetual loop.

Types

type Args

type Args struct {
	Concurrency int
	Log         LoggerInterface
	LogColor    bool
	Pool        *Pool
	Port        int
	SourceDir   string
	TargetDir   string
	Watcher     *fsnotify.Watcher
	Websocket   bool
}

Args are the set of arguments accepted by NewContext.

type Config

type Config struct {
	// Concurrency is the number of concurrent workers to run during the build
	// step.
	//
	// Defaults to 10.
	Concurrency int

	// Log specifies a logger to use.
	//
	// Defaults to an instance of Logger running at informational level.
	Log LoggerInterface

	// LogColor specifies whether messages sent to Log should be color. You may
	// want to set to true if you know output is going to a terminal.
	//
	// Defaults to false.
	LogColor bool

	// Port specifies the port on which to serve content from TargetDir over
	// HTTP.
	//
	// Defaults to not running if left unset.
	Port int

	// SourceDir is the directory containing source files.
	//
	// Defaults to ".".
	SourceDir string

	// TargetDir is the directory where the site will be built to.
	//
	// Defaults to "./public".
	TargetDir string

	// Websocket indicates that Modulir should be started in development
	// mode with a websocket that provides features like live reload.
	//
	// Defaults to false.
	Websocket bool
}

Config contains configuration.

type Context

type Context struct {
	// Concurrency is the number of concurrent workers to run during the build
	// step.
	Concurrency int

	// FirstRun indicates whether this is the first run of the build loop.
	FirstRun bool

	// Forced causes the Changed function to always return true regardless of
	// the path it's invoked on, thereby prompting all jobs that use it to
	// execute.
	//
	// Make sure to unset it after your build run is finished.
	Forced bool

	// Jobs is a channel over which jobs to be done are transmitted.
	Jobs chan *Job

	// Log is a logger that can be used to print information.
	Log LoggerInterface

	// LogColor specifies whether messages sent to Log should be color. You may
	// want to set to true if you know output is going to a terminal.
	LogColor bool

	// Pool is the job pool used to build the static site.
	Pool *Pool

	// Port specifies the port on which to serve content from TargetDir over
	// HTTP.
	Port int

	// QuickPaths are a set of paths for which Changed will return true when
	// the context is in "quick rebuild mode". During this time all the normal
	// file system checks that Changed makes will be bypassed to enable a
	// faster build loop.
	//
	// Make sure that all paths added here are normalized with filepath.Clean.
	//
	// Make sure to unset it after your build run is finished.
	QuickPaths map[string]struct{}

	// SourceDir is the directory containing source files.
	SourceDir string

	// Stats tracks various statistics about the build process.
	//
	// Statistics are reset between build loops, but are cumulative between
	// build phases within a loop (i.e. calls to Wait).
	Stats *Stats

	// TargetDir is the directory where the site will be built to.
	TargetDir string

	// Watcher is a file system watcher that picks up changes to source files
	// and restarts the build loop.
	Watcher *fsnotify.Watcher

	// Websocket indicates that Modulir should be started in development
	// mode with a websocket that provides features like live reload.
	//
	// Defaults to false.
	Websocket bool
	// contains filtered or unexported fields
}

Context contains useful state that can be used by a user-provided build function.

func NewContext

func NewContext(args *Args) *Context

NewContext initializes and returns a new Context.

func (*Context) AddJob

func (c *Context) AddJob(name string, f func() (bool, error))

AddJob is a shortcut for adding a new job to the Jobs channel.

func (*Context) AllowError

func (c *Context) AllowError(executed bool, err error) bool

AllowError is a helper that's useful for when an error coming back from a job should be logged, but shouldn't fail the build.

func (*Context) Changed

func (c *Context) Changed(path string) bool

Changed returns whether the target path's modified time has changed since the last time it was checked. It also saves the last modified time for future checks.

This function is very hot in that it gets checked many times, and probably many times for every single job in a build loop. It needs to be optimized fairly carefully for both speed and lack of contention when running concurrently with other jobs.

func (*Context) ChangedAny

func (c *Context) ChangedAny(paths ...string) bool

ChangedAny is the same as Changed except it returns true if any of the given paths have changed.

func (*Context) ResetBuild

func (c *Context) ResetBuild()

ResetBuild signals to the Context to do the bookkeeping it needs to do for the next build round.

func (*Context) StartRound

func (c *Context) StartRound()

StartRound starts a new round for the context, also starting it on its attached job pool.

func (*Context) Wait

func (c *Context) Wait() []error

Wait waits on the job pool to execute its current round of jobs.

The worker pool is then primed for a new round so that more jobs can be enqueued.

Returns nil if the round of jobs executed successfully, and a set of errors that occurred otherwise.

type Job

type Job struct {
	// Duration is the time it took the job to run. It's set regardless of
	// whether the job's finished state was executed, not executed, or errored.
	Duration time.Duration

	// Err is an error that the job produced, if any.
	Err error

	// Executed is whether the job "did work", signaled by it returning true.
	Executed bool

	// F is the function which makes up the job's workload.
	F func() (bool, error)

	// Name is a name for the job which is helpful for informational and
	// debugging purposes.
	Name string
}

Job is a wrapper for a piece of work that should be executed by the job pool.

func NewJob

func NewJob(name string, f func() (bool, error)) *Job

NewJob initializes and returns a new Job.

func (*Job) Error

func (j *Job) Error() string

Error returns the error message of the error wrapped in the job if this was an errored job. Job implements the error interface so that it can return itself in situations where error handling is being done but job errors may be mixed in with other sorts of errors.

It panics if the job wasn't errored, so be careful to only use this when iterating across something like Pool.JobsErrored.

type Level

type Level uint32

Level represents a logging level.

const (
	// LevelError sets a logger to show error messages only.
	LevelError Level = 1

	// LevelWarn sets a logger to show warning messages or anything more
	// severe.
	LevelWarn Level = 2

	// LevelInfo sets a logger to show informational messages or anything more
	// severe.
	LevelInfo Level = 3

	// LevelDebug sets a logger to show informational messages or anything more
	// severe.
	LevelDebug Level = 4
)

type Logger

type Logger struct {
	// Level is the minimum logging level that will be emitted by this logger.
	//
	// For example, a Level set to LevelWarn will emit warnings and errors, but
	// not informational or debug messages.
	//
	// Always set this with a constant like LevelWarn because the individual
	// values are not guaranteed to be stable.
	Level Level
	// contains filtered or unexported fields
}

Logger is a basic implementation of LoggerInterface.

func (*Logger) Debugf

func (l *Logger) Debugf(format string, v ...interface{})

Debugf logs a debug message using Printf conventions.

func (*Logger) Errorf

func (l *Logger) Errorf(format string, v ...interface{})

Errorf logs a warning message using Printf conventions.

func (*Logger) Infof

func (l *Logger) Infof(format string, v ...interface{})

Infof logs an informational message using Printf conventions.

func (*Logger) Warnf

func (l *Logger) Warnf(format string, v ...interface{})

Warnf logs a warning message using Printf conventions.

type LoggerInterface

type LoggerInterface interface {
	// Debugf logs a debug message using Printf conventions.
	Debugf(format string, v ...interface{})

	// Errorf logs a warning message using Printf conventions.
	Errorf(format string, v ...interface{})

	// Infof logs an informational message using Printf conventions.
	Infof(format string, v ...interface{})

	// Warnf logs a warning message using Printf conventions.
	Warnf(format string, v ...interface{})
}

LoggerInterface is an interface that should be implemented by loggers used with the library. Logger provides a basic implementation, but it's also compatible with libraries such as Logrus.

type Pool

type Pool struct {
	Jobs chan *Job

	// JobsAll is a slice of all the jobs that were fed into the pool on the
	// last run.
	JobsAll []*Job

	// JobsErrored is a slice of jobs that errored on the last run.
	//
	// See also JobErrors which is a shortcut for extracting all the errors
	// from the jobs.
	JobsErrored []*Job

	// JobsExecuted is a slice of jobs that were executed on the last run.
	JobsExecuted []*Job
	// contains filtered or unexported fields
}

Pool is a worker group that runs a number of jobs at a configured concurrency.

func NewPool

func NewPool(log LoggerInterface, concurrency int) *Pool

NewPool initializes a new pool with the given jobs and at the given concurrency. It calls Init so that the pool is fully spun up and ready to start a round.

func (*Pool) JobErrors

func (p *Pool) JobErrors() []error

JobErrors is a shortcut from extracting all the errors out of JobsErrored, the set of jobs that errored on the last round.

func (*Pool) LogErrors

func (p *Pool) LogErrors()

LogErrors logs a limited set of errors that occurred during a build.

func (*Pool) LogErrorsSlice

func (p *Pool) LogErrorsSlice(errs []error)

LogErrorsSlice logs a limited set of errors from the given slice.

func (*Pool) LogSlowest

func (p *Pool) LogSlowest()

LogSlowest logs a limited set of executed jobs from the last build starting with the slowest jobs on top.

func (*Pool) LogSlowestSlice

func (p *Pool) LogSlowestSlice(jobs []*Job)

LogSlowestSlice logs a limited set of executed jobs from the given slice.

func (*Pool) StartRound

func (p *Pool) StartRound(roundNum int)

StartRound begins an execution round. Internal statistics and other tracking are all reset.

func (*Pool) Wait

func (p *Pool) Wait() bool

Wait waits until all jobs are finished and stops the pool.

Returns true if the round of jobs all executed successfully, and false otherwise. In the latter case, the caller should stop and observe the contents of Errors.

If the pool isn't running, it falls through without doing anything so it's safe to call Wait multiple times.

type Stats

type Stats struct {
	// JobsErrored is a slice of jobs that errored on the last run.
	//
	// Differs from JobsExecuted somewhat in that only one run of errors are
	// tracked because the build loop fails through after a single unsuccessful
	// run.
	JobsErrored []*Job

	// JobsExecuted is a slice of jobs that were executed across all runs.
	JobsExecuted []*Job

	// LoopDuration is the total amount of time spent in the user's build loop
	// enqueuing jobs. Jobs may be running in the background during this time,
	// but all the time spent waiting for jobs to finish is excluded.
	LoopDuration time.Duration

	// NumJobs is the total number of jobs generated for the build loop.
	NumJobs int

	// NumRounds is the number of "rounds" in the build which are used in the
	// case of multi-step builds where jobs from one round may depend on the
	// result of jobs from other rounds.
	NumRounds int

	// Start is the start time of the build loop.
	Start time.Time
	// contains filtered or unexported fields
}

Stats tracks various statistics about the build process.

func (*Stats) Reset

func (s *Stats) Reset()

Reset resets statistics.

Directories

Path Synopsis
modules
mmarkdownext
Package mmarkdownext provides an extended version of Markdown that does several passes to add additional niceties like adding footnotes and allowing Go template helpers to be used..
Package mmarkdownext provides an extended version of Markdown that does several passes to add additional niceties like adding footnotes and allowing Go template helpers to be used..
mtemplatemd
Package mtemplatemd provides a template helper function which allows an external Markdown file to be included and rendered.
Package mtemplatemd provides a template helper function which allows an external Markdown file to be included and rendered.
scripts

Jump to

Keyboard shortcuts

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