Skip to content

Commit 919b2d8

Browse files
committed
The logic to generate manifest source from existing parsed manifest data structures misquoted some package version requirement ranges.
This fixes those cases, producing a semantically equivalent package manifests. Since the model does not capture how a particular range was specified, it is not possible to recreate the original shorthands. A future improvement can either extend the model to record the original spelling of the range requirements, or can apply heuristics to shorten the rules in the future (e.g. automatically derive `upToNextMajor()` etc. This also eliminates an extra whitespace before the minimum tools version declaration when the specified tools version allows it, so older parsers can parse the generated manifests. rdar://76559428
1 parent 9650406 commit 919b2d8

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

Sources/PackageModel/ManifestSourceGeneration.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ extension Manifest {
2525
public var generatedManifestFileContents: String {
2626
/// Only write out the major and minor (not patch) versions of the
2727
/// tools version, since the patch version doesn't change semantics.
28+
/// We leave out the spacer if the tools version doesn't support it.
2829
return """
29-
// swift-tools-version: \(toolsVersion.major).\(toolsVersion.minor)
30+
// swift-tools-version:\(toolsVersion < .v5_4 ? "" : " ")\(toolsVersion.major).\(toolsVersion.minor)
3031
import PackageDescription
3132
3233
let package = \(SourceCodeFragment(from: self).generateSourceCode())
@@ -129,9 +130,9 @@ fileprivate extension SourceCodeFragment {
129130
params.append(SourceCodeFragment(key: "url", string: data.location))
130131
switch data.requirement {
131132
case .exact(let version):
132-
params.append(SourceCodeFragment(enum: "exact", string: version.description))
133+
params.append(SourceCodeFragment(enum: "exact", string: "\(version)"))
133134
case .range(let range):
134-
params.append(SourceCodeFragment(enum: "range", string: range.description))
135+
params.append(SourceCodeFragment("\"\(range.lowerBound)\"..<\"\(range.upperBound)\""))
135136
case .revision(let revision):
136137
params.append(SourceCodeFragment(enum: "revision", string: revision))
137138
case .branch(let branch):

Tests/WorkspaceTests/ManifestSourceGenerationTests.swift

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,14 @@ class ManifestSourceGenerationTests: XCTestCase {
3737
completion: $0)
3838
}
3939

40-
// Generate source code for the loaded manifest, write it out to replace the manifest file contents, and load it again.
40+
// Generate source code for the loaded manifest,
4141
let newContents = manifest.generatedManifestFileContents
42+
43+
// Check that the tools version was serialized properly.
44+
let versionSpacing = (toolsVersion >= .v5_4) ? " " : ""
45+
XCTAssertTrue(newContents.hasPrefix("// swift-tools-version:\(versionSpacing)\(toolsVersion.major).\(toolsVersion.minor)"), newContents)
46+
47+
// Write out the generated manifest to replace the old manifest file contents, and load it again.
4248
try fs.writeFileContents(packageDir.appending(component: Manifest.filename), bytes: ByteString(encodingAsUTF8: newContents))
4349
let newManifest = try tsc_await {
4450
manifestLoader.load(at: packageDir,
@@ -159,6 +165,35 @@ class ManifestSourceGenerationTests: XCTestCase {
159165
try testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_3)
160166
}
161167

168+
func testPackageDependencyVariations() throws {
169+
let manifestContents = """
170+
// swift-tools-version:5.4
171+
import PackageDescription
172+
173+
let package = Package(
174+
name: "MyPackage",
175+
dependencies: [
176+
.package(url: "/foo1", from: "1.0.0"),
177+
.package(url: "/foo2", .revision("58e9de4e7b79e67c72a46e164158e3542e570ab6")),
178+
.package(path: "../foo3"),
179+
.package(path: "/path/to/foo4"),
180+
.package(url: "/foo5", .exact("1.2.3")),
181+
.package(url: "/foo6", "1.2.3"..<"2.0.0"),
182+
.package(url: "/foo7", .branch("master")),
183+
.package(url: "/foo8", .upToNextMinor(from: "1.3.4")),
184+
.package(url: "/foo9", .upToNextMajor(from: "1.3.4")),
185+
.package(path: "~/path/to/foo10"),
186+
.package(path: "~foo11"),
187+
.package(path: "~/path/to/~/foo12"),
188+
.package(path: "~"),
189+
.package(path: "file:///path/to/foo13"),
190+
]
191+
)
192+
"""
193+
try testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_3)
194+
}
195+
196+
162197
func testResources() throws {
163198
let manifestContents = """
164199
// swift-tools-version:5.3

0 commit comments

Comments
 (0)