Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions Plugins/SwordBuildToolPlugin/SwordBuildToolPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,20 @@ struct SwordBuildToolPlugin: BuildToolPlugin {
let targets = transitiveTargets(for: sourceModule)
let targetByName = Dictionary(targets.map { ($0.name, $0) }, uniquingKeysWith: { (first, _) in first })
let targetSourceModules = targetByName.values.compactMap(\.sourceModule)
let inputPaths = ([sourceModule] + targetSourceModules).flatMap { sourceModule in
sourceModule.sourceFiles(withSuffix: "swift").map(\.path)
let inputDirectories = ([sourceModule] + targetSourceModules).compactMap { sourceModule in
relativePath(
from: context.package.directoryURL,
to: URL(fileURLWithPath: sourceModule.directory.string, isDirectory: true).standardized
)
}
let output = context.pluginWorkDirectory.appending("Sword.generated.swift")
var arguments = [String]()
let targetNames = targetByName.keys
if !targetNames.isEmpty {
arguments += ["--targets"] + targetNames
}
if !inputPaths.isEmpty {
arguments += ["--inputs"] + inputPaths.map(\.string)
if !inputDirectories.isEmpty {
arguments += ["--inputs"] + inputDirectories
}
arguments += ["--output", output.string]
return [
Expand All @@ -46,6 +49,17 @@ struct SwordBuildToolPlugin: BuildToolPlugin {
}
}
}

private func relativePath(from baseURL: URL, to absoluteURL: URL) -> String? {
guard absoluteURL.path.hasPrefix(baseURL.path) else { return nil }

var relative = absoluteURL.path.replacingOccurrences(of: baseURL.path, with: "")
if relative.hasPrefix("/") {
relative.removeFirst()
}

return relative
}
}

#if canImport(XcodeProjectPlugin)
Expand Down
5 changes: 2 additions & 3 deletions Sources/SwordCommand/SwordCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,11 @@ struct SwordCommand: ParsableCommand {
}

let fileManager = FileManager.default
let currentDirectoryPath = URL(filePath: fileManager.currentDirectoryPath)
let absolutePath = currentDirectoryPath.appending(path: path)
let absolutePath = URL(filePath: fileManager.currentDirectoryPath).appending(path: path)
return fileManager.subpaths(atPath: absolutePath.path())?.compactMap { element -> URL? in
guard element.hasSuffix(".swift") else { return nil }

let elementAbsolutePath = currentDirectoryPath.appending(path: element)
let elementAbsolutePath = absolutePath.appending(path: element)
return elementAbsolutePath.path().isFile ? elementAbsolutePath : nil
} ?? []
}
Expand Down
14 changes: 14 additions & 0 deletions Sources/SwordGenerator/Logging/Logging.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import os

enum Logging {
static let logger = Logger(subsystem: "com.rockname.sword", category: "Generator")
static let signposter = OSSignposter(logger: logger)

static func recordInterval<R>(name: StaticString, body: () throws -> R) rethrows -> R {
let signpostID = signposter.makeSignpostID()
let state = signposter.beginInterval(name, id: signpostID)
let result = try body()
signposter.endInterval(name, state)
return result
}
}
102 changes: 57 additions & 45 deletions Sources/SwordGenerator/Parser/SwordParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,43 +19,51 @@ package struct SwordParser {
let moduleRegistry = ModuleRegistry()
let importRegistry = ImportRegistry()

for sourceFile in sourceFiles {
let visitors: [SyntaxVisitor] = [
ComponentVisitor(
componentRegistry: componentRegistry,
sourceFile: sourceFile
),
SubcomponentVisitor(
componentRegistry: componentRegistry,
sourceFile: sourceFile
),
DependencyVisitor(
dependencyRegistry: dependencyRegistry,
sourceFile: sourceFile
),
ModuleVisitor(
moduleRegistry: moduleRegistry,
sourceFile: sourceFile
),
ImportVisitor(
importRegistry: importRegistry,
sourceFile: sourceFile
),
]
for visitor in visitors {
visitor.walk(sourceFile.tree)
Logging.recordInterval(name: "parseSourceFiles") {
for sourceFile in sourceFiles {
let visitors: [SyntaxVisitor] = [
ComponentVisitor(
componentRegistry: componentRegistry,
sourceFile: sourceFile
),
SubcomponentVisitor(
componentRegistry: componentRegistry,
sourceFile: sourceFile
),
DependencyVisitor(
dependencyRegistry: dependencyRegistry,
sourceFile: sourceFile
),
ModuleVisitor(
moduleRegistry: moduleRegistry,
sourceFile: sourceFile
),
ImportVisitor(
importRegistry: importRegistry,
sourceFile: sourceFile
),
]
for visitor in visitors {
visitor.walk(sourceFile.tree)
}
}
}

for target in targets {
importRegistry.register(target)
for target in targets {
importRegistry.register(target)
}
}

let componentValidationResult = ComponentValidator(componentRegistry: componentRegistry)
.validate()
let dependencyValidationResult = DependencyValidator(dependencyRegistry: dependencyRegistry)
.validate()
let moduleValidationResult = ModuleValidator(moduleRegistry: moduleRegistry).validate()
let componentValidationResult = Logging.recordInterval(name: "makeComponentTree") {
ComponentValidator(componentRegistry: componentRegistry)
.validate()
}
let dependencyValidationResult = Logging.recordInterval(name: "makeDependencies") {
DependencyValidator(dependencyRegistry: dependencyRegistry)
.validate()
}
let moduleValidationResult = Logging.recordInterval(name: "makeModules") {
ModuleValidator(moduleRegistry: moduleRegistry).validate()
}
guard
case .valid((let component, let subcomponentsByParent)) = componentValidationResult,
case .valid(let dependenciesByComponentName) = dependencyValidationResult,
Expand All @@ -72,19 +80,23 @@ package struct SwordParser {
exit(1)
}

let bindingGraphFactory = BindingGraphFactory(
subcomponentsByParent: subcomponentsByParent,
dependenciesByComponentName: dependenciesByComponentName,
modulesByComponentName: modulesByComponentName
)
let bindingGraph = bindingGraphFactory.makeBindingGraph(rootComponent: component)
let bindingGraphValidationResult = BindingGraphValidator(bindingGraph: bindingGraph).validate()

guard case .valid = bindingGraphValidationResult else {
for report in bindingGraphValidationResult.reports {
reporter.send(report)
let bindingGraph = Logging.recordInterval(name: "makeBindingGraph") {
let bindingGraphFactory = BindingGraphFactory(
subcomponentsByParent: subcomponentsByParent,
dependenciesByComponentName: dependenciesByComponentName,
modulesByComponentName: modulesByComponentName
)
let bindingGraph = bindingGraphFactory.makeBindingGraph(rootComponent: component)
let bindingGraphValidationResult = BindingGraphValidator(bindingGraph: bindingGraph)
.validate()
guard case .valid = bindingGraphValidationResult else {
for report in bindingGraphValidationResult.reports {
reporter.send(report)
}
exit(1)
}
exit(1)

return bindingGraph
}

return (
Expand Down
12 changes: 7 additions & 5 deletions Sources/SwordGenerator/SwordGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ package struct SwordGenerator {
output: String
) throws {
let (bindingGraph, imports) = try parser.parse(sourceFiles: sourceFiles, targets: targets)
try exporter.export(
bindingGraph: bindingGraph,
imports: imports,
outputPath: URL(filePath: output)
)
try Logging.recordInterval(name: "exportBindingGraph") {
try exporter.export(
bindingGraph: bindingGraph,
imports: imports,
outputPath: URL(filePath: output)
)
}
}
}