diff --git a/Plugins/SwordBuildToolPlugin/SwordBuildToolPlugin.swift b/Plugins/SwordBuildToolPlugin/SwordBuildToolPlugin.swift index b21b96e..7c9898a 100644 --- a/Plugins/SwordBuildToolPlugin/SwordBuildToolPlugin.swift +++ b/Plugins/SwordBuildToolPlugin/SwordBuildToolPlugin.swift @@ -9,8 +9,11 @@ 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]() @@ -18,8 +21,8 @@ struct SwordBuildToolPlugin: BuildToolPlugin { 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 [ @@ -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) diff --git a/Sources/SwordCommand/SwordCommand.swift b/Sources/SwordCommand/SwordCommand.swift index 1e932a5..eb283c6 100644 --- a/Sources/SwordCommand/SwordCommand.swift +++ b/Sources/SwordCommand/SwordCommand.swift @@ -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 } ?? [] } diff --git a/Sources/SwordGenerator/Logging/Logging.swift b/Sources/SwordGenerator/Logging/Logging.swift new file mode 100644 index 0000000..3fc3312 --- /dev/null +++ b/Sources/SwordGenerator/Logging/Logging.swift @@ -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(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 + } +} diff --git a/Sources/SwordGenerator/Parser/SwordParser.swift b/Sources/SwordGenerator/Parser/SwordParser.swift index 6d562b7..e94e839 100644 --- a/Sources/SwordGenerator/Parser/SwordParser.swift +++ b/Sources/SwordGenerator/Parser/SwordParser.swift @@ -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, @@ -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 ( diff --git a/Sources/SwordGenerator/SwordGenerator.swift b/Sources/SwordGenerator/SwordGenerator.swift index a2792f4..9b010be 100644 --- a/Sources/SwordGenerator/SwordGenerator.swift +++ b/Sources/SwordGenerator/SwordGenerator.swift @@ -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) + ) + } } }