Package Collection Format

Package Collections (SE-0291) are short, curated lists of packages and associated metadata that can be imported by SwiftPM to make package discovery easier. This is a draft of the format that all package collections must adhere to.

Creating a package collection

A package collection is a JSON document that contains a list of packages and metadata per package.

To begin, define the top-level metadata about the collection:

  • name : The name of the package collection, for display purposes only.
  • overview : A description of the package collection. Optional.
  • keywords : An array of keywords that the package collection is associated with. Optional.
  • formatVersion : The version of the format to which the package collection conforms. Currently, 1.0 is the only allowed value.
  • revision : The revision number of this package collection. Optional.
  • generatedAt : The ISO 8601-formatted date-time string when the package collection was generated.
  • generatedBy : The author of this package collection. Optional.
{
  "name": "Jane Doe"
}
  • packages : An array of package objects.

Add packages to the collection

Each item in the packages array is a package object with the following properties:

  • url : The URL of the package. Currently only Git repository URLs are supported.
  • summary : A description of the package. Optional.
  • keywords : An array of keywords that the package is associated with. Optional.
  • readmeURL : The URL of the package's README. Optional.
  • versions : An array of version objects representing the most recent and/or relevant releases of the package.

Add versions to a package

A version object has metadata extracted from Package.swift and optionally additional metadata from other sources:

  • version : The semantic version string.
  • packageName : The name of the package.
  • targets : An array of the package version's targets.
    • name : The target name.
    • moduleName : The module name if this target can be imported as a module. Optional.
  • products : An array of the package version's products.
    • name : The product name.
    • type : The product type. This must have the same JSON representation as SwiftPM's PackageModel.ProductType .
    • target : An array of the product’s targets.
{
  "name": "MyProduct",
  "type": {
    "library": ["automatic"]
  },
  "targets": ["MyTarget"]
}
  • toolsVersion : The tools (semantic) version specified in Package.swift .
  • minimumPlatformVersions : An array of the package version’s supported platforms specified in Package.swift . Optional.
{    
  "name": "macOS",    
  "version": "10.15"
}
  • verifiedPlatforms : An array of platforms in which the package version has been tested and verified. Valid platform names include macOS , iOS , tvOS , watchOS , Linux , Android , and Windows . This is different from platforms in Package.swift . Optional.
{
  "name": "macOS"
}
  • verifiedSwiftVersions : An array of Swift versions that the package version has been tested and verified for. Values must be semantic version strings. This is different from swiftLanguageVersions in Package.swift . Optional.
  • license : The package version's license. Optional.
    • name : License name. SPDX identifier ( e.g. , Apache-2.0 , MIT , etc.) preferred.
    • url : The URL of the license file.

Other requirements

  • The number of versions included for each package will be limited--the current proposal is at most two major versions and up to three minor versions per major version.

Sample package collection

{
  "name": "Sample Package Collection",
  "overview": "This is a sample package collection listing made-up packages.",
  "keywords": ["sample package collection"],
  "formatVersion": "1.0",
  "revision": 3,
  "generatedAt": "2020-10-22T06:03:52Z",
  "packages": [
    {
      "url": "https://www.example.com/repos/RepoOne.git",
      "summary": "Package One",
      "readmeURL": "https://www.example.com/repos/RepoOne/README",
      "versions": [
        {
          "version": "0.1.0",
          "packageName": "PackageOne",
          "targets": [
            {
              "name": "Foo",
              "moduleName": "Foo"
            }
          ],
          "products": [
            {
              "name": "Foo",
              "type": {
                "library": ["automatic"]
              },
              "targets": ["Foo"]
            }
          ],
          "toolsVersion": "5.1",
          "verifiedPlatforms": [
            { "name": "macOS" },
            { "name": "iOS" },
            { "name": "Linux" }
          ],
          "verifiedSwiftVersions": ["5.1"],
          "license": {
            "name": "Apache-2.0",
            "url": "https://www.example.com/repos/RepoOne/LICENSE"
          }
        }
      ]
    },
    {
      "url": "https://www.example.com/repos/RepoTwo.git",
      "summary": "Package Two",
      "readmeURL": "https://www.example.com/repos/RepoTwo/README",
      "versions": [
        {
          "version": "2.1.0",
          "packageName": "PackageTwo",
          "targets": [
            {
              "name": "Bar",
              "moduleName": "Bar"
            }
          ],
          "products": [
            {
              "name": "Bar",
              "type": {
                "library": ["automatic"]
              },
              "targets": ["Bar"]
            }
          ],
          "toolsVersion": "5.2"
        },
        {
          "version": "1.8.3",
          "packageName": "PackageTwo",
          "targets": [
            {
              "name": "Bar",
              "moduleName": "Bar"
            }
          ],
          "products": [
            {
              "name": "Bar",
              "type": {
                "library": ["automatic"]
              },
              "targets": ["Bar"]
            }
          ],
          "toolsVersion": "5.0"
        }        
      ]
    }
  ]
}
7 Likes

Have you considered the use of alternative formats such as TOML (as is used in Cargo) or YAML rather than JSON?

Was this format designed de novo, or is it based on some prior art or existing standard (as have been discussed by the community in the past)? How does the format proposed here compare to what's used by other package managers?

What is the rationale for these limits (and in particular, 50 packages and 100 KB)? How will this be enforced? If a file is 100 KB in one file system but more than that in another, will it be usable on one machine but rejected by another?

4 Likes

We believe JSON is the format that is the most straight-forward to use in this case.

The format was designed de novo for the use cases described in the package collections proposal. I personally am not aware of previous discussions on this. Do you think there is information missing or shouldn't be included?

The actual numbers are debatable, but since SwiftPM will be the primary consumer of package collections and clients of libSwiftPM will be able to access the data, there needs to be limits in place to help ensure smooth UX. The limits will be enforced when SwiftPM imports a package collection.

To +1 what Yim's saying here:

A different, human readable, format would make sense if humans were to write/edit/read those files -- but they won't, right? It is for tools to generate and consume, thus I don't think formats like YAML/TOML/HOCON add value here. If anything, another binary format could be fun some day to be slightly more efficient, but JSON seems like a good default IMHO :slight_smile:

4 Likes

I beg you to please reconsider having hard limits. It would actually prevent me from using the feature for fear that my collection would someday grow one package beyond the limit. A smooth UX degradation for collections that grow too large can be managed, but falling off a cliff where the system refuses to function cannot.

2 Likes

This doesn't make much sense to me. What about libSwiftPM requires that such limits exist (and why wouldn't we fix that limitation instead of baking a hard limit into the format?)

1 Like

Thanks @dabrahams @scanon. I will leave the size requirements out of the format proposal. I am keeping the limit on the number of versions to include though, because I think that is important to keep the collection data relevant.

2 Likes

Can you say a little more about why that's important? It seems to me that people may have good reasons to select older versions of packages. I assume that would still be possible, somehow; how does keeping older versions out of the collection change the relevance of the collection?

Certainly, and nothing with the Package Collections feature will prevent users from using the versions that they want. The intention is that a package collection would contain enough data to introduce users to a package and help them get started with it, and for that listing the latest version should suffice. If users are familiar with the package and think a specific version would work better for them, they should be able to use it even if it's not listed in the collection. In other words, package collection is a discovery mechanism; the proposal doesn't put any restrictions on how dependencies are defined.

Besides, if semantic versioning is followed then minor versions must be backwards compatible, so IMO there is no need for collection to list more than a few minor versions. The only time I would not use the latest minor version is if it contains a bug or if there are underlying changes to the logic that I am not ready to upgrade to yet, but that kind of information is expected to be found elsewhere and not in package collections.

1 Like

All well and good, but why limit the number of major versions?

All well and good, but why limit the number of major versions?

It's probably uncommon to be couple major versions behind though?

Sure, it's uncommon. People mostly won't list too many versions. Any hard limits, though, will just limit this tool's flexibility. If you want to discourage listing too many versions, give people a warning, and maybe an interactive prompt to automatically eliminate older major versions when they add a new one.

I understand. There will be a tool for generating collections, which by default will choose the latest versions, and on the client side we could ignore the extra versions instead of rejecting the entire collection.

Terms of Service

Privacy Policy

Cookie Policy