From e5e38378601c01e0ea87d9df28202dc5a2c1f133 Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Fri, 12 Jul 2024 14:28:35 -0400 Subject: [PATCH 01/13] RFC: Meta Spec v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new RFC for Meta Spec v2. Based on the [PGXN Meta Sketch] and additional research. Notable differences from v1: * Introduce the term "package" separate from "distribution". The "package" is the bundle of objects being distributed as a…package. * Use only one version for the entire distribution, rather than separate versions for each extension included in the distribution. This allows the deletion of the notes on comparing versions. * Make "Source Distribution" the formal term, but mostly refer to it as "Distribution". Will be distinguished from binary distributions that ship with their own metadata (see #2). * Use JSON data types as the base types instead of generic "list" and "map" types. * Add "Path", "purl", and "Platform" types * Use SPDX License Expressions instead of Perl Software::License-based structures. * Use the term "property" to describe object key/value pairs, to align with JSON Schema. * Use an array of objects to describe maintainers. * Replace the `provides` property with `contents`, with support for multiple kinds of PostgreSQL extensions, including TLEs, loadable modules, and background workers. * Move the `tags` property to the new `classifications` object, and add support for curated categories borrowed from [Trunk]. * Replace `no_index` with `ignore` and use the gitignore format instead of separate lists of files and directories. * Rename `prereqs` to `packages` and move it into the new `dependencies` property, which also has `postgres`, `pipeline`, `platforms`, and `variations` properties. Use [purls]. to specify dependencies, so that any supported packaging dependency can be specified, as well as PGXN packages and Postgres core extensions and tools. * Remove `release_status`; we'll instead depend on [SemVer] to indicate pre-releases. * Simplify the `resources` object and add `badges` to it. * Add the `artifacts` property, so the extension author can include links to other packages or sources for a release. Also configure `#` to hide a line in `json` code blocks and use it to encode proper JSON objects without showing the surrounding braces. Readers can hit the eye button that appears on hover to make the hidden lines appear. [PGXN Meta Sketch]: https://justatheory.com/2024/03/rfc-pgxn-metadata-sketch/ [Trunk]: https://pgt.dev [purls]: https://github.com/package-url/purl-spec/blob/master/PURL-SPECIFICATION.rs [SemVer] https://semver.org --- book.toml | 3 + text/0001-meta-spec-v1.md | 3 + text/0003-meta-spec-v2.md | 1208 +++++++++++++++++++++++++++++++++++++ 3 files changed, 1214 insertions(+) create mode 100644 text/0003-meta-spec-v2.md diff --git a/book.toml b/book.toml index a45cbe4..cf1b2ef 100644 --- a/book.toml +++ b/book.toml @@ -16,3 +16,6 @@ heading-split-level = 0 [output.html.playground] runnable = false + +[output.html.code.hidelines] +json = "#" \ No newline at end of file diff --git a/text/0001-meta-spec-v1.md b/text/0001-meta-spec-v1.md index b9d1ba0..1388908 100644 --- a/text/0001-meta-spec-v1.md +++ b/text/0001-meta-spec-v1.md @@ -7,6 +7,9 @@ * **Category:** Packaging * **Pull Request:** [pgxn/rfcs#1](https://github.com/pgxn/rfcs/pull/1) +> **Note:** This RFC has been superseded by [RFC--3](0003-meta-spec-v2.md). +> However, it remains fully supported by the PGXN toolchain. + Name ==== diff --git a/text/0003-meta-spec-v2.md b/text/0003-meta-spec-v2.md new file mode 100644 index 0000000..460f4bf --- /dev/null +++ b/text/0003-meta-spec-v2.md @@ -0,0 +1,1208 @@ +{{#title PGXN RFC–3 — Meta Spec v2}} +* **RFC:** 3 +* **Title:** PGXN Meta Spec v2 +* **Slug:** `meta-spec-v2` +* **Start Date:** 2024-07-11 +* **Status:** Proposed Standard +* **Category:** Packaging +* **Supersedes:** [RFC--1](0001-meta-spec-v1.md "Meta Spec v1") +* **Pull Request:** [pgxn/rfcs#3](https://github.com/pgxn/rfcs/pull/3) +* **Implementation Issue:** TBD + +# RFC--3 --- Meta Spec v2 + +> **Note:** This RFC Supersedes but does not replace [PGXN Meta Spec +> v1](0001-meta-spec-v1.md). + +## Abstract + +This document describes version 2.0.0 of the [PGXN] source distribution +metadata specification, also known as the "PGXN Meta Spec." PGXN metadata +ships with PGXN source distribution archives, and serves to describe the their +contents for the benefit of automated indexing, distribution, discovery, +full-text search, binary packaging, and more. + +## Introduction + +Distribution metadata describe important properties of source code [archive +files][archive file] distributed on the PostgreSQL Extension Network, or +[PGXN]. Tools that build PGXN source distribution archives must create a +metadata file in accordance with this specification and include it in the +distribution archive for use by automated tools that index, examine, package, +or install PGXN source distributions. + +## Guide-level explanation + +TODO. + + + +### Terminology ### + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", +"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be +interpreted as described in [IETF RFC 2119]. + +This RFC makes use of the following additional terms: + +#### Package #### + +A collection of extensions that are released, versioned, and distributed +together. + +#### Source Distribution #### + +An [archive file] of the source code for the release of a [Package](#package), +together with metadata defined by this spec, distributed for other developers +to build, install, and use. The file name of a Source Distribution consists of +the package name, a dash, and the version, e.g., `pgtap-1.14.3.zip`. + +Usually referred to as a "Distribution", including in this document. The full +term "Source Distribution" is used where necessary to distinguish from binary +distributions of a [Package](#package) (not covered by this RFC). + +#### Extension #### + +A software component that extends the capabilities of a PostgreSQL database or +cluster. Extensions **MAY** be `CREATE EXTENSION` [extensions], [background +workers], command-line apps, [loadable modules], shared libraries, and more. + +#### Consumer #### + +Code that reads a metadata file, deserializes it into a data structure in +memory, or interprets its elements. + +#### Producer #### + +Code that constructs a metadata data structure, serializes it into a byte +stream, and/or writes it to disk. + +## Reference-level explanation + +### Data Types ### + +Properties in the [Structure](#structure) section describe data elements, each +of which has an associated data type as described herein. Each is based on the +primitive types defined by [JSON]: *object*, *array*, *string*, *number*, and +*boolean*. Other types are subtypes of these primitives and define compound +data structures or define constraints on the values of a data element. + +#### Boolean #### + +A *Boolean* is used to provide a true or false value. It **MUST** be +represented as a defined (not `null`) value. + +#### String #### + +A *String* is data element containing a non-zero length sequence of Unicode +characters. + +#### Array #### + +An *Array* is an ordered collection of one or more data elements. Items in an +Array **MAY** be of mixed types. + +#### Object #### + +An **Object** is an unordered set of key/value pairs, or "properties". +Property values are indexed by their corresponding [String](#string) keys. An +Object's values **MAY** be of mixed types. + +#### Term #### + +A *Term* is a [String](#string) that **MUST** be at least two characters long, +and contain no slash (`/`), backslash (`\`), control, or space characters. + +#### Tag #### + +A *Tag* is a [String](#string) that **MUST** be at least two and no more than +255 characters long, and contain no slash (`/`), backslash (`\`), or control +characters. + +#### URI #### + +*URI* is a [String](#string) containing a valid Uniform Resource Identifier or +Locator as defined by [IETF RFC 3986]. + +#### Path #### + +*Path* is a [String](#string) with a relative file path that identifies a file +in the [Distribution](#source-distribution). The path **MUST** be specified +with unix conventions. + +#### Version #### + +A *Version* is a [String](#string) containing a value that describes the +version number of extensions or distributions, and adhere to the format of the +[Semantic Versioning 2.0.0 Specification][semver] with the exception of [Build +metadata], which is reserved for use by downstream packaging systems. + +#### Version Range #### + +A *Version Range* is a [String](#string) that describes a range of +[Versions](#version) that **MAY** be present or installed to fulfill +dependencies. + +The simplest format for a Version Range is just the [Versions](#version) +itself, e.g. `2.4.2`. This means that **at least** version 2.4.2 must be +present. Versions may also be truncated to their major or minor parts, as +appropriate. For example, `2.4` means that **at least** version 2.4.0 must be +present. + +Alternatively, a version range **may** use the operators `<` (less than), `<=` +(less than or equal), `>` (greater than), `>=` (greater than or equal), `==` +(equal), and `!=` (not equal). For example, the specification `< 2` means that +any version less than version 2 is suitable. + +For more complicated situations, version specifications **may** be AND-ed +together using commas. The specification `>= 1.2, != 1.5.2, < 2.0` +indicates a version that must be **at least** 1.2, **less than** 2.0, and +**not equal to** 1.5.2. + +#### License String #### + +A *License String* is a [String](#string) identifying a licenses. Its values +are restricted to and defined by the [SPDX License List]. Examples: + +* `PostgreSQL` +* `MIT` +* `Apache-2.0` +* `BSD-2-Clause` +* `GPL-2.0-only` + +#### License Expression #### + +A *License Expression* is a [String](#string) that represents one or more +licenses by combining [License Strings](#license-string) into a single value. +The format is defined by [SPDX Standard License Expression]. Examples: + +* `LGPL-2.1-only OR MIT` +* `LGPL-2.1-only AND MIT AND BSD-2-Clause` +* `GPL-2.0-or-later WITH Bison-exception-2.2` +* `LGPL-2.1-only OR BSD-3-Clause AND MIT` + +#### purl #### + +A *purl* is a [String](#string) containing a valid package in the format +defined by the [purl spec]. All known [purl Types] **MAY** be used, as well as +`pgxn` for PGXN packages and `postgres` for PostgreSQL core [contrib] or +development packages. Some examples: + +* `pkg:pgxn/pgtap` +* `pkg:postgres:pg_regress` +* `pkg:generic/python3@3` +* `pkg:pypi/pyarrow@11.0.0` + +#### Platform #### + +A *Platform* is a [String](#string) that identifies a computing platform as a +one to three dash-delimited substrings: An OS name, the OS version, and the +architecture: `$os-$version-$architecture`. + +If the string contains no dash, it represents only the OS. If it contains a +single dash, the values represent the OS and the architecture. The complete +list of values will be determined by the [bulid farm animals]. Some likely +Examples: + +* `linux`: Any Linux +* `linux-amd64`: Any Linux on amd64/x86_64 +* `gnulinux-amd64`: [GNU] Linux on amd64/x86_64 +* `musllinux-1.2-arm64`: [musl] Linux v1.2 on arm64/aarch64 +* `darwin`: Any Darwin (macOS) +* `darwin-23.5.0-arm64`: Darwin (macOS) 23.5.0 on arm64/aarch64 + +### Structure + +The metadata structure is an [Object](#object). This section describes valid +properties of the [Object](#object). + +Any properties not described in this specification document (whether top-level +or within [Objects](#object) described herein) are considered *custom +properties* and **MUST** begin with an "x" or "X" and be followed by an +underscore; i.e., they **MUST** match the regular expression pattern +`^[xX]_.`. If a custom property refers to an [Object](#object), properties +within it do not need an "x_" or "X_" prefix. + +Metadata [Consumers](#consumer) **MAY** ignore any or all custom properties. +All other properties not described herein are invalid and **SHOULD** be +ignored by [Consumers](#consumer). [Producers](#producer) **MUST NOT** +generate or output invalid properties. + +For each property, one or more examples are provided followed by a +description. The description begins with the version of spec in which the +property was added or in which the definition was modified, whether the +property is **REQUIRED** or **OPTIONAL**, and the data type of the value. +These items are in parentheses, brackets, and braces, respectively. + +If a data type is an [Object](#object), valid sub-properties will be described +as well. + +All examples are represented as [JSON]. + + + +#### Required Properties + +##### abstract ##### + +``` json +#{ + "abstract": "Unit testing for PostgreSQL" +#} +``` + +(Spec 1) [required] {[String](#string)} + +This is a short description of the purpose of the [Package](#package) provided +by the [Distribution](#source-distribution). + +##### maintainers ##### + +```json +#{ + "maintainers": [ + { + "name": "David E. Wheeler", + "url": "https://pgxn.org/user/theory" + } + ] +#} +``` + +```json +#{ + "maintainers": [ + { + "name": "David E. Wheeler", + "email": "theory@pgxn.org", + "url": "https://pgxn.org/user/theory" + }, + { + "name": "Josh Berkus", + "email": "jberkus@pgxn.org" + } + ] +#} +``` + +(Spec 2) [required] {[Array](#array) of [Objects]{#object}} + +This property indicates the person(s) to contact concerning the +[Distribution](#source-distribution). Each [Object](#object) in the +[Array](#array) consists of the following properties: + +* **name**: The name of the maintainer. **REQUIRED**. +* **email**: The email address of the maintainer. +* **url**: The URL for the maintainer. + +Either `email` or `url` or both **MUST** be present. + +This property provides a general contact list independent of other structured +fields provided within the [resources](#resources) field, such as `issues`. +The addressee(s) can be contacted for any purpose including but not limited +to: (security) problems with the [Distribution](#source-distribution), +questions about the [Distribution](#source-distribution), or bugs in the +[Distribution](#source-distribution). + +A [Distribution](#source-distribution)'s original author is usually the +contact listed within this field. Co-maintainers, successor maintainers, or +mailing lists devoted to the distribution **MAY** also be listed in addition +to or instead of the original author. + +##### license ##### + +``` json +#{ + "license": "MIT" +#} +``` + +``` json +#{ + "license": "MIT AND BSD-2-Clause" +#} +``` + +(Spec 1) [required] {[License String](#license-string) or [License Expression](#license-expression)} + +One or more licenses that apply to some or all of the files in the +[Distribution](#source-distribution). For [License +Expressions](#license-expression), the [Distribution](#source-distribution) +documentation **SHOULD** be consulted to clarify the interpretation of +multiple licenses. + +##### contents ###### + +``` json +#{ + "contents": { + "extensions": { + "pair": { + "sql": "sql/pair.sql", + "doc": "doc/pair.md", + "abstract": "A key/value pair data type", + "preload": "session", + "tle": true, + "control": "pair.control" + } + } + } +#} +``` + +``` json +#{ + "contents": { + "workers": { + "pair_pruner": { + "bin": "bin/pair_pruner", + "doc": "doc/pair_pruner.md", + "abstract": "A worker to periodically prune pairs" + } + }, + "modules": { + "lib_pair": { + "lib": "lib/lib_pair", + "doc": "doc/lib_pair.md", + "abstract": "A library hooking function calls to convert pairs to named parameters", + "load": "shared_preload_libraries" + } + } + } +#} +``` + +``` json +#{ + "contents": { + "apps": { + "pair_rand": { + "bin": "bin/pair_rand", + "doc": "doc/pair_rand.md", + "abstract": "Command to generate random pairs of strings" + } + }, + "libraries": { + "ruby_pair": { + "dir": "lib/gems", + "abstract": "Ruby libraries required to run the extension" + } + } + } +#} +``` + +(Spec 1) [required] {[Object](#object) of [Objects](#object) of [Terms](#term)} + +A description of what's included in the [Package](#package) provided by the +[Distribution](#source-distribution). This information is used by [PGXN] to +build indexes identifying in which [Package](#package) various +[Extensions](#extension) can be found. + +The properties of `contents` identify the types of [Extensions](#extension) in +the [Distribution](#source-distribution). At least one property **MUST** be +present in the `contents` object. The properties are as follows: + +* **extensions**: [Object](#object) describing `CREATE EXTENSION` + [extensions]. Properties are extension name [Terms](#term) pointing to + [Objects](#object) with the following fields: + * **sql**: A [Path](#path) pointing to the SQL file used by `CREATE + EXTENSION`. **REQUIRED**. + * **control**: A [Path](#path) pointing to the [control file] used by + `CREATE EXTENSION`. **REQUIRED**. + * **doc**: A [Path](#path) pointing to the main documentation file for + the extension, which **SHOULD** be more than a README. + * **abstract**: A [String](#string) containing a short description of + the extension. + * **tle**: A [Boolean](#boolean) that, when `true`, indicates that the + extension can be used as a [trusted language extension]. +* **workers**: [Object](#object) describing [background workers]. Properties + are worker name [Terms](#term) pointing to [Objects](#object) with the + following properties: + * **src**: A [Path](#path) pointing to the main source file for the + background worker. **REQUIRED**. + * **doc**: A [Path](#path) pointing to the main documentation file for + the background worker, which **SHOULD** be more than a README. + * **abstract**: A [String](#string) containing a short description of + the background worker. +* **apps**: [Objects](#object) describing applications, command-line or + otherwise. Properties are are app name [Terms](#term) pointing to + [Objects](#object) with the following properties: + * **src**: A [Path](#path) pointing to the main source file for the app. + **REQUIRED**. + * **doc**: A [Path](#path) pointing to the main documentation file for + the app, which **SHOULD** be more than a README. + * **abstract**: A [String](#string) containing a short description of + the app. +* **modules**: [Objects](#object) describing [loadable modules] that can be + loaded into Postgres. Properties are module name [Terms](#term) pointing + to [Objects](#object) with the following properties: + * **src**: A [Path](#path) pointing to the main source file for the + module. **REQUIRED**. + * **doc**: A [Path](#path) pointing to the main documentation file for + the module, which **SHOULD** be more than a README. + * **abstract**: A [String](#string) containing a short description of + the module. + * **preload**: A [String](#string) that indicates that the extension's + libraries **MAY** be loaded in advance. Its three possible values are: + `shared`, `session`, and `local`. Extensions that require early or + late loading of their module **MAY** optionally append a space and + then either `early` or `late`. +* **libraries**: [Objects](#object) listing other libraries that **MAY** + ship in the package and need to be installed but are not [loadable + modules], such as a dynamic library used by an app. Properties are library + name [Terms](#term) pointing to [Objects](#object) with the following + properties: + * **src**: A [Path](#path) pointing to the main source file or directory + of files for the library. **REQUIRED**. + * **doc**: A [Path](#path) pointing to the main documentation file for + the library, which **SHOULD** be more than a README. + * **abstract**: A [String](#string) containing a short description of + the app. + +##### meta-spec ##### + +``` json +#{ + "meta-spec": { + "version": "2.0.0", + "url": "https://pgxn.org/meta/v2/spec.txt" + } +#} +``` + +(Spec 1) [required] {[Map](#Map)} + +This field indicates the [Version](#Version) of the PGXN Meta Spec that +**SHOULD** be used to interpret the metadata. Consumers **MUST** check this +key as soon as possible and abort further metadata processing if the meta-spec +[Version](#version) is not supported by the consumer. + +The following properties are valid, but only `version` is **REQUIRED**. + +* **version**: The [Version](#version) of the PGXN Meta Spec against which + the metadata object was generated. + +* **url**: The [URI](#uri) of the metadata specification corresponding to + the given version. This is strictly for human-consumption and **SHOULD + NOT** impact the interpretation of the metadata structure. + +##### name ##### + +Example: + +``` json +#{ + "name": "pgTAP" +#} +``` + +(Spec 1) [required] {[Term](#Term)} + +This property is the name of the [Package](#package) provided by the +[Distribution](#source-distribution). This is usually the same as the name of +the "main extension" in the [contents](#contents) of the [Package](#package), +but **MAY** be completely unrelated. This value will be used in the +[Distribution](#source-distribution) file name on [PGXN]. + +##### version ##### + +``` json +#{ + "version": "1.3.6" +#} +``` + +(Spec 1) [required] {[Version](#version)} + +This property gives the version of the [Distribution](#source-distribution) to +which the metadata structure refers. Its value **MUST** be a +[Version](#version). + +All of the items listed in [contents](#contents) will be considered to have +this version; any references they make to a version, such as the [control +file], **SHOULD** be compatible with this version. + +#### Optional Fields #### + +##### description ##### + +``` json +#{ + "description": "pgTAP is a suite of database functions that make it easy to write TAP-emitting unit tests in psql scripts or xUnit-style test functions." +#} +``` + +(Spec 1) [optional] {[String](#string)} + +A longer, more complete description of the purpose or intended use of the +[Package](#package) provided by the [Distribution](#source-distribution), +answering the question "what is this thing and what value is it?" + +##### generated_by ##### + +Example: + +``` json +#{ + "generated_by": "Module::Build::PGXN version 0.42" +#} +``` + +(Spec 1) [optional] {[String](#string)} + +This property indicates the tool that was used to create this metadata. There +are no defined semantics for this property, but it is traditional to use a +string in the form "Software package version 1.23", or the maintainer's name +if the metadata was generated by hand. + +##### classification ##### + +``` json +#{ + "classifications": { + "tags": [ + "testing", + "pair", + "parameter" + ], + "categories": [ + "Machine Learning" + ] + } +#} +``` + +(Spec 2) [optional] {[Object](#object) of [Arrays](#array) of [Tags](#tag)} + +Classification metadata associates additional information about the +[Package](#package) provided by the [Distribution](#source-distribution) to +improve discovery. This [Object](#object) **MUST** contain at least one of the +following properties: + +* **tags**: An [Array](#array) of one or more keyword [Tags](#tag)s that + describe the distribution. +* **categories**: An [Array](#array) of at least one and no more than three + of the following [Strings](#string) that categorize the distribution: + * Analytics + * Auditing and Logging + * Change Data Capture + * Connectors + * Data and Transformations + * Debugging + * Index and Table Optimizations + * Machine Learning + * Metrics + * Orchestration + * Procedural Languages + * Query Optimizations + * Search + * Security + * Tooling and Admin + +#### ignore #### + +``` json +#{ + "ignore": [ + "/src/private", + "/src/file.sql", + "*.html" + ] +#} +``` + +(Spec 2) [optional] {[Array](#Array) of [Strings](#string)} + +This [Array](#array) describes any files or directories that are private to +the [Distribution](#source-distribution) and **SHOULD** be ignored by indexing +or search tools. Values are [Paths](#path) or [Strings](#string) based on a +subset of the [gitignore format]. + +##### dependencies ##### + +``` json +#{ + "dependencies": { + "postgres": { + "version": "14" + }, + } +#} +``` + +``` json +#{ + "dependencies": { + "postgres": { + "version": ">= 12, < 17", + "with": [ "xml", "uuid", "perl" ] + }, + "pipeline": "pgxs", + "packages": { + "build": { + "requires": { + "pkg:generic/awk": 0, + "pkg:generic/perl": "5.20" + }, + "recommends": { + "pkg:generic/jq": 0, + "pkg:generic/perl": "5.40" + } + } + } + } +#} +``` + +``` json +#{ + "dependencies": { + "pipeline": "pgrx", + "platforms": [ + "linux-amd64", + "linux-amd64v3", + "gnulinux-arm64", + "musllinux-amd64", + "darwin-23.5.0-arm64" + ], + "packages": { + "configure": { + "requires": { "pkg:cargo/cargo-pgrx": "=0.11.4" } + }, + "test": { + "requires": { + "pkg:postgres/pg_regress": 0, + "pkg:postgres/plpgsql": 0, + "pkg:pgxn/pgtap": "1.1.0" + } + }, + "run": { + "requires": { + "pkg:postgres/plperl": 0, + "pkg:pgxn/hostname": 0 + } + } + } + } +#} +``` + +``` json +#{ + "dependencies": { + "postgres": { + "version": ">= 15, < 16" + }, + "pipeline": "pgxs", + "platforms": [ + "linux-amd64", "linux-arm64", + "darwin-amd64", "darwin-arm64" + ], + "packages": { + "configure": { + "requires": { + "pkg:cargo/cargo-pgrx": "=0.11.4", + "pkg:generic/bison": 0, + "pkg:generic/cmake": 0, + "pkg:generic/flex": 0, + "pkg:generic/readline": 0, + "pkg:generic/openssl": 0, + "pkg:generic/pkg-config": 0 + } + }, + "run": { + "requires": { + "pkg:generic/penblas": 0, + "pkg:generic/python3": 0, + "pkg:generic/readline": 0, + "pkg:generic/openssl": 0, + "pkg:generic/bison" + }, + "recommends": { + "pkg:pypi/pyarrow": "11.0.0", + "pkg:pypi/catboost": 0, + "pkg:pypi/lightgbm": 0, + "pkg:pypi/torch": 0, + "pkg:pypi/langchain": 0 + } + } + }, + "variations": [ + { + "where": { + "platforms": ["linux"] + }, + "dependencies": { + "packages": { + "run": { + "recommends": { + "pkg:pypi/auto-gptq": 0, + "pkg:pypi/xformers": 0 + } + } + } + } + } + ] + } +#} +``` + +(Spec 2) [optional] {[Object](#object)} + +This property identifies dependencies required to configure, build, test, +install, and run the [Package](#package) provided by the +[Distribution](#source-distribution), expressed as [purls](#purl). These +include not only PGXN packages, but also external libraries, system +dependencies, and versions of PostgreSQL --- as well as any OS and +architectures ([arm64], [amd64], etc.). + +[Consumers](#consumer) **SHOULD** use this data to determine what dependencies +to install. + +Properties: + +* **platforms**: An [Array](#array) of one or more [Platform](#platform) + strings that identify OSes and architectures supported by the + [Package](#package) provided by the [Distribution](#source-distribution). + If this property is not present, [Consumers](#consumer) **SHOULD** assume + that the [Package](#package) supports any platform that PostgreSQL + supports. This property is typically needed only when the + [Package](#package) depends on platform-specific features. + +* **postgres**: An [Object](#object) describing the versions of PostgreSQL + required by the [Package](#package) provided by the + [Distribution](#source-distribution). The object supports the following + properties: + * **version**: A [Version Range](#version-range) identifying the + supported versions of PostgreSQL. **REQUIRED**. + * **with**: An [Array](#array) of [Terms](#term) that correspond + features that are required to be compiled into PostgreSQL. Each + corresponds to the appropriate `--with` [configure flags]. + **OPTIONAL**. + +* **pipeline**: A [Term](#term) identifying the build pipeline required to + configure, build, test, and install the [Package](#package) provided by + the [Distribution](#source-distribution). Supported values + **MAY** include: + + * pgxs + * meson + * pgrx + * autoconf + * gem + * cpan + * pip + * go + * rust + + If this field is not present, [Consumers](#consumer) **MAY** use + heuristics to ascertain the pipeline to use, such as the presence or + absence of a `configure.sh`, `Makefile`, or `Cargo.toml` file. + +* **packages**: An [Object](#object) defining dependencies required for + different phases of the build process. The supported property names are + `configure`, `build`, `test`, `run`, and `develop`. Values are + [Objects](#object) with at least one of the properties `requires`, + `recommends`, `suggests`, and `conflicts` pointing to [Objects](#object) + with [purls](#purl) property keys pointing to [Version + Range](#version-range) values. + + See the [Package Spec](#packages-spec) for the full definition of this + property. + +* **variations**: An [Array](#array) of [Object](#object)s that define + dependency variations. Each object contains two properties: + * **where**: An [Object](#object) containing the subset of the + [dependencies](#dependencies) to identify a variation, such as + `{ "platforms": ["gnulinux-arm64", "gnulinux-amd64"] }` for Linux + configurations, or `{"postgres": { "version": ">= 16, < 17" }}` for + PostgreSQL versions. **MUST NOT** include a `variations` property. + * **dependencies**: An [Object](#object) containing the subset of + [dependencies](#dependencies) required for the `where` property's + configuration. **MUST NOT** include a `variations` property. + +##### resources ##### + +``` json +#{ + "resources": { + "homepage": "https://pair.example.com", + "issues": "https://github.com/example/pair/issues", + "docs": "https://pair.example.com/docs", + "support": "https://github.com/example/pair/discussions", + "repository": "https://github.com/example/pair", + "badges": [ + { + "alt": "Test Status", + "src": "https://test.packages.postgresql.org/github.com/example/pair.svg" + } + ] + } +#} +``` + +(Spec 2) [optional] {[Object](#object)} + +This property provides external information about the [Package](#package) +provided by the [Distribution](#source-distribution). [Consumers](#consumer) +**MAY** use this data for links and displaying useful information about the +package. + +The `resources` object **MUST** contain at least one of the following +properties: + +* **homepage**: [URI](#uri) for the official home of the project on the web. +* **issues**: [URI](#uri) for the package's issue tracking system. +* **repository**: [URI](#uri) for the package's source code repository. +* **docs**: [URI](#uri) for the package's documentation. +* **support**: [URI](#uri) for support resources and contacts for the + package. +* **badges**: An [Array](#array) of [Objects](#object) linking to badge + images that **SHOULD** follow the [Shields badge specification]. It + **MUST** have at least one entry, and all entries require two properties: + * **src**: The [URI](#uri) for the badge. + * **alt**: Alt text for the badge. + +##### artifacts ##### + +``` json +#{ + "artifacts": [ + { + "type": "source", + "url": "https://github.com/theory/pg-pair/releases/download/v1.1.0/pair-1.1.0.zip", + "sha256": "2b9d2416096d2930be51e5332b70bcd97846947777a93e4a3d65fe1b5fd7b004" + }, + { + "type": "binary", + "url": "https://github.com/theory/pg-pair/releases/download/v1.1.0/pair-1.1.0-linux-amd64.tar.gz", + "sha1": "12d9bc5cfb6bc3c453627eac69511f48be63cfc0" + }, + { + "type": "binary", + "url": "https://github.com/theory/pg-pair/releases/download/v1.1.0/pair-1.1.0-linux-arm64.tar.gz", + "sha1": "787dc39137f7d1510a33ab0a1b8905cd5f3f72d1" + } + ] +#} +``` + +(Spec 2) [optional] {[Array](#array)} + +An [Array](#array) of [Objects](#objects) describing links and checksums for +downloading the [Package](#package) provided by the +[Distribution](#source-distribution) in one or more formats, including source +code, binaries, system packages, and more. [Consumers](#consumer) my use this +information to determine the best option for installing an extension on a +particular system. Useful for projects that publish their own binaries, such +as in GitHub releases. + +The [Array](#array) **MUST** have at least one [Object](#object). The +properties of each [Object](#object) are: + +* **url**: A [URI](#uri) to download the artifact. **REQUIRED**. +* **sha256** or **sha512**: A [String](#string) containing a SHA-256 or + SHA-512 checksum in hex format. **REQUIRED**. +* **type**: The type of artifact. **MUST** be a single lowercase word + describing the artifact, such as none of `binary`, `source`, `rpm`, + `homebrew`, etc. **REQUIRED**. +* **platform**: A [Platform](#platform) string identifying the platform the + artifact was built for. **RECOMMENDED** for packages compiled for a + specific platform, such as a C [Extension](#extension) compiled for + `linux-arm64`. + +Each URL **MUST** properly resolve and the checksum **MUST** match. + +### Packages Spec ### + +The `packages` sub-property of the [dependencies](#dependencies) property +defines the relationship between a [Distribution](#source-distribution) and +external dependencies --- including other PGXN [Packages](#package), system +packages, and third-party packages --- expressed as [purls](#purl). The +structure is an [Object](#object) that specifies package dependencies into +*Phases* of activity in the installation process, and *Relationships* that +indicate how dependencies **SHOULD** be resolved. + +For example, to specify that the [PGXN] extension `pgtap` is required during +the `test` phase, this entry would appear in the +[Distribution](#source-distribution) metadata: + +``` json +#{ + "packages": { + "test": { + "requires": { "pkg:pgxn/pgtap": 0 } + } + } +#} +``` + +All known [purl Types] **SHOULD** be used to identify dependencies. +[Producers](#producer) **MAY** specify dependencies of two additional types as +appropriate: + +* **`pkg:pgxn`**: Packages distributed via [PGXN]. These **MUST** include + package name, e.g., `pkg:pgxn/pair`. +* **`pkg:postgres`**: Dependencies distributed as part of the PostgreSQL + core, including [contrib] or development packages such as [auto_explain], + [dblink], [pg_regress], and [pg_isolation_regress]. Example: + `pkg:postgres/dblink`. + +Versions **SHOULD** not be included in [purls](#purl), but in the [Version +Range](#version-range) values the [purls](#purl) properties point to. For +example, this specification requires the `pair` PGXN package version 1.2.0 or +greater but not 1.5.2: + + +``` json +#{ + "packages": { + "test": { + "requires": { "pkg:pgxn/pair": ">= 1.2, != 1.5.2" } + } + } +#} +``` + +[Producers](#producer) **SHOULD** avoid OS-specific [purls](#purl) such as +`pkg:rpm:/libreadline-dev` unless the [Distribution](#source-distribution) +supports only OSes that provide such packages. See the "variations" property +of the [dependencies](#dependencies) object for platform-specific dependency +specification. + +[Consumers](#consumer) **SHOULD** use [Repology] to resolve `pkg:generic` +[purls](#purl) to packages specific to the platform on which an extension is +being built. This is useful for specifying system dependencies that vary by +name and packaging system. Otherwise, they **MAY** use whatever techniques or +heuristics are appropriate to install dependencies. + +#### Phases #### + +Requirements for regular use **MUST** be listed in the `runtime` phase. Other +requirements **SHOULD** be listed in the earliest stage in which they are +required, and [Consumers](#consumer) **MUST** accumulate and satisfy +requirements across phases before executing the action. For example, `build` +requirements **MUST** also be available during the `test` phase. + + before action | requirements that **MUST** be met +----------------|----------------------------------- + ./configure | configure + make | configure, runtime, build + make test | configure, runtime, build, test + +Consumers that install the [Package](#package) provided by the +[Distribution](#source-distribution) **MUST** ensure that *runtime* +requirements are also installed and **MAY** install dependencies from other +phases. + + after action | requirements that **MUST** be met +----------------|----------------------------------- + make install | runtime + +* **configure**: The configure phase occurs before any dynamic configuration + has been attempted. Dependencies required by the configure phase **MUST** + be available for use before the build tool has been executed. + +* **build**: The build phase is when the + [Distribution](#source-distribution)'s source code is compiled (if + necessary) and otherwise made ready for installation. + +* **test**: The test phase is when the + [Distribution](#source-distribution)'s automated test suite is run. Any + dependency needed only for testing and not for subsequent use **SHOULD** + be listed here. + +* **runtime**: The runtime phase refers not only to when the contents of the + [Package](#package) provided by the [Distribution](#source-distribution) + are installed, but also to its continued use. Any package that is a + dependency for regular use of this [Package](#package) **SHOULD** be + indicated here. + +* **develop**: The develop phase's packages are needed to work on the + [Package](#package)'s source code as its maintainer does. These tools + might be needed to build a release archive, to run maintainer-only tests, + or to perform other tasks related to developing new versions of the + [Package](#package). + +#### Relationships #### + +* **requires**: These dependencies **MUST** be installed for proper + completion of the phase. + +* **recommends**: **RECOMMENDED** dependencies are *strongly* encouraged and + **SHOULD** be satisfied except in resource constrained environments. + +* **suggests**: These dependencies are **OPTIONAL**, are suggested for + enhanced operation of the described distribution, and **MAY** be + satisfied. + +* **conflicts**: These dependencies **MUST NOT** be installed when the phase + is in operation. This is a very rare situation, and the conflicts + relationship **SHOULD** be used with great caution, or not at all. + +### Serialization ### + +Distribution metadata **SHOULD** be serialized as JSON-encoded data and +packaged with distributions as the file `META.json`. + +## Drawbacks + +This design adds significant complexity over and above that provided by the +[v1 spec](0001-meta-spec-v1.md). The features and services planned for PGXN, +including automated binary packaging require that complexity, however. That +said, the [v1 spec](0001-meta-spec-v1.md) remains valid and can continue to be +used by projects unless they need additional metadata to support new features. + +We plan to develop an [SDK] and [CLI] to reduce or eliminate the toil of +maintaining the metadata, and to automate conversion from the [v1 +spec](0001-meta-spec-v1.md) when new features are needed. + +## Rationale and alternatives + +There are currently no developer-focused alternatives to the PGXN Meta Spec. +Other extension registries, such as [Trunk], [PGXMan], [StackBuilder], and +the community [Yum] and Apt repositories decouple maintenance of build +metadata and dependencies, in particular, from the developer. Instead they're +independently and manually managed by volunteers or employees of teh companies +who developed them. + +They also tend to have formats specific to the platforms they serve, rather +than to PostgreSQL specifically. + +Without this metadata, it would be difficult to develop a cross-platform, +community binary packaging registry of all PGXN distributions. With this +format, even if extension authors don't adopt the new format, PGXN maintainers +can develop PGXN Meta Spec v2 overlays to merge with developer [v1 +spec](0001-meta-spec-v1.md) files, both to assist with build automation and to +create pull requests for the original projects. + +## Prior art + +The PGXN Meta Spec v2 is based on the [v1 spec](0001-meta-spec-v1.md), which +is itself based on the [CPAN Meta Spec]. Dependency specification is inspired +by the [purl spec] and [Repology], as well as the [RPM Packaging Guidelines]. + +## Unresolved questions + +* Can we rely on [Repology] to resolve system dependencies? +* How, exactly, do we configure loadable modules, esp when used with an + extension? +* Is it better to bundle dependencies into a package as loadable modules, or + to create separate distributions that just contain the loadable modules + and depend on them? +* Should any of this be deferred? For example, maybe omit the `archives` + property. +* Do we need to continue to treat package names as globally unique, or can + we categorize under username? This has implications for integration into + existing PGXN services; perhaps it'd be better to keep uniqueness as it is + and look to change it at some future time? +* What controls do we need to encode into badges in the + [resources](#resources) object? Do we limit URL formats or domains to + prevent crapping things up? Does it matter? +* Can we get away with allowing only one version for the entire + distribution? This is a change from the [v1 spec](0001-meta-spec-v1.md), + which allowed independent versions for each extension included in a + distribution. Many people found the version variation confusing. Will + developers find it too painful to switch? Very few extensions on PGXN + currently include more than one extension, so hopefully not. + +## Future possibilities + +Successful adoption of this standard will mean most extensions use it to +distribute on PGXN. We'll separately need an initiative to work with extension +authors to onboard them into PGXN, perhaps by pull requests adding the +metadata and CI workflows. + +Or perhaps in the future we'll be able to recognize extensions on GitHub and +other repositories and automatically index them. Seems tricky without +[Go-style module paths]. + +## See Also ## + +* [CPAN Meta Spec] +* [PGXN] +* [JSON] +* [Semantic Versioning 2.0.0][semver] +* [Repology] +* [purl spec] + +## Contributors ## + +The PGXN Meta Spec was originally based on the [CPAN Meta Spec], which was +written by Ken Williams in 2003 and has since been updated by Randy Sims, +David Golden, Ricardo Signes, Adam Kennedy, and contributors. + + [PGXN]: https://pgxn.org "PostgreSQL Extension Network" + [source code repository]: https://github.org/pgxn/pgxn-meta-spec + [PostgreSQL License]: https://www.postgresql.org/about/licence/ + [CC BY-SA 4.0]: https://creativecommons.org/licenses/by-sa/4.0/ "Attribution-Sharealike 4.0 International" + [Github Flavored Markdown]: https://github.github.com/gfm/ + [Markdown]: https://daringfireball.net/projects/markdown/ + [master.pgxn.org/meta/spec.txt]: https://master.pgxn.org/meta/spec.txt + [pgxn.org/spec/]: https://pgxn.org/spec/ + [archive file]: https://en.wikipedia.org/wiki/Archive_file + "Wikipedia: “Archive file”" + [`semver`]: https://pgxn.org/dist/semver/ + [`vector`]: https://pgxn.org/dist/vector/ + [`citus`]: https://pgxn.org/dist/citus/ + [`CREATE EXTENSION` statement]: https://www.postgresql.org/docs/current/static/sql-createextension.html + [IETF RFC 2119]: https://www.ietf.org/rfc/rfc2119.txt + [JSON]: https://json.org/ + [IETF RFC 3986]: https://www.rfc-editor.org/info/rfc3986 + "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax" + [purl spec]: https://github.com/package-url/purl-spec/blob/master/PURL-SPECIFICATION.rst + "package-url/purl-spec: A minimal specification a “mostly universal” package URL" + [percent-encoded]: https://github.com/package-url/purl-spec/blob/master/PURL-SPECIFICATION.rst#character-encoding + "Package URL specification: Character encoding" + [purl Types]: https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst + "Package URL Type definitions" + [semver]: https://semver.org/ + [SPDX License List]: https://github.com/spdx/license-list-data/ + [SPDX Standard License Expression]: https://spdx.github.io/spdx-spec/v3.0/annexes/SPDX-license-expressions/ + [control file]: https://www.postgresql.org/docs/current/extend-extensions.html + [trusted language extension]: https://github.com/aws/pg_tle + "pg_tle: Framework for building trusted language extensions for PostgreSQL" + [background workers]: https://www.postgresql.org/docs/current/bgworker.html + "PostgreSQL Docs: Background Worker Processes" + [loadable modules]: https://www.postgresql.org/docs/16/gist-extensibility.html + [gitignore format]: https://git-scm.com/docs/gitignore + [bulid farm animals]: https://buildfarm.postgresql.org/cgi-bin/show_members.pl + [configure flags]: https://www.postgresql.org/docs/current/install-make.html#CONFIGURE-OPTIONS-FEATURES + [Repology API]: https://repology.org/api "Repology, the packaging hub: API" + [contrib]: https://www.postgresql.org/docs/current/contrib.html + [auto_explain]: https://www.postgresql.org/docs/current/auto-explain.html + [dblink]: https://www.postgresql.org/docs/current/dblink.html + [pg_regress]: https://github.com/postgres/postgres/tree/master/src/test/regress + [pg_isolation_regress]: https://github.com/postgres/postgres/tree/master/src/test/isolation + [Shields badge specification]: https://github.com/badges/shields/blob/master/spec/SPECIFICATION.md + [CPAN Meta Spec]: https://metacpan.org/pod/CPAN::Meta::Spec + [musl]: https://musl.libc.org/ + [GNU]: https://www.gnu.org/software/libc/ + [SDK]: https://en.wikipedia.org/wiki/Software_development_kit + "Wikipedia: Software development kit" + [CLI]: https://en.wikipedia.org/wiki/Command-line_interface + "Wikipedia: Command-line interface" + [Repology]: https://repology.org/ "Repology, the packaging hub" + [RPM Packaging Guidelines]: https://docs.fedoraproject.org/en-US/packaging-guidelines/ + [Go-style module paths]: https://go.dev/ref/mod#module-path From e3bc4c6b2f2663760a77753cf5077c2e80e1cd3a Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Fri, 12 Jul 2024 17:47:11 -0400 Subject: [PATCH 02/13] New pass through RFC-3; various improvements: * Add the "Package Name" type that disallows leading digits. [Discussion](https://github.com/pgxn/rfcs/pull/2#discussion_r1674980330). * Document the Number type and allow `0` as a valid value for a Version Range. * Add the "Path Pattern" type and use it for the "ignore" property. * Merge "License" into "License Expression" * Rename "Version" to "SemVer", to distinguish it from any other versions used for dependencies. * Make "Version Range" not-specific to SemVers, since it's used for all sorts of dependency version requirements. Also, disallow version truncation in Version Ranges, since different version formats will have different rules. * Document that purl version expressions are valid but ignored. * Fix various spelling, grammatical, syntax, and narrative errors and clumsiness. * Update spec URLs to point to rfcs.pgxn.org. * Rename `generated_by` to `producer`. * Add question about preloading. * Note quality binary distribution as sign of success. --- text/0003-meta-spec-v2.md | 287 +++++++++++++++++++++----------------- 1 file changed, 159 insertions(+), 128 deletions(-) diff --git a/text/0003-meta-spec-v2.md b/text/0003-meta-spec-v2.md index 460f4bf..c17feac 100644 --- a/text/0003-meta-spec-v2.md +++ b/text/0003-meta-spec-v2.md @@ -26,7 +26,7 @@ full-text search, binary packaging, and more. Distribution metadata describe important properties of source code [archive files][archive file] distributed on the PostgreSQL Extension Network, or -[PGXN]. Tools that build PGXN source distribution archives must create a +[PGXN]. Tools that create PGXN source distribution archives must write a metadata file in accordance with this specification and include it in the distribution archive for use by automated tools that index, examine, package, or install PGXN source distributions. @@ -67,20 +67,23 @@ together. #### Source Distribution #### -An [archive file] of the source code for the release of a [Package](#package), -together with metadata defined by this spec, distributed for other developers -to build, install, and use. The file name of a Source Distribution consists of -the package name, a dash, and the version, e.g., `pgtap-1.14.3.zip`. +An [archive file] of the source code for the release of single version of a +[Package](#package), together with metadata defined by this spec, distributed +for other DBAs, packagers, and developers to build, install, and use. The file +name of a Source Distribution consists of the [Package Name](#package-name), a +dash, and the [SemVer](#semver) version, e.g., `pgtap-1.14.3.zip`. Usually referred to as a "Distribution", including in this document. The full term "Source Distribution" is used where necessary to distinguish from binary -distributions of a [Package](#package) (not covered by this RFC). +distributions of a [Package](#package), as in +[RFC--2](0002-binary-distribution-format.md). #### Extension #### -A software component that extends the capabilities of a PostgreSQL database or -cluster. Extensions **MAY** be `CREATE EXTENSION` [extensions], [background -workers], command-line apps, [loadable modules], shared libraries, and more. +A software component that extends the capabilities of or experience using a +PostgreSQL database or cluster. Extensions **MAY** be `CREATE EXTENSION` +[extensions], [background workers], command-line apps, [loadable modules], +shared libraries, and more. #### Consumer #### @@ -112,6 +115,10 @@ represented as a defined (not `null`) value. A *String* is data element containing a non-zero length sequence of Unicode characters. +#### Number #### + +A *Number* is an integer or decimal number. + #### Array #### An *Array* is an ordered collection of one or more data elements. Items in an @@ -128,6 +135,15 @@ Object's values **MAY** be of mixed types. A *Term* is a [String](#string) that **MUST** be at least two characters long, and contain no slash (`/`), backslash (`\`), control, or space characters. +#### Package Name #### + +A *Package Name* is a [String](#string) with the following constraints: + +* **MUST** be at least two characters long. +* **MUST NOT** start with a digit or include a digit after a dash (`-`) +* **MUST NOT** contain slash (`/`), backslash (`\`), control, or space + characters. + #### Tag #### A *Tag* is a [String](#string) that **MUST** be at least two and no more than @@ -143,54 +159,65 @@ Locator as defined by [IETF RFC 3986]. *Path* is a [String](#string) with a relative file path that identifies a file in the [Distribution](#source-distribution). The path **MUST** be specified -with unix conventions. - -#### Version #### - -A *Version* is a [String](#string) containing a value that describes the -version number of extensions or distributions, and adhere to the format of the -[Semantic Versioning 2.0.0 Specification][semver] with the exception of [Build -metadata], which is reserved for use by downstream packaging systems. +with Unix conventions. + +#### Path Pattern #### + +*Path Pattern* is a [String](#string) that defines a pattern to identify one +or more files in the [Distribution](#source-distribution). Its format, based +on the [gitignore format] and [fnmatch], is as follows: + +* The slash (`/`) is used as the directory separator. Separators may occur + at the beginning, middle or end of the pattern. +* If there is a separator at the beginning or middle (or both) of the + pattern, then the pattern is relative to the root directory level of the + [Distribution](#source-distribution). Otherwise the pattern may also match + at any level below the root directory. +* If there is a separator at the end of the pattern then the pattern will + only match directories, otherwise the pattern can match both files and + directories. +* An asterisk `(*)` matches anything except a slash. The character `?` + matches any one character except `/` The range notation, e.g. [a-zA-Z], + can be used to match one of the characters in a range. + +#### SemVer #### + +A *SemVer* is a [String](#string) containing a value that describes the +version number of extensions or distributions, and adheres to the format of +the [Semantic Versioning 2.0.0 Specification][semver] with the exception of +[Build metadata], which is reserved for use by downstream packaging systems. #### Version Range #### -A *Version Range* is a [String](#string) that describes a range of -[Versions](#version) that **MAY** be present or installed to fulfill -dependencies. +A *Version Range* is a [String](#string) or [Number](#number) that describes a +range of [SemVers](#semver) or other versioning format that **MAY** be present +or installed to fulfill dependencies. + +A Version Range of the number `0` indicates all available versions. No other +[Number](#number) values are allowed. -The simplest format for a Version Range is just the [Versions](#version) -itself, e.g. `2.4.2`. This means that **at least** version 2.4.2 must be -present. Versions may also be truncated to their major or minor parts, as -appropriate. For example, `2.4` means that **at least** version 2.4.0 must be -present. +Often a Version Range is just a single version. For a [SemVer], for example, +`2.4.2` means that **at least** version 2.4.2 must be present. Alternatively, a version range **may** use the operators `<` (less than), `<=` (less than or equal), `>` (greater than), `>=` (greater than or equal), `==` -(equal), and `!=` (not equal). For example, the specification `< 2` means that -any version less than version 2 is suitable. +(equal), and `!=` (not equal). For example, the specification `< 2.0` means +that any version less than version 2.0 is suitable. For more complicated situations, version specifications **may** be AND-ed -together using commas. The specification `>= 1.2, != 1.5.2, < 2.0` -indicates a version that must be **at least** 1.2, **less than** 2.0, and +together using commas. The specification `>= 1.2.0, != 1.5.2, < 2.0.0` +indicates a version that must be **at least** 1.2.0, **less than** 2.0.0, and **not equal to** 1.5.2. -#### License String #### +#### License Expression #### -A *License String* is a [String](#string) identifying a licenses. Its values -are restricted to and defined by the [SPDX License List]. Examples: +A *License Expression* is a [String](#string) that represents one or more +licenses from the [SPDX License List] in a single value. The format is defined +by [SPDX Standard License Expression]. Examples: * `PostgreSQL` * `MIT` * `Apache-2.0` -* `BSD-2-Clause` -* `GPL-2.0-only` - -#### License Expression #### - -A *License Expression* is a [String](#string) that represents one or more -licenses by combining [License Strings](#license-string) into a single value. -The format is defined by [SPDX Standard License Expression]. Examples: - * `LGPL-2.1-only OR MIT` * `LGPL-2.1-only AND MIT AND BSD-2-Clause` * `GPL-2.0-or-later WITH Bison-exception-2.2` @@ -201,11 +228,12 @@ The format is defined by [SPDX Standard License Expression]. Examples: A *purl* is a [String](#string) containing a valid package in the format defined by the [purl spec]. All known [purl Types] **MAY** be used, as well as `pgxn` for PGXN packages and `postgres` for PostgreSQL core [contrib] or -development packages. Some examples: +development packages. Versions appearing after a `@` are valid but ignored. +Some examples: * `pkg:pgxn/pgtap` * `pkg:postgres:pg_regress` -* `pkg:generic/python3@3` +* `pkg:generic/python3` * `pkg:pypi/pyarrow@11.0.0` #### Platform #### @@ -216,9 +244,10 @@ architecture: `$os-$version-$architecture`. If the string contains no dash, it represents only the OS. If it contains a single dash, the values represent the OS and the architecture. The complete -list of values will be determined by the [bulid farm animals]. Some likely -Examples: +list of values will be derived from the [bulid farm animals] in another RFC. +Some likely Examples: +* `any`: Any platform * `linux`: Any Linux * `linux-amd64`: Any Linux on amd64/x86_64 * `gnulinux-amd64`: [GNU] Linux on amd64/x86_64 @@ -246,7 +275,7 @@ generate or output invalid properties. For each property, one or more examples are provided followed by a description. The description begins with the version of spec in which the property was added or in which the definition was modified, whether the -property is **REQUIRED** or **OPTIONAL**, and the data type of the value. +property is **required** or **optional**, and the data type of the value. These items are in parentheses, brackets, and braces, respectively. If a data type is an [Object](#object), valid sub-properties will be described @@ -304,7 +333,7 @@ by the [Distribution](#source-distribution). #} ``` -(Spec 2) [required] {[Array](#array) of [Objects]{#object}} +(Spec 2) [required] {[Array](#array) of [Objects](#object)} This property indicates the person(s) to contact concerning the [Distribution](#source-distribution). Each [Object](#object) in the @@ -342,13 +371,13 @@ to or instead of the original author. #} ``` -(Spec 1) [required] {[License String](#license-string) or [License Expression](#license-expression)} +(Spec 1) [required] {[License Expression](#license-expression)} One or more licenses that apply to some or all of the files in the [Distribution](#source-distribution). For [License -Expressions](#license-expression), the [Distribution](#source-distribution) -documentation **SHOULD** be consulted to clarify the interpretation of -multiple licenses. +Expressions](#license-expression) containing multiple licenses, the +[Distribution](#source-distribution) documentation **SHOULD** clarify the +interpretation of those licenses. ##### contents ###### @@ -360,7 +389,6 @@ multiple licenses. "sql": "sql/pair.sql", "doc": "doc/pair.md", "abstract": "A key/value pair data type", - "preload": "session", "tle": true, "control": "pair.control" } @@ -384,7 +412,7 @@ multiple licenses. "lib": "lib/lib_pair", "doc": "doc/lib_pair.md", "abstract": "A library hooking function calls to convert pairs to named parameters", - "load": "shared_preload_libraries" + "preload": "session" } } } @@ -454,7 +482,7 @@ present in the `contents` object. The properties are as follows: * **abstract**: A [String](#string) containing a short description of the app. * **modules**: [Objects](#object) describing [loadable modules] that can be - loaded into Postgres. Properties are module name [Terms](#term) pointing + loaded into PostgreSQL. Properties are module name [Terms](#term) pointing to [Objects](#object) with the following properties: * **src**: A [Path](#path) pointing to the main source file for the module. **REQUIRED**. @@ -473,7 +501,7 @@ present in the `contents` object. The properties are as follows: name [Terms](#term) pointing to [Objects](#object) with the following properties: * **src**: A [Path](#path) pointing to the main source file or directory - of files for the library. **REQUIRED**. + of files for the library. **REQUIRED**. * **doc**: A [Path](#path) pointing to the main documentation file for the library, which **SHOULD** be more than a README. * **abstract**: A [String](#string) containing a short description of @@ -485,22 +513,24 @@ present in the `contents` object. The properties are as follows: #{ "meta-spec": { "version": "2.0.0", - "url": "https://pgxn.org/meta/v2/spec.txt" + "url": "https://rfcs.pgxn.org/0003-meta-spec-v2.html" } #} ``` (Spec 1) [required] {[Map](#Map)} -This field indicates the [Version](#Version) of the PGXN Meta Spec that -**SHOULD** be used to interpret the metadata. Consumers **MUST** check this -key as soon as possible and abort further metadata processing if the meta-spec -[Version](#version) is not supported by the consumer. +This field indicates the [SemVer](#semver) of the PGXN Meta Spec that +**SHOULD** be used to interpret the metadata. [Consumers](#consumer) **MUST** +check this key as soon as possible and abort further metadata processing if +the meta-spec [SemVer](#semver) is not supported by the +[Consumers](#consumer). The following properties are valid, but only `version` is **REQUIRED**. -* **version**: The [Version](#version) of the PGXN Meta Spec against which - the metadata object was generated. +* **version**: The [SemVer](#semver) of the PGXN Meta Spec against which + the metadata object was generated. **MUST** be a valid, released v2 spec + version, usually `2.0.0`. * **url**: The [URI](#uri) of the metadata specification corresponding to the given version. This is strictly for human-consumption and **SHOULD @@ -508,20 +538,19 @@ The following properties are valid, but only `version` is **REQUIRED**. ##### name ##### -Example: - ``` json #{ "name": "pgTAP" #} ``` -(Spec 1) [required] {[Term](#Term)} +(Spec 1) [required] {[Package Name](#package-name)} This property is the name of the [Package](#package) provided by the [Distribution](#source-distribution). This is usually the same as the name of the "main extension" in the [contents](#contents) of the [Package](#package), -but **MAY** be completely unrelated. This value will be used in the +but **MAY** be different to comply with the [Package Name](#package-name) +constraints, or be completely unrelated. This value will be used in the [Distribution](#source-distribution) file name on [PGXN]. ##### version ##### @@ -532,11 +561,11 @@ but **MAY** be completely unrelated. This value will be used in the #} ``` -(Spec 1) [required] {[Version](#version)} +(Spec 1) [required] {[SemVer](#semver)} This property gives the version of the [Distribution](#source-distribution) to which the metadata structure refers. Its value **MUST** be a -[Version](#version). +[SemVer](#semver). All of the items listed in [contents](#contents) will be considered to have this version; any references they make to a version, such as the [control @@ -558,24 +587,22 @@ A longer, more complete description of the purpose or intended use of the [Package](#package) provided by the [Distribution](#source-distribution), answering the question "what is this thing and what value is it?" -##### generated_by ##### - -Example: +##### producer ##### ``` json #{ - "generated_by": "Module::Build::PGXN version 0.42" + "producer": "Module::Build::PGXN version 0.42" #} ``` -(Spec 1) [optional] {[String](#string)} +(Spec 2) [optional] {[String](#string)} -This property indicates the tool that was used to create this metadata. There -are no defined semantics for this property, but it is traditional to use a -string in the form "Software package version 1.23", or the maintainer's name -if the metadata was generated by hand. +This property indicates the [Producer](#producer) that created the metadata. +There are no defined semantics for this property, but it is traditional to use +a string in the form "Software package version 1.23.0", or the maintainer's +name if the metadata was generated by hand. -##### classification ##### +##### classifications ##### ``` json #{ @@ -631,12 +658,11 @@ following properties: #} ``` -(Spec 2) [optional] {[Array](#Array) of [Strings](#string)} +(Spec 2) [optional] {[Array](#Array) of [Path Patterns](#path-pattern)} This [Array](#array) describes any files or directories that are private to the [Distribution](#source-distribution) and **SHOULD** be ignored by indexing -or search tools. Values are [Paths](#path) or [Strings](#string) based on a -subset of the [gitignore format]. +or search tools. ##### dependencies ##### @@ -644,7 +670,7 @@ subset of the [gitignore format]. #{ "dependencies": { "postgres": { - "version": "14" + "version": "14.0" }, } #} @@ -654,7 +680,7 @@ subset of the [gitignore format]. #{ "dependencies": { "postgres": { - "version": ">= 12, < 17", + "version": ">= 12.0, < 17.0", "with": [ "xml", "uuid", "perl" ] }, "pipeline": "pgxs", @@ -687,7 +713,7 @@ subset of the [gitignore format]. ], "packages": { "configure": { - "requires": { "pkg:cargo/cargo-pgrx": "=0.11.4" } + "requires": { "pkg:cargo/cargo-pgrx": "==0.11.4" } }, "test": { "requires": { @@ -711,7 +737,7 @@ subset of the [gitignore format]. #{ "dependencies": { "postgres": { - "version": ">= 15, < 16" + "version": ">= 15.0, < 16.0" }, "pipeline": "pgxs", "platforms": [ @@ -721,7 +747,7 @@ subset of the [gitignore format]. "packages": { "configure": { "requires": { - "pkg:cargo/cargo-pgrx": "=0.11.4", + "pkg:cargo/cargo-pgrx": "==0.11.4", "pkg:generic/bison": 0, "pkg:generic/cmake": 0, "pkg:generic/flex": 0, @@ -772,10 +798,9 @@ subset of the [gitignore format]. This property identifies dependencies required to configure, build, test, install, and run the [Package](#package) provided by the -[Distribution](#source-distribution), expressed as [purls](#purl). These -include not only PGXN packages, but also external libraries, system -dependencies, and versions of PostgreSQL --- as well as any OS and -architectures ([arm64], [amd64], etc.). +[Distribution](#source-distribution). These include not only PGXN packages, +but also external libraries, system dependencies, and versions of PostgreSQL +--- as well as any OS and architectures ([arm64], [amd64], etc.). [Consumers](#consumer) **SHOULD** use this data to determine what dependencies to install. @@ -796,10 +821,9 @@ Properties: properties: * **version**: A [Version Range](#version-range) identifying the supported versions of PostgreSQL. **REQUIRED**. - * **with**: An [Array](#array) of [Terms](#term) that correspond - features that are required to be compiled into PostgreSQL. Each - corresponds to the appropriate `--with` [configure flags]. - **OPTIONAL**. + * **with**: An [Array](#array) of [Terms](#term) that specify features + that are required to be compiled into PostgreSQL. Each corresponds to + the appropriate `--with` [configure flags]. **OPTIONAL**. * **pipeline**: A [Term](#term) identifying the build pipeline required to configure, build, test, and install the [Package](#package) provided by @@ -835,9 +859,9 @@ Properties: dependency variations. Each object contains two properties: * **where**: An [Object](#object) containing the subset of the [dependencies](#dependencies) to identify a variation, such as - `{ "platforms": ["gnulinux-arm64", "gnulinux-amd64"] }` for Linux - configurations, or `{"postgres": { "version": ">= 16, < 17" }}` for - PostgreSQL versions. **MUST NOT** include a `variations` property. + `{ "platforms": ["linux"] }` for Linux configurations, or + `{"postgres": { "version": ">= 16.0, < 17.0" }}` for PostgreSQL + versions. **MUST NOT** include a `variations` property. * **dependencies**: An [Object](#object) containing the subset of [dependencies](#dependencies) required for the `where` property's configuration. **MUST NOT** include a `variations` property. @@ -882,7 +906,7 @@ properties: images that **SHOULD** follow the [Shields badge specification]. It **MUST** have at least one entry, and all entries require two properties: * **src**: The [URI](#uri) for the badge. - * **alt**: Alt text for the badge. + * **alt**: Alternate text for accessability. ##### artifacts ##### @@ -910,13 +934,12 @@ properties: (Spec 2) [optional] {[Array](#array)} -An [Array](#array) of [Objects](#objects) describing links and checksums for -downloading the [Package](#package) provided by the -[Distribution](#source-distribution) in one or more formats, including source -code, binaries, system packages, and more. [Consumers](#consumer) my use this -information to determine the best option for installing an extension on a -particular system. Useful for projects that publish their own binaries, such -as in GitHub releases. +An [Array](#array) of [Objects](#objects) describing non-PGXN links and +checksums for downloading the [Distribution](#source-distribution) in one or +more formats, including source code, binaries, system packages, etc. +[Consumers](#consumer) **MAY** use this information to determine the best +option for installing an extension on a particular system. Useful for projects +that publish their own binaries, such as in GitHub releases. The [Array](#array) **MUST** have at least one [Object](#object). The properties of each [Object](#object) are: @@ -939,10 +962,11 @@ Each URL **MUST** properly resolve and the checksum **MUST** match. The `packages` sub-property of the [dependencies](#dependencies) property defines the relationship between a [Distribution](#source-distribution) and external dependencies --- including other PGXN [Packages](#package), system -packages, and third-party packages --- expressed as [purls](#purl). The -structure is an [Object](#object) that specifies package dependencies into -*Phases* of activity in the installation process, and *Relationships* that -indicate how dependencies **SHOULD** be resolved. +packages, and third-party packages --- expressed as [purls](#purl) mapped +[Version Ranges](#version-range). The structure is an [Object](#object) that +specifies package dependencies for *Phases* of activity in the installation +process, and *Relationships* that indicate how dependencies **SHOULD** be +resolved. For example, to specify that the [PGXN] extension `pgtap` is required during the `test` phase, this entry would appear in the @@ -979,14 +1003,14 @@ greater but not 1.5.2: #{ "packages": { "test": { - "requires": { "pkg:pgxn/pair": ">= 1.2, != 1.5.2" } + "requires": { "pkg:pgxn/pair": ">= 1.2.0, != 1.5.2" } } } #} ``` [Producers](#producer) **SHOULD** avoid OS-specific [purls](#purl) such as -`pkg:rpm:/libreadline-dev` unless the [Distribution](#source-distribution) +`pkg:rpm/libreadline-dev` unless the [Distribution](#source-distribution) supports only OSes that provide such packages. See the "variations" property of the [dependencies](#dependencies) object for platform-specific dependency specification. @@ -1011,7 +1035,7 @@ requirements **MUST** also be available during the `test` phase. make | configure, runtime, build make test | configure, runtime, build, test -Consumers that install the [Package](#package) provided by the +[Consumers](#consumer) that install the [Package](#package) provided by the [Distribution](#source-distribution) **MUST** ensure that *runtime* requirements are also installed and **MAY** install dependencies from other phases. @@ -1050,7 +1074,7 @@ phases. * **requires**: These dependencies **MUST** be installed for proper completion of the phase. -* **recommends**: **RECOMMENDED** dependencies are *strongly* encouraged and +* **recommends**: These dependencies are *strongly* encouraged and **SHOULD** be satisfied except in resource constrained environments. * **suggests**: These dependencies are **OPTIONAL**, are suggested for @@ -1070,9 +1094,9 @@ packaged with distributions as the file `META.json`. This design adds significant complexity over and above that provided by the [v1 spec](0001-meta-spec-v1.md). The features and services planned for PGXN, -including automated binary packaging require that complexity, however. That -said, the [v1 spec](0001-meta-spec-v1.md) remains valid and can continue to be -used by projects unless they need additional metadata to support new features. +including automated binary packaging, require that complexity. That said, the +[v1 spec](0001-meta-spec-v1.md) remains valid and can continue to be used by +projects unless they need additional metadata to support new features. We plan to develop an [SDK] and [CLI] to reduce or eliminate the toil of maintaining the metadata, and to automate conversion from the [v1 @@ -1082,13 +1106,13 @@ spec](0001-meta-spec-v1.md) when new features are needed. There are currently no developer-focused alternatives to the PGXN Meta Spec. Other extension registries, such as [Trunk], [PGXMan], [StackBuilder], and -the community [Yum] and Apt repositories decouple maintenance of build +the community [Yum] and [Apt] repositories decouple maintenance of build metadata and dependencies, in particular, from the developer. Instead they're -independently and manually managed by volunteers or employees of teh companies -who developed them. +independently and manually managed by volunteers or employees of the companies +who develope and maintain them. They also tend to have formats specific to the platforms they serve, rather -than to PostgreSQL specifically. +than to PostgreSQL generally. Without this metadata, it would be difficult to develop a cross-platform, community binary packaging registry of all PGXN distributions. With this @@ -1101,13 +1125,16 @@ create pull requests for the original projects. The PGXN Meta Spec v2 is based on the [v1 spec](0001-meta-spec-v1.md), which is itself based on the [CPAN Meta Spec]. Dependency specification is inspired -by the [purl spec] and [Repology], as well as the [RPM Packaging Guidelines]. +by the [purl spec] and [Repology], and the [RPM Packaging Guidelines]. ## Unresolved questions * Can we rely on [Repology] to resolve system dependencies? -* How, exactly, do we configure loadable modules, esp when used with an - extension? +* How, exactly, do we configure loadable modules, especially when used with + an extension? +* How do we properly annotate module pre-loading? How do we handle load + order issues (such as one module depending on another)? Or optional + pre-loading? * Is it better to bundle dependencies into a package as loadable modules, or to create separate distributions that just contain the loadable modules and depend on them? @@ -1130,14 +1157,19 @@ by the [purl spec] and [Repology], as well as the [RPM Packaging Guidelines]. ## Future possibilities Successful adoption of this standard will mean most extensions use it to -distribute on PGXN. We'll separately need an initiative to work with extension -authors to onboard them into PGXN, perhaps by pull requests adding the -metadata and CI workflows. +distribute on [PGXN]. We'll separately need an initiative to work with +extension authors to onboard them into PGXN, perhaps by pull requests adding +the metadata and CI workflows. Or perhaps in the future we'll be able to recognize extensions on GitHub and other repositories and automatically index them. Seems tricky without [Go-style module paths]. +The real success of this standard will be apparent in binary distribution +automation. The goal is for the metadata to be sufficient sufficient to +automate dependency resolution and binary packaging of 99% of the +distributions on PGXN. + ## See Also ## * [CPAN Meta Spec] @@ -1159,8 +1191,6 @@ David Golden, Ricardo Signes, Adam Kennedy, and contributors. [CC BY-SA 4.0]: https://creativecommons.org/licenses/by-sa/4.0/ "Attribution-Sharealike 4.0 International" [Github Flavored Markdown]: https://github.github.com/gfm/ [Markdown]: https://daringfireball.net/projects/markdown/ - [master.pgxn.org/meta/spec.txt]: https://master.pgxn.org/meta/spec.txt - [pgxn.org/spec/]: https://pgxn.org/spec/ [archive file]: https://en.wikipedia.org/wiki/Archive_file "Wikipedia: “Archive file”" [`semver`]: https://pgxn.org/dist/semver/ @@ -1187,6 +1217,7 @@ David Golden, Ricardo Signes, Adam Kennedy, and contributors. "PostgreSQL Docs: Background Worker Processes" [loadable modules]: https://www.postgresql.org/docs/16/gist-extensibility.html [gitignore format]: https://git-scm.com/docs/gitignore + [fnmatch]: https://www.man7.org/linux/man-pages/man3/fnmatch.3.html [bulid farm animals]: https://buildfarm.postgresql.org/cgi-bin/show_members.pl [configure flags]: https://www.postgresql.org/docs/current/install-make.html#CONFIGURE-OPTIONS-FEATURES [Repology API]: https://repology.org/api "Repology, the packaging hub: API" From f2e5360f8165f54dad4a0813bff1dfd1a81e7e7c Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Fri, 12 Jul 2024 18:06:45 -0400 Subject: [PATCH 03/13] Add missing links --- text/0003-meta-spec-v2.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/text/0003-meta-spec-v2.md b/text/0003-meta-spec-v2.md index c17feac..53c71e9 100644 --- a/text/0003-meta-spec-v2.md +++ b/text/0003-meta-spec-v2.md @@ -177,7 +177,7 @@ on the [gitignore format] and [fnmatch], is as follows: only match directories, otherwise the pattern can match both files and directories. * An asterisk `(*)` matches anything except a slash. The character `?` - matches any one character except `/` The range notation, e.g. [a-zA-Z], + matches any one character except `/` The range notation, e.g., `[a-zA-Z]`, can be used to match one of the characters in a range. #### SemVer #### @@ -185,7 +185,7 @@ on the [gitignore format] and [fnmatch], is as follows: A *SemVer* is a [String](#string) containing a value that describes the version number of extensions or distributions, and adheres to the format of the [Semantic Versioning 2.0.0 Specification][semver] with the exception of -[Build metadata], which is reserved for use by downstream packaging systems. +[build metadata], which is reserved for use by downstream packaging systems. #### Version Range #### @@ -1208,11 +1208,14 @@ David Golden, Ricardo Signes, Adam Kennedy, and contributors. [purl Types]: https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst "Package URL Type definitions" [semver]: https://semver.org/ + [build metadata]: https://semver.org/#spec-item-10 [SPDX License List]: https://github.com/spdx/license-list-data/ [SPDX Standard License Expression]: https://spdx.github.io/spdx-spec/v3.0/annexes/SPDX-license-expressions/ [control file]: https://www.postgresql.org/docs/current/extend-extensions.html [trusted language extension]: https://github.com/aws/pg_tle "pg_tle: Framework for building trusted language extensions for PostgreSQL" + [extensions]: https://www.postgresql.org/docs/current/sql-createextension.html + "PostgreSQL Docs: CREATE EXTENSION" [background workers]: https://www.postgresql.org/docs/current/bgworker.html "PostgreSQL Docs: Background Worker Processes" [loadable modules]: https://www.postgresql.org/docs/16/gist-extensibility.html @@ -1237,3 +1240,10 @@ David Golden, Ricardo Signes, Adam Kennedy, and contributors. [Repology]: https://repology.org/ "Repology, the packaging hub" [RPM Packaging Guidelines]: https://docs.fedoraproject.org/en-US/packaging-guidelines/ [Go-style module paths]: https://go.dev/ref/mod#module-path + [arm64]: https://en.wikipedia.org/wiki/AArch64 "Wikipedia: AArch64" + [amd64]: https://en.wikipedia.org/wiki/amd64 "Wikipedia: AMD64" + [Trunk]: https://pgt.dev "Trunk — A Postgres Extension Registry" + [PGXMan]: https://pgxman.com/ "npm for PostgreSQL" + [StackBuilder]: https://www.enterprisedb.com/docs/supported-open-source/postgresql/installing/using_stackbuilder/ + [Apt]: https://wiki.postgresql.org/wiki/Apt "PostgreSQL packages for Debian and Ubuntu" + [Yum]: https://yum.postgresql.org "PostgreSQL Yum Repository" From 80702c30e6af392c404b5a17fc1f53bd71459354 Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Wed, 17 Jul 2024 14:47:13 -0400 Subject: [PATCH 04/13] Disallow dots (.) in terms Instead of having a separate "package name" type. A quick check of the PGXN database and [1000+ PostgreSQL EXTENSIONs] shows no existing extensions contain a dot. This will simplify parsing a package name from a semver in file names, since dots are required for semantic versions. [1000+ PostgreSQL EXTENSIONs]: https://gist.github.com/joelonsql/e5aa27f8cc9bd22b8999b7de8aee9d47 --- text/0003-meta-spec-v2.md | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/text/0003-meta-spec-v2.md b/text/0003-meta-spec-v2.md index 53c71e9..687dad8 100644 --- a/text/0003-meta-spec-v2.md +++ b/text/0003-meta-spec-v2.md @@ -70,8 +70,8 @@ together. An [archive file] of the source code for the release of single version of a [Package](#package), together with metadata defined by this spec, distributed for other DBAs, packagers, and developers to build, install, and use. The file -name of a Source Distribution consists of the [Package Name](#package-name), a -dash, and the [SemVer](#semver) version, e.g., `pgtap-1.14.3.zip`. +name of a Source Distribution consists of the Package [Name](#name), a dash, +and the [SemVer](#semver) version, e.g., `pgtap-1.14.3.zip`. Usually referred to as a "Distribution", including in this document. The full term "Source Distribution" is used where necessary to distinguish from binary @@ -133,16 +133,8 @@ Object's values **MAY** be of mixed types. #### Term #### A *Term* is a [String](#string) that **MUST** be at least two characters long, -and contain no slash (`/`), backslash (`\`), control, or space characters. - -#### Package Name #### - -A *Package Name* is a [String](#string) with the following constraints: - -* **MUST** be at least two characters long. -* **MUST NOT** start with a digit or include a digit after a dash (`-`) -* **MUST NOT** contain slash (`/`), backslash (`\`), control, or space - characters. +and contain no slash (`/`), backslash (`\`), dot (`.`), control, or space +characters. #### Tag #### @@ -544,13 +536,12 @@ The following properties are valid, but only `version` is **REQUIRED**. #} ``` -(Spec 1) [required] {[Package Name](#package-name)} +(Spec 1) [required] {[Term](#term)} This property is the name of the [Package](#package) provided by the [Distribution](#source-distribution). This is usually the same as the name of the "main extension" in the [contents](#contents) of the [Package](#package), -but **MAY** be different to comply with the [Package Name](#package-name) -constraints, or be completely unrelated. This value will be used in the +but **MAY** be completely unrelated. This value will be used in the [Distribution](#source-distribution) file name on [PGXN]. ##### version ##### From b6f11039fbb5141a0b8b64187bf424681fcea26b Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Thu, 18 Jul 2024 18:32:12 -0400 Subject: [PATCH 05/13] Fix a few errors, improve platform --- text/0003-meta-spec-v2.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/text/0003-meta-spec-v2.md b/text/0003-meta-spec-v2.md index 687dad8..b478a6e 100644 --- a/text/0003-meta-spec-v2.md +++ b/text/0003-meta-spec-v2.md @@ -168,7 +168,7 @@ on the [gitignore format] and [fnmatch], is as follows: * If there is a separator at the end of the pattern then the pattern will only match directories, otherwise the pattern can match both files and directories. -* An asterisk `(*)` matches anything except a slash. The character `?` +* An asterisk (`*`) matches anything except a slash. The character `?` matches any one character except `/` The range notation, e.g., `[a-zA-Z]`, can be used to match one of the characters in a range. @@ -224,7 +224,7 @@ development packages. Versions appearing after a `@` are valid but ignored. Some examples: * `pkg:pgxn/pgtap` -* `pkg:postgres:pg_regress` +* `pkg:postgres/pg_regress` * `pkg:generic/python3` * `pkg:pypi/pyarrow@11.0.0` @@ -235,9 +235,10 @@ one to three dash-delimited substrings: An OS name, the OS version, and the architecture: `$os-$version-$architecture`. If the string contains no dash, it represents only the OS. If it contains a -single dash, the values represent the OS and the architecture. The complete -list of values will be derived from the [bulid farm animals] in another RFC. -Some likely Examples: +single dash, the first value represents the OS and second value is a version +if it starts with an integer followed by a dot and the architecture if it does +not start with a digit. The complete list of values will be derived from the +[bulid farm animals] in another RFC. Some likely Examples: * `any`: Any platform * `linux`: Any Linux @@ -1209,7 +1210,7 @@ David Golden, Ricardo Signes, Adam Kennedy, and contributors. "PostgreSQL Docs: CREATE EXTENSION" [background workers]: https://www.postgresql.org/docs/current/bgworker.html "PostgreSQL Docs: Background Worker Processes" - [loadable modules]: https://www.postgresql.org/docs/16/gist-extensibility.html + [loadable modules]: https://www.postgresql.org/docs/current/sql-load.html [gitignore format]: https://git-scm.com/docs/gitignore [fnmatch]: https://www.man7.org/linux/man-pages/man3/fnmatch.3.html [bulid farm animals]: https://buildfarm.postgresql.org/cgi-bin/show_members.pl From 0d7e2b2b9279445e13107c72c1be9c4592248cb5 Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Fri, 19 Jul 2024 16:56:47 -0400 Subject: [PATCH 06/13] Simplify contents into three types * extensions: `CREATE EXTENSION` extensions * modules: loadable modules for extensions, hooks, and workers * apps: Programs and scripts like pg_top, pgAdmin, or pg_partman scripts Add an example from pg_partman, which includes all three types. --- text/0003-meta-spec-v2.md | 146 +++++++++++++++++++++++--------------- 1 file changed, 87 insertions(+), 59 deletions(-) diff --git a/text/0003-meta-spec-v2.md b/text/0003-meta-spec-v2.md index b478a6e..def25ed 100644 --- a/text/0003-meta-spec-v2.md +++ b/text/0003-meta-spec-v2.md @@ -379,11 +379,11 @@ interpretation of those licenses. "contents": { "extensions": { "pair": { - "sql": "sql/pair.sql", + "control": "pair.control", + "sql": "pair-1.2.0.sql", "doc": "doc/pair.md", "abstract": "A key/value pair data type", - "tle": true, - "control": "pair.control" + "tle": true } } } @@ -393,19 +393,20 @@ interpretation of those licenses. ``` json #{ "contents": { - "workers": { - "pair_pruner": { - "bin": "bin/pair_pruner", - "doc": "doc/pair_pruner.md", - "abstract": "A worker to periodically prune pairs" - } - }, "modules": { - "lib_pair": { - "lib": "lib/lib_pair", - "doc": "doc/lib_pair.md", - "abstract": "A library hooking function calls to convert pairs to named parameters", - "preload": "session" + "my_worker": { + "type": "worker", + "lib": "lib/my_bgw", + "doc": "doc/my_bgw.md", + "preload": "server", + "abstract": "My background worker" + }, + "my_hook": { + "type": "hook", + "lib": "lib/my_hook", + "doc": "doc/my_hook.md", + "preload": "session", + "abstract": "My hook" } } } @@ -416,17 +417,51 @@ interpretation of those licenses. #{ "contents": { "apps": { - "pair_rand": { - "bin": "bin/pair_rand", - "doc": "doc/pair_rand.md", - "abstract": "Command to generate random pairs of strings" - } + "my_app": { + "lang": "perl", + "bin": "blib/script/app", + "lib": "blib/lib", + "man": "blib/libdoc", + "html": "blib/libhtml", + "doc": "doc/app.md", + "abstract": "blah blah blah" + } + } +#} +``` + +``` json +#{ + "extensions": { + "pg_partman": { + "control": "pg_partman.control", + "sql": "sql/types/types.sql", + "doc": "doc/pg_partman.md", + "abstract": "Extension to manage partitioned tables by time or ID" + } + }, + "modules": { + "pg_partman_bgw": { + "type": "worker", + "lib": "src/pg_partman_bgw", + "preload": "server" + } + }, + "apps": { + "check_unique_constraint": { + "lang": "python", + "bin": "bin/common/check_unique_constraint.py", + "abstract": "Check that all rows in a partition set are unique for the given columns" }, - "libraries": { - "ruby_pair": { - "dir": "lib/gems", - "abstract": "Ruby libraries required to run the extension" - } + "dump_partition": { + "lang": "python", + "bin": "bin/common/dump_partition.py", + "abstract": "Dump out and then drop all tables contained in a schema." + }, + "vacuum_maintenance": { + "lang": "python", + "bin": "bin/common/vacuum_maintenance.py", + "abstract": "Performing vacuum maintenance on to avoid excess vacuuming and transaction id wraparound issues" } } #} @@ -437,7 +472,8 @@ interpretation of those licenses. A description of what's included in the [Package](#package) provided by the [Distribution](#source-distribution). This information is used by [PGXN] to build indexes identifying in which [Package](#package) various -[Extensions](#extension) can be found. +[Extensions](#extension) can be found, and to create binary distribution +packages. The properties of `contents` identify the types of [Extensions](#extension) in the [Distribution](#source-distribution). At least one property **MUST** be @@ -446,59 +482,51 @@ present in the `contents` object. The properties are as follows: * **extensions**: [Object](#object) describing `CREATE EXTENSION` [extensions]. Properties are extension name [Terms](#term) pointing to [Objects](#object) with the following fields: - * **sql**: A [Path](#path) pointing to the SQL file used by `CREATE - EXTENSION`. **REQUIRED**. * **control**: A [Path](#path) pointing to the [control file] used by `CREATE EXTENSION`. **REQUIRED**. + * **sql**: A [Path](#path) pointing to the main SQL file, usually the + one used by `CREATE EXTENSION`. **REQUIRED**. * **doc**: A [Path](#path) pointing to the main documentation file for the extension, which **SHOULD** be more than a README. * **abstract**: A [String](#string) containing a short description of the extension. * **tle**: A [Boolean](#boolean) that, when `true`, indicates that the extension can be used as a [trusted language extension]. -* **workers**: [Object](#object) describing [background workers]. Properties - are worker name [Terms](#term) pointing to [Objects](#object) with the - following properties: - * **src**: A [Path](#path) pointing to the main source file for the - background worker. **REQUIRED**. - * **doc**: A [Path](#path) pointing to the main documentation file for - the background worker, which **SHOULD** be more than a README. - * **abstract**: A [String](#string) containing a short description of - the background worker. -* **apps**: [Objects](#object) describing applications, command-line or - otherwise. Properties are are app name [Terms](#term) pointing to - [Objects](#object) with the following properties: - * **src**: A [Path](#path) pointing to the main source file for the app. - **REQUIRED**. - * **doc**: A [Path](#path) pointing to the main documentation file for - the app, which **SHOULD** be more than a README. - * **abstract**: A [String](#string) containing a short description of - the app. * **modules**: [Objects](#object) describing [loadable modules] that can be loaded into PostgreSQL. Properties are module name [Terms](#term) pointing to [Objects](#object) with the following properties: - * **src**: A [Path](#path) pointing to the main source file for the - module. **REQUIRED**. + * **type**: A [Term](#term) identifying the type of the module, one of + "extension", "worker", or "hook". **REQUIRED**. + * **lib**: A [Path](#path) pointing to the shared object file, without + the suffix. **REQUIRED**. * **doc**: A [Path](#path) pointing to the main documentation file for the module, which **SHOULD** be more than a README. * **abstract**: A [String](#string) containing a short description of the module. * **preload**: A [String](#string) that indicates that the extension's libraries **MAY** be loaded in advance. Its three possible values are: - `shared`, `session`, and `local`. Extensions that require early or - late loading of their module **MAY** optionally append a space and - then either `early` or `late`. -* **libraries**: [Objects](#object) listing other libraries that **MAY** - ship in the package and need to be installed but are not [loadable - modules], such as a dynamic library used by an app. Properties are library - name [Terms](#term) pointing to [Objects](#object) with the following - properties: - * **src**: A [Path](#path) pointing to the main source file or directory - of files for the library. **REQUIRED**. + `server` if the module requires loading on server start, and `session` + if the module can be loaded in a session. Omit this field if the + module does not require preloading. +* **apps**: [Objects](#object) describing applications, command-line or + otherwise. Properties are are app name [Terms](#term) pointing to + [Objects](#object) with the following properties: + * **bin**: A [Path](#path) pointing to the application. This file need + not be present in the distribution, but should be present once the + package has been built. **REQUIRED**. + * **lang**: A [Term](#term) indicating the implementation language. + Required for apps that need the `'#!{cmd}` shebang line modified + before installing. * **doc**: A [Path](#path) pointing to the main documentation file for - the library, which **SHOULD** be more than a README. + the app, which **SHOULD** be more than a README. * **abstract**: A [String](#string) containing a short description of the app. + * **lib**: A [Path](#path) pointing to a directory of additional files + to install, such as support libraries or modules. + * **man**: A [Path](#path) pointing to a manpage or directory of + man pages created by the build process. + * **html**: A [Path](#path) pointing to an HTML file or directory of + HTML files created by the build process. ##### meta-spec ##### From 8b65962792b4bf8176dc49fd31b9c0e74f36a21a Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Fri, 19 Jul 2024 18:13:49 -0400 Subject: [PATCH 07/13] Links and fixes --- text/0003-meta-spec-v2.md | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/text/0003-meta-spec-v2.md b/text/0003-meta-spec-v2.md index def25ed..7815333 100644 --- a/text/0003-meta-spec-v2.md +++ b/text/0003-meta-spec-v2.md @@ -82,8 +82,8 @@ distributions of a [Package](#package), as in A software component that extends the capabilities of or experience using a PostgreSQL database or cluster. Extensions **MAY** be `CREATE EXTENSION` -[extensions], [background workers], command-line apps, [loadable modules], -shared libraries, and more. +[extensions], [background workers][bgw], [hooks][hook], command-line apps, and +more. #### Consumer #### @@ -395,7 +395,7 @@ interpretation of those licenses. "contents": { "modules": { "my_worker": { - "type": "worker", + "type": "bgw", "lib": "lib/my_bgw", "doc": "doc/my_bgw.md", "preload": "server", @@ -442,7 +442,7 @@ interpretation of those licenses. }, "modules": { "pg_partman_bgw": { - "type": "worker", + "type": "bgw", "lib": "src/pg_partman_bgw", "preload": "server" } @@ -492,11 +492,14 @@ present in the `contents` object. The properties are as follows: the extension. * **tle**: A [Boolean](#boolean) that, when `true`, indicates that the extension can be used as a [trusted language extension]. -* **modules**: [Objects](#object) describing [loadable modules] that can be - loaded into PostgreSQL. Properties are module name [Terms](#term) pointing - to [Objects](#object) with the following properties: +* **modules**: [Objects](#object) describing [loadable modules] (a.k.a., + shared library) that can be loaded into PostgreSQL. Properties are module + name [Terms](#term) pointing to [Objects](#object) with the following + properties: * **type**: A [Term](#term) identifying the type of the module, one of - "extension", "worker", or "hook". **REQUIRED**. + "extension" for a module supporting a `CREATE EXTENSION` extension, + "bgw" for a [background worker][bgw], or "hook" for a [hook]. + **REQUIRED**. * **lib**: A [Path](#path) pointing to the shared object file, without the suffix. **REQUIRED**. * **doc**: A [Path](#path) pointing to the main documentation file for @@ -504,7 +507,7 @@ present in the `contents` object. The properties are as follows: * **abstract**: A [String](#string) containing a short description of the module. * **preload**: A [String](#string) that indicates that the extension's - libraries **MAY** be loaded in advance. Its three possible values are: + libraries **MAY** be loaded in advance. Its two possible values are: `server` if the module requires loading on server start, and `session` if the module can be loaded in a session. Omit this field if the module does not require preloading. @@ -523,7 +526,7 @@ present in the `contents` object. The properties are as follows: the app. * **lib**: A [Path](#path) pointing to a directory of additional files to install, such as support libraries or modules. - * **man**: A [Path](#path) pointing to a manpage or directory of + * **man**: A [Path](#path) pointing to a man page or directory of man pages created by the build process. * **html**: A [Path](#path) pointing to an HTML file or directory of HTML files created by the build process. @@ -1236,8 +1239,10 @@ David Golden, Ricardo Signes, Adam Kennedy, and contributors. "pg_tle: Framework for building trusted language extensions for PostgreSQL" [extensions]: https://www.postgresql.org/docs/current/sql-createextension.html "PostgreSQL Docs: CREATE EXTENSION" - [background workers]: https://www.postgresql.org/docs/current/bgworker.html + [bgw]: https://www.postgresql.org/docs/current/bgworker.html "PostgreSQL Docs: Background Worker Processes" + [hook]: https://wiki.postgresql.org/wiki/PostgresServerExtensionPoints#Hooks + "PostgreSQL Wiki: Hooks" [loadable modules]: https://www.postgresql.org/docs/current/sql-load.html [gitignore format]: https://git-scm.com/docs/gitignore [fnmatch]: https://www.man7.org/linux/man-pages/man3/fnmatch.3.html From bca822eb0e814ed3ef417f8acb112484db2ea81b Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Wed, 24 Jul 2024 17:55:45 -0400 Subject: [PATCH 08/13] Various tweaks and improvements * Add missing `contents` key to example * Rename "Path Pattern" to "Glob" * Fix ignore header * Fix missing package version * Use "cargo" instead of "rust" for pipeline value * Tweak wording on phases * Add url property to badge --- text/0003-meta-spec-v2.md | 102 ++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 48 deletions(-) diff --git a/text/0003-meta-spec-v2.md b/text/0003-meta-spec-v2.md index 7815333..fd2ba69 100644 --- a/text/0003-meta-spec-v2.md +++ b/text/0003-meta-spec-v2.md @@ -153,11 +153,11 @@ Locator as defined by [IETF RFC 3986]. in the [Distribution](#source-distribution). The path **MUST** be specified with Unix conventions. -#### Path Pattern #### +#### Glob #### -*Path Pattern* is a [String](#string) that defines a pattern to identify one -or more files in the [Distribution](#source-distribution). Its format, based -on the [gitignore format] and [fnmatch], is as follows: +*Glob* is a [String](#string) that defines a pattern to identify one or more +files in the [Distribution](#source-distribution). Its format, based on the +[gitignore format] and [fnmatch], is as follows: * The slash (`/`) is used as the directory separator. Separators may occur at the beginning, middle or end of the pattern. @@ -425,6 +425,7 @@ interpretation of those licenses. "html": "blib/libhtml", "doc": "doc/app.md", "abstract": "blah blah blah" + } } } #} @@ -432,36 +433,38 @@ interpretation of those licenses. ``` json #{ - "extensions": { - "pg_partman": { - "control": "pg_partman.control", - "sql": "sql/types/types.sql", - "doc": "doc/pg_partman.md", - "abstract": "Extension to manage partitioned tables by time or ID" - } - }, - "modules": { - "pg_partman_bgw": { - "type": "bgw", - "lib": "src/pg_partman_bgw", - "preload": "server" - } - }, - "apps": { - "check_unique_constraint": { - "lang": "python", - "bin": "bin/common/check_unique_constraint.py", - "abstract": "Check that all rows in a partition set are unique for the given columns" + "contents": { + "extensions": { + "pg_partman": { + "control": "pg_partman.control", + "sql": "sql/types/types.sql", + "doc": "doc/pg_partman.md", + "abstract": "Extension to manage partitioned tables by time or ID" + } }, - "dump_partition": { - "lang": "python", - "bin": "bin/common/dump_partition.py", - "abstract": "Dump out and then drop all tables contained in a schema." + "modules": { + "pg_partman_bgw": { + "type": "bgw", + "lib": "src/pg_partman_bgw", + "preload": "server" + } }, - "vacuum_maintenance": { - "lang": "python", - "bin": "bin/common/vacuum_maintenance.py", - "abstract": "Performing vacuum maintenance on to avoid excess vacuuming and transaction id wraparound issues" + "apps": { + "check_unique_constraint": { + "lang": "python", + "bin": "bin/common/check_unique_constraint.py", + "abstract": "Check that all rows in a partition set are unique for the given columns" + }, + "dump_partition": { + "lang": "python", + "bin": "bin/common/dump_partition.py", + "abstract": "Dump out and then drop all tables contained in a schema." + }, + "vacuum_maintenance": { + "lang": "python", + "bin": "bin/common/vacuum_maintenance.py", + "abstract": "Performing vacuum maintenance on to avoid excess vacuuming and transaction id wraparound issues" + } } } #} @@ -669,7 +672,7 @@ following properties: * Security * Tooling and Admin -#### ignore #### +##### ignore ##### ``` json #{ @@ -681,7 +684,7 @@ following properties: #} ``` -(Spec 2) [optional] {[Array](#Array) of [Path Patterns](#path-pattern)} +(Spec 2) [optional] {[Array](#Array) of [Globs](#glob)} This [Array](#array) describes any files or directories that are private to the [Distribution](#source-distribution) and **SHOULD** be ignored by indexing @@ -785,7 +788,7 @@ or search tools. "pkg:generic/python3": 0, "pkg:generic/readline": 0, "pkg:generic/openssl": 0, - "pkg:generic/bison" + "pkg:generic/bison": 0 }, "recommends": { "pkg:pypi/pyarrow": "11.0.0", @@ -846,7 +849,7 @@ Properties: supported versions of PostgreSQL. **REQUIRED**. * **with**: An [Array](#array) of [Terms](#term) that specify features that are required to be compiled into PostgreSQL. Each corresponds to - the appropriate `--with` [configure flags]. **OPTIONAL**. + the appropriate `--with` [configure flag]. **OPTIONAL**. * **pipeline**: A [Term](#term) identifying the build pipeline required to configure, build, test, and install the [Package](#package) provided by @@ -861,19 +864,19 @@ Properties: * cpan * pip * go - * rust + * cargo If this field is not present, [Consumers](#consumer) **MAY** use heuristics to ascertain the pipeline to use, such as the presence or absence of a `configure.sh`, `Makefile`, or `Cargo.toml` file. * **packages**: An [Object](#object) defining dependencies required for - different phases of the build process. The supported property names are - `configure`, `build`, `test`, `run`, and `develop`. Values are - [Objects](#object) with at least one of the properties `requires`, - `recommends`, `suggests`, and `conflicts` pointing to [Objects](#object) - with [purls](#purl) property keys pointing to [Version - Range](#version-range) values. + different phases of the build process, runtime, and development. The + supported property names are `configure`, `build`, `test`, `run`, and + `develop`. Values are [Objects](#object) with at least one of the + properties `requires`, `recommends`, `suggests`, and `conflicts` pointing + to [Objects](#object) with [purls](#purl) property keys pointing to + [Version Range](#version-range) values. See the [Package Spec](#packages-spec) for the full definition of this property. @@ -902,7 +905,8 @@ Properties: "badges": [ { "alt": "Test Status", - "src": "https://test.packages.postgresql.org/github.com/example/pair.svg" + "src": "https://github.com/theory/kv-pair/workflows/CI/badge.svg", + "url": "https://test.packages.postgresql.org/github.com/example" } ] } @@ -927,9 +931,11 @@ properties: package. * **badges**: An [Array](#array) of [Objects](#object) linking to badge images that **SHOULD** follow the [Shields badge specification]. It - **MUST** have at least one entry, and all entries require two properties: - * **src**: The [URI](#uri) for the badge. - * **alt**: Alternate text for accessability. + **MUST** have at least one entry, and all entries support these + properties: + * **src**: The [URI](#uri) for the badge. **REQUIRED.** + * **alt**: Alternate text for accessability. **REQUIRED** + * **url**: The URL the badge links to. ##### artifacts ##### @@ -1247,7 +1253,7 @@ David Golden, Ricardo Signes, Adam Kennedy, and contributors. [gitignore format]: https://git-scm.com/docs/gitignore [fnmatch]: https://www.man7.org/linux/man-pages/man3/fnmatch.3.html [bulid farm animals]: https://buildfarm.postgresql.org/cgi-bin/show_members.pl - [configure flags]: https://www.postgresql.org/docs/current/install-make.html#CONFIGURE-OPTIONS-FEATURES + [configure flag]: https://www.postgresql.org/docs/current/install-make.html#CONFIGURE-OPTIONS-FEATURES [Repology API]: https://repology.org/api "Repology, the packaging hub: API" [contrib]: https://www.postgresql.org/docs/current/contrib.html [auto_explain]: https://www.postgresql.org/docs/current/auto-explain.html From 7e2066297d3c358ac3c22b82c4fb23a699691ba0 Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Tue, 30 Jul 2024 16:05:27 -0400 Subject: [PATCH 09/13] Clarify path symantics and name META.json Also link to the Repology API. --- text/0003-meta-spec-v2.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/text/0003-meta-spec-v2.md b/text/0003-meta-spec-v2.md index fd2ba69..465c3f2 100644 --- a/text/0003-meta-spec-v2.md +++ b/text/0003-meta-spec-v2.md @@ -18,9 +18,9 @@ This document describes version 2.0.0 of the [PGXN] source distribution metadata specification, also known as the "PGXN Meta Spec." PGXN metadata -ships with PGXN source distribution archives, and serves to describe the their -contents for the benefit of automated indexing, distribution, discovery, -full-text search, binary packaging, and more. +ships with PGXN source distribution archives in a fila named `META.json`, and +serves to describe the their contents for the benefit of automated indexing, +distribution, discovery, full-text search, binary packaging, and more. ## Introduction @@ -151,7 +151,8 @@ Locator as defined by [IETF RFC 3986]. *Path* is a [String](#string) with a relative file path that identifies a file in the [Distribution](#source-distribution). The path **MUST** be specified -with Unix conventions. +with Unix conventions. It may begin with a slash, but will still be considered +relative to the directory containing the `META.json` file. #### Glob #### @@ -1044,11 +1045,11 @@ supports only OSes that provide such packages. See the "variations" property of the [dependencies](#dependencies) object for platform-specific dependency specification. -[Consumers](#consumer) **SHOULD** use [Repology] to resolve `pkg:generic` -[purls](#purl) to packages specific to the platform on which an extension is -being built. This is useful for specifying system dependencies that vary by -name and packaging system. Otherwise, they **MAY** use whatever techniques or -heuristics are appropriate to install dependencies. +[Consumers](#consumer) **SHOULD** use the [Repology API] to resolve +`pkg:generic` [purls](#purl) to packages specific to the platform on which an +extension is being built. This is useful for specifying system dependencies +that vary by name and packaging system. Otherwise, they **MAY** use whatever +techniques or heuristics are appropriate to install dependencies. #### Phases #### From 64e6d63d3328b5cc012e2c980dd92572c5945992 Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Fri, 13 Sep 2024 17:08:37 -0400 Subject: [PATCH 10/13] Require sha512 for artifacts And fix a couple of version references and links. --- text/0003-meta-spec-v2.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/text/0003-meta-spec-v2.md b/text/0003-meta-spec-v2.md index 465c3f2..8dc1bc4 100644 --- a/text/0003-meta-spec-v2.md +++ b/text/0003-meta-spec-v2.md @@ -365,7 +365,7 @@ to or instead of the original author. #} ``` -(Spec 1) [required] {[License Expression](#license-expression)} +(Spec 2) [required] {[License Expression](#license-expression)} One or more licenses that apply to some or all of the files in the [Distribution](#source-distribution). For [License @@ -471,7 +471,7 @@ interpretation of those licenses. #} ``` -(Spec 1) [required] {[Object](#object) of [Objects](#object) of [Terms](#term)} +(Spec 2) [required] {[Object](#object) of [Objects](#object) of [Terms](#term)} A description of what's included in the [Package](#package) provided by the [Distribution](#source-distribution). This information is used by [PGXN] to @@ -546,7 +546,7 @@ present in the `contents` object. The properties are as follows: #} ``` -(Spec 1) [required] {[Map](#Map)} +(Spec 2) [required] {[Map](#Map)} This field indicates the [SemVer](#semver) of the PGXN Meta Spec that **SHOULD** be used to interpret the metadata. [Consumers](#consumer) **MUST** @@ -946,17 +946,17 @@ properties: { "type": "source", "url": "https://github.com/theory/pg-pair/releases/download/v1.1.0/pair-1.1.0.zip", - "sha256": "2b9d2416096d2930be51e5332b70bcd97846947777a93e4a3d65fe1b5fd7b004" + "sha512": "862ad251d31d159b4940e0d56f6c3e951cbb0ea171370025185b335ebc8d3cb8321e912167299b885e72042955c84191ca691608a2be326e605c8efc703b67b2" }, { "type": "binary", "url": "https://github.com/theory/pg-pair/releases/download/v1.1.0/pair-1.1.0-linux-amd64.tar.gz", - "sha1": "12d9bc5cfb6bc3c453627eac69511f48be63cfc0" + "sha512": "862ad251d31d159b4940e0d56f6c3e951cbb0ea171370025185b335ebc8d3cb8321e912167299b885e72042955c84191ca691608a2be326e605c8efc703b67b2" }, { "type": "binary", "url": "https://github.com/theory/pg-pair/releases/download/v1.1.0/pair-1.1.0-linux-arm64.tar.gz", - "sha1": "787dc39137f7d1510a33ab0a1b8905cd5f3f72d1" + "sha512": "862ad251d31d159b4940e0d56f6c3e951cbb0ea171370025185b335ebc8d3cb8321e912167299b885e72042955c84191ca691608a2be326e605c8efc703b67b2" } ] #} @@ -964,7 +964,7 @@ properties: (Spec 2) [optional] {[Array](#array)} -An [Array](#array) of [Objects](#objects) describing non-PGXN links and +An [Array](#array) of [Objects](#object) describing non-PGXN links and checksums for downloading the [Distribution](#source-distribution) in one or more formats, including source code, binaries, system packages, etc. [Consumers](#consumer) **MAY** use this information to determine the best @@ -975,8 +975,8 @@ The [Array](#array) **MUST** have at least one [Object](#object). The properties of each [Object](#object) are: * **url**: A [URI](#uri) to download the artifact. **REQUIRED**. -* **sha256** or **sha512**: A [String](#string) containing a SHA-256 or - SHA-512 checksum in hex format. **REQUIRED**. +* **sha512**: A [String](#string) containing a SHA-512 hash digest for the + artifact in hex format. **REQUIRED**. * **type**: The type of artifact. **MUST** be a single lowercase word describing the artifact, such as none of `binary`, `source`, `rpm`, `homebrew`, etc. **REQUIRED**. From 9a06d453b64eaf116395ec26bcef754dee08f07f Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Thu, 27 Mar 2025 16:29:51 -0400 Subject: [PATCH 11/13] Edit pass, minor tweaks Notable changes: * Exclude parent directory components (`..`) from paths and globs * Note contents items that need not be part of the source, but should exist after building * Limit the number of tags to 32 * Remove discussion of using Repology to resolve `pkg:generic` dependencies * Remove answered and irrelevant questions * Add question about supporting pipeline features --- text/0003-meta-spec-v2.md | 127 +++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 58 deletions(-) diff --git a/text/0003-meta-spec-v2.md b/text/0003-meta-spec-v2.md index 8dc1bc4..2583c4c 100644 --- a/text/0003-meta-spec-v2.md +++ b/text/0003-meta-spec-v2.md @@ -29,7 +29,7 @@ files][archive file] distributed on the PostgreSQL Extension Network, or [PGXN]. Tools that create PGXN source distribution archives must write a metadata file in accordance with this specification and include it in the distribution archive for use by automated tools that index, examine, package, -or install PGXN source distributions. +or build and install PGXN source distributions. ## Guide-level explanation @@ -69,9 +69,9 @@ together. An [archive file] of the source code for the release of single version of a [Package](#package), together with metadata defined by this spec, distributed -for other DBAs, packagers, and developers to build, install, and use. The file -name of a Source Distribution consists of the Package [Name](#name), a dash, -and the [SemVer](#semver) version, e.g., `pgtap-1.14.3.zip`. +for DBAs, packagers, and developers to build, install, and use. The file name +of a Source Distribution consists of the Package [Name](#name), a dash, and +the [SemVer](#semver) version, e.g., `pgtap-1.14.3.zip`. Usually referred to as a "Distribution", including in this document. The full term "Source Distribution" is used where necessary to distinguish from binary @@ -100,10 +100,10 @@ stream, and/or writes it to disk. ### Data Types ### Properties in the [Structure](#structure) section describe data elements, each -of which has an associated data type as described herein. Each is based on the -primitive types defined by [JSON]: *object*, *array*, *string*, *number*, and -*boolean*. Other types are subtypes of these primitives and define compound -data structures or define constraints on the values of a data element. +of which has an associated data type as described herein. Each is based on +[JSON] primitive types: *object*, *array*, *string*, *number*, and *boolean*. +Other types are subtypes of these primitives and define compound data +structures or define constraints on the values of a data element. #### Boolean #### @@ -112,7 +112,7 @@ represented as a defined (not `null`) value. #### String #### -A *String* is data element containing a non-zero length sequence of Unicode +A *String* is data element containing a sequence of one or more Unicode characters. #### Number #### @@ -132,15 +132,15 @@ Object's values **MAY** be of mixed types. #### Term #### -A *Term* is a [String](#string) that **MUST** be at least two characters long, -and contain no slash (`/`), backslash (`\`), dot (`.`), control, or space -characters. +A *Term* is a [String](#string) that **MUST** be at least two Unicode +characters long, and contain no slash (`/`), backslash (`\`), dot (`.`), +control, or space characters. #### Tag #### A *Tag* is a [String](#string) that **MUST** be at least two and no more than -255 characters long, and contain no slash (`/`), backslash (`\`), or control -characters. +255 Unicode characters long, and contain no slash (`/`), backslash (`\`), or +control characters. #### URI #### @@ -151,8 +151,9 @@ Locator as defined by [IETF RFC 3986]. *Path* is a [String](#string) with a relative file path that identifies a file in the [Distribution](#source-distribution). The path **MUST** be specified -with Unix conventions. It may begin with a slash, but will still be considered -relative to the directory containing the `META.json` file. +with Unix conventions and **MUST NOT** include parent directory components +(`..`). It may begin with a slash, but will still be considered relative to +the directory containing the `META.json` file. #### Glob #### @@ -172,13 +173,14 @@ files in the [Distribution](#source-distribution). Its format, based on the * An asterisk (`*`) matches anything except a slash. The character `?` matches any one character except `/` The range notation, e.g., `[a-zA-Z]`, can be used to match one of the characters in a range. +* Parent directory components (`..`) are not allowed. #### SemVer #### A *SemVer* is a [String](#string) containing a value that describes the -version number of extensions or distributions, and adheres to the format of -the [Semantic Versioning 2.0.0 Specification][semver] with the exception of -[build metadata], which is reserved for use by downstream packaging systems. +version number of distributions, and adheres to the format of the [Semantic +Versioning 2.0.0 Specification][semver] with the exception of [build +metadata], which is reserved for use by downstream packaging systems. #### Version Range #### @@ -189,8 +191,8 @@ or installed to fulfill dependencies. A Version Range of the number `0` indicates all available versions. No other [Number](#number) values are allowed. -Often a Version Range is just a single version. For a [SemVer], for example, -`2.4.2` means that **at least** version 2.4.2 must be present. +Often a Version Range is just a single version. For example, `2.4.2` means +that **at least** version 2.4.2 must be present. Alternatively, a version range **may** use the operators `<` (less than), `<=` (less than or equal), `>` (greater than), `>=` (greater than or equal), `==` @@ -205,8 +207,8 @@ indicates a version that must be **at least** 1.2.0, **less than** 2.0.0, and #### License Expression #### A *License Expression* is a [String](#string) that represents one or more -licenses from the [SPDX License List] in a single value. The format is defined -by [SPDX Standard License Expression]. Examples: +licenses from the [SPDX License List]. The format is defined by [SPDX Standard +License Expression]. Examples: * `PostgreSQL` * `MIT` @@ -220,9 +222,9 @@ by [SPDX Standard License Expression]. Examples: A *purl* is a [String](#string) containing a valid package in the format defined by the [purl spec]. All known [purl Types] **MAY** be used, as well as -`pgxn` for PGXN packages and `postgres` for PostgreSQL core [contrib] or -development packages. Versions appearing after a `@` are valid but ignored. -Some examples: +`pgxn` for PGXN packages and `postgres` for PostgreSQL core [contrib], +[procedural language], or development packages. Versions appearing after a `@` +are valid but ignored. Some examples: * `pkg:pgxn/pgtap` * `pkg:postgres/pg_regress` @@ -239,7 +241,7 @@ If the string contains no dash, it represents only the OS. If it contains a single dash, the first value represents the OS and second value is a version if it starts with an integer followed by a dot and the architecture if it does not start with a digit. The complete list of values will be derived from the -[bulid farm animals] in another RFC. Some likely Examples: +[bulid farm animals] in another RFC. Some likely examples: * `any`: Any platform * `linux`: Any Linux @@ -497,9 +499,9 @@ present in the `contents` object. The properties are as follows: * **tle**: A [Boolean](#boolean) that, when `true`, indicates that the extension can be used as a [trusted language extension]. * **modules**: [Objects](#object) describing [loadable modules] (a.k.a., - shared library) that can be loaded into PostgreSQL. Properties are module - name [Terms](#term) pointing to [Objects](#object) with the following - properties: + shared libraries) that can be loaded into PostgreSQL. Properties are + module name [Terms](#term) pointing to [Objects](#object) with the + following properties: * **type**: A [Term](#term) identifying the type of the module, one of "extension" for a module supporting a `CREATE EXTENSION` extension, "bgw" for a [background worker][bgw], or "hook" for a [hook]. @@ -520,7 +522,7 @@ present in the `contents` object. The properties are as follows: [Objects](#object) with the following properties: * **bin**: A [Path](#path) pointing to the application. This file need not be present in the distribution, but should be present once the - package has been built. **REQUIRED**. + package has been built. **REQUIRED**. * **lang**: A [Term](#term) indicating the implementation language. Required for apps that need the `'#!{cmd}` shebang line modified before installing. @@ -529,11 +531,17 @@ present in the `contents` object. The properties are as follows: * **abstract**: A [String](#string) containing a short description of the app. * **lib**: A [Path](#path) pointing to a directory of additional files - to install, such as support libraries or modules. - * **man**: A [Path](#path) pointing to a man page or directory of - man pages created by the build process. + to install, such as support libraries or modules. This directory need + not be present in the distribution, but should be present once the + package has been built. + * **man**: A [Path](#path) pointing to a man page or directory of man + pages created by the build process. This directory need not be present + in the distribution, but should be present once the package has been + built. * **html**: A [Path](#path) pointing to an HTML file or directory of - HTML files created by the build process. + HTML files created by the build process. This directory need not be + present in the distribution, but should be present once the package + has been built. ##### meta-spec ##### @@ -653,8 +661,8 @@ Classification metadata associates additional information about the improve discovery. This [Object](#object) **MUST** contain at least one of the following properties: -* **tags**: An [Array](#array) of one or more keyword [Tags](#tag)s that - describe the distribution. +* **tags**: An [Array](#array) of at least one and no more than 32 keyword + [Tags](#tag)s that describe the distribution. * **categories**: An [Array](#array) of at least one and no more than three of the following [Strings](#string) that categorize the distribution: * Analytics @@ -827,7 +835,7 @@ This property identifies dependencies required to configure, build, test, install, and run the [Package](#package) provided by the [Distribution](#source-distribution). These include not only PGXN packages, but also external libraries, system dependencies, and versions of PostgreSQL ---- as well as any OS and architectures ([arm64], [amd64], etc.). +--- as well as any OS and architecture requirements ([arm64], [amd64], etc.). [Consumers](#consumer) **SHOULD** use this data to determine what dependencies to install. @@ -866,6 +874,7 @@ Properties: * pip * go * cargo + * maven If this field is not present, [Consumers](#consumer) **MAY** use heuristics to ascertain the pipeline to use, such as the presence or @@ -951,11 +960,13 @@ properties: { "type": "binary", "url": "https://github.com/theory/pg-pair/releases/download/v1.1.0/pair-1.1.0-linux-amd64.tar.gz", + "platform": "linux-amd64", "sha512": "862ad251d31d159b4940e0d56f6c3e951cbb0ea171370025185b335ebc8d3cb8321e912167299b885e72042955c84191ca691608a2be326e605c8efc703b67b2" }, { "type": "binary", "url": "https://github.com/theory/pg-pair/releases/download/v1.1.0/pair-1.1.0-linux-arm64.tar.gz", + "platform": "linux-arm64", "sha512": "862ad251d31d159b4940e0d56f6c3e951cbb0ea171370025185b335ebc8d3cb8321e912167299b885e72042955c84191ca691608a2be326e605c8efc703b67b2" } ] @@ -992,7 +1003,7 @@ Each URL **MUST** properly resolve and the checksum **MUST** match. The `packages` sub-property of the [dependencies](#dependencies) property defines the relationship between a [Distribution](#source-distribution) and external dependencies --- including other PGXN [Packages](#package), system -packages, and third-party packages --- expressed as [purls](#purl) mapped +packages, and third-party packages --- expressed as [purls](#purl) mapped to [Version Ranges](#version-range). The structure is an [Object](#object) that specifies package dependencies for *Phases* of activity in the installation process, and *Relationships* that indicate how dependencies **SHOULD** be @@ -1013,17 +1024,17 @@ the `test` phase, this entry would appear in the ``` All known [purl Types] **SHOULD** be used to identify dependencies. -[Producers](#producer) **MAY** specify dependencies of two additional types as +[Producers](#producer) **MAY** specify dependencies on two additional types as appropriate: * **`pkg:pgxn`**: Packages distributed via [PGXN]. These **MUST** include package name, e.g., `pkg:pgxn/pair`. * **`pkg:postgres`**: Dependencies distributed as part of the PostgreSQL - core, including [contrib] or development packages such as [auto_explain], - [dblink], [pg_regress], and [pg_isolation_regress]. Example: - `pkg:postgres/dblink`. + core, including [contrib], [procedural language], or development packages + such as [auto_explain], [dblink], [plperl], [pg_regress], and + [pg_isolation_regress]. Example: `pkg:postgres/dblink`. -Versions **SHOULD** not be included in [purls](#purl), but in the [Version +Versions **SHOULD NOT** be included in [purls](#purl), but in the [Version Range](#version-range) values the [purls](#purl) properties point to. For example, this specification requires the `pair` PGXN package version 1.2.0 or greater but not 1.5.2: @@ -1045,11 +1056,11 @@ supports only OSes that provide such packages. See the "variations" property of the [dependencies](#dependencies) object for platform-specific dependency specification. -[Consumers](#consumer) **SHOULD** use the [Repology API] to resolve +The use of `pkg:generic` [purls](#purl) is useful for specifying system +dependencies that vary by name and packaging system. [Consumers](#consumer) +**MAY** use whatever techniques or heuristics are appropriate to resolve `pkg:generic` [purls](#purl) to packages specific to the platform on which an -extension is being built. This is useful for specifying system dependencies -that vary by name and packaging system. Otherwise, they **MAY** use whatever -techniques or heuristics are appropriate to install dependencies. +extension is being built. #### Phases #### @@ -1139,7 +1150,7 @@ Other extension registries, such as [Trunk], [PGXMan], [StackBuilder], and the community [Yum] and [Apt] repositories decouple maintenance of build metadata and dependencies, in particular, from the developer. Instead they're independently and manually managed by volunteers or employees of the companies -who develope and maintain them. +who develop and maintain them. They also tend to have formats specific to the platforms they serve, rather than to PostgreSQL generally. @@ -1149,7 +1160,7 @@ community binary packaging registry of all PGXN distributions. With this format, even if extension authors don't adopt the new format, PGXN maintainers can develop PGXN Meta Spec v2 overlays to merge with developer [v1 spec](0001-meta-spec-v1.md) files, both to assist with build automation and to -create pull requests for the original projects. +create pull requests for upstream projects. ## Prior art @@ -1160,14 +1171,8 @@ by the [purl spec] and [Repology], and the [RPM Packaging Guidelines]. ## Unresolved questions * Can we rely on [Repology] to resolve system dependencies? -* How, exactly, do we configure loadable modules, especially when used with - an extension? -* How do we properly annotate module pre-loading? How do we handle load - order issues (such as one module depending on another)? Or optional - pre-loading? -* Is it better to bundle dependencies into a package as loadable modules, or - to create separate distributions that just contain the loadable modules - and depend on them? +* How do we handle load order issues (such as one module depending on + another)? * Should any of this be deferred? For example, maybe omit the `archives` property. * Do we need to continue to treat package names as globally unique, or can @@ -1183,6 +1188,9 @@ by the [purl spec] and [Repology], and the [RPM Packaging Guidelines]. distribution. Many people found the version variation confusing. Will developers find it too painful to switch? Very few extensions on PGXN currently include more than one extension, so hopefully not. +* To what extent do we want to support pipeline customization? For example, + some pgrx extensions support `--feature` options, and some need + environment variable set, [like pglogical]. ## Future possibilities @@ -1257,8 +1265,10 @@ David Golden, Ricardo Signes, Adam Kennedy, and contributors. [configure flag]: https://www.postgresql.org/docs/current/install-make.html#CONFIGURE-OPTIONS-FEATURES [Repology API]: https://repology.org/api "Repology, the packaging hub: API" [contrib]: https://www.postgresql.org/docs/current/contrib.html + [procedural language]: https://www.postgresql.org/docs/current/xplang.html [auto_explain]: https://www.postgresql.org/docs/current/auto-explain.html [dblink]: https://www.postgresql.org/docs/current/dblink.html + [plperl]: https://www.postgresql.org/docs/current/plperl.html [pg_regress]: https://github.com/postgres/postgres/tree/master/src/test/regress [pg_isolation_regress]: https://github.com/postgres/postgres/tree/master/src/test/isolation [Shields badge specification]: https://github.com/badges/shields/blob/master/spec/SPECIFICATION.md @@ -1279,3 +1289,4 @@ David Golden, Ricardo Signes, Adam Kennedy, and contributors. [StackBuilder]: https://www.enterprisedb.com/docs/supported-open-source/postgresql/installing/using_stackbuilder/ [Apt]: https://wiki.postgresql.org/wiki/Apt "PostgreSQL packages for Debian and Ubuntu" [Yum]: https://yum.postgresql.org "PostgreSQL Yum Repository" + [like pglogical]: https://github.com/2ndQuadrant/pglogical/issues/492 From 4021dee6141c206cf3f97bbdd429354d22776e1f Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Thu, 27 Mar 2025 18:10:18 -0400 Subject: [PATCH 12/13] Lock down current diretory components, too --- text/0003-meta-spec-v2.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/text/0003-meta-spec-v2.md b/text/0003-meta-spec-v2.md index 2583c4c..efb8402 100644 --- a/text/0003-meta-spec-v2.md +++ b/text/0003-meta-spec-v2.md @@ -152,8 +152,9 @@ Locator as defined by [IETF RFC 3986]. *Path* is a [String](#string) with a relative file path that identifies a file in the [Distribution](#source-distribution). The path **MUST** be specified with Unix conventions and **MUST NOT** include parent directory components -(`..`). It may begin with a slash, but will still be considered relative to -the directory containing the `META.json` file. +(`..`). A current directory component (`.`) may only be used at the start of +the path (e.g., `./README.md`). It may begin with a slash, but will still be +considered relative to the directory containing the `META.json` file. #### Glob #### @@ -173,7 +174,9 @@ files in the [Distribution](#source-distribution). Its format, based on the * An asterisk (`*`) matches anything except a slash. The character `?` matches any one character except `/` The range notation, e.g., `[a-zA-Z]`, can be used to match one of the characters in a range. -* Parent directory components (`..`) are not allowed. +* Parent anc current directory components (`..`) are not allowed. +* Current directory components (`.`) are not allowed except at the start of + the glob (e.g., `./.git*`). #### SemVer #### From 32f1e89824650907f962844efd9cc567360567b6 Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Tue, 20 May 2025 17:08:15 -0400 Subject: [PATCH 13/13] Expland Glob definition, fix typo --- text/0003-meta-spec-v2.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/text/0003-meta-spec-v2.md b/text/0003-meta-spec-v2.md index efb8402..f9f6eab 100644 --- a/text/0003-meta-spec-v2.md +++ b/text/0003-meta-spec-v2.md @@ -172,8 +172,16 @@ files in the [Distribution](#source-distribution). Its format, based on the only match directories, otherwise the pattern can match both files and directories. * An asterisk (`*`) matches anything except a slash. The character `?` - matches any one character except `/` The range notation, e.g., `[a-zA-Z]`, - can be used to match one of the characters in a range. + matches any one character except `/`. +* A double asterisk (`**`) matches any characters across zero or more + directory components, and must be delimited by forward slashes or + terminations (the beginning and/or end of a glob expression). +* A character class, e.g., `[a-zA-Z]`, matches one of the characters in the + class. Use a `!` as the first character to negate the class (`e.g., `[!a]` + matches any character other than `a`). +* Alternations (`{...,...}`) match an arbitrary sequence of one or more + comma separated sub-globs. For example, `{a?c,x?z,foo}` matches any of the + alternative globs `a?c`, `x?z`, or `foo`. * Parent anc current directory components (`..`) are not allowed. * Current directory components (`.`) are not allowed except at the start of the glob (e.g., `./.git*`). @@ -891,7 +899,7 @@ Properties: to [Objects](#object) with [purls](#purl) property keys pointing to [Version Range](#version-range) values. - See the [Package Spec](#packages-spec) for the full definition of this + See the [Packages Spec](#packages-spec) for the full definition of this property. * **variations**: An [Array](#array) of [Object](#object)s that define