Temporary fix of SwiftPM Bug using task.sh
SwiftPM has currently a bug, that products or targets of dependencies are taken into consideration when resolving names, regardless if they're used or not by the root package. This stops Swift PM from working on packages, that declare this package as a dependency and define their own TaskCLI target, as they collide with the definitions of this package. This is resolved, by prefixing TaskCLI with the package name. The product collision - which causes swift run - to run this package's task executable is resolved, by adding that product only temporarily during task execution using task.sh. See https://github.com/swiftlang/swift-package-manager/issues/8482
This commit is contained in:
@@ -3,27 +3,15 @@ import _NIOFileSystem
|
||||
public struct DoccFinder {
|
||||
static let fileManager = FileSystem.shared
|
||||
|
||||
public static func getTargetsWithDocumentation(at paths: String...) async throws -> [String] {
|
||||
try await Self.getTargetsWithDocumentation(at: paths)
|
||||
}
|
||||
public static func hasDoccFolder(at path: String) async throws -> Bool {
|
||||
let itemPath = FilePath(path)
|
||||
var hasDoccFolder = false
|
||||
|
||||
static func getTargetsWithDocumentation(at paths: [String]) async throws -> [String] {
|
||||
var resolved: [String] = []
|
||||
|
||||
for path in paths {
|
||||
let itemPath = FilePath(path)
|
||||
|
||||
try await withSubdirectories(at: itemPath) { targetPath in
|
||||
print("Target path is", targetPath.description)
|
||||
try await withSubdirectories(at: targetPath) { subdirectory in
|
||||
guard subdirectory.description.hasSuffix(".docc") else { return }
|
||||
guard let target = targetPath.lastComponent?.description else { return }
|
||||
resolved.append(target)
|
||||
}
|
||||
}
|
||||
try await withSubdirectories(at: itemPath) { subdirectory in
|
||||
guard subdirectory.description.hasSuffix(".docc") else { return }
|
||||
hasDoccFolder = true
|
||||
}
|
||||
|
||||
return resolved
|
||||
return hasDoccFolder
|
||||
}
|
||||
|
||||
private static func withSubdirectories(at path: FilePath, body: (FilePath) async throws -> Void) async throws {
|
||||
|
||||
@@ -90,7 +90,7 @@ struct GenerateDocumentationCommand: AsyncParsableCommand {
|
||||
("{{project.tagline}}", "🗂️ Monitor filesystem events on Linux using modern Swift concurrency"),
|
||||
("{{project.links}}", """
|
||||
<li><a href="inotify/documentation/inotify/">Inotify</a>: The actual library.</li>\
|
||||
<li><a href="taskcli/documentation/taskcli/">TaskCLI</a>: The project build command.</li>
|
||||
<li><a href="inotifytaskcli/documentation/inotifytaskcli/">TaskCLI</a>: The project build command.</li>
|
||||
"""),
|
||||
]
|
||||
|
||||
@@ -106,9 +106,32 @@ struct GenerateDocumentationCommand: AsyncParsableCommand {
|
||||
}
|
||||
|
||||
private static func targets(for projectDirectory: URL) async throws -> [String] {
|
||||
let sourcesDirectory = projectDirectory.appending(path: "Sources").path
|
||||
let testsDirectory = projectDirectory.appending(path: "Tests").path
|
||||
return try await DoccFinder.getTargetsWithDocumentation(at: sourcesDirectory, testsDirectory)
|
||||
let packages = try await Self.packageTargets()
|
||||
var packagesWithDoccFolder: [(name: String, path: String)] = []
|
||||
for package in packages {
|
||||
guard try await DoccFinder.hasDoccFolder(at: package.path) else { continue }
|
||||
packagesWithDoccFolder.append(package)
|
||||
}
|
||||
return packagesWithDoccFolder.map { $0.name }
|
||||
}
|
||||
|
||||
private static func packageTargets() async throws -> [(name: String, path: String)] {
|
||||
let packageDescription = try await Subprocess.run(
|
||||
.name("swift"),
|
||||
arguments: ["package", "describe", "--type", "json"],
|
||||
output: .data(limit: 20_000)
|
||||
)
|
||||
|
||||
struct PackageDescription: Codable {
|
||||
let targets: [Target]
|
||||
}
|
||||
struct Target: Codable {
|
||||
let name: String
|
||||
let path: String
|
||||
}
|
||||
|
||||
let package = try JSONDecoder().decode(PackageDescription.self, from: packageDescription.standardOutput)
|
||||
return package.targets.map { ($0.name, $0.path) }
|
||||
}
|
||||
|
||||
private static func makeRunScript(for targets: [String]) -> String {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# ``TaskCLI``
|
||||
# ``InotifyTaskCLI``
|
||||
|
||||
The build tool for the Swift Inotify project.
|
||||
|
||||
@@ -6,10 +6,14 @@ The build tool for the Swift Inotify project.
|
||||
|
||||
`TaskCLI` is a small command-line executable (exposed as `task` in `Package.swift`) that automates project-level workflows. Its primary purpose is running integration tests and generating documentation inside Linux Docker containers, so you can validate inotify-dependent code on the correct platform even when developing on macOS.
|
||||
|
||||
Because of a Swift Package Manager Bug in the [package dependency resolution][swiftpm-bug], the executable needs to be run using the `task.sh` shell script.
|
||||
|
||||
[swiftpm-bug]: https://github.com/swiftlang/swift-package-manager/issues/8482
|
||||
|
||||
### Running the Tests
|
||||
|
||||
```bash
|
||||
swift run task test
|
||||
./task.sh test
|
||||
```
|
||||
|
||||
This launches a `swift:latest` Docker container with the repository mounted at `/code`, then executes two test passes:
|
||||
@@ -22,7 +26,7 @@ The container is started with `--security-opt systempaths=unconfined` so that th
|
||||
### Generating Documentation
|
||||
|
||||
```bash
|
||||
swift run task generate-documentation
|
||||
./task.sh generate-documentation
|
||||
```
|
||||
|
||||
This copies the project to a temporary directory, injects the `swift-docc-plugin` dependency via `swift package add-dependency` (if absent), and runs documentation generation inside a `swift:latest` Docker container. The resulting static sites are written to `./public/inotify/` and `./public/taskcli/`, ready for deployment to GitHub Pages.
|
||||
|
||||
Reference in New Issue
Block a user