1 Commits

Author SHA1 Message Date
T. R. Bernstein
541b9d68a0 Use Shwift library instead of Subprocess
Some checks failed
Docs / docs (push) Has been cancelled
Docs / deploy (push) Has been cancelled
Shwift has a concise API, which makes writing shell code nice and easy.
This is an opinionated decision.
2026-03-20 21:44:05 +01:00
8 changed files with 46 additions and 79 deletions

View File

@@ -1,5 +1,5 @@
{
"originHash" : "17ce26ba5c862ca674cd3ceeb43a9fe8a5c5251c5561de65e632a06d79916342",
"originHash" : "0cb2e87817f52021ac25ffee6b27396f6d94e9fd604ca83db7f20a10e65fe6cf",
"pins" : [
{
"identity" : "noora",
@@ -28,13 +28,22 @@
"version" : "4.2.1"
}
},
{
"identity" : "shwift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/GeorgeLyon/Shwift",
"state" : {
"revision" : "d7be04898d094ddce6140cc6a2e9a83fc994b66d",
"version" : "3.1.1"
}
},
{
"identity" : "swift-argument-parser",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-argument-parser",
"state" : {
"revision" : "626b5b7b2f45e1b0b1c6f4a309296d1d21d7311b",
"version" : "1.7.1"
"revision" : "c5d11a805e765f52ba34ec7284bd4fcd6ba68615",
"version" : "1.7.0"
}
},
{
@@ -73,15 +82,6 @@
"version" : "2.95.0"
}
},
{
"identity" : "swift-subprocess",
"kind" : "remoteSourceControl",
"location" : "https://github.com/swiftlang/swift-subprocess.git",
"state" : {
"revision" : "ba5888ad7758cbcbe7abebac37860b1652af2d9c",
"version" : "0.3.0"
}
},
{
"identity" : "swift-system",
"kind" : "remoteSourceControl",

View File

@@ -11,11 +11,10 @@ let package = Package(
)
],
dependencies: [
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.7.1"),
.package(url: "https://github.com/apple/swift-log", from: "1.10.1"),
.package(url: "https://github.com/apple/swift-nio", from: "2.95.0"),
.package(url: "https://github.com/apple/swift-system", from: "1.6.4"),
.package(url: "https://github.com/swiftlang/swift-subprocess.git", from: "0.3.0"),
.package(url: "https://github.com/GeorgeLyon/Shwift", from: "3.1.1"),
.package(url: "https://github.com/tuist/Noora", from: "0.55.1")
],
targets: [
@@ -39,10 +38,9 @@ let package = Package(
.executableTarget(
name: "InotifyTaskCLI",
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "Logging", package: "swift-log"),
.product(name: "_NIOFileSystem", package: "swift-nio"),
.product(name: "Subprocess", package: "swift-subprocess"),
.product(name: "Script", package: "Shwift"),
.product(name: "Noora", package: "Noora")
],
path: "Sources/TaskCLI"

View File

@@ -6,8 +6,8 @@ public actor Inotify {
private var excludedItemNames: Set<String> = []
private var watches = InotifyWatchManager()
private var eventReader: any DispatchSourceRead
private nonisolated let eventStream: AsyncStream<RawInotifyEvent>
public nonisolated var events: AsyncCompactMapSequence<AsyncStream<RawInotifyEvent>, InotifyEvent> {
private var eventStream: AsyncStream<RawInotifyEvent>
public var events: AsyncCompactMapSequence<AsyncStream<RawInotifyEvent>, InotifyEvent> {
self.eventStream.compactMap(self.transform(_:))
}

View File

@@ -1,4 +1,4 @@
import ArgumentParser
import Script
@main
struct Command: AsyncParsableCommand {

View File

@@ -1,9 +0,0 @@
struct Docker {
static func getLinuxPlatformStringWithHostArchitecture() -> String {
#if arch(x86_64)
return "linux/amd64"
#else
return "linux/arm64"
#endif
}
}

View File

@@ -1,10 +1,9 @@
import ArgumentParser
import Foundation
import Logging
import Script
import Noora
import Subprocess
struct GenerateDocumentationCommand: AsyncParsableCommand {
struct GenerateDocumentationCommand: Script {
static let configuration = CommandConfiguration(
commandName: "generate-documentation",
abstract: "Generate DocC documentation of all targets inside a Linux container.",
@@ -24,6 +23,7 @@ struct GenerateDocumentationCommand: AsyncParsableCommand {
let logger = global.makeLogger(labeled: "swift-inotify.cli.task.generate-documentation")
let fileManager = FileManager.default
let projectDirectory = URL(fileURLWithPath: fileManager.currentDirectoryPath)
let docker = try await executable(named: "docker")
let targets = try await Self.targets(for: projectDirectory)
@@ -42,21 +42,16 @@ struct GenerateDocumentationCommand: AsyncParsableCommand {
let script = Self.makeRunScript(for: targets)
logger.debug("Container script", metadata: ["script": "\(script)"])
let dockerRunResult = try await Subprocess.run(
.name("docker"),
arguments: [
do {
try await docker(
"run", "--rm",
"-v", "\(tempDirectory.path):/code",
"-v", "swift-inotify-build-cache:/code/.build",
"--platform", Docker.getLinuxPlatformStringWithHostArchitecture(),
"--platform", "linux/arm64",
"-w", "/code",
"swift:latest",
"/bin/bash", "-c", script
],
output: .standardOutput,
error: .standardError
)
if !dockerRunResult.terminationStatus.isSuccess {
"/bin/bash", "-c", script,
)
} catch {
noora.error("Documentation generation failed.")
return
}
@@ -108,12 +103,10 @@ struct GenerateDocumentationCommand: AsyncParsableCommand {
}
private static func packageTargets() async throws -> [(name: String, path: String)] {
let packageDescriptionResult = try await Subprocess.run(
.name("swift"),
arguments: ["package", "describe", "--type", "json"],
output: .data(limit: 10_000),
error: .standardError
)
let swift = try await executable(named: "swift")
let packageDescriptionOutput = try await outputOf {
try await swift("package", "describe", "--type", "json")
}
struct PackageDescription: Codable {
let targets: [Target]
@@ -123,11 +116,8 @@ struct GenerateDocumentationCommand: AsyncParsableCommand {
let path: String
}
if !packageDescriptionResult.terminationStatus.isSuccess {
throw GenerateDocumentationError.unableToReadPackageDescription
}
let package = try JSONDecoder().decode(PackageDescription.self, from: packageDescriptionResult.standardOutput)
let data = Data(packageDescriptionOutput.utf8)
let package = try JSONDecoder().decode(PackageDescription.self, from: data)
return package.targets.map { ($0.name, $0.path) }
}
@@ -172,16 +162,13 @@ struct GenerateDocumentationCommand: AsyncParsableCommand {
// MARK: - Dependency Injection
private func injectDoccPluginDependency(in directory: URL, logger: Logger) async throws {
let swiftRunResult = try await Subprocess.run(
.name("swift"),
arguments: [
let swift = try await executable(named: "swift")
do {
try await swift(
"package", "--package-path", directory.path(percentEncoded: false),
"add-dependency", "--from", Self.doccPluginMinVersion, Self.doccPluginURL
],
output: .standardOutput,
error: .standardError
)
if !swiftRunResult.terminationStatus.isSuccess {
)
} catch {
throw GenerateDocumentationError.dependencyInjectionFailed
}
@@ -191,14 +178,11 @@ struct GenerateDocumentationCommand: AsyncParsableCommand {
enum GenerateDocumentationError: Error, CustomStringConvertible {
case dependencyInjectionFailed
case unableToReadPackageDescription
var description: String {
switch self {
case .dependencyInjectionFailed:
"Failed to add swift-docc-plugin dependency to Package.swift."
case .unableToReadPackageDescription:
"Failed to read the package description."
}
}
}

View File

@@ -1,4 +1,4 @@
import ArgumentParser
import Script
import Logging
struct GlobalOptions: ParsableArguments {

View File

@@ -1,9 +1,8 @@
import ArgumentParser
import Foundation
import Script
import Noora
import Subprocess
struct TestCommand: AsyncParsableCommand {
struct TestCommand: Script {
static let configuration = CommandConfiguration(
commandName: "test",
abstract: "Run swift test in a linux container.",
@@ -18,26 +17,21 @@ struct TestCommand: AsyncParsableCommand {
let noora = Noora()
let logger = global.makeLogger(labeled: "swift-inotify.cli.task.test")
let currentDirectory = FileManager.default.currentDirectoryPath
let docker = Executable(path: "/opt/homebrew/bin/docker")
noora.info("Running tests on Linux.")
logger.debug("Current directory", metadata: ["current-directory": "\(currentDirectory)"])
let dockerRunResult = try await Subprocess.run(
.name("docker"),
arguments: [
do {
try await docker(
"run",
"-v", "\(currentDirectory):/code",
"-v", "swift-inotify-build-cache:/code/.build",
"--security-opt", "systempaths=unconfined",
"--platform", Docker.getLinuxPlatformStringWithHostArchitecture(),
"--platform", "linux/arm64",
"-w", "/code", "swift:latest",
"/bin/bash", "-c", "swift test --skip InotifyLimitTests; swift test --skip-build --filter InotifyLimitTests"
],
output: .standardOutput,
error: .standardError
)
if dockerRunResult.terminationStatus.isSuccess {
)
noora.success("All tests completed successfully.")
} else {
} catch {
noora.error("Not all tests completed successfully.")
}
}