Skip to content

Commit

Permalink
First draft of a --graph mode
Browse files Browse the repository at this point in the history
  • Loading branch information
amalloy committed Nov 15, 2014
1 parent 960ddfe commit 752ffae
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 4 deletions.
3 changes: 2 additions & 1 deletion project.clj
Expand Up @@ -13,13 +13,14 @@
[org.clojure/tools.logging "0.2.3"]
[clj-logging-config "1.9.6"]
[clojopts/clojopts "0.3.4"]
[org.flatland/useful "0.11.1"]
[org.flatland/useful "0.11.3"]
[fs "1.3.2"]
[factual/jlk-time "0.1"]
[clj-time "0.6.0"]
[digest "1.4.0"]
[com.google.guava/guava "14.0.1"]
[cheshire "5.2.0"]
[rhizome "0.2.1"]
[slingshot "0.10.3"]
[factual/fnparse "2.3.0"]
[commons-codec/commons-codec "1.6"]
Expand Down
17 changes: 14 additions & 3 deletions src/drake/core.clj
Expand Up @@ -15,6 +15,7 @@
drake.event
[drake.stdin :as stdin]
[drake.steps :as steps]
[drake.viz :as viz :refer [viz]]
[drake.plugins :as plugins]
[drake.fs :as dfs :refer [fs]]
[drake.protocol :refer [get-protocol-name get-protocol]]
Expand Down Expand Up @@ -587,6 +588,14 @@
(count steps)
")")}))))))))))

(defn graph-steps
"Shows a graph visualizing workflow of steps to run, and saves it to drake.png"
[parse-tree steps-to-run]
(require 'rhizome.dot 'rhizome.viz)
(let [img (viz dot->image (viz/step-tree parse-tree steps-to-run))]
;; (viz view-image img) ; re-enable if we can figure out how to make it stay on-screen
(viz save-image img "drake.png")))

(defn print-steps
"Prints inputs and outputs of steps to run."
[parse-tree steps-to-run]
Expand Down Expand Up @@ -614,6 +623,8 @@
(info "Nothing to do.")
(:print *options*)
(print-steps parse-tree steps-to-run)
(:graph *options*)
(graph-steps parse-tree steps-to-run)
(:preview *options*)
(println (steps-report parse-tree steps-to-run))
:else
Expand Down Expand Up @@ -764,11 +775,11 @@

(defn- check-for-conflicts
[opts]
(let [groups [#{:print :auto}
#{:print :preview}
(let [groups [#{:print :auto :graph}
#{:print :preview :graph}
#{:branch :merge-branch}
#{:debug :trace :quiet}]
crossovers [[#{:quiet :step-delay} #{:print :preview}]]
crossovers [[#{:quiet :step-delay} #{:print :preview :graph}]]
option-list (fn [opts] (str/join ", " (map #(str "--" (name %)) opts)))
complain (fn [msg]
(println msg)
Expand Down
2 changes: 2 additions & 0 deletions src/drake/options.clj
Expand Up @@ -60,6 +60,8 @@
:user-name "name")
(no-arg print p
"Runs Drake in \"print\" mode. Instead of executing steps, Drake just prints inputs, outputs and tags of each step that is scheduled to run to stdout. This is useful if some outside actions need to be taken before or after running Drake. Standard target matching rules apply. Inputs are prepended by I, outputs by O, and input and output tags by %I and %O respectively. It also outputs \"S\" to signify beginning of each step.")
(no-arg graph g
"Runs Drake in \"graph\" mode. Instead of executing steps, Drake just draws a graph of all the inputs and outputs in the workflow, with color-coding to indicate which will be run. The graph is saved to a file named drake.png in the current directory. Files which will be built are colored green, and those which were forced will be outlined in black as well.")
(with-arg logfile l
"Specify the log file. If not absolute, will be relative to the workflow file, default is drake.log in the directory of the workflow file."
:type :str
Expand Down
46 changes: 46 additions & 0 deletions src/drake/viz.clj
@@ -0,0 +1,46 @@
(ns drake.viz
(:require [clojure.string :as s]
[flatland.useful.map :as map])
(:import (java.util.regex Pattern)))

(defmacro dot [f & args]
`(@(ns-resolve '~'rhizome.dot '~f) ~@args))

(defmacro viz [f & args]
`(@(ns-resolve '~'rhizome.viz '~f) ~@args))

(defn strip-base [parse-tree]
(let [base (get-in parse-tree [:vars "BASE"])
re (re-pattern (format "^%s/" (Pattern/quote base)))]
(fn [target]
(s/replace target re ""))))

(defn step-tree [parse-tree steps-to-run]
(let [run? (into {} (map (juxt :index identity) steps-to-run))
depends (fn [graph k vs]
(update-in graph [k] (fnil into []) vs))
steps (:steps parse-tree)
{:keys [graph built forced]}
,,(reduce (fn [acc {:keys [built forced input outputs]}]
(-> acc
(update-in [:graph] depends input outputs)
(update-in [:built] into (when built outputs))
(update-in [:forced] into (when forced outputs))))
{:graph {}, :built #{}, :forced #{}}
(for [[i {:keys [inputs outputs]}] (map-indexed vector steps)
:let [built (run? i),
forced (and built
(= "forced" (:cause (run? i))))]
input inputs]
(map/keyed [built forced input outputs])))
target-name (strip-base parse-tree)]
(dot graph->dot (distinct (apply concat (keys graph)
(vals graph)))
graph
:node->descriptor (fn [target]
(merge {:label (target-name target)
:fillcolor "palegreen"}
(when (built target)
{:style "filled"})
(when (forced target)
{:penwidth 3}))))))

0 comments on commit 752ffae

Please sign in to comment.