File: DOTJobGraphSerializer.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (73 lines) | stat: -rw-r--r-- 2,549 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//===--------------- DOTJobGraphSerializer.swift - Swift GraphViz ---------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

/// Serializes the job graph to a .dot file
@_spi(Testing) public struct DOTJobGraphSerializer {
  var kindCounter = [Job.Kind: Int]()
  var hasEmittedStyling = Set<String>()
  let jobs: [Job]

  /// Creates a serializer that will serialize the given set of top level jobs.
  public init(jobs: [Job]) {
    self.jobs = jobs
  }

  /// Gets the name of the tool that's being invoked from a job
  func findToolName(_ path: VirtualPath) -> String {
    switch path {
    case .absolute(let abs): return abs.components.last!
    case .relative(let rel): return rel.components.last!
    default: fatalError("no tool for kind \(path)")
    }
  }

  /// Gets a unique label for a job name
  mutating func label(for job: Job) -> String {
    var label = "\(job.kind)"
    if let count = kindCounter[job.kind] {
      label += " \(count)"
    }
    label += " (\(findToolName(job.tool)))"
    kindCounter[job.kind, default: 0] += 1
    return label
  }

  /// Quote the name and escape the quotes
  func quoteName(_ name: String) -> String {
    return "\"" + name.replacingOccurrences(of: "\"", with: "\\\"") + "\""
  }

  public mutating func writeDOT<Stream: TextOutputStream>(to stream: inout Stream) {
    stream.write("digraph Jobs {\n")
    for job in jobs {
      let jobName = quoteName(label(for: job))
      if !hasEmittedStyling.contains(jobName) {
        stream.write("  \(jobName) [style=bold];\n")
      }
      for input in job.inputs {
        let inputName = quoteName(input.file.name)
        if hasEmittedStyling.insert(inputName).inserted {
          stream.write("  \(inputName) [fontsize=12];\n")
        }
        stream.write("  \(inputName) -> \(jobName) [color=blue];\n")
      }
      for output in job.outputs {
        let outputName = quoteName(output.file.name)
        if hasEmittedStyling.insert(outputName).inserted {
          stream.write("  \(outputName) [fontsize=12];\n")
        }
        stream.write("  \(jobName) -> \(outputName) [color=green];\n")
      }
    }
    stream.write("}\n")
  }
}