Compare commits
1 Commits
a942b15483
...
94d01db8aa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94d01db8aa |
31
.github/workflows/docs.yml
vendored
31
.github/workflows/docs.yml
vendored
@@ -33,25 +33,24 @@ jobs:
|
|||||||
awk 'BEGIN{done=0} /dependencies: \[/ && done==0 {print; print "\t\t.package(url: \"https://github.com/apple/swift-docc-plugin.git\", from: \"1.4.0\"),"; done=1; next}1' Package.swift > Package.swift.tmp
|
awk 'BEGIN{done=0} /dependencies: \[/ && done==0 {print; print "\t\t.package(url: \"https://github.com/apple/swift-docc-plugin.git\", from: \"1.4.0\"),"; done=1; next}1' Package.swift > Package.swift.tmp
|
||||||
mv Package.swift.tmp Package.swift
|
mv Package.swift.tmp Package.swift
|
||||||
fi
|
fi
|
||||||
- name: Generate Docs
|
- name: Generate Inotify Docs
|
||||||
run: |
|
run: |
|
||||||
swift package generate-documentation --target Inotify
|
swift package --allow-writing-to-directory ./public/inotify \
|
||||||
swift package generate-documentation --target TaskCLI
|
generate-documentation \
|
||||||
- name: Transform for Static Hosting
|
--target Inotify \
|
||||||
run: |
|
|
||||||
OUTPUTS=.build/plugins/Swift-DocC/outputs
|
|
||||||
|
|
||||||
mkdir -p ./public/inotify ./public/taskcli
|
|
||||||
|
|
||||||
docc process-archive transform-for-static-hosting \
|
|
||||||
"$OUTPUTS/Inotify.doccarchive" \
|
|
||||||
--output-path ./public/inotify \
|
--output-path ./public/inotify \
|
||||||
--hosting-base-path swift-inotify/inotify
|
--transform-for-static-hosting \
|
||||||
|
--hosting-base-path swift-inotify/inotify \
|
||||||
docc process-archive transform-for-static-hosting \
|
--disable-indexing
|
||||||
"$OUTPUTS/TaskCLI.doccarchive" \
|
- name: Generate TaskCLI Docs
|
||||||
|
run: |
|
||||||
|
swift package --allow-writing-to-directory ./public/taskcli \
|
||||||
|
generate-documentation \
|
||||||
|
--target TaskCLI \
|
||||||
--output-path ./public/taskcli \
|
--output-path ./public/taskcli \
|
||||||
--hosting-base-path swift-inotify/taskcli
|
--transform-for-static-hosting \
|
||||||
|
--hosting-base-path swift-inotify/taskcli \
|
||||||
|
--disable-indexing
|
||||||
- name: Create Index Page
|
- name: Create Index Page
|
||||||
run: |
|
run: |
|
||||||
cat > ./public/index.html <<'HTML'
|
cat > ./public/index.html <<'HTML'
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1 @@
|
|||||||
.build
|
.build
|
||||||
public
|
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ import ArgumentParser
|
|||||||
struct Command: AsyncParsableCommand {
|
struct Command: AsyncParsableCommand {
|
||||||
static let configuration = CommandConfiguration(
|
static let configuration = CommandConfiguration(
|
||||||
abstract: "Project tasks of Astzweig's Swift Inotify project.",
|
abstract: "Project tasks of Astzweig's Swift Inotify project.",
|
||||||
subcommands: [TestCommand.self, GenerateDocsCommand.self]
|
subcommands: [TestCommand.self]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,178 +0,0 @@
|
|||||||
import ArgumentParser
|
|
||||||
import AsyncAlgorithms
|
|
||||||
import Foundation
|
|
||||||
import Logging
|
|
||||||
import Noora
|
|
||||||
import Subprocess
|
|
||||||
|
|
||||||
struct GenerateDocsCommand: AsyncParsableCommand {
|
|
||||||
static let configuration = CommandConfiguration(
|
|
||||||
commandName: "generate-docs",
|
|
||||||
abstract: "Generate DocC documentation inside a Linux container.",
|
|
||||||
aliases: ["gd"],
|
|
||||||
)
|
|
||||||
|
|
||||||
@OptionGroup var global: GlobalOptions
|
|
||||||
|
|
||||||
private static let doccPluginURL = "https://github.com/apple/swift-docc-plugin.git"
|
|
||||||
private static let doccPluginMinVersion = "1.4.0"
|
|
||||||
private static let targets = ["Inotify", "TaskCLI"]
|
|
||||||
private static let hostingBasePath = "swift-inotify"
|
|
||||||
private static let skipItems: Set<String> = [".git", ".build", ".swiftpm", "public"]
|
|
||||||
|
|
||||||
// MARK: - Run
|
|
||||||
|
|
||||||
func run() async throws {
|
|
||||||
let noora = Noora()
|
|
||||||
let logger = global.makeLogger(labeled: "swift-inotify.cli.task.generate-docs")
|
|
||||||
let fileManager = FileManager.default
|
|
||||||
let projectDirectory = URL(fileURLWithPath: fileManager.currentDirectoryPath)
|
|
||||||
|
|
||||||
noora.info("Generating DocC documentation on Linux.")
|
|
||||||
logger.debug("Current directory", metadata: ["current-directory": "\(projectDirectory.path(percentEncoded: false))"])
|
|
||||||
|
|
||||||
let tempDirectory = try copyProject(from: projectDirectory)
|
|
||||||
logger.info("Copied project to temporary directory.", metadata: ["path": "\(tempDirectory.path(percentEncoded: false))"])
|
|
||||||
|
|
||||||
defer {
|
|
||||||
try? fileManager.removeItem(at: tempDirectory)
|
|
||||||
logger.info("Cleaned up temporary directory.")
|
|
||||||
}
|
|
||||||
|
|
||||||
try await injectDoccPluginDependency(in: tempDirectory, logger: logger)
|
|
||||||
let script = Self.makeRunScript()
|
|
||||||
|
|
||||||
logger.debug("Container script", metadata: ["script": "\(script)"])
|
|
||||||
let dockerResult = try await Subprocess.run(
|
|
||||||
.name("docker"),
|
|
||||||
arguments: [
|
|
||||||
"run", "--rm",
|
|
||||||
"-v", "\(tempDirectory.path(percentEncoded: false)):/code",
|
|
||||||
"--platform", "linux/arm64",
|
|
||||||
"-w", "/code",
|
|
||||||
"swift:latest",
|
|
||||||
"/bin/bash", "-c", script,
|
|
||||||
],
|
|
||||||
preferredBufferSize: 10,
|
|
||||||
) { execution, standardInput, standardOutput, standardError in
|
|
||||||
print("")
|
|
||||||
let stdout = standardOutput.lines()
|
|
||||||
let stderr = standardError.lines()
|
|
||||||
for try await line in merge(stdout, stderr) {
|
|
||||||
noora.passthrough("\(line)")
|
|
||||||
}
|
|
||||||
print("")
|
|
||||||
}
|
|
||||||
|
|
||||||
guard dockerResult.terminationStatus.isSuccess else {
|
|
||||||
noora.error("Documentation generation failed.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try copyResults(from: tempDirectory, to: projectDirectory)
|
|
||||||
|
|
||||||
noora.success(
|
|
||||||
.alert("Documentation generated successfully.",
|
|
||||||
takeaways: Self.targets.map {
|
|
||||||
"./public/\($0.lowercased())/"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func generateDocsCommand() -> String {
|
|
||||||
Self.targets.map {
|
|
||||||
"swift package generate-documentation --target \($0)"
|
|
||||||
}.joined(separator: " && ")
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func transformDocsForStaticHostingCommand() -> String {
|
|
||||||
Self.targets.map { target in
|
|
||||||
let lowercased = target.lowercased()
|
|
||||||
return "docc process-archive transform-for-static-hosting" +
|
|
||||||
" $OUTPUTS/\(target).doccarchive" +
|
|
||||||
" --output-path ./public/\(lowercased)" +
|
|
||||||
" --hosting-base-path \(Self.hostingBasePath)/\(lowercased)"
|
|
||||||
}.joined(separator: " && ")
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func outputPathsForDocTargets() -> String {
|
|
||||||
Self.targets.map { "./public/\($0.lowercased())" }.joined(separator: " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func makeRunScript() -> String {
|
|
||||||
let generateDocs = Self.generateDocsCommand()
|
|
||||||
let transformDocs = Self.transformDocsForStaticHostingCommand()
|
|
||||||
let outputDirs = Self.outputPathsForDocTargets()
|
|
||||||
|
|
||||||
return "set -euo pipefail && \(generateDocs)" +
|
|
||||||
" && OUTPUTS=.build/plugins/Swift-DocC/outputs" +
|
|
||||||
" && mkdir -p \(outputDirs)" +
|
|
||||||
" && \(transformDocs)"
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Project Copy
|
|
||||||
|
|
||||||
private func copyProject(from source: URL) throws -> URL {
|
|
||||||
let fileManager = FileManager.default
|
|
||||||
let tempDirectory = fileManager.temporaryDirectory.appending(path: "swift-inotify-docs-\(UUID().uuidString)")
|
|
||||||
try fileManager.createDirectory(at: tempDirectory, withIntermediateDirectories: true)
|
|
||||||
|
|
||||||
let contents = try fileManager.contentsOfDirectory(at: source, includingPropertiesForKeys: nil)
|
|
||||||
for item in contents {
|
|
||||||
guard !Self.skipItems.contains(item.lastPathComponent) else { continue }
|
|
||||||
try fileManager.copyItem(at: item, to: tempDirectory.appending(path: item.lastPathComponent))
|
|
||||||
}
|
|
||||||
|
|
||||||
return tempDirectory
|
|
||||||
}
|
|
||||||
|
|
||||||
private func copyResults(from tempDirectory: URL, to projectDirectory: URL) throws {
|
|
||||||
let fileManager = FileManager.default
|
|
||||||
let source = tempDirectory.appending(path: "public")
|
|
||||||
let destination = projectDirectory.appending(path: "public")
|
|
||||||
|
|
||||||
if fileManager.fileExists(atPath: destination.path(percentEncoded: false)) {
|
|
||||||
try fileManager.removeItem(at: destination)
|
|
||||||
}
|
|
||||||
try fileManager.copyItem(at: source, to: destination)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Dependency Injection
|
|
||||||
|
|
||||||
private func injectDoccPluginDependency(in directory: URL, logger: Logger) async throws {
|
|
||||||
let packageSwiftURL = directory.appending(path: "Package.swift")
|
|
||||||
let contents = try String(contentsOf: packageSwiftURL, encoding: .utf8)
|
|
||||||
|
|
||||||
guard !contents.contains("swift-docc-plugin") else {
|
|
||||||
logger.info("swift-docc-plugin dependency already present.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = try await Subprocess.run(
|
|
||||||
.name("swift"),
|
|
||||||
arguments: [
|
|
||||||
"package", "--package-path", directory.path(percentEncoded: false),
|
|
||||||
"add-dependency", Self.doccPluginURL,
|
|
||||||
"--from", Self.doccPluginMinVersion,
|
|
||||||
],
|
|
||||||
) { _ in }
|
|
||||||
|
|
||||||
guard result.terminationStatus.isSuccess else {
|
|
||||||
throw GenerateDocsError.dependencyInjectionFailed
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info("Injected swift-docc-plugin dependency.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum GenerateDocsError: Error, CustomStringConvertible {
|
|
||||||
case dependencyInjectionFailed
|
|
||||||
|
|
||||||
var description: String {
|
|
||||||
switch self {
|
|
||||||
case .dependencyInjectionFailed:
|
|
||||||
"Failed to add swift-docc-plugin dependency to Package.swift."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,7 @@ The build tool for the Swift Inotify project.
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
`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.
|
`TaskCLI` is a small command-line executable (exposed as `task` in `Package.swift`) that automates project-level workflows. Its primary purpose is running the integration test suite inside a Linux Docker container, so you can validate the inotify-dependent code on the correct platform even when developing on macOS.
|
||||||
|
|
||||||
### Running the Tests
|
### Running the Tests
|
||||||
|
|
||||||
@@ -19,16 +19,6 @@ This launches a `swift:latest` Docker container with the repository mounted at `
|
|||||||
|
|
||||||
The container is started with `--security-opt systempaths=unconfined` so that the limit tests can write to `/proc/sys/fs/inotify/*`.
|
The container is started with `--security-opt systempaths=unconfined` so that the limit tests can write to `/proc/sys/fs/inotify/*`.
|
||||||
|
|
||||||
### Generating Documentation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
swift run task generate-docs
|
|
||||||
```
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
The working tree is never modified — all changes happen in the temporary copy, which is cleaned up automatically.
|
|
||||||
|
|
||||||
### Verbosity
|
### Verbosity
|
||||||
|
|
||||||
Pass one or more `-v` flags to increase log output:
|
Pass one or more `-v` flags to increase log output:
|
||||||
@@ -50,12 +40,7 @@ Docker must be installed and running on the host machine. The container uses the
|
|||||||
|
|
||||||
- ``Command``
|
- ``Command``
|
||||||
- ``TestCommand``
|
- ``TestCommand``
|
||||||
- ``GenerateDocsCommand``
|
|
||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
|
|
||||||
- ``GlobalOptions``
|
- ``GlobalOptions``
|
||||||
|
|
||||||
### Errors
|
|
||||||
|
|
||||||
- ``GenerateDocsError``
|
|
||||||
|
|||||||
Reference in New Issue
Block a user