Skip to content

Commit 8ee8d40

Browse files
authored
The logic to generate manifest source from existing parsed manifest data structures misquoted some package version requirement ranges. (#3415)
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 8ee8d40

File tree

2 files changed

+39
-4
lines changed

2 files changed

+39
-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: 35 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,34 @@ 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+
162196
func testResources() throws {
163197
let manifestContents = """
164198
// swift-tools-version:5.3

0 commit comments

Comments
 (0)