module

package
v0.9.0-alpha.4 Latest Latest
Warning

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

Go to latest
Published: May 1, 2024 License: Apache-2.0 Imports: 11 Imported by: 3

Documentation

Overview

Package module defines the Version type along with support code.

WARNING: THIS PACKAGE IS EXPERIMENTAL. ITS API MAY CHANGE AT ANY TIME.

The Version type holds a pair of module path and version. The module path conforms to the checks implemented by Check.

Escaped Paths

Module versions appear as substrings of file system paths (as stored by the modcache package). In general we cannot rely on file systems to be case-sensitive. Although module paths cannot currently contain upper case characters because OCI registries forbid that, versions can. That is, we cannot rely on the file system to keep foo.com/v@v1.0.0-PRE and foo.com/v@v1.0.0-PRE separate. Windows and macOS don't. Instead, we must never require two different casings of a file path.

One possibility would be to make the escaped form be the lowercase hexadecimal encoding of the actual path bytes. This would avoid ever needing different casings of a file path, but it would be fairly illegible to most programmers when those paths appeared in the file system (including in file paths in compiler errors and stack traces) in web server logs, and so on. Instead, we want a safe escaped form that leaves most paths unaltered.

The safe escaped form is to replace every uppercase letter with an exclamation mark followed by the letter's lowercase equivalent.

For example,

foo.com/v@v1.0.0-PRE ->  foo.com/v@v1.0.0-!p!r!e

Versions that avoid upper-case letters are left unchanged. Note that because import paths are ASCII-only and avoid various problematic punctuation (like : < and >), the escaped form is also ASCII-only and avoids the same problematic punctuation.

Neither versions nor module paths allow exclamation marks, so there is no need to define how to escape a literal !.

Unicode Restrictions

Today, paths are disallowed from using Unicode.

Although paths are currently disallowed from using Unicode, we would like at some point to allow Unicode letters as well, to assume that file systems and URLs are Unicode-safe (storing UTF-8), and apply the !-for-uppercase convention for escaping them in the file system. But there are at least two subtle considerations.

First, note that not all case-fold equivalent distinct runes form an upper/lower pair. For example, U+004B ('K'), U+006B ('k'), and U+212A ('K' for Kelvin) are three distinct runes that case-fold to each other. When we do add Unicode letters, we must not assume that upper/lower are the only case-equivalent pairs. Perhaps the Kelvin symbol would be disallowed entirely, for example. Or perhaps it would escape as "!!k", or perhaps as "(212A)".

Second, it would be nice to allow Unicode marks as well as letters, but marks include combining marks, and then we must deal not only with case folding but also normalization: both U+00E9 ('é') and U+0065 U+0301 ('e' followed by combining acute accent) look the same on the page and are treated by some file systems as the same path. If we do allow Unicode marks in paths, there must be some kind of normalization to allow only one canonical encoding of any character used in an import path.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Check

func Check(path, version string) error

Check checks that a given module path, version pair is valid. In addition to the path being a valid module path and the version being a valid semantic version, the two must correspond. For example, the path "foo.com/bar@v2" only corresponds to semantic versions beginning with "v2.".

func CheckFilePath

func CheckFilePath(path string) error

CheckFilePath checks that a slash-separated file path is valid. The definition of a valid file path is the same as the definition of a valid import path except that the set of allowed characters is larger: all Unicode letters, ASCII digits, the ASCII space character (U+0020), and the ASCII punctuation characters “!#$%&()+,-.=@[]^_{}~”. (The excluded punctuation characters, " * < > ? ` ' | / \ and :, have special meanings in certain shells or operating systems.)

CheckFilePath may be less restrictive in the future, but see the top-level package documentation for additional information about subtleties of Unicode.

func CheckImportPath

func CheckImportPath(path string) error

CheckImportPath checks that an import path is valid.

A valid import path consists of one or more valid path elements separated by slashes (U+002F), optionally followed by an @vN (major version) qualifier. The path part must not begin with nor end in a slash.

A valid path element is a non-empty string made up of lower case ASCII letters, ASCII digits, and limited ASCII punctuation: - . and _ Punctuation characters may not be adjacent and must be between non-punctuation characters.

The element prefix up to the first dot must not be a reserved file name on Windows, regardless of case (CON, com1, NuL, and so on).

func CheckPath

func CheckPath(mpath string) (err error)

CheckPath checks that a module path is valid. A valid module path is a valid import path, as checked by CheckImportPath, with three additional constraints.

First, the leading path element (up to the first slash, if any), by convention a domain name, must contain only lower-case ASCII letters, ASCII digits, dots (U+002E), and dashes (U+002D); it must contain at least one dot and cannot start with a dash.

Second, there must be a final major version of the form @vN where N looks numeric (ASCII digits) and must not begin with a leading zero.

Third, no path element may begin with a dot.

func CheckPathMajor

func CheckPathMajor(v, pathMajor string) error

CheckPathMajor returns a non-nil error if the semantic version v does not match the path major version pathMajor.

func CheckPathWithoutVersion

func CheckPathWithoutVersion(basePath string) (err error)

CheckPathWithoutVersion is like CheckPath except that it expects a module path without a major version.

func EscapePath

func EscapePath(path string) (escaped string, err error)

EscapePath returns the escaped form of the given module path (without the major version suffix). It fails if the module path is invalid.

func EscapeVersion

func EscapeVersion(v string) (escaped string, err error)

EscapeVersion returns the escaped form of the given module version. Versions must be in (possibly non-canonical) semver form and must be valid file names and not contain exclamation marks.

func OSDirFS

func OSDirFS(p string) fs.FS

OSDirFS is like os.DirFS but the returned value implements OSRootFS by returning p.

func Sort

func Sort(list []Version)

Sort sorts the list by Path, breaking ties by comparing Version fields. The Version fields are interpreted as semantic versions (using semver.Compare) optionally followed by a tie-breaking suffix introduced by a slash character, like in "v0.0.1/module.cue".

func SplitPathVersion

func SplitPathVersion(path string) (prefix, version string, ok bool)

SplitPathVersion returns a prefix and version suffix such that prefix+"@"+version == path. SplitPathVersion returns with ok=false when presented with a path with an invalid version suffix.

For example, SplitPathVersion("foo.com/bar@v0.1") returns ("foo.com/bar", "v0.1", true).

Types

type ImportPath

type ImportPath struct {
	// Path holds the base package/directory path, similar
	// to that returned by [Version.BasePath].
	Path string

	// Version holds the version of the import
	// or empty if not present. Note: in general this
	// will contain a major version only, but there's no
	// guarantee of that.
	Version string

	// Qualifier holds the package qualifier within the path.
	// This will be derived from the last component of Path
	// if it wasn't explicitly present in the import path.
	// This is not guaranteed to be a valid CUE identifier.
	Qualifier string

	// ExplicitQualifier holds whether the qualifier was explicitly
	// present in the import path.
	ExplicitQualifier bool
}

ImportPath holds the various components of an import path.

func ParseImportPath

func ParseImportPath(p string) ImportPath

ParseImportPath returns the various components of an import path.

func (ImportPath) Canonical

func (parts ImportPath) Canonical() ImportPath

Canonical returns the canonical form of the import path. Specifically, it will only include the package qualifier if it's different from the last component of parts.Path.

func (ImportPath) String

func (parts ImportPath) String() string

func (ImportPath) Unqualified

func (parts ImportPath) Unqualified() ImportPath

Unqualified returns the import path without any package qualifier.

type InvalidPathError

type InvalidPathError struct {
	Kind string // "module", "import", or "file"
	Path string
	Err  error
}

An InvalidPathError indicates a module, import, or file path doesn't satisfy all naming constraints. See CheckPath, CheckImportPath, and CheckFilePath for specific restrictions.

func (*InvalidPathError) Error

func (e *InvalidPathError) Error() string

func (*InvalidPathError) Unwrap

func (e *InvalidPathError) Unwrap() error

type InvalidVersionError

type InvalidVersionError struct {
	Version string
	Err     error
}

An InvalidVersionError indicates an error specific to a version, with the module path unknown or specified externally.

A ModuleError may wrap an InvalidVersionError, but an InvalidVersionError must not wrap a ModuleError.

func (*InvalidVersionError) Error

func (e *InvalidVersionError) Error() string

func (*InvalidVersionError) Unwrap

func (e *InvalidVersionError) Unwrap() error

type ModuleError

type ModuleError struct {
	Path    string
	Version string
	Err     error
}

A ModuleError indicates an error specific to a module.

func (*ModuleError) Error

func (e *ModuleError) Error() string

func (*ModuleError) Unwrap

func (e *ModuleError) Unwrap() error

type OSRootFS

type OSRootFS interface {
	fs.FS

	// OSRoot returns the root directory of the FS
	// as an OS file path. If it wasn't possible to do that,
	// it returns the empty string.
	OSRoot() string
}

OSRootFS can be implemented by an fs.FS implementation to return its root directory as an OS file path.

type SourceLoc

type SourceLoc struct {
	// FS is the filesystem containing the source.
	FS fs.FS
	// Dir is the directory within the above filesystem.
	Dir string
}

SourceLoc represents the location of some CUE source code.

type Version

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

A Version (for clients, a module.Version) is defined by a module path and version pair. These are stored in their plain (unescaped) form. This type is comparable.

func MustNewVersion

func MustNewVersion(path string, version string) Version

func MustParseVersion

func MustParseVersion(s string) Version

func NewVersion

func NewVersion(path string, version string) (Version, error)

NewVersion forms a Version from the given path and version. The version must be canonical, empty or "none". If the path doesn't have a major version suffix, one will be added if the version isn't empty; if the version is empty, it's an error.

As a special case, the path "local" is used to mean all packages held in the gen, pkg and usr directories.

func ParseVersion

func ParseVersion(s string) (Version, error)

ParseVersion parses a $module@$version string into a Version. The version must be canonical (i.e. it can't be just a major version).

func (Version) BasePath

func (m Version) BasePath() string

BasePath returns the path part of m without its major version suffix.

func (Version) Equal

func (m Version) Equal(m1 Version) bool

Equal reports whether m is equal to m1.

func (Version) IsCanonical

func (m Version) IsCanonical() bool

IsCanonical reports whether m is valid and has a canonical semver version.

func (Version) IsLocal

func (m Version) IsLocal() bool

func (Version) IsValid

func (m Version) IsValid() bool

IsValid reports whether m is non-zero.

func (Version) Path

func (m Version) Path() string

Path returns the module path part of the Version, which always includes the major version suffix unless a module path, like "github.com/foo/bar@v0". Note that in general the path should include the major version suffix even though it's implied from the version. The Canonical method can be used to add the major version suffix if not present. The BasePath method can be used to obtain the path without the suffix.

func (Version) String

func (m Version) String() string

String returns the string form of the Version: (Path@Version, or just Path if Version is empty).

func (Version) Version

func (m Version) Version() string

Version returns the version part of m. This is either a canonical semver version or "none" or the empty string.

type Versions

type Versions struct{}

Versions implements mvs.Versions[Version].

func (Versions) Max

func (Versions) Max(v1, v2 string) string

Max implements mvs.Reqs.Max.

It is consistent with semver.Compare except that as a special case, the version "" is considered higher than all other versions. The main module (also known as the target) has no version and must be chosen over other versions of the same module in the module dependency graph.

See [mvs.Reqs] for more detail.

func (Versions) New

func (Versions) New(p, v string) (Version, error)

New implements mvs.Versions[Version].New.

func (Versions) Path

func (Versions) Path(v Version) string

New implements mvs.Versions[Version].Path.

func (Versions) Version

func (Versions) Version(v Version) string

New implements mvs.Versions[Version].Version.

Jump to

Keyboard shortcuts

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