resolve

package
v0.6.0-2a Latest Latest
Warning

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

Go to latest
Published: Jun 3, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package resolve handles import resolution and lock file management.

Resolves import paths (bare URLs, with // subdirs, local ./ paths) to concrete sources. Detects whether each import is a UB library (it has kind-prefixed body files at the root) or a Go library. Detects cycles at resolve time and reports them as compile errors. Enforces same-repo imports sharing a version.

Reads and writes unobin.lock - pins git commits and content hashes per import for reproducible compiles.

Index

Constants

This section is empty.

Variables

View Source
var ErrEmptyImportRef = errors.New("empty import reference")

ErrEmptyImportRef is returned when the source string is empty.

View Source
var ErrRemoteNotImplemented = errors.New("remote resolver not implemented")

ErrRemoteNotImplemented is retained for callers that switched on it while the resolver was a stub. New callers should not depend on it.

Functions

func ContainsMainUB

func ContainsMainUB(s *Source) bool

ContainsMainUB reports whether s has a `main.ub` at its root, which marks the directory as a factory: runnable and not importable.

func ExtractImports

func ExtractImports(f *lang.File) (map[string]ImportRef, []error)

ExtractImports walks the `imports:` block of f and parses each value into an ImportRef. Returns a map of alias to ref plus any per-import parse errors. Shape problems with the block itself are reported by `lang.ValidateImports` and silently skipped here so the two passes don't both report the same errors.

func IsUBLibrary

func IsUBLibrary(s *Source) bool

IsUBLibrary reports whether s is a UB-implemented library: a directory holding at least one `.ub` file and no `main.ub` (a `main.ub` marks a factory, which is not importable). Every `.ub` file in a library is expected to be a kind-prefixed body (`resource-*.ub`, `data-*.ub`, or `action-*.ub`); a misnamed one is caught when the library is parsed, not here, so the author gets a clear error rather than having the whole directory silently treated as a Go library. Sources with no `.ub` files are Go libraries.

func SplitRepoSubdir added in v0.6.0

func SplitRepoSubdir(s string) (url, subdir string, err error)

SplitRepoSubdir separates a repo URL from its optional subdir at the `//` separator. Without `//`, the whole input is the URL and there is no subdir.

func UBKey

func UBKey(ref ImportRef) string

UBKey is the dedup key for a UB-library import. Remote imports key on URL, subdir, and version; the `//<subdir>` segment is included only when the import names a subdirectory, so root-of-repo refs read cleanly in cycle errors and other diagnostics. Local imports key on path.

func ValidateCompositeBody

func ValidateCompositeBody(kind, typeName string, f *lang.File) []error

ValidateCompositeBody checks a composite body against the floor and ceiling rules for its kind, which comes from the file's `<kind>-` name prefix:

  • data: at least one output, may hold data, no resources, no actions.
  • action: at least one action, may hold data, no resources; outputs are optional.
  • resource: at least one resource, may hold data and actions; outputs are optional.

typeName names the composite in the messages. Returns one error per violated rule, in a fixed order, so a body reports every problem at once. The resolver does not run this during the walk; the compile command runs it over each resolved library so that print-graph and fetch stay lenient.

func WithDefaultScheme added in v0.6.0

func WithDefaultScheme(url string) string

WithDefaultScheme prepends `https://` to a bare URL like `github.com/owner/repo` so go-git knows to fetch it over HTTPS. URLs that already include a scheme (`https://`, `http://`, `ssh://`, `file://`, ...) or look like SCP-style ssh (`user@host:path`) or look like a filesystem path are left alone.

Types

type ImportRef

type ImportRef interface {
	// contains filtered or unexported methods
}

ImportRef is a parsed value from an `imports:` block.

func ParseImportRef

func ParseImportRef(raw string) (ImportRef, error)

ParseImportRef parses a string from an `imports:` block. Local imports start with `.` or `/`; remote imports name a repo URL and use the Terraform-style `//` separator to denote a subdirectory within the repo. Without `//` the whole string is the repo URL and the import has no subdir.

type LocalImport

type LocalImport struct {
	Path string
}

LocalImport names a sibling on the operator's filesystem. Local imports do not have pinned versions; their content is whatever the developer has at the path now. Compile from a clean checkout to make the result reproducible.

type LocalResolver

type LocalResolver struct {
	Root string
}

LocalResolver resolves *LocalImport refs against a working directory root. Relative paths in the import are joined to Root.

func NewLocalResolver

func NewLocalResolver(root string) *LocalResolver

NewLocalResolver returns a LocalResolver rooted at root. Pass the directory containing the main.ub or library type bodies that own the imports.

func (*LocalResolver) Resolve

func (r *LocalResolver) Resolve(ref ImportRef) (*Source, error)

Resolve implements Resolver. The ref must be a *LocalImport; remote refs return an error so a misrouted call surfaces clearly.

type RemoteImport

type RemoteImport struct {
	URL     string
	Subdir  string
	Version string
}

RemoteImport names an importable repo by host + owner/name and an optional subdir within the repo. The import string carries no version; Version is filled in from unobin.lock as the walk descends.

type RemoteResolver

type RemoteResolver struct {
	CacheRoot string
}

RemoteResolver resolves *RemoteImport refs by fetching the named git repo at the requested constraint, caching the working tree under CacheRoot, and exposing the requested subdir as a Source.

CacheRoot is the directory holding `imports/<host>/<path>/<commit>/`. `NewRemoteResolver` defaults it to `<user-cache-dir>/unobin`.

func NewRemoteResolver

func NewRemoteResolver() (*RemoteResolver, error)

NewRemoteResolver returns a RemoteResolver with CacheRoot set to the user's cache directory (XDG_CACHE_HOME or its platform default) joined with `unobin`.

func (*RemoteResolver) CleanImports added in v0.6.0

func (r *RemoteResolver) CleanImports() (string, error)

CleanImports removes the cached import sources and returns the directory that was removed. It is a no-op when nothing is cached.

func (*RemoteResolver) ImportsDir added in v0.6.0

func (r *RemoteResolver) ImportsDir() string

ImportsDir is the directory holding cached import sources, a sibling of the toolchain cache under CacheRoot.

func (*RemoteResolver) Resolve

func (r *RemoteResolver) Resolve(ref ImportRef) (*Source, error)

Resolve fetches the repo named by ref, caches it, and returns a Source rooted at the import's subdir, with FS and Commit always set. A UB library (one with kind-prefixed body files at the subdir root) also gets its content Hash set for lock-file integrity.

type Resolution

type Resolution struct {
	Kind         ResolutionKind
	LocalAlias   string
	Ref          ImportRef
	Path         string
	Version      string
	CanonicalKey string
	SourcePath   string
}

Resolution describes one import after the walker reaches it. For Go imports, Path is the canonical Go-import path (URL plus subdir when present) and Version is the pinned version. For UB imports, CanonicalKey is the dedup key (see UBKey) and visitors look up their per-library state by that key. SourcePath is the on-disk directory where the resolver fetched the import, useful for compile-time inspection.

func WalkUB

func WalkUB(
	refs map[string]ImportRef, resolver Resolver, v UBVisitor, versions map[string]string,
) ([]Resolution, error)

WalkUB walks refs and every UB library they transitively reach, invoking the visitor for each import. The returned slice mirrors refs in resolved form, alias-sorted, so callers can build their own alias-to-resolution map without per-site visitor callbacks. Cycles through UB libraries are reported as errors.

versions maps a repository URL to the version selected for it in the lock; every remote import is walked at its repository's selected version. A remote import whose repository is not in the map has no version and is an error: the lock must supply it.

type ResolutionKind

type ResolutionKind int

ResolutionKind tags how an import was resolved.

const (
	// ResolutionGo names a Go-library import: a remote ref whose resolved
	// source has no kind-prefixed body files at its root.
	ResolutionGo ResolutionKind = iota + 1
	// ResolutionUB names a UB-library import: a ref whose resolved source
	// has kind-prefixed body files at its root.
	ResolutionUB
)

type Resolver

type Resolver interface {
	Resolve(ref ImportRef) (*Source, error)
}

Resolver turns an ImportRef into a Source. Implementations cover one kind of import each (local filesystem, remote git, etc.); callers dispatch by type-switching on the ref.

type Source

type Source struct {
	FS     fs.FS
	Path   string
	Commit string
	Hash   string
}

Source is the file tree of a resolved import, rooted at the import's subdirectory, or the repo root when there is no subdir. For remote imports, Commit and Hash record the resolved git commit and a content hash so the lock file can pin reproducibility. Local imports leave both empty since their content is whatever the developer has now. Path is the on-disk directory the source was fetched into, which the dev CLI uses for compile-time inspection of Go-library source.

type UBLibrary

type UBLibrary struct {
	Bodies      map[string]*lang.File
	Kinds       map[string]string
	BodyImports map[string][]Resolution
}

UBLibrary has everything the visitor needs about a UB library the first time the walker reaches it. Bodies maps composite type name to the parsed body file; the type name comes from a kind-prefixed filename (`<kind>-<type>.ub`). Kinds maps the same type name to its kind (`resource`, `data`, or `action`). BodyImports maps the type name to the resolved imports declared by that body, in alias-sorted order so callers see a stable view across runs.

type UBVisitor

type UBVisitor interface {
	// OnGoImport is called for every site whose import resolves to a
	// Go library. May fire multiple times with the same path when the
	// same library is imported from several sites; visitors that need
	// uniqueness dedup themselves.
	OnGoImport(alias, path, version string) error
	// OnUBLibrary is called once per canonical key. alias is the local
	// alias of whichever site first reached the library (which matters
	// when the visitor names a directory or package after it).
	OnUBLibrary(alias, canonicalKey string, ref ImportRef, lib *UBLibrary) error
}

UBVisitor is implemented by callers that want to consume the walked import graph. The walker invokes its methods as it descends.

Jump to

Keyboard shortcuts

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