Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add flag to toggle clusters on/off #55

Merged
merged 3 commits into from May 28, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 8 additions & 6 deletions Sources/SourceDocsCLI/PackageCommand.swift
Expand Up @@ -12,7 +12,7 @@ import SourceDocsLib
struct PackageCommand: ParsableCommand {
static var configuration = CommandConfiguration(
commandName: "package",
abstract: "Generate PACKAGE.md from Swift package description."
abstract: "Generate Package.md from Swift package description."
)

@Option(name: .shortAndLong, default: FileManager.default.currentDirectoryPath,
Expand All @@ -33,13 +33,15 @@ struct PackageCommand: ParsableCommand {
)
var reproducibleDocs: Bool

@Flag(name: .shortAndLong, help: "Disable clusters in module dependency diagram")
var noClusters: Bool

func run() throws {
do {
try PackageProcessor(
inputPath: inputFolder,
outputPath: outputFolder,
reproducibleDocs: reproducibleDocs
).run()
let processor = try PackageProcessor(inputPath: inputFolder, outputPath: outputFolder,
reproducibleDocs: reproducibleDocs)
processor.clustersEnabled = noClusters == false
try processor.run()
} catch PackageProcessor.Error.invalidInput {
fputs("Error:".red + " Package.swift not found at \(inputFolder)\n".white, stdout)
} catch {
Expand Down
Expand Up @@ -11,12 +11,12 @@ final class DependencyGraphGenerator: GraphGenerator {

let basePath: URL
let dependencyTree: PackageDependency
let canRenderDOT: Bool
var canRenderDOT = true
var clustersEnabled = true

init(basePath: URL, dependencyTree: PackageDependency, canRenderDOT: Bool) {
init(basePath: URL, dependencyTree: PackageDependency) {
self.basePath = basePath
self.dependencyTree = dependencyTree
self.canRenderDOT = canRenderDOT
}

func run() throws {
Expand All @@ -42,16 +42,24 @@ final class DependencyGraphGenerator: GraphGenerator {
func generateDOT(from dependencyTree: PackageDependency) -> String {
let edges = extractEdges(from: dependencyTree)

let clusterPrefix = clustersEnabled ? "cluster" : ""

let graph = """
digraph PackageDependencyGraph {
rankdir = LR
graph [fontname="Helvetica-light", style = filled, color = "#eaeaea"]
node [shape=box, fontname="Helvetica", style=filled, color="#fafafa"]
node [shape=box, fontname="Helvetica", style=filled]
edge [color="#545454"]

subgraph cluster {
subgraph \(clusterPrefix)Package {
node [color="#caecec"]
\(dependencyTree.nodeTitle)
}

subgraph \(clusterPrefix)Dependencies {
label = "Package Dependencies"
\(edges.joined(separator: "\n "))
node [color="#eeccaa"]
\(indented: edges.joined(separator: "\n"))
}
}
"""
Expand All @@ -69,6 +77,9 @@ final class DependencyGraphGenerator: GraphGenerator {

extension PackageDependency {
var nodeTitle: String {
return "\"\(name)\\n\(version)\""
let versionLabel = version == "unspecified" ? "" : "\\n\(version)"
return """
"\(name)\(versionLabel)"
"""
}
}
14 changes: 14 additions & 0 deletions Sources/SourceDocsLib/PackageProcessor/GraphGenerator.swift
Expand Up @@ -19,3 +19,17 @@ extension GraphGenerator {
return "\"\(string)\""
}
}

extension DefaultStringInterpolation {
mutating func appendInterpolation(indented string: String) {
let indent = String(description.reversed().prefix { " \t".contains($0) })
if indent.isEmpty {
appendInterpolation(string)
} else {
let value = string
.split(separator: "\n", omittingEmptySubsequences: false)
.joined(separator: "\n" + indent)
appendLiteral(value)
}
}
}
25 changes: 16 additions & 9 deletions Sources/SourceDocsLib/PackageProcessor/ModuleGraphGenerator.swift
Expand Up @@ -11,12 +11,12 @@ final class ModuleGraphGenerator: GraphGenerator {

let basePath: URL
let packageDump: PackageDump
let canRenderDOT: Bool
var canRenderDOT = true
var clustersEnabled = true

init(basePath: URL, packageDump: PackageDump, canRenderDOT: Bool) {
init(basePath: URL, packageDump: PackageDump) {
self.basePath = basePath
self.packageDump = packageDump
self.canRenderDOT = canRenderDOT
}

func run() throws {
Expand Down Expand Up @@ -48,18 +48,22 @@ final class ModuleGraphGenerator: GraphGenerator {
}
}

let clusters = [
cluster(with: regularNodes, name: "Regular", label: "Program Modules", color: "#caecec"),
cluster(with: testNodes, name: "Test", label: "Test Modules", color: "#aaccee"),
cluster(with: externalNodes, name: "External", label: "External Dependencies", color: "#eeccaa")
]

return """
digraph ModuleDependencyGraph {
rankdir = LR
graph [fontname="Helvetica-light", style = filled, color = "#eaeaea"]
node [shape=box, fontname="Helvetica", style=filled]
edge [color="#545454"]

\(cluster(with: regularNodes, name: "Regular", label: "Program Modules", color: "#caecec"))
\(cluster(with: testNodes, name: "Test", label: "Test Modules", color: "#aaccee"))
\(cluster(with: externalNodes, name: "External", label: "External Dependencies", color: "#fafafa"))
\(indented: clusters.joined(separator: "\n"))

\(edges.joined(separator: "\n "))
\(indented: edges.joined(separator: "\n"))
}
"""
}
Expand All @@ -68,11 +72,14 @@ final class ModuleGraphGenerator: GraphGenerator {
if nodes.isEmpty {
return ""
}

let clusterPrefix = clustersEnabled ? "cluster" : ""

return """
subgraph cluster\(name) {
subgraph \(clusterPrefix)\(name) {
label = "\(label)"
node [color="\(color)"]
\(nodes.joined(separator: "\n "))
\(indented: nodes.joined(separator: "\n"))
}
"""
}
Expand Down
25 changes: 18 additions & 7 deletions Sources/SourceDocsLib/PackageProcessor/PackageProcessor.swift
Expand Up @@ -11,9 +11,11 @@ import System
import MarkdownGenerator

public final class PackageProcessor {
let inputPath: URL
let outputPath: URL
let reproducibleDocs: Bool
public let inputPath: URL
public let outputPath: URL
public let reproducibleDocs: Bool
public var clustersEnabled: Bool = true

let canRenderDOT: Bool
let packageDump: PackageDump
let packageDependencyTree: PackageDependency
Expand Down Expand Up @@ -46,10 +48,7 @@ public final class PackageProcessor {
public func run() throws {
fputs("Processing package...\n".green, stdout)
try createOutputFolderIfNeeded()
try ModuleGraphGenerator(basePath: outputPath, packageDump: packageDump,
canRenderDOT: canRenderDOT).run()
try DependencyGraphGenerator(basePath: outputPath, dependencyTree: packageDependencyTree,
canRenderDOT: canRenderDOT).run()
try generateGraphs()

let content: [MarkdownConvertible] = [
MarkdownHeader(title: "Package: **\(packageDump.name)**"),
Expand All @@ -67,6 +66,18 @@ public final class PackageProcessor {
fputs("Done 🎉\n".green, stdout)
}

func generateGraphs() throws {
let modules = ModuleGraphGenerator(basePath: outputPath, packageDump: packageDump)
modules.canRenderDOT = canRenderDOT
modules.clustersEnabled = clustersEnabled
try modules.run()

let dependencies = DependencyGraphGenerator(basePath: outputPath, dependencyTree: packageDependencyTree)
dependencies.canRenderDOT = canRenderDOT
dependencies.clustersEnabled = clustersEnabled
try dependencies.run()
}

func createOutputFolderIfNeeded() throws {
if FileManager.default.fileExists(atPath: outputPath.path) {
return
Expand Down
22 changes: 14 additions & 8 deletions docs/PackageDependencies.dot
@@ -1,17 +1,23 @@
digraph PackageDependencyGraph {
rankdir = LR
graph [fontname="Helvetica-light", style = filled, color = "#eaeaea"]
node [shape=box, fontname="Helvetica", style=filled, color="#fafafa"]
node [shape=box, fontname="Helvetica", style=filled]
edge [color="#545454"]

subgraph cluster {
subgraph clusterPackage {
node [color="#caecec"]
"SourceDocs"
}

subgraph clusterDependencies {
label = "Package Dependencies"
"SourceDocs\nunspecified" -> "swift-argument-parser\n0.0.5"
"SourceDocs\nunspecified" -> "SwiftPM\n0.4.0"
"SourceDocs\nunspecified" -> "SourceKitten\n0.29.0"
"SourceDocs\nunspecified" -> "MarkdownGenerator\n0.5.0"
"SourceDocs\nunspecified" -> "Rainbow\n3.1.5"
"SourceDocs\nunspecified" -> "System\n1.0.0"
node [color="#eeccaa"]
"SourceDocs" -> "swift-argument-parser\n0.0.5"
"SourceDocs" -> "SwiftPM\n0.4.0"
"SourceDocs" -> "SourceKitten\n0.29.0"
"SourceDocs" -> "MarkdownGenerator\n0.5.0"
"SourceDocs" -> "Rainbow\n3.1.5"
"SourceDocs" -> "System\n1.0.0"
"SwiftPM\n0.4.0" -> "llbuild\n0.1.1"
"SourceKitten\n0.29.0" -> "Commandant\n0.17.0"
"SourceKitten\n0.29.0" -> "SWXMLHash\n5.0.1"
Expand Down
Binary file modified docs/PackageDependencies.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 20 additions & 20 deletions docs/PackageModules.dot
Expand Up @@ -5,28 +5,28 @@ digraph ModuleDependencyGraph {
edge [color="#545454"]

subgraph clusterRegular {
label = "Program Modules"
node [color="#caecec"]
"SourceDocsCLI"
"SourceDocsLib"
"SourceDocsDemo"
}
label = "Program Modules"
node [color="#caecec"]
"SourceDocsCLI"
"SourceDocsLib"
"SourceDocsDemo"
}
subgraph clusterTest {
label = "Test Modules"
node [color="#aaccee"]
"SourceDocsCLITests"
"SourceDocsLibTests"
}
label = "Test Modules"
node [color="#aaccee"]
"SourceDocsCLITests"
"SourceDocsLibTests"
}
subgraph clusterExternal {
label = "External Dependencies"
node [color="#fafafa"]
"ArgumentParser"
"MarkdownGenerator"
"Rainbow"
"SourceKittenFramework"
"SwiftPM-auto"
"System"
}
label = "External Dependencies"
node [color="#eeccaa"]
"ArgumentParser"
"MarkdownGenerator"
"Rainbow"
"SourceKittenFramework"
"SwiftPM-auto"
"System"
}

"SourceDocsCLI" -> "ArgumentParser"
"SourceDocsCLI" -> "SourceDocsLib"
Expand Down
Binary file modified docs/PackageModules.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions docs/reference/SourceDocsLib/classes/PackageProcessor.md
Expand Up @@ -6,6 +6,31 @@
public final class PackageProcessor
```

## Properties
### `inputPath`

```swift
public let inputPath: URL
```

### `outputPath`

```swift
public let outputPath: URL
```

### `reproducibleDocs`

```swift
public let reproducibleDocs: Bool
```

### `clustersEnabled`

```swift
public var clustersEnabled: Bool = true
```

## Methods
### `init(inputPath:outputPath:reproducibleDocs:)`

Expand Down