diff options
| author | 2024-03-06 09:05:45 -0800 | |
|---|---|---|
| committer | 2024-03-06 18:05:45 +0100 | |
| commit | fc3741365c27f1d703e8a736af95b95ff811cc45 (patch) | |
| tree | 929f1d5e20d1469d63a3dfe81d38d89f9a073c5a /vendor/golang.org/x/mod/module | |
| parent | [chore/bugfix] Little DB fixes (#2726) (diff) | |
| download | gotosocial-fc3741365c27f1d703e8a736af95b95ff811cc45.tar.xz | |
[bugfix] Fix Swagger spec and add test script (#2698)
* Add Swagger spec test script
* Fix Swagger spec errors not related to statuses with polls
* Add API tests that post a status with a poll
* Fix creating a status with a poll from form params
* Fix Swagger spec errors related to statuses with polls (this is the last error)
* Fix Swagger spec warnings not related to unused definitions
* Suppress a duplicate list update params definition that was somehow causing wrong param names
* Add Swagger test to CI
- updates Drone config
- vendorizes go-swagger
- fixes a file extension issue that caused the test script to generate JSON instead of YAML with the vendorized version
* Put `Sample: ` on its own line everywhere
* Remove unused id param from emojiCategoriesGet
* Add 5 more pairs of profile fields to account update API Swagger
* Remove Swagger prefix from dummy fields
It makes the generated code look weird
* Manually annotate params for statusCreate operation
* Fix all remaining Swagger spec warnings
- Change some models into operation parameters
- Ignore models that already correspond to manually documented operation parameters but can't be trivially changed (those with file fields)
* Documented that creating a status with scheduled_at isn't implemented yet
* sign drone.yml
* Fix filter API Swagger errors
* fixup! Fix filter API Swagger errors
---------
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Diffstat (limited to 'vendor/golang.org/x/mod/module')
| -rw-r--r-- | vendor/golang.org/x/mod/module/module.go | 841 | ||||
| -rw-r--r-- | vendor/golang.org/x/mod/module/pseudo.go | 250 | 
2 files changed, 1091 insertions, 0 deletions
| diff --git a/vendor/golang.org/x/mod/module/module.go b/vendor/golang.org/x/mod/module/module.go new file mode 100644 index 000000000..2a364b229 --- /dev/null +++ b/vendor/golang.org/x/mod/module/module.go @@ -0,0 +1,841 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package module defines the module.Version type along with support code. +// +// The [module.Version] type is a simple Path, Version pair: +// +//	type Version struct { +//		Path string +//		Version string +//	} +// +// There are no restrictions imposed directly by use of this structure, +// but additional checking functions, most notably [Check], verify that +// a particular path, version pair is valid. +// +// # Escaped Paths +// +// Module paths appear as substrings of file system paths +// (in the download cache) and of web server URLs in the proxy protocol. +// In general we cannot rely on file systems to be case-sensitive, +// nor can we rely on web servers, since they read from file systems. +// That is, we cannot rely on the file system to keep rsc.io/QUOTE +// and rsc.io/quote separate. Windows and macOS don't. +// Instead, we must never require two different casings of a file path. +// Because we want the download cache to match the proxy protocol, +// and because we want the proxy protocol to be possible to serve +// from a tree of static files (which might be stored on a case-insensitive +// file system), the proxy protocol must never require two different casings +// of a URL path either. +// +// 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, +// +//	github.com/Azure/azure-sdk-for-go ->  github.com/!azure/azure-sdk-for-go. +//	github.com/GoogleCloudPlatform/cloudsql-proxy -> github.com/!google!cloud!platform/cloudsql-proxy +//	github.com/Sirupsen/logrus -> github.com/!sirupsen/logrus. +// +// Import paths 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. +// +// Import paths have never allowed 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. +package module + +// IMPORTANT NOTE +// +// This file essentially defines the set of valid import paths for the go command. +// There are many subtle considerations, including Unicode ambiguity, +// security, network, and file system representations. +// +// This file also defines the set of valid module path and version combinations, +// another topic with many subtle considerations. +// +// Changes to the semantics in this file require approval from rsc. + +import ( +	"errors" +	"fmt" +	"path" +	"sort" +	"strings" +	"unicode" +	"unicode/utf8" + +	"golang.org/x/mod/semver" +) + +// A Version (for clients, a module.Version) is defined by a module path and version pair. +// These are stored in their plain (unescaped) form. +type Version struct { +	// Path is a module path, like "golang.org/x/text" or "rsc.io/quote/v2". +	Path string + +	// Version is usually a semantic version in canonical form. +	// There are three exceptions to this general rule. +	// First, the top-level target of a build has no specific version +	// and uses Version = "". +	// Second, during MVS calculations the version "none" is used +	// to represent the decision to take no version of a given module. +	// Third, filesystem paths found in "replace" directives are +	// represented by a path with an empty version. +	Version string `json:",omitempty"` +} + +// String returns a representation of the Version suitable for logging +// (Path@Version, or just Path if Version is empty). +func (m Version) String() string { +	if m.Version == "" { +		return m.Path +	} +	return m.Path + "@" + m.Version +} + +// A ModuleError indicates an error specific to a module. +type ModuleError struct { +	Path    string +	Version string +	Err     error +} + +// VersionError returns a [ModuleError] derived from a [Version] and error, +// or err itself if it is already such an error. +func VersionError(v Version, err error) error { +	var mErr *ModuleError +	if errors.As(err, &mErr) && mErr.Path == v.Path && mErr.Version == v.Version { +		return err +	} +	return &ModuleError{ +		Path:    v.Path, +		Version: v.Version, +		Err:     err, +	} +} + +func (e *ModuleError) Error() string { +	if v, ok := e.Err.(*InvalidVersionError); ok { +		return fmt.Sprintf("%s@%s: invalid %s: %v", e.Path, v.Version, v.noun(), v.Err) +	} +	if e.Version != "" { +		return fmt.Sprintf("%s@%s: %v", e.Path, e.Version, e.Err) +	} +	return fmt.Sprintf("module %s: %v", e.Path, e.Err) +} + +func (e *ModuleError) Unwrap() error { return e.Err } + +// 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. +type InvalidVersionError struct { +	Version string +	Pseudo  bool +	Err     error +} + +// noun returns either "version" or "pseudo-version", depending on whether +// e.Version is a pseudo-version. +func (e *InvalidVersionError) noun() string { +	if e.Pseudo { +		return "pseudo-version" +	} +	return "version" +} + +func (e *InvalidVersionError) Error() string { +	return fmt.Sprintf("%s %q invalid: %s", e.noun(), e.Version, e.Err) +} + +func (e *InvalidVersionError) Unwrap() error { return e.Err } + +// An InvalidPathError indicates a module, import, or file path doesn't +// satisfy all naming constraints. See [CheckPath], [CheckImportPath], +// and [CheckFilePath] for specific restrictions. +type InvalidPathError struct { +	Kind string // "module", "import", or "file" +	Path string +	Err  error +} + +func (e *InvalidPathError) Error() string { +	return fmt.Sprintf("malformed %s path %q: %v", e.Kind, e.Path, e.Err) +} + +func (e *InvalidPathError) Unwrap() error { return e.Err } + +// 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 "yaml/v2" only corresponds to +// semantic versions beginning with "v2.". +func Check(path, version string) error { +	if err := CheckPath(path); err != nil { +		return err +	} +	if !semver.IsValid(version) { +		return &ModuleError{ +			Path: path, +			Err:  &InvalidVersionError{Version: version, Err: errors.New("not a semantic version")}, +		} +	} +	_, pathMajor, _ := SplitPathVersion(path) +	if err := CheckPathMajor(version, pathMajor); err != nil { +		return &ModuleError{Path: path, Err: err} +	} +	return nil +} + +// firstPathOK reports whether r can appear in the first element of a module path. +// The first element of the path must be an LDH domain name, at least for now. +// To avoid case ambiguity, the domain name must be entirely lower case. +func firstPathOK(r rune) bool { +	return r == '-' || r == '.' || +		'0' <= r && r <= '9' || +		'a' <= r && r <= 'z' +} + +// modPathOK reports whether r can appear in a module path element. +// Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~. +// +// This matches what "go get" has historically recognized in import paths, +// and avoids confusing sequences like '%20' or '+' that would change meaning +// if used in a URL. +// +// TODO(rsc): We would like to allow Unicode letters, but that requires additional +// care in the safe encoding (see "escaped paths" above). +func modPathOK(r rune) bool { +	if r < utf8.RuneSelf { +		return r == '-' || r == '.' || r == '_' || r == '~' || +			'0' <= r && r <= '9' || +			'A' <= r && r <= 'Z' || +			'a' <= r && r <= 'z' +	} +	return false +} + +// importPathOK reports whether r can appear in a package import path element. +// +// Import paths are intermediate between module paths and file paths: we allow +// disallow characters that would be confusing or ambiguous as arguments to +// 'go get' (such as '@' and ' ' ), but allow certain characters that are +// otherwise-unambiguous on the command line and historically used for some +// binary names (such as '++' as a suffix for compiler binaries and wrappers). +func importPathOK(r rune) bool { +	return modPathOK(r) || r == '+' +} + +// fileNameOK reports whether r can appear in a file name. +// For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters. +// If we expand the set of allowed characters here, we have to +// work harder at detecting potential case-folding and normalization collisions. +// See note about "escaped paths" above. +func fileNameOK(r rune) bool { +	if r < utf8.RuneSelf { +		// Entire set of ASCII punctuation, from which we remove characters: +		//     ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~ +		// We disallow some shell special characters: " ' * < > ? ` | +		// (Note that some of those are disallowed by the Windows file system as well.) +		// We also disallow path separators / : and \ (fileNameOK is only called on path element characters). +		// We allow spaces (U+0020) in file names. +		const allowed = "!#$%&()+,-.=@[]^_{}~ " +		if '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' { +			return true +		} +		return strings.ContainsRune(allowed, r) +	} +	// It may be OK to add more ASCII punctuation here, but only carefully. +	// For example Windows disallows < > \, and macOS disallows :, so we must not allow those. +	return unicode.IsLetter(r) +} + +// 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, for a final path element of the form /vN, where N looks numeric +// (ASCII digits and dots) must not begin with a leading zero, must not be /v1, +// and must not contain any dots. For paths beginning with "gopkg.in/", +// this second requirement is replaced by a requirement that the path +// follow the gopkg.in server's conventions. +// Third, no path element may begin with a dot. +func CheckPath(path string) (err error) { +	defer func() { +		if err != nil { +			err = &InvalidPathError{Kind: "module", Path: path, Err: err} +		} +	}() + +	if err := checkPath(path, modulePath); err != nil { +		return err +	} +	i := strings.Index(path, "/") +	if i < 0 { +		i = len(path) +	} +	if i == 0 { +		return fmt.Errorf("leading slash") +	} +	if !strings.Contains(path[:i], ".") { +		return fmt.Errorf("missing dot in first path element") +	} +	if path[0] == '-' { +		return fmt.Errorf("leading dash in first path element") +	} +	for _, r := range path[:i] { +		if !firstPathOK(r) { +			return fmt.Errorf("invalid char %q in first path element", r) +		} +	} +	if _, _, ok := SplitPathVersion(path); !ok { +		return fmt.Errorf("invalid version") +	} +	return nil +} + +// 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). (It must not begin with nor end in a slash.) +// +// A valid path element is a non-empty string made up of +// ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~. +// It must not end with a dot (U+002E), nor contain two dots in a row. +// +// 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). The element +// must not have a suffix of a tilde followed by one or more ASCII digits +// (to exclude paths elements that look like Windows short-names). +// +// CheckImportPath may be less restrictive in the future, but see the +// top-level package documentation for additional information about +// subtleties of Unicode. +func CheckImportPath(path string) error { +	if err := checkPath(path, importPath); err != nil { +		return &InvalidPathError{Kind: "import", Path: path, Err: err} +	} +	return nil +} + +// pathKind indicates what kind of path we're checking. Module paths, +// import paths, and file paths have different restrictions. +type pathKind int + +const ( +	modulePath pathKind = iota +	importPath +	filePath +) + +// checkPath checks that a general path is valid. kind indicates what +// specific constraints should be applied. +// +// checkPath returns an error describing why the path is not valid. +// Because these checks apply to module, import, and file paths, +// and because other checks may be applied, the caller is expected to wrap +// this error with [InvalidPathError]. +func checkPath(path string, kind pathKind) error { +	if !utf8.ValidString(path) { +		return fmt.Errorf("invalid UTF-8") +	} +	if path == "" { +		return fmt.Errorf("empty string") +	} +	if path[0] == '-' && kind != filePath { +		return fmt.Errorf("leading dash") +	} +	if strings.Contains(path, "//") { +		return fmt.Errorf("double slash") +	} +	if path[len(path)-1] == '/' { +		return fmt.Errorf("trailing slash") +	} +	elemStart := 0 +	for i, r := range path { +		if r == '/' { +			if err := checkElem(path[elemStart:i], kind); err != nil { +				return err +			} +			elemStart = i + 1 +		} +	} +	if err := checkElem(path[elemStart:], kind); err != nil { +		return err +	} +	return nil +} + +// checkElem checks whether an individual path element is valid. +func checkElem(elem string, kind pathKind) error { +	if elem == "" { +		return fmt.Errorf("empty path element") +	} +	if strings.Count(elem, ".") == len(elem) { +		return fmt.Errorf("invalid path element %q", elem) +	} +	if elem[0] == '.' && kind == modulePath { +		return fmt.Errorf("leading dot in path element") +	} +	if elem[len(elem)-1] == '.' { +		return fmt.Errorf("trailing dot in path element") +	} +	for _, r := range elem { +		ok := false +		switch kind { +		case modulePath: +			ok = modPathOK(r) +		case importPath: +			ok = importPathOK(r) +		case filePath: +			ok = fileNameOK(r) +		default: +			panic(fmt.Sprintf("internal error: invalid kind %v", kind)) +		} +		if !ok { +			return fmt.Errorf("invalid char %q", r) +		} +	} + +	// Windows disallows a bunch of path elements, sadly. +	// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file +	short := elem +	if i := strings.Index(short, "."); i >= 0 { +		short = short[:i] +	} +	for _, bad := range badWindowsNames { +		if strings.EqualFold(bad, short) { +			return fmt.Errorf("%q disallowed as path element component on Windows", short) +		} +	} + +	if kind == filePath { +		// don't check for Windows short-names in file names. They're +		// only an issue for import paths. +		return nil +	} + +	// Reject path components that look like Windows short-names. +	// Those usually end in a tilde followed by one or more ASCII digits. +	if tilde := strings.LastIndexByte(short, '~'); tilde >= 0 && tilde < len(short)-1 { +		suffix := short[tilde+1:] +		suffixIsDigits := true +		for _, r := range suffix { +			if r < '0' || r > '9' { +				suffixIsDigits = false +				break +			} +		} +		if suffixIsDigits { +			return fmt.Errorf("trailing tilde and digits in path element") +		} +	} + +	return nil +} + +// 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 CheckFilePath(path string) error { +	if err := checkPath(path, filePath); err != nil { +		return &InvalidPathError{Kind: "file", Path: path, Err: err} +	} +	return nil +} + +// badWindowsNames are the reserved file path elements on Windows. +// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file +var badWindowsNames = []string{ +	"CON", +	"PRN", +	"AUX", +	"NUL", +	"COM1", +	"COM2", +	"COM3", +	"COM4", +	"COM5", +	"COM6", +	"COM7", +	"COM8", +	"COM9", +	"LPT1", +	"LPT2", +	"LPT3", +	"LPT4", +	"LPT5", +	"LPT6", +	"LPT7", +	"LPT8", +	"LPT9", +} + +// SplitPathVersion returns prefix and major version such that prefix+pathMajor == path +// and version is either empty or "/vN" for N >= 2. +// As a special case, gopkg.in paths are recognized directly; +// they require ".vN" instead of "/vN", and for all N, not just N >= 2. +// SplitPathVersion returns with ok = false when presented with +// a path whose last path element does not satisfy the constraints +// applied by [CheckPath], such as "example.com/pkg/v1" or "example.com/pkg/v1.2". +func SplitPathVersion(path string) (prefix, pathMajor string, ok bool) { +	if strings.HasPrefix(path, "gopkg.in/") { +		return splitGopkgIn(path) +	} + +	i := len(path) +	dot := false +	for i > 0 && ('0' <= path[i-1] && path[i-1] <= '9' || path[i-1] == '.') { +		if path[i-1] == '.' { +			dot = true +		} +		i-- +	} +	if i <= 1 || i == len(path) || path[i-1] != 'v' || path[i-2] != '/' { +		return path, "", true +	} +	prefix, pathMajor = path[:i-2], path[i-2:] +	if dot || len(pathMajor) <= 2 || pathMajor[2] == '0' || pathMajor == "/v1" { +		return path, "", false +	} +	return prefix, pathMajor, true +} + +// splitGopkgIn is like SplitPathVersion but only for gopkg.in paths. +func splitGopkgIn(path string) (prefix, pathMajor string, ok bool) { +	if !strings.HasPrefix(path, "gopkg.in/") { +		return path, "", false +	} +	i := len(path) +	if strings.HasSuffix(path, "-unstable") { +		i -= len("-unstable") +	} +	for i > 0 && ('0' <= path[i-1] && path[i-1] <= '9') { +		i-- +	} +	if i <= 1 || path[i-1] != 'v' || path[i-2] != '.' { +		// All gopkg.in paths must end in vN for some N. +		return path, "", false +	} +	prefix, pathMajor = path[:i-2], path[i-2:] +	if len(pathMajor) <= 2 || pathMajor[2] == '0' && pathMajor != ".v0" { +		return path, "", false +	} +	return prefix, pathMajor, true +} + +// MatchPathMajor reports whether the semantic version v +// matches the path major version pathMajor. +// +// MatchPathMajor returns true if and only if [CheckPathMajor] returns nil. +func MatchPathMajor(v, pathMajor string) bool { +	return CheckPathMajor(v, pathMajor) == nil +} + +// CheckPathMajor returns a non-nil error if the semantic version v +// does not match the path major version pathMajor. +func CheckPathMajor(v, pathMajor string) error { +	// TODO(jayconrod): return errors or panic for invalid inputs. This function +	// (and others) was covered by integration tests for cmd/go, and surrounding +	// code protected against invalid inputs like non-canonical versions. +	if strings.HasPrefix(pathMajor, ".v") && strings.HasSuffix(pathMajor, "-unstable") { +		pathMajor = strings.TrimSuffix(pathMajor, "-unstable") +	} +	if strings.HasPrefix(v, "v0.0.0-") && pathMajor == ".v1" { +		// Allow old bug in pseudo-versions that generated v0.0.0- pseudoversion for gopkg .v1. +		// For example, gopkg.in/yaml.v2@v2.2.1's go.mod requires gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405. +		return nil +	} +	m := semver.Major(v) +	if pathMajor == "" { +		if m == "v0" || m == "v1" || semver.Build(v) == "+incompatible" { +			return nil +		} +		pathMajor = "v0 or v1" +	} else if pathMajor[0] == '/' || pathMajor[0] == '.' { +		if m == pathMajor[1:] { +			return nil +		} +		pathMajor = pathMajor[1:] +	} +	return &InvalidVersionError{ +		Version: v, +		Err:     fmt.Errorf("should be %s, not %s", pathMajor, semver.Major(v)), +	} +} + +// PathMajorPrefix returns the major-version tag prefix implied by pathMajor. +// An empty PathMajorPrefix allows either v0 or v1. +// +// Note that [MatchPathMajor] may accept some versions that do not actually begin +// with this prefix: namely, it accepts a 'v0.0.0-' prefix for a '.v1' +// pathMajor, even though that pathMajor implies 'v1' tagging. +func PathMajorPrefix(pathMajor string) string { +	if pathMajor == "" { +		return "" +	} +	if pathMajor[0] != '/' && pathMajor[0] != '.' { +		panic("pathMajor suffix " + pathMajor + " passed to PathMajorPrefix lacks separator") +	} +	if strings.HasPrefix(pathMajor, ".v") && strings.HasSuffix(pathMajor, "-unstable") { +		pathMajor = strings.TrimSuffix(pathMajor, "-unstable") +	} +	m := pathMajor[1:] +	if m != semver.Major(m) { +		panic("pathMajor suffix " + pathMajor + "passed to PathMajorPrefix is not a valid major version") +	} +	return m +} + +// CanonicalVersion returns the canonical form of the version string v. +// It is the same as [semver.Canonical] except that it preserves the special build suffix "+incompatible". +func CanonicalVersion(v string) string { +	cv := semver.Canonical(v) +	if semver.Build(v) == "+incompatible" { +		cv += "+incompatible" +	} +	return cv +} + +// 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/go.mod". +func Sort(list []Version) { +	sort.Slice(list, func(i, j int) bool { +		mi := list[i] +		mj := list[j] +		if mi.Path != mj.Path { +			return mi.Path < mj.Path +		} +		// To help go.sum formatting, allow version/file. +		// Compare semver prefix by semver rules, +		// file by string order. +		vi := mi.Version +		vj := mj.Version +		var fi, fj string +		if k := strings.Index(vi, "/"); k >= 0 { +			vi, fi = vi[:k], vi[k:] +		} +		if k := strings.Index(vj, "/"); k >= 0 { +			vj, fj = vj[:k], vj[k:] +		} +		if vi != vj { +			return semver.Compare(vi, vj) < 0 +		} +		return fi < fj +	}) +} + +// EscapePath returns the escaped form of the given module path. +// It fails if the module path is invalid. +func EscapePath(path string) (escaped string, err error) { +	if err := CheckPath(path); err != nil { +		return "", err +	} + +	return escapeString(path) +} + +// EscapeVersion returns the escaped form of the given module version. +// Versions are allowed to be in non-semver form but must be valid file names +// and not contain exclamation marks. +func EscapeVersion(v string) (escaped string, err error) { +	if err := checkElem(v, filePath); err != nil || strings.Contains(v, "!") { +		return "", &InvalidVersionError{ +			Version: v, +			Err:     fmt.Errorf("disallowed version string"), +		} +	} +	return escapeString(v) +} + +func escapeString(s string) (escaped string, err error) { +	haveUpper := false +	for _, r := range s { +		if r == '!' || r >= utf8.RuneSelf { +			// This should be disallowed by CheckPath, but diagnose anyway. +			// The correctness of the escaping loop below depends on it. +			return "", fmt.Errorf("internal error: inconsistency in EscapePath") +		} +		if 'A' <= r && r <= 'Z' { +			haveUpper = true +		} +	} + +	if !haveUpper { +		return s, nil +	} + +	var buf []byte +	for _, r := range s { +		if 'A' <= r && r <= 'Z' { +			buf = append(buf, '!', byte(r+'a'-'A')) +		} else { +			buf = append(buf, byte(r)) +		} +	} +	return string(buf), nil +} + +// UnescapePath returns the module path for the given escaped path. +// It fails if the escaped path is invalid or describes an invalid path. +func UnescapePath(escaped string) (path string, err error) { +	path, ok := unescapeString(escaped) +	if !ok { +		return "", fmt.Errorf("invalid escaped module path %q", escaped) +	} +	if err := CheckPath(path); err != nil { +		return "", fmt.Errorf("invalid escaped module path %q: %v", escaped, err) +	} +	return path, nil +} + +// UnescapeVersion returns the version string for the given escaped version. +// It fails if the escaped form is invalid or describes an invalid version. +// Versions are allowed to be in non-semver form but must be valid file names +// and not contain exclamation marks. +func UnescapeVersion(escaped string) (v string, err error) { +	v, ok := unescapeString(escaped) +	if !ok { +		return "", fmt.Errorf("invalid escaped version %q", escaped) +	} +	if err := checkElem(v, filePath); err != nil { +		return "", fmt.Errorf("invalid escaped version %q: %v", v, err) +	} +	return v, nil +} + +func unescapeString(escaped string) (string, bool) { +	var buf []byte + +	bang := false +	for _, r := range escaped { +		if r >= utf8.RuneSelf { +			return "", false +		} +		if bang { +			bang = false +			if r < 'a' || 'z' < r { +				return "", false +			} +			buf = append(buf, byte(r+'A'-'a')) +			continue +		} +		if r == '!' { +			bang = true +			continue +		} +		if 'A' <= r && r <= 'Z' { +			return "", false +		} +		buf = append(buf, byte(r)) +	} +	if bang { +		return "", false +	} +	return string(buf), true +} + +// MatchPrefixPatterns reports whether any path prefix of target matches one of +// the glob patterns (as defined by [path.Match]) in the comma-separated globs +// list. This implements the algorithm used when matching a module path to the +// GOPRIVATE environment variable, as described by 'go help module-private'. +// +// It ignores any empty or malformed patterns in the list. +// Trailing slashes on patterns are ignored. +func MatchPrefixPatterns(globs, target string) bool { +	for globs != "" { +		// Extract next non-empty glob in comma-separated list. +		var glob string +		if i := strings.Index(globs, ","); i >= 0 { +			glob, globs = globs[:i], globs[i+1:] +		} else { +			glob, globs = globs, "" +		} +		glob = strings.TrimSuffix(glob, "/") +		if glob == "" { +			continue +		} + +		// A glob with N+1 path elements (N slashes) needs to be matched +		// against the first N+1 path elements of target, +		// which end just before the N+1'th slash. +		n := strings.Count(glob, "/") +		prefix := target +		// Walk target, counting slashes, truncating at the N+1'th slash. +		for i := 0; i < len(target); i++ { +			if target[i] == '/' { +				if n == 0 { +					prefix = target[:i] +					break +				} +				n-- +			} +		} +		if n > 0 { +			// Not enough prefix elements. +			continue +		} +		matched, _ := path.Match(glob, prefix) +		if matched { +			return true +		} +	} +	return false +} diff --git a/vendor/golang.org/x/mod/module/pseudo.go b/vendor/golang.org/x/mod/module/pseudo.go new file mode 100644 index 000000000..9cf19d325 --- /dev/null +++ b/vendor/golang.org/x/mod/module/pseudo.go @@ -0,0 +1,250 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Pseudo-versions +// +// Code authors are expected to tag the revisions they want users to use, +// including prereleases. However, not all authors tag versions at all, +// and not all commits a user might want to try will have tags. +// A pseudo-version is a version with a special form that allows us to +// address an untagged commit and order that version with respect to +// other versions we might encounter. +// +// A pseudo-version takes one of the general forms: +// +//	(1) vX.0.0-yyyymmddhhmmss-abcdef123456 +//	(2) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456 +//	(3) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456+incompatible +//	(4) vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456 +//	(5) vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456+incompatible +// +// If there is no recently tagged version with the right major version vX, +// then form (1) is used, creating a space of pseudo-versions at the bottom +// of the vX version range, less than any tagged version, including the unlikely v0.0.0. +// +// If the most recent tagged version before the target commit is vX.Y.Z or vX.Y.Z+incompatible, +// then the pseudo-version uses form (2) or (3), making it a prerelease for the next +// possible semantic version after vX.Y.Z. The leading 0 segment in the prerelease string +// ensures that the pseudo-version compares less than possible future explicit prereleases +// like vX.Y.(Z+1)-rc1 or vX.Y.(Z+1)-1. +// +// If the most recent tagged version before the target commit is vX.Y.Z-pre or vX.Y.Z-pre+incompatible, +// then the pseudo-version uses form (4) or (5), making it a slightly later prerelease. + +package module + +import ( +	"errors" +	"fmt" +	"strings" +	"time" + +	"golang.org/x/mod/internal/lazyregexp" +	"golang.org/x/mod/semver" +) + +var pseudoVersionRE = lazyregexp.New(`^v[0-9]+\.(0\.0-|\d+\.\d+-([^+]*\.)?0\.)\d{14}-[A-Za-z0-9]+(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$`) + +const PseudoVersionTimestampFormat = "20060102150405" + +// PseudoVersion returns a pseudo-version for the given major version ("v1") +// preexisting older tagged version ("" or "v1.2.3" or "v1.2.3-pre"), revision time, +// and revision identifier (usually a 12-byte commit hash prefix). +func PseudoVersion(major, older string, t time.Time, rev string) string { +	if major == "" { +		major = "v0" +	} +	segment := fmt.Sprintf("%s-%s", t.UTC().Format(PseudoVersionTimestampFormat), rev) +	build := semver.Build(older) +	older = semver.Canonical(older) +	if older == "" { +		return major + ".0.0-" + segment // form (1) +	} +	if semver.Prerelease(older) != "" { +		return older + ".0." + segment + build // form (4), (5) +	} + +	// Form (2), (3). +	// Extract patch from vMAJOR.MINOR.PATCH +	i := strings.LastIndex(older, ".") + 1 +	v, patch := older[:i], older[i:] + +	// Reassemble. +	return v + incDecimal(patch) + "-0." + segment + build +} + +// ZeroPseudoVersion returns a pseudo-version with a zero timestamp and +// revision, which may be used as a placeholder. +func ZeroPseudoVersion(major string) string { +	return PseudoVersion(major, "", time.Time{}, "000000000000") +} + +// incDecimal returns the decimal string incremented by 1. +func incDecimal(decimal string) string { +	// Scan right to left turning 9s to 0s until you find a digit to increment. +	digits := []byte(decimal) +	i := len(digits) - 1 +	for ; i >= 0 && digits[i] == '9'; i-- { +		digits[i] = '0' +	} +	if i >= 0 { +		digits[i]++ +	} else { +		// digits is all zeros +		digits[0] = '1' +		digits = append(digits, '0') +	} +	return string(digits) +} + +// decDecimal returns the decimal string decremented by 1, or the empty string +// if the decimal is all zeroes. +func decDecimal(decimal string) string { +	// Scan right to left turning 0s to 9s until you find a digit to decrement. +	digits := []byte(decimal) +	i := len(digits) - 1 +	for ; i >= 0 && digits[i] == '0'; i-- { +		digits[i] = '9' +	} +	if i < 0 { +		// decimal is all zeros +		return "" +	} +	if i == 0 && digits[i] == '1' && len(digits) > 1 { +		digits = digits[1:] +	} else { +		digits[i]-- +	} +	return string(digits) +} + +// IsPseudoVersion reports whether v is a pseudo-version. +func IsPseudoVersion(v string) bool { +	return strings.Count(v, "-") >= 2 && semver.IsValid(v) && pseudoVersionRE.MatchString(v) +} + +// IsZeroPseudoVersion returns whether v is a pseudo-version with a zero base, +// timestamp, and revision, as returned by [ZeroPseudoVersion]. +func IsZeroPseudoVersion(v string) bool { +	return v == ZeroPseudoVersion(semver.Major(v)) +} + +// PseudoVersionTime returns the time stamp of the pseudo-version v. +// It returns an error if v is not a pseudo-version or if the time stamp +// embedded in the pseudo-version is not a valid time. +func PseudoVersionTime(v string) (time.Time, error) { +	_, timestamp, _, _, err := parsePseudoVersion(v) +	if err != nil { +		return time.Time{}, err +	} +	t, err := time.Parse("20060102150405", timestamp) +	if err != nil { +		return time.Time{}, &InvalidVersionError{ +			Version: v, +			Pseudo:  true, +			Err:     fmt.Errorf("malformed time %q", timestamp), +		} +	} +	return t, nil +} + +// PseudoVersionRev returns the revision identifier of the pseudo-version v. +// It returns an error if v is not a pseudo-version. +func PseudoVersionRev(v string) (rev string, err error) { +	_, _, rev, _, err = parsePseudoVersion(v) +	return +} + +// PseudoVersionBase returns the canonical parent version, if any, upon which +// the pseudo-version v is based. +// +// If v has no parent version (that is, if it is "vX.0.0-[…]"), +// PseudoVersionBase returns the empty string and a nil error. +func PseudoVersionBase(v string) (string, error) { +	base, _, _, build, err := parsePseudoVersion(v) +	if err != nil { +		return "", err +	} + +	switch pre := semver.Prerelease(base); pre { +	case "": +		// vX.0.0-yyyymmddhhmmss-abcdef123456 → "" +		if build != "" { +			// Pseudo-versions of the form vX.0.0-yyyymmddhhmmss-abcdef123456+incompatible +			// are nonsensical: the "vX.0.0-" prefix implies that there is no parent tag, +			// but the "+incompatible" suffix implies that the major version of +			// the parent tag is not compatible with the module's import path. +			// +			// There are a few such entries in the index generated by proxy.golang.org, +			// but we believe those entries were generated by the proxy itself. +			return "", &InvalidVersionError{ +				Version: v, +				Pseudo:  true, +				Err:     fmt.Errorf("lacks base version, but has build metadata %q", build), +			} +		} +		return "", nil + +	case "-0": +		// vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456 → vX.Y.Z +		// vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456+incompatible → vX.Y.Z+incompatible +		base = strings.TrimSuffix(base, pre) +		i := strings.LastIndexByte(base, '.') +		if i < 0 { +			panic("base from parsePseudoVersion missing patch number: " + base) +		} +		patch := decDecimal(base[i+1:]) +		if patch == "" { +			// vX.0.0-0 is invalid, but has been observed in the wild in the index +			// generated by requests to proxy.golang.org. +			// +			// NOTE(bcmills): I cannot find a historical bug that accounts for +			// pseudo-versions of this form, nor have I seen such versions in any +			// actual go.mod files. If we find actual examples of this form and a +			// reasonable theory of how they came into existence, it seems fine to +			// treat them as equivalent to vX.0.0 (especially since the invalid +			// pseudo-versions have lower precedence than the real ones). For now, we +			// reject them. +			return "", &InvalidVersionError{ +				Version: v, +				Pseudo:  true, +				Err:     fmt.Errorf("version before %s would have negative patch number", base), +			} +		} +		return base[:i+1] + patch + build, nil + +	default: +		// vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456 → vX.Y.Z-pre +		// vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456+incompatible → vX.Y.Z-pre+incompatible +		if !strings.HasSuffix(base, ".0") { +			panic(`base from parsePseudoVersion missing ".0" before date: ` + base) +		} +		return strings.TrimSuffix(base, ".0") + build, nil +	} +} + +var errPseudoSyntax = errors.New("syntax error") + +func parsePseudoVersion(v string) (base, timestamp, rev, build string, err error) { +	if !IsPseudoVersion(v) { +		return "", "", "", "", &InvalidVersionError{ +			Version: v, +			Pseudo:  true, +			Err:     errPseudoSyntax, +		} +	} +	build = semver.Build(v) +	v = strings.TrimSuffix(v, build) +	j := strings.LastIndex(v, "-") +	v, rev = v[:j], v[j+1:] +	i := strings.LastIndex(v, "-") +	if j := strings.LastIndex(v, "."); j > i { +		base = v[:j] // "vX.Y.Z-pre.0" or "vX.Y.(Z+1)-0" +		timestamp = v[j+1:] +	} else { +		base = v[:i] // "vX.0.0" +		timestamp = v[i+1:] +	} +	return base, timestamp, rev, build, nil +} | 
