Skip to content

Commit baa239f

Browse files
authored
Updates to support version-specific manifest (#16)
Requires swiftlang/swift-package-manager#3226
1 parent aaf3eba commit baa239f

File tree

10 files changed

+393
-462
lines changed

10 files changed

+393
-462
lines changed

PackageCollectionFormats/v1.md

+1-195
Original file line numberDiff line numberDiff line change
@@ -1,197 +1,3 @@
11
# Package Collection
22

3-
Package collections are short, curated lists of packages and associated metadata that can be imported
4-
by SwiftPM to make package discovery easier. Educators and community influencers can publish
5-
package collections to go along with course materials or blog posts, removing the friction of using
6-
packages for the first time and the cognitive overload of deciding which packages are useful for
7-
a particular task. Enterprises may use collections to narrow the decision space for their internal
8-
engineering teams, focusing them on a trusted set of vetted packages.
9-
10-
## Creating a Package Collection
11-
12-
A package collection is a JSON document that contains a list of packages and metadata per package.
13-
14-
To begin, define the top-level metadata about the collection:
15-
16-
* `name`: The name of the package collection, for display purposes only.
17-
* `overview`: A description of the package collection. **Optional.**
18-
* `keywords`: An array of keywords that the collection is associated with. **Optional.**
19-
* `formatVersion`: The version of the format to which the collection conforms. Currently, `1.0` is the only allowed value.
20-
* `revision`: The revision number of this package collection. **Optional.**
21-
* `generatedAt`: The ISO 8601-formatted datetime string when the package collection was generated.
22-
* `generatedBy`: The author of this package collection. **Optional.**
23-
* `name`: The author name.
24-
* `packages`: An array of package objects.
25-
26-
#### Add packages to the collection
27-
28-
Each item in the `packages` array is a package object with the following properties:
29-
30-
* `url`: The URL of the package. Currently only Git repository URLs are supported.
31-
* `summary`: A description of the package. **Optional.**
32-
* `keywords`: An array of keywords that the package is associated with. **Optional.**
33-
* `readmeURL`: The URL of the package's README. **Optional.**
34-
* `license`: The package's *current* license information. **Optional.**
35-
* `url`: The URL of the license file.
36-
* `name`: License name. [SPDX identifier](https://spdx.org/licenses/) (e.g., `Apache-2.0`, `MIT`, etc.) preferred. Omit if unknown. **Optional.**
37-
* `versions`: An array of version objects representing the most recent and/or relevant releases of the package.
38-
39-
#### Add versions to a package
40-
41-
A version object has metadata extracted from `Package.swift` and optionally additional metadata from other sources:
42-
43-
* `version`: The semantic version string.
44-
* `packageName`: The name of the package.
45-
* `targets`: An array of the package version's targets.
46-
* `name`: The target name.
47-
* `moduleName`: The module name if this target can be imported as a module. **Optional.**
48-
* `products`: An array of the package version's products.
49-
* `name`: The product name.
50-
* `type`: The product type. This must have the same JSON representation as SwiftPM's `PackageModel.ProductType`.
51-
* `target`: An array of the product’s targets.
52-
53-
```json
54-
{
55-
"name": "MyProduct",
56-
"type": {
57-
"library": ["automatic"]
58-
},
59-
"targets": ["MyTarget"]
60-
}
61-
```
62-
63-
* `toolsVersion`: The tools (semantic) version specified in `Package.swift`.
64-
* `minimumPlatformVersions`: An array of the package version’s supported platforms specified in `Package.swift`. **Optional.**
65-
66-
```json
67-
{
68-
"name": "macOS",
69-
"version": "10.15"
70-
}
71-
```
72-
73-
* `verifiedCompatibility`: An array of compatible platforms and Swift versions that has been tested and verified for. Valid platform names include `macOS`, `iOS`, `tvOS`, `watchOS`, `Linux`, `Android`, and `Windows`. Swift version should be semantic version string and as specific as possible. **Optional.**
74-
75-
```json
76-
{
77-
"platform": {
78-
"name": "macOS"
79-
},
80-
"swiftVersion": "5.3.2"
81-
}
82-
```
83-
84-
* `license`: The package version's license. **Optional.**
85-
* `url`: The URL of the license file.
86-
* `name`: License name. [SPDX identifier](https://spdx.org/licenses/) (e.g., `Apache-2.0`, `MIT`, etc.) preferred. Omit if unknown. **Optional.**
87-
88-
## Example
89-
90-
```json
91-
{
92-
"name": "Sample Package Collection",
93-
"overview": "This is a sample package collection listing made-up packages.",
94-
"keywords": ["sample package collection"],
95-
"formatVersion": "1.0",
96-
"revision": 3,
97-
"generatedAt": "2020-10-22T06:03:52Z",
98-
"packages": [
99-
{
100-
"url": "https://www.example.com/repos/RepoOne.git",
101-
"summary": "Package One",
102-
"readmeURL": "https://www.example.com/repos/RepoOne/README",
103-
"license": {
104-
"name": "Apache-2.0",
105-
"url": "https://www.example.com/repos/RepoOne/LICENSE"
106-
},
107-
"versions": [
108-
{
109-
"version": "0.1.0",
110-
"packageName": "PackageOne",
111-
"targets": [
112-
{
113-
"name": "Foo",
114-
"moduleName": "Foo"
115-
}
116-
],
117-
"products": [
118-
{
119-
"name": "Foo",
120-
"type": {
121-
"library": ["automatic"]
122-
},
123-
"targets": ["Foo"]
124-
}
125-
],
126-
"toolsVersion": "5.1",
127-
"verifiedCompatibility": [
128-
{
129-
"platform": { "name": "macOS" },
130-
"swiftVersion": "5.1"
131-
},
132-
{
133-
"platform": { "name": "iOS" },
134-
"swiftVersion": "5.1"
135-
},
136-
{
137-
"platform": { "name": "Linux" },
138-
"swiftVersion": "5.1"
139-
}
140-
],
141-
"license": {
142-
"name": "Apache-2.0",
143-
"url": "https://www.example.com/repos/RepoOne/LICENSE"
144-
}
145-
}
146-
]
147-
},
148-
{
149-
"url": "https://www.example.com/repos/RepoTwo.git",
150-
"summary": "Package Two",
151-
"readmeURL": "https://www.example.com/repos/RepoTwo/README",
152-
"versions": [
153-
{
154-
"version": "2.1.0",
155-
"packageName": "PackageTwo",
156-
"targets": [
157-
{
158-
"name": "Bar",
159-
"moduleName": "Bar"
160-
}
161-
],
162-
"products": [
163-
{
164-
"name": "Bar",
165-
"type": {
166-
"library": ["automatic"]
167-
},
168-
"targets": ["Bar"]
169-
}
170-
],
171-
"toolsVersion": "5.2"
172-
},
173-
{
174-
"version": "1.8.3",
175-
"packageName": "PackageTwo",
176-
"targets": [
177-
{
178-
"name": "Bar",
179-
"moduleName": "Bar"
180-
}
181-
],
182-
"products": [
183-
{
184-
"name": "Bar",
185-
"type": {
186-
"library": ["automatic"]
187-
},
188-
"targets": ["Bar"]
189-
}
190-
],
191-
"toolsVersion": "5.0"
192-
}
193-
]
194-
}
195-
]
196-
}
197-
```
3+
This file has been relocated to [PackageCollectionsModel/Formats/v1](https://github.com/apple/swift-package-manager/tree/main/Sources/PackageCollectionsModel/Formats/v1.md) in SwiftPM.

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,13 @@ for details.
1616

1717
[`package-collection-generate`](Sources/PackageCollectionGenerator/README.md) is a Swift
1818
command-line tool that helps generate package collections.
19+
20+
## Validating a Package Collection
21+
22+
[`package-collection-validate`](Sources/PackageCollectionValidator/README.md) is a Swift
23+
command-line tool that validates package collections against the defined format.
24+
25+
## Comparing Package Collections
26+
27+
[`package-collection-diff`](Sources/PackageCollectionDiff/README.md) is a Swift
28+
command-line tool that compares two package collections to determine if they are different from each other.

Sources/PackageCollectionGenerator/Models/PackageCollectionExtensions.swift

+29-12
Original file line numberDiff line numberDiff line change
@@ -57,25 +57,36 @@ extension PackageCollectionModel.V1.Collection.Package.Version: CustomStringConv
5757
"""
5858
Version {
5959
version=\(self.version),
60-
packageName=\(self.packageName),
61-
targets=\(self.targets),
62-
products=\(self.products),
63-
toolsVersion=\(self.toolsVersion),
64-
minimumPlatformVersions=\(self.minimumPlatformVersions.map { "\($0)" } ?? "nil"),
60+
manifests=\(self.manifests),
61+
defaultToolsVersion=\(self.defaultToolsVersion),
6562
verifiedCompatibility=\(self.verifiedCompatibility.map { "\($0)" } ?? "nil"),
6663
license=\(self.license.map { "\($0)" } ?? "nil")
6764
}
6865
"""
6966
}
7067
}
7168

69+
extension PackageCollectionModel.V1.Collection.Package.Version.Manifest: CustomStringConvertible {
70+
public var description: String {
71+
"""
72+
{
73+
toolsVersion=\(self.toolsVersion),
74+
packageName=\(self.packageName),
75+
targets=\(self.targets),
76+
products=\(self.products),
77+
minimumPlatformVersions=\(self.minimumPlatformVersions.map { "\($0)" } ?? "nil")
78+
}
79+
"""
80+
}
81+
}
82+
7283
extension PackageCollectionModel.V1.Target: CustomStringConvertible {
7384
public var description: String {
7485
"""
7586
Target(
76-
name=\(self.name),
77-
moduleName=\(self.moduleName.map { "\($0)" } ?? "nil")
78-
)
87+
name=\(self.name),
88+
moduleName=\(self.moduleName.map { "\($0)" } ?? "nil")
89+
)
7990
"""
8091
}
8192
}
@@ -84,14 +95,20 @@ extension PackageCollectionModel.V1.Product: CustomStringConvertible {
8495
public var description: String {
8596
"""
8697
Product(
87-
name=\(self.name),
88-
type=\(self.type),
89-
targets=\(self.targets)
90-
)
98+
name=\(self.name),
99+
type=\(self.type),
100+
targets=\(self.targets)
101+
)
91102
"""
92103
}
93104
}
94105

106+
extension PackageCollectionsModel.PackageCollectionModel.V1.ProductType.LibraryType: CustomStringConvertible {
107+
public var description: String {
108+
"\(self.rawValue)"
109+
}
110+
}
111+
95112
extension PackageCollectionModel.V1.PlatformVersion: CustomStringConvertible {
96113
public var description: String {
97114
"\(self.name)(\(self.version))"

Sources/PackageCollectionGenerator/PackageCollectionGenerate.swift

+35-22
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,8 @@ public struct PackageCollectionGenerate: ParsableCommand {
111111
print("Package collection saved to \(outputAbsolutePath)", inColor: .cyan, verbose: self.verbose)
112112
}
113113

114-
private func generateMetadata(
115-
for package: PackageCollectionGeneratorInput.Package,
116-
jsonDecoder: JSONDecoder
117-
) throws -> Model.Collection.Package {
114+
private func generateMetadata(for package: PackageCollectionGeneratorInput.Package,
115+
jsonDecoder: JSONDecoder) throws -> Model.Collection.Package {
118116
print("Processing Package(\(package.url))", inColor: .cyan, verbose: self.verbose)
119117

120118
// Try to locate the directory where the repository might have been cloned to previously
@@ -168,11 +166,9 @@ public struct PackageCollectionGenerate: ParsableCommand {
168166
}
169167
}
170168

171-
private func generateMetadata(
172-
for package: PackageCollectionGeneratorInput.Package,
173-
gitDirectoryPath: AbsolutePath,
174-
jsonDecoder: JSONDecoder
175-
) throws -> Model.Collection.Package {
169+
private func generateMetadata(for package: PackageCollectionGeneratorInput.Package,
170+
gitDirectoryPath: AbsolutePath,
171+
jsonDecoder: JSONDecoder) throws -> Model.Collection.Package {
176172
// Select versions if none specified
177173
let versions = try package.versions ?? self.defaultVersions(for: gitDirectoryPath)
178174
// Load the manifest for each version and extract metadata
@@ -200,17 +196,37 @@ public struct PackageCollectionGenerate: ParsableCommand {
200196
)
201197
}
202198

203-
private func generateMetadata(
204-
for version: String,
205-
excludedProducts: Set<String>,
206-
excludedTargets: Set<String>,
207-
gitDirectoryPath: AbsolutePath,
208-
jsonDecoder: JSONDecoder
209-
) throws -> Model.Collection.Package.Version {
199+
private func generateMetadata(for version: String,
200+
excludedProducts: Set<String>,
201+
excludedTargets: Set<String>,
202+
gitDirectoryPath: AbsolutePath,
203+
jsonDecoder: JSONDecoder) throws -> Model.Collection.Package.Version {
210204
// Check out the git tag
211205
print("Checking out version \(version)", inColor: .yellow, verbose: self.verbose)
212206
try ShellUtilities.run(Git.tool, "-C", gitDirectoryPath.pathString, "checkout", version)
213207

208+
let defaultManifest = try self.defaultManifest(
209+
excludedProducts: excludedProducts,
210+
excludedTargets: excludedTargets,
211+
gitDirectoryPath: gitDirectoryPath,
212+
jsonDecoder: jsonDecoder
213+
)
214+
// TODO: Use `describe` to obtain all manifest-related data, including version-specific manifests
215+
let manifests = [defaultManifest.toolsVersion: defaultManifest]
216+
217+
return Model.Collection.Package.Version(
218+
version: version,
219+
manifests: manifests,
220+
defaultToolsVersion: defaultManifest.toolsVersion,
221+
verifiedCompatibility: nil,
222+
license: nil
223+
)
224+
}
225+
226+
private func defaultManifest(excludedProducts: Set<String>,
227+
excludedTargets: Set<String>,
228+
gitDirectoryPath: AbsolutePath,
229+
jsonDecoder: JSONDecoder) throws -> Model.Collection.Package.Version.Manifest {
214230
// Run `swift package dump-package` to generate JSON manifest from `Package.swift`
215231
let manifestJSON = try ShellUtilities.run(ShellUtilities.shell, "-c", "cd \(gitDirectoryPath) && swift package dump-package")
216232
let manifest = try jsonDecoder.decode(PackageManifest.self, from: manifestJSON.data(using: .utf8) ?? Data())
@@ -242,8 +258,8 @@ public struct PackageCollectionGenerate: ParsableCommand {
242258
minimumPlatformVersions = platforms.map { Model.PlatformVersion(name: $0.platformName, version: $0.version) }
243259
}
244260

245-
return Model.Collection.Package.Version(
246-
version: version,
261+
return Model.Collection.Package.Version.Manifest(
262+
toolsVersion: manifest.toolsVersion._version,
247263
packageName: manifest.name,
248264
targets: manifest.targets.filter { publicTargets.contains($0.name) }.map { target in
249265
Model.Target(
@@ -252,10 +268,7 @@ public struct PackageCollectionGenerate: ParsableCommand {
252268
)
253269
},
254270
products: products,
255-
toolsVersion: manifest.toolsVersion._version,
256-
minimumPlatformVersions: minimumPlatformVersions,
257-
verifiedCompatibility: nil,
258-
license: nil
271+
minimumPlatformVersions: minimumPlatformVersions
259272
)
260273
}
261274

0 commit comments

Comments
 (0)