pkg

package
v0.1.0-dev.20260818065907 Latest Latest
Warning

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

Go to latest
Published: Aug 18, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package pkg provides package management actions for the operation graph.

Index

Constants

View Source
const (
	Install      op.ActionName = "pkg.install"
	Installed    op.ActionName = "pkg.installed"
	NotInstalled op.ActionName = "pkg.not_installed"
	Observe      op.ActionName = "pkg.observe"
	Remove       op.ActionName = "pkg.remove"
	Update       op.ActionName = "pkg.update"
	Upgrade      op.ActionName = "pkg.upgrade"
	VersionGTE   op.ActionName = "pkg.version_gte"
)

Action-name constants for the pkg provider's plan-mode actions.

Each constant is the short dotted action label its method dispatches under. Pass these to plan.Plan, op.ReceiverRegistry().BuildAction, RuntimeEnvironment.ActionByName, or WithActionNamed in place of a string literal so a typo is a compile error and rename / find-references work through the constant.

Variables

This section is empty.

Functions

This section is empty.

Types

type MutationKind

type MutationKind string

MutationKind identifies the package mutation a Receipt records, so Provider.CompensatePackageMutation can invert it: remove a newly-installed package, restore a pre-existing one's prior version, reinstall a removed package, or best-effort restore an upgraded package's prior version.

const (
	// MutationInstall records an install; its undo removes a newly-installed package, or restores a pre-existing one's
	// prior version when the install drifted it.
	MutationInstall MutationKind = "install"

	// MutationRemove records a removal; its undo reinstalls a package that was present before.
	MutationRemove MutationKind = "remove"

	// MutationUpgrade records an upgrade; its undo best-effort restores the package's prior version.
	MutationUpgrade MutationKind = "upgrade"
)

type Observation

type Observation struct {
	op.ObservationBase

	// Version is the version string the platform's package manager reports for the package at
	// observation time. Empty when `Exists` is false.
	Version string
}

Observation captures the runtime-observed state of a *Resource (a host package) at the moment it was observed.

Distinct from Resource, which carries identity (the purl URI, `Name`, `Type`). An observation is a point-in-time metadata snapshot record — not a Resource, never cataloged — whose identity comes from the resource it references (op.ObservationBase.OfResource, by pointer value). It embeds op.ObservationBase (the back-link + op.ObservationBase.Exists) and adds the package-specific measurement field: `Version`.

func NewObservation

func NewObservation(ofResource *Resource, exists bool, version string) *Observation

NewObservation constructs a *Observation anchored to the resource it observes.

Parameters:

  • `ofResource`: the *Resource this observation is of. Must be non-nil (asserted by op.NewObservationBase).
  • `exists`: true when the package was installed at observation time.
  • `version`: the installed version reported by the package manager.

Returns:

  • `*Observation`: the constructed observation.

func (*Observation) String

func (o *Observation) String() string

String returns a debug-oriented single-line representation of the observation.

Returns:

  • `string`: `pkg.Observation{of=<OfResource.URI()>, exists=<bool>, version=<string>}`.

type Provider

type Provider struct {
	op.ProviderBase
}

Provider is a thin veneer over the platform's Composite package-manager router.

It carries no convergence policy of its own: each verb projects its *Resource slice into a platform.PURL slice, calls the router once, and adapts the router's per-package platform.Receipt slice into the provider's *Receipt compensation state. All convergence and verification live in the platform's leaf drivers.

+devlore:access=planned

func NewProvider

func NewProvider(runtimeEnvironment *op.RuntimeEnvironment) *Provider

NewProvider constructs a package-management Provider bound to the given runtime environment.

Parameters:

  • `runtimeEnvironment`: the runtime environment that supplies the platform abstraction and status sink.

Returns:

  • `*Provider`: the initialized provider.

func (*Provider) CompensateInstall

func (p *Provider) CompensateInstall(activation *op.ActivationRecord, stack *op.RecoveryStack) error

CompensateInstall reverses an install by unwinding its recovery stack.

Each entry is a self-describing *Receipt naming Provider.CompensatePackageMutation, so unwinding removes each newly-installed package and restores any pre-existing one whose version the install drifted.

Parameters:

Returns:

  • `error`: the joined errors from the per-package compensations, or nil when all succeed.

func (*Provider) CompensatePackageMutation

func (p *Provider) CompensatePackageMutation(activationRecord *op.ActivationRecord, receipt *Receipt) error

CompensatePackageMutation inverts one package mutation, dispatching on the receipt's MutationKind: remove a newly-installed package or restore a pre-existing one's drifted version (install), reinstall a removed package (remove), or best-effort restore an upgraded package's prior version (upgrade). It is the single undo named by every package receipt; the verb companions (Provider.CompensateInstall / Provider.CompensateRemove / Provider.CompensateUpgrade) just unwind the stack of these.

Parameters:

  • `activationRecord`: the dispatch activation (the required floor for compensating actions — step 27).
  • `receipt`: the package *Receipt to invert; a nil receipt or nil resource is a no-op.

Returns:

  • `error`: a missing platform, an unknown kind, or any removal / reinstall failure.

func (*Provider) CompensateRemove

func (p *Provider) CompensateRemove(activation *op.ActivationRecord, stack *op.RecoveryStack) error

CompensateRemove reverses a removal by unwinding its recovery stack — each entry reinstalls a package that was present before.

Parameters:

Returns:

  • `error`: the joined errors from the per-package compensations, or nil when all succeed.

func (*Provider) CompensateUpgrade

func (p *Provider) CompensateUpgrade(activation *op.ActivationRecord, stack *op.RecoveryStack) error

CompensateUpgrade reverses an upgrade by unwinding its recovery stack — each entry best-effort restores its package's prior version.

Parameters:

Returns:

  • `error`: the joined errors from the per-package compensations, or nil when all succeed.

func (*Provider) Install

func (p *Provider) Install(
	activationRecord *op.ActivationRecord,
	packages []*Resource,
	kwargs map[string]any,
) (result []*Resource, stack *op.RecoveryStack, err error)

Install installs each package via the platform's Composite router.

Parameters:

  • `activationRecord`: the dispatch activation (the required floor for compensable actions — step 27).
  • `packages`: package resources to install, each carrying its requested version.
  • `kwargs`: opaque native-installer flags passed through to the routed leaf (e.g. `cask`).

Returns:

  • `result`: the input packages, each with Type set to the purl type of the leaf that handled it.
  • `stack`: a op.RecoveryStack carrying one self-describing *Receipt per package, in input order, so a failed run unwinds it in reverse — each receipt routes to Provider.CompensatePackageMutation.
  • `error`: non-nil if no packages were specified, no platform is available, or any package failed to install.

func (*Provider) Installed

func (p *Provider) Installed(name *Resource) (bool, error)

Installed reports whether the named package is installed, querying the router by purl.

Parameters:

  • `name`: the package resource to check.

Returns:

  • `bool`: true when the package is installed.
  • `error`: non-nil when no platform is available.

func (*Provider) NotInstalled

func (p *Provider) NotInstalled(name *Resource) (bool, error)

NotInstalled reports whether the named package is not installed, querying the router by purl.

Parameters:

  • `name`: the package resource to check.

Returns:

  • `bool`: true when the package is not installed.
  • `error`: non-nil when no platform is available.

func (*Provider) Observe

func (p *Provider) Observe(resource *Resource) (*Observation, error)

Observe captures the runtime-observed state of `resource` as an *Observation.

Asks the platform's Composite router for the installed version of the package identified by `resource`. When a platform exists and the router reports a non-empty version, the Observation carries `Exists=true` and the version string; otherwise it carries `Exists=false`.

Parameters:

  • `resource`: the *Resource whose installed state to observe.

Returns:

  • `*Observation`: the constructed observation; never nil.
  • `error`: always nil — a missing platform or an uninstalled package is a valid observation, not a failure; the error return keeps the announced fallible-action shape.

func (*Provider) Remove

func (p *Provider) Remove(
	activationRecord *op.ActivationRecord,
	packages []*Resource,
	kwargs map[string]any,
) (result []*Resource, stack *op.RecoveryStack, err error)

Remove removes each package via the platform's Composite router.

Parameters:

  • `activationRecord`: the dispatch activation (the required floor for compensable actions — step 27).
  • `packages`: package resources to remove.
  • `kwargs`: opaque native-installer flags passed through to the routed leaf.

Returns:

  • `result`: the input packages, each with Type set to the purl type of the leaf that handled it.
  • `stack`: a op.RecoveryStack carrying one self-describing *Receipt per package, in input order.
  • `error`: non-nil if no packages were specified, no platform is available, or any package failed to remove.

func (*Provider) Update

func (p *Provider) Update() error

Update forces an immediate index refresh on every leaf via the platform's Composite router.

Returns:

  • `error`: aggregated per-leaf refresh failures, or non-nil when no platform is available.

func (*Provider) Upgrade

func (p *Provider) Upgrade(
	activationRecord *op.ActivationRecord,
	packages []*Resource,
	kwargs map[string]any,
) (result []*Resource, stack *op.RecoveryStack, err error)

Upgrade upgrades each package to the latest available version via the platform's Composite router.

Parameters:

  • `activationRecord`: the dispatch activation (the required floor for compensable actions — step 27).
  • `packages`: package resources to upgrade.
  • `kwargs`: opaque native-installer flags passed through to the routed leaf.

Returns:

  • `result`: the input packages, each with Type set to the purl type of the leaf that handled it.
  • `stack`: a op.RecoveryStack carrying one self-describing *Receipt per package, in input order.
  • `error`: non-nil if no packages were specified, no platform is available, or any package failed to upgrade.

func (*Provider) VersionGTE

func (p *Provider) VersionGTE(name *Resource, version string) (bool, error)

VersionGTE reports whether the installed version of `name` is greater than or equal to `version`.

Parameters:

  • `name`: the package resource to check.
  • `version`: the minimum version string to compare against.

Returns:

  • `bool`: true when the installed version is non-empty and >= `version`.
  • `error`: non-nil when no platform is available.

type Receipt

type Receipt struct {
	op.ReceiptBase

	// Manager is the purl type of the leaf that handled the package.
	Manager string

	// InstalledBefore records whether the package was present before the action.
	InstalledBefore bool

	// PreviousVersion is the version observed before the action.
	PreviousVersion string
	// contains filtered or unexported fields
}

Receipt holds the per-package compensation state Provider.CompensatePackageMutation needs to undo one package mutation.

The embedded op.ReceiptBase carries the affected Resource and the opaque op.ReceiptBase.TransactionID minted at op.ReceiptBase.Commit. One Receipt records one package: `kind` is the mutation it undoes, `Manager` is the purl type of the leaf that handled it, `InstalledBefore` records whether the package was present before the action (so unwind does not remove a package the user already had), and `PreviousVersion` is the version observed before the action (so an upgrade or a drifted install can be best-effort restored). A multi-package verb pushes one Receipt per package onto a op.RecoveryStack.

func NewReceipt

func NewReceipt(resource *Resource, kind MutationKind, manager string, installedBefore bool, previousVersion string) *Receipt

NewReceipt builds a per-package *Receipt that declares its undo at construction.

The receipt names [compensatePackageMutationAction] as its compensating action (so Provider.CompensatePackageMutation inverts it regardless of which verb or dispatcher created it) and records the mutation kind and the package fields. The transactionID is minted later at op.ReceiptBase.Commit.

Parameters:

  • `resource`: the package *Resource the mutation affected.
  • `kind`: the MutationKind the receipt records.
  • `manager`: the purl type of the leaf that handled the package.
  • `installedBefore`: whether the package was present before the action.
  • `previousVersion`: the version observed before the action.

Returns:

  • `*Receipt`: the constructed receipt, born naming its compensator.

func (*Receipt) Kind

func (r *Receipt) Kind() MutationKind

Kind returns the MutationKind this receipt records, or "" when unset.

Returns:

  • `MutationKind`: the recorded mutation kind.

func (*Receipt) MarshalJSON

func (r *Receipt) MarshalJSON() ([]byte, error)

MarshalJSON encodes the receipt's compensation state as JSON.

Delegates to Receipt.MarshalYAML for the serialized-shape value, then runs json.Marshal over it.

Returns:

func (*Receipt) MarshalYAML

func (r *Receipt) MarshalYAML() (any, error)

MarshalYAML returns the receipt's compensation state as an anonymous struct value the encoder serializes.

This is the `receipt` sub-field the recovery stack embeds: the resource URI, transaction id, mutation kind, and the package fields. The base execution state (`action`/`compensating_action`/`result`/`status`) rides the stack-owned envelope, so it is not repeated here; resume reconstructs the receipt in Receipt.RestoreEncoded.

Returns:

  • `any`: the populated anonymous struct for the encoder to walk.
  • `error`: nil under normal conditions.

func (*Receipt) RestoreEncoded

func (r *Receipt) RestoreEncoded(
	runtimeEnvironment *op.RuntimeEnvironment, base op.ReceiptData, fields map[string]any,
) error

RestoreEncoded reconstructs the receipt from its codec-decoded envelope.

It is the op.Receipt.RestoreEncoded override for package receipts. The recovery stack already decoded the envelope, so this consumes decoded values, never bytes: `base` carries the execution state and `fields` the receipt sub-field. It rehydrates the resource from its URI via DiscoverResource, seeds the base via op.NewReceiptBase + op.ReceiptBase.Restore, and restores the kind and package fields.

Parameters:

  • `runtimeEnvironment`: the resume environment; its catalog must hold (or be able to construct) the resource.
  • `base`: the codec-decoded base execution state.
  • `fields`: the receipt sub-field, decoded to a format-neutral map.

Returns:

  • `error`: a missing catalog or a DiscoverResource failure (an external-system interaction). The envelope itself arrives post-op.LoadTrace — checksum-verified — so document-derived failures panic (docs/architecture/5-graph-trace-integrity.md).

type Resource

type Resource struct {
	op.ResourceBase
	Name    string // package name ("jq", "curl", "VisualStudioCode")
	Type    string // purl type / manager ("brew", "deb", "port", "winget")
	Version string // requested version (purl @version); empty means latest
}

Resource identifies a host package by its package-URL (purl) coordinates.

`Name` and `Type` together form the versionless purl encoded in the op.ResourceBase URI; "git" and "git@2.39.0" intern to the same catalog entry. `Version` is the requested version (the purl `@version`; empty means latest) — mutable state on the Resource, not part of its identity. Runtime-observed state (the installed version reported by the platform's package manager) lives on a separate *Observation minted by Provider.Observe.

func DiscoverResource

func DiscoverResource(runtimeEnvironment *op.RuntimeEnvironment, value any) (*Resource, error)

DiscoverResource registers a pkg.Resource via op.ResourceCatalog.Discover without claiming production.

Used by the framework's resource registry adapter for slot coercion (when starlark supplies a string package name and the slot expects a *pkg.Resource), and by callers holding a reference handle without claiming production (receipt rehydration is the canonical example).

Discover does not stamp a producer, so unlike NewResource it takes only `runtimeEnvironment` — no unit reference is needed.

Nil-Catalog tolerance: returns the unlinked candidate when no catalog is present.

Parameters:

  • `runtimeEnvironment`: the session runtime environment.
  • `value`: a string package name with an optional manager prefix.

Returns:

  • `*Resource`: the canonical catalog entry (or the unlinked candidate when no catalog is present).
  • `error`: if `value` is not a string or the manager prefix is unknown.

func NewResource

func NewResource(runtimeEnvironment *op.RuntimeEnvironment, producerID string, value any) (*Resource, error)

NewResource constructs a pkg.Resource and claims production via op.ResourceCatalog.GetOrCreate.

Use NewResource from a producer dispatch context — typically a provider method that has received an op.ActivationRecord from the framework. The returned Resource is the canonical catalog entry, stamped with `producerID = activationRecord.CallerID.ID()` (or empty when `Unit` is nil for non-graph dispatch). Use DiscoverResource instead when the caller is not claiming production (rehydration, reference handles, the framework's slot-coercion adapter).

Today no pkg provider method actually claims production — Install / Remove / Upgrade all take an existing `[]*Resource` and return the same pointers with their `Type` field updated to reflect which platform manager handled them. URIs (purls) are unchanged. NewResource exists for symmetry with the m.4 two-constructor pattern and as a stable surface for any future pkg producer that creates a new purl.

The value is a string package name with an optional manager prefix and optional version (e.g., "jq", "brew:jq", "port:wget", "git@2.39.0"). When no prefix is present, the platform's default purl type is used; the prefix otherwise resolves through platform.Platform.ResolvePurlType. The `@version` tail becomes the Resource's requested version and is excluded from the versionless catalog URI.

Nil-Catalog tolerance: returns the unlinked candidate when no catalog is present.

Parameters:

  • `runtimeEnvironment`: the session runtime environment (must have `Platform` set).
  • `producerID`: the producing caller's id (`activationRecord.CallerID`), or "" for caller-less dispatch. for non-graph dispatch.
  • `value`: a string package name with an optional manager prefix.

Returns:

  • `*Resource`: the canonical catalog entry (or the unlinked candidate when no catalog is present).
  • `error`: if `value` is not a string or the manager prefix is unknown.

func (*Resource) Addressing

func (r *Resource) Addressing() op.AddressingMode

Addressing reports that pkg.Resource is location-keyed: identity is the package URI (the purl).

The installed state (version, presence) under that purl is mutable, and the catalog uses op.AddressingLocation semantics — content drift triggers shadow chains, not new URIs.

Returns:

func (*Resource) CanConvertFrom

func (*Resource) CanConvertFrom(source reflect.Type) bool

CanConvertFrom reports whether `source` can be projected into a *Resource via Resource.ConvertFrom.

Opts the pkg Resource into the framework's op.TargetConverter contract — accepted source shape is `string` (interpreted as a package identifier, either a bare name like "jq" or a purl-prefixed form like "brew:jq"). The framework consults this probe both at plan-time via [op.typesAreInterconvertible] (the bubble-up parameter-consistency check) and at dispatch-time via op.Convert step 7 (env-less fallback). The canonical dispatch-time path remains the registered constructor at op.Convert step 6, which receives the full op.RuntimeEnvironment and parses any manager prefix via [buildCandidate].

Cheap-probe contract: this method is called against a nil-or-zero `*Resource` receiver by [op.typesAreInterconvertible] during plan-time bubble-up checks. MUST NOT dereference receiver fields.

Parameters:

  • `source`: the candidate source type to test.

Returns:

  • `bool`: true when `source` is `string`.

func (*Resource) ConvertFrom

func (*Resource) ConvertFrom(value any) (any, error)

ConvertFrom projects `value` into an env-less unlinked *Resource.

Used by op.Convert step 7 when the env-aware registered constructor (step 6) is unavailable — env-less library callers, tests, or op.RuntimeEnvironment.Registry-missing contexts. The returned Resource carries only the Name set from `value`; the manager prefix is NOT parsed here, and the canonical URI on the embedded op.ResourceBase is not populated. Provider methods consuming the projected Resource are responsible for re-canonicalization via their own NewResource/DiscoverResource path when full identity is required.

Parameters:

  • `value`: the source value; must be `string`.

Returns:

  • `any`: the constructed unlinked *Resource.
  • `error`: non-nil when `value` is not a `string`.

func (*Resource) Digest

func (r *Resource) Digest() (op.Digest, error)

Digest returns the honest content hash: sha256 of (installed version + "\n" + canonical purl URI).

The canonical purl encodes the package identity (type + name); the installed version encodes the mutable state. Hashing the pair gives a stable, content-addressable token that changes when either the identity (which would normally mean a different URI / different Resource) or the installed state changes.

Uninstalled packages produce a deterministic digest of (empty version + URI), distinct from any installed digest for the same package, and distinct across different packages (since URIs differ).

Always fresh — re-queries the version at call time via Resource.Etag. Errors when Etag would error.

Returns:

  • `op.Digest`: sha256 algorithm with 32 raw bytes.
  • `error`: any error from Resource.Etag (no Platform, no manager for Type).

func (*Resource) Equal

func (r *Resource) Equal(other any) bool

Equal reports whether r and other identify the same pkg resource.

Strict equality: other must be a *pkg.Resource (not merely an op.Resource with the same URI). Once the type check passes, URI comparison is delegated to op.ResourceBase.Equal. A cross-type URI collision is treated as a caller-side construction error, not a case Equal needs to disambiguate.

Parameters:

  • `other`: the value to compare against; may be any, including nil or a non-Resource.

Returns:

  • `bool`: true if `other` is a *pkg.Resource with the same URI as r.

func (*Resource) Etag

func (r *Resource) Etag() (string, error)

Etag returns the currently-installed version of the package as a cheap change-detection token.

Empty string when the package is not installed (a valid state, distinguishable from errors by the nil error return). The catalog uses Etag as the cheap signal; mismatch triggers a full Resource.Digest comparison.

Always fresh — queries the platform's Composite package-manager router at call time. Does not consult Resource.Version, which is the requested version rather than installed state. The router routes by purl type; an unknown type reports "" (absent), not an error. Errors only when the runtime environment has no Platform.

Returns:

  • `string`: the installed version string, or "" when uninstalled.
  • `error`: when Platform is missing.

func (*Resource) String

func (r *Resource) String() string

String returns a compact JSON representation of the resource.

Returns:

  • `string`: the compact JSON encoding of r.

func (*Resource) UnmarshalJSON

func (r *Resource) UnmarshalJSON(data []byte) error

UnmarshalJSON populates the receiver from its JSON document (a bare purl string).

The caller pre-seeds the receiver's embedded op.ResourceBase with a valid op.RuntimeEnvironment before invoking this method; the runtime environment provides the platform needed to parse the purl. Rehydration flows through DiscoverResource (non-production claim).

Parameters:

  • `data`: JSON-encoded purl string.

Returns:

  • `error`: non-nil if the RuntimeEnvironment is missing, the JSON does not decode as a string, or resource construction fails.

func (*Resource) UnmarshalText

func (r *Resource) UnmarshalText(text []byte) error

UnmarshalText populates the receiver from raw UTF-8 bytes containing the purl string.

Parameters:

  • `text`: UTF-8 bytes containing the purl.

Returns:

  • `error`: missing RuntimeEnvironment on receiver, or rehydration failure.

func (*Resource) UnmarshalYAML

func (r *Resource) UnmarshalYAML(unmarshal func(any) error) error

UnmarshalYAML populates the receiver from its YAML document (a bare purl scalar).

Parameters:

  • `unmarshal`: yaml decode hook supplied by the YAML library; called with a *string target.

Returns:

  • `error`: missing RuntimeEnvironment on receiver, decode failure, or rehydration failure.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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