diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b4c4795..45a271c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: ${{ runner.os }}-spm-xcode-${{ matrix.xcode }}- - name: Install System Dependencies run: | - brew install graphviz + brew bundle - name: Build and Test run: | swift test -c release @@ -58,7 +58,7 @@ jobs: ${{ runner.os }}-spm-xcode-${{ matrix.xcode }}- - name: Install System Dependencies run: | - brew install graphviz + brew bundle - name: Build and Test run: | swift test -c release @@ -89,7 +89,7 @@ jobs: - name: Install System Dependencies run: | apt-get update - apt-get install -y libxml2-dev graphviz + apt-get install -y libxml2-dev graphviz-dev - name: Build and Test run: swift test -c release --enable-test-discovery diff --git a/Brewfile b/Brewfile new file mode 100644 index 00000000..3b10a00f --- /dev/null +++ b/Brewfile @@ -0,0 +1 @@ +brew 'graphviz' diff --git a/Brewfile.lock.json b/Brewfile.lock.json new file mode 100644 index 00000000..5ef7c8be --- /dev/null +++ b/Brewfile.lock.json @@ -0,0 +1,72 @@ +{ + "entries": { + "brew": { + "graphviz": { + "version": "2.47.0", + "bottle": { + "rebuild": 0, + "cellar": "/usr/local/Cellar", + "prefix": "/usr/local", + "root_url": "https://homebrew.bintray.com/bottles", + "files": { + "arm64_big_sur": { + "url": "https://homebrew.bintray.com/bottles/graphviz-2.47.0.arm64_big_sur.bottle.tar.gz", + "sha256": "e4263e38be3d51648bffba45b0572dafd16254ce27fc3d1b13c555dff1110d5a" + }, + "big_sur": { + "url": "https://homebrew.bintray.com/bottles/graphviz-2.47.0.big_sur.bottle.tar.gz", + "sha256": "7972126b79753efa1f0c3519d6a063079cb1ff02c69759864a865e4ae6b4f193" + }, + "catalina": { + "url": "https://homebrew.bintray.com/bottles/graphviz-2.47.0.catalina.bottle.tar.gz", + "sha256": "e5d3b7b652e5cf828c0a2afc2fadb31090f3d7f10389766857404b4359b695e3" + }, + "mojave": { + "url": "https://homebrew.bintray.com/bottles/graphviz-2.47.0.mojave.bottle.tar.gz", + "sha256": "d045a9a68315b4e3fa61c7a0a813da345be8197892d070162d909f4985ff3bd7" + } + } + } + }, + "sqlite": { + "version": "3.35.3", + "bottle": { + "rebuild": 0, + "cellar": ":any", + "prefix": "/usr/local", + "root_url": "https://homebrew.bintray.com/bottles", + "files": { + "arm64_big_sur": { + "url": "https://homebrew.bintray.com/bottles/sqlite-3.35.3.arm64_big_sur.bottle.tar.gz", + "sha256": "dc73e344c364d891047ab1b4fa54c25196b5fb61ac646d3ac3c731311d81e9a4" + }, + "big_sur": { + "url": "https://homebrew.bintray.com/bottles/sqlite-3.35.3.big_sur.bottle.tar.gz", + "sha256": "6f491b7ef85515ede5f193db760117c39f4d4f2dadb482c2f48410b2ea00d1eb" + }, + "catalina": { + "url": "https://homebrew.bintray.com/bottles/sqlite-3.35.3.catalina.bottle.tar.gz", + "sha256": "615597e87a1804124b019e35609539878eaf17e52f58ef03ce2ed1cd9536b299" + }, + "mojave": { + "url": "https://homebrew.bintray.com/bottles/sqlite-3.35.3.mojave.bottle.tar.gz", + "sha256": "996aa3f07c2a41ef497bed0c00fbff1272d89e3a282ac8661e7ad5533f09d533" + } + } + } + } + } + }, + "system": { + "macos": { + "catalina": { + "HOMEBREW_VERSION": "3.0.10-23-g5e0b08d", + "HOMEBREW_PREFIX": "/usr/local", + "Homebrew/homebrew-core": "98313dbb946cca3ddc973624b80f39fd1b481c81", + "CLT": "12.4.0.0.1.1610135815", + "Xcode": "12.4", + "macOS": "10.15.7" + } + } + } +} diff --git a/Package.resolved b/Package.resolved index df1701fe..88d6192e 100644 --- a/Package.resolved +++ b/Package.resolved @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/SwiftDocOrg/GraphViz.git", "state": { "branch": null, - "revision": "c4746cb3ff6f5e7c5d5540c40b98555521c3ee43", - "version": "0.1.3" + "revision": "cf52b27bf7086e9ca5665cef0de57d0481bbab41", + "version": "0.3.0" } }, { diff --git a/Package.swift b/Package.swift index cd55d64b..9586cfcb 100644 --- a/Package.swift +++ b/Package.swift @@ -6,7 +6,7 @@ import PackageDescription let package = Package( name: "swift-doc", platforms: [ - .macOS(.v10_13) + .macOS(.v10_15) ], products: [ .executable(name: "swift-doc", targets: ["swift-doc"]), @@ -17,7 +17,7 @@ let package = Package( .package(url: "https://github.com/SwiftDocOrg/SwiftSemantics.git", .upToNextMinor(from: "0.1.0")), .package(url: "https://github.com/SwiftDocOrg/CommonMark.git", .upToNextMinor(from: "0.4.0")), .package(url: "https://github.com/SwiftDocOrg/SwiftMarkup.git", .upToNextMinor(from: "0.2.1")), - .package(url: "https://github.com/SwiftDocOrg/GraphViz.git", .upToNextMinor(from: "0.1.2")), + .package(url: "https://github.com/SwiftDocOrg/GraphViz.git", .upToNextMinor(from: "0.3.0")), .package(url: "https://github.com/NSHipster/HypertextLiteral.git", .upToNextMinor(from: "0.0.2")), .package(url: "https://github.com/SwiftDocOrg/Markup.git", .upToNextMinor(from: "0.0.3")), .package(url: "https://github.com/NSHipster/SwiftSyntaxHighlighter.git", .revision("1.1.3")), diff --git a/Package@swift-5.2.swift b/Package@swift-5.2.swift index ad8be933..d3981b5b 100644 --- a/Package@swift-5.2.swift +++ b/Package@swift-5.2.swift @@ -14,7 +14,7 @@ let package = Package( .package(url: "https://github.com/SwiftDocOrg/SwiftSemantics.git", .upToNextMinor(from: "0.1.0")), .package(url: "https://github.com/SwiftDocOrg/CommonMark.git", .upToNextMinor(from: "0.4.0")), .package(url: "https://github.com/SwiftDocOrg/SwiftMarkup.git", .upToNextMinor(from: "0.2.1")), - .package(url: "https://github.com/SwiftDocOrg/GraphViz.git", .upToNextMinor(from: "0.1.2")), + .package(url: "https://github.com/SwiftDocOrg/GraphViz.git", .upToNextMinor(from: "0.3.0")), .package(url: "https://github.com/NSHipster/HypertextLiteral.git", .upToNextMinor(from: "0.0.2")), .package(url: "https://github.com/SwiftDocOrg/Markup.git", .upToNextMinor(from: "0.0.3")), .package(url: "https://github.com/NSHipster/SwiftSyntaxHighlighter.git", .revision("1.0.2")), diff --git a/Sources/swift-doc/Extensions/SwiftDoc+Extensions.swift b/Sources/swift-doc/Extensions/SwiftDoc+Extensions.swift index a25fa93f..6d118e51 100644 --- a/Sources/swift-doc/Extensions/SwiftDoc+Extensions.swift +++ b/Sources/swift-doc/Extensions/SwiftDoc+Extensions.swift @@ -1,7 +1,6 @@ import SwiftDoc import SwiftSemantics import GraphViz -import DOT import struct Foundation.URL extension Symbol { diff --git a/Sources/swift-doc/Helpers/Await.swift b/Sources/swift-doc/Helpers/Await.swift new file mode 100644 index 00000000..e97dfb09 --- /dev/null +++ b/Sources/swift-doc/Helpers/Await.swift @@ -0,0 +1,34 @@ +import Foundation + +func _await(_ body: (@escaping (Result) -> Void) -> Void) throws -> T { + return try _await(body).get() +} + +func _await(_ body: (@escaping (T) -> Void) -> Void) -> T { + let condition = NSCondition() + var value: T? + + body { output in + condition.lock { + value = output + condition.signal() + } + } + + condition.lock { + while value == nil { + condition.wait() + } + } + + return value! +} + +fileprivate extension NSCondition { + func lock(_ body: () throws -> T) rethrows -> T { + lock() + defer { unlock() } + + return try body() + } +} diff --git a/Sources/swift-doc/Subcommands/Diagram.swift b/Sources/swift-doc/Subcommands/Diagram.swift index 280bc596..0ca09594 100644 --- a/Sources/swift-doc/Subcommands/Diagram.swift +++ b/Sources/swift-doc/Subcommands/Diagram.swift @@ -3,8 +3,6 @@ import Foundation import SwiftDoc import SwiftSemantics import GraphViz -import DOT - extension SwiftDoc { struct Diagram: ParsableCommand { diff --git a/Sources/swift-doc/Supporting Types/Components/Relationships.swift b/Sources/swift-doc/Supporting Types/Components/Relationships.swift index 7e647134..6fd8f23d 100644 --- a/Sources/swift-doc/Supporting Types/Components/Relationships.swift +++ b/Sources/swift-doc/Supporting Types/Components/Relationships.swift @@ -5,7 +5,8 @@ import SwiftSemantics import Foundation import HypertextLiteral import GraphViz -import DOT + +fileprivate typealias SVG = HypertextLiteral.HTML extension StringBuilder { // MARK: buildIf @@ -51,7 +52,8 @@ struct Relationships: Component { let algorithm: LayoutAlgorithm = graph.nodes.count > 3 ? .neato : .dot do { - return try HypertextLiteral.HTML(String(data: graph.render(using: algorithm, to: .svg), encoding: .utf8) ?? "") + let data = try _await { graph.render(using: algorithm, to: .svg, completion: $0) } + return SVG(String(data: data, encoding: .utf8) ?? "") } catch { logger.warning("Failed to generate relationship graph for \(symbol.id). Please ensure that GraphViz binaries are accessible from your PATH. (\(error))") return nil