Skip to content

Commit c0454c0

Browse files
committed
Add a subcommand to swift-syntax-dev-utils to verify that .spi.yml is up-to-date
.spi.yml at one point got out of sync of the libraries we added to Package.swift. Add a verification script to make sure that they match. The idea is that for every library that every library that is exposed by SwiftSyntax should be documentated on swiftpackageindex.com. rdar://108901461
1 parent 44f6968 commit c0454c0

File tree

3 files changed

+82
-1
lines changed

3 files changed

+82
-1
lines changed

SwiftSyntaxDevUtils/Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import PackageDescription
66
let package = Package(
77
name: "swift-syntax-dev-utils",
88
platforms: [
9-
.macOS(.v10_15)
9+
.macOS(.v13)
1010
],
1111
products: [
1212
.executable(name: "swift-syntax-dev-utils", targets: ["swift-syntax-dev-utils"])

SwiftSyntaxDevUtils/Sources/swift-syntax-dev-utils/SwiftSyntaxDevUtils.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ struct SwiftSyntaxDevUtils: ParsableCommand {
3030
GenerateSourceCode.self,
3131
Test.self,
3232
VerifySourceCode.self,
33+
VerifySpiYml.self,
3334
]
3435
)
3536

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import ArgumentParser
14+
import Foundation
15+
import RegexBuilder
16+
17+
struct VerifySpiYml: ParsableCommand {
18+
static let configuration = CommandConfiguration(
19+
abstract: "Verify that the .spi.yml file contains all libraries from Package.swift"
20+
)
21+
22+
/// Returns all libraries declared in `Package.swift`.
23+
///
24+
/// Note: It would be nice if we could compile Package.swift with this file and reallly
25+
/// inspect the package targets instead of doing regex scraping, but this is good enough
26+
/// for now.
27+
private func librariesInPackageManifest() throws -> [String] {
28+
let extractNameRegex = Regex {
29+
#/^.*/#
30+
#".library(name: ""#
31+
Capture(ZeroOrMore(.word))
32+
#"""#
33+
#/.*$/#
34+
}
35+
let packageFile = Paths.packageDir.appending(component: "Package.swift")
36+
let packageFileContents = try String(contentsOf: packageFile)
37+
return
38+
packageFileContents
39+
.components(separatedBy: "\n")
40+
.filter({ !$0.matches(of: extractNameRegex).isEmpty })
41+
.map { $0.replacing(extractNameRegex) { $0.1 } }
42+
.sorted()
43+
}
44+
/// Returns all targets listed in `.spi.yml`.
45+
///
46+
/// Note: It would be nice to actually parse the .yml file but then we would need to add
47+
/// a dependency from this script on a YAML parser and that just doesn’t seem worth it.
48+
private func targetsInSwiftPackageIndexManifest() throws -> [String] {
49+
let extractTargetRegex = Regex {
50+
#/^ - /#
51+
Capture(ZeroOrMore(.word))
52+
#/$/#
53+
}
54+
let spiYmlFile = Paths.packageDir.appending(component: ".spi.yml")
55+
let spiYmlFileContents = try String(contentsOf: spiYmlFile)
56+
return
57+
spiYmlFileContents
58+
.components(separatedBy: "\n")
59+
.filter({ !$0.matches(of: extractTargetRegex).isEmpty })
60+
.map { $0.replacing(extractTargetRegex) { $0.1 } }
61+
.sorted()
62+
}
63+
64+
func run() throws {
65+
let difference = try targetsInSwiftPackageIndexManifest().difference(from: librariesInPackageManifest())
66+
67+
if !difference.isEmpty {
68+
var message = ".spi.yml did not contain the same libraries as Package.swift:\n"
69+
for change in difference {
70+
switch change {
71+
case .insert(_, let element, _):
72+
message += " - Unexpected in .spi.yml: \(element)\n"
73+
case .remove(_, let element, _):
74+
message += " - Missing in .spi.yml: \(element)"
75+
}
76+
}
77+
throw ScriptExectutionError(message: message)
78+
}
79+
}
80+
}

0 commit comments

Comments
 (0)