Skip to content
Browse files

Almost there with needs to run test.

  • Loading branch information...
1 parent bc7b7c2 commit 5819eabab746faf74ea0b1d9ad40f846c2453041 @KrisJordan committed Jan 5, 2011
Showing with 104 additions and 44 deletions.
  1. +10 −7 Cakefile
  2. +3 −2 docs/dag.html
  3. +1 −1 docs/icing.html
  4. +40 −18 docs/rules.html
  5. +3 −2 src/dag.coffee
  6. +1 −1 src/icing.coffee
  7. +46 −13 src/rules.coffee
View
17 Cakefile
@@ -5,13 +5,16 @@ option '-s','--spec','Run vows with spec option'
task 'version', -> console.log '0.1'
task 'test', ['spec/*'], (options) ->
- args = []
- if options.spec?
- args.push '--spec'
- command = "vows #{args.join ' '} #{this.prereqs.join(' ')}"
- this.exec command
+ args = []
+ if options.spec?
+ args.push '--spec'
+ command = "vows #{args.join ' '} #{this.prereqs.join(' ')}"
+ this.exec command
-task 'docs', 'Generate docco documentation', ['src/*'], (options) ->
- this.exec "docco #{this.prereqs.join(' ')}"
+task 'docs', 'Generate docco documentation', ['src/*'],
+ exec: (options) -> this.exec "docco #{this.prereqs.join(' ')}"
+ outputs: ->
+ for prereq in this.prereqs
+ prereq.replace /src\/(.*).coffee/,"docs/$1.html"
task 'all', 'Test and Document', ['test','docs'], (options) -> this.finished()
View
5 docs/dag.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html> <html> <head> <title>dag.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="dag.html"> dag.coffee </a> <a class="source" href="icing.html"> icing.coffee </a> <a class="source" href="rules.html"> rules.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> dag.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-1">&#182;</a> </div> <p><strong>dag</strong> is a simple library for constructing and operating on
+<!DOCTYPE html> <html> <head> <title>dag.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="dag.html"> dag.coffee </a> <a class="source" href="icing.html"> icing.coffee </a> <a class="source" href="rules.html"> rules.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> dag.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-1">&#182;</a> </div> <p><strong>dag</strong> is a simple library for working with
<a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph">directed acyclic graphs</a>.
Its primary purpose is to support command execution pipelines for <strong>icing</strong>.</p>
@@ -17,7 +17,7 @@
it has outbound edges."</p>
<p><em>Disclaimer: dag's intention is not to be a complete or robust
-DAG library. Nor is it meant to be highly performant, just simple.</em></p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <p><strong>Dependencies</strong> </p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">_ = </span><span class="nx">require</span> <span class="s1">&#39;underscore&#39;</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <h3>Graph</h3> </td> <td class="code"> <div class="highlight"><pre><span class="k">class</span> <span class="nx">Graph</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>A graph is just a collection of Nodes and Arcs. We keep maps
+DAG library. Nor is it meant to be highly performant, just simple.</em></p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <p><strong>Dependencies</strong></p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">_ = </span><span class="nx">require</span> <span class="s1">&#39;underscore&#39;</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <h3>Graph</h3> </td> <td class="code"> <div class="highlight"><pre><span class="k">class</span> <span class="nx">Graph</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>A graph is just a collection of Nodes and Arcs. We keep maps
of node names and arcs to ensure each node or arc between two
nodes is represented by a single, unique object in the graph.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">constructor: </span><span class="nf">(@nodes = new NodeList, @arcs = new ArcList) -&gt;</span>
<span class="vi">@nodeMap = </span><span class="p">{}</span>
@@ -139,6 +139,7 @@
<span class="nv">isEmpty: </span><span class="o">-&gt;</span> <span class="nx">@items</span><span class="p">.</span><span class="nx">length</span> <span class="o">==</span> <span class="mi">0</span>
<span class="nv">pop: </span><span class="o">-&gt;</span> <span class="nx">do</span> <span class="nx">@items</span><span class="p">.</span><span class="nx">pop</span>
<span class="nv">shift: </span><span class="o">-&gt;</span> <span class="nx">do</span> <span class="nx">@items</span><span class="p">.</span><span class="nx">shift</span>
+ <span class="nv">count: </span><span class="o">-&gt;</span> <span class="nx">@items</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">pluck: </span><span class="nf">(property) -&gt;</span>
<span class="nx">_</span><span class="p">(</span><span class="nx">@items</span><span class="p">).</span><span class="nx">pluck</span> <span class="nx">property</span>
View
2 docs/icing.html
@@ -74,7 +74,7 @@
<span class="nv">recipeNode = </span><span class="p">{}</span>
<span class="nv">runNextRecipeCallback = </span><span class="nf">( ok = true, report = {} ) -&gt;</span>
<span class="k">if</span> <span class="o">not</span> <span class="nx">ok</span>
- <span class="nx">console</span><span class="p">.</span><span class="nx">error</span> <span class="s2">&quot;===== #{report.rule.target} Failed =====&quot;</span>
+ <span class="nx">console</span><span class="p">.</span><span class="nx">error</span> <span class="s2">&quot;===== #{report.target} Failed =====&quot;</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">error</span> <span class="nx">report</span><span class="p">.</span><span class="nx">message</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">1</span>
View
58 docs/rules.html
@@ -21,6 +21,7 @@
<span class="nv">_ = </span><span class="nx">require</span> <span class="s1">&#39;underscore&#39;</span>
<span class="nv">assert = </span><span class="nx">require</span> <span class="s1">&#39;assert&#39;</span>
<span class="p">{</span> <span class="nx">globSync</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">&#39;glob&#39;</span>
+<span class="nv">fs = </span><span class="nx">require</span> <span class="s1">&#39;fs&#39;</span>
<span class="k">class</span> <span class="nx">RuleGraph</span> <span class="k">extends</span> <span class="nx">Graph</span>
<span class="nv">recipeNodesTo: </span><span class="nf">(target) -&gt;</span>
@@ -34,57 +35,78 @@
<span class="nv">graph = </span><span class="k">this</span>
<span class="nv">target = </span><span class="k">new</span> <span class="nx">RecipeNode</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">target</span><span class="p">,</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">recipe</span>
- <span class="nx">graph</span><span class="p">.</span><span class="nx">node</span> <span class="nx">target</span>
+ <span class="nx">graph</span><span class="p">.</span><span class="nx">node</span> <span class="nx">target</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <p>Glob Prereqs</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">rule.prereqs = </span><span class="nx">_</span><span class="p">(</span><span class="nx">rule</span><span class="p">.</span><span class="nx">prereqs</span><span class="p">)</span>
+ <span class="p">.</span><span class="nx">chain</span><span class="p">()</span>
+ <span class="p">.</span><span class="nx">map</span><span class="p">(</span> <span class="nf">(prereq) -&gt;</span>
+ <span class="nv">globbed = </span><span class="nx">globSync</span> <span class="nx">prereq</span>
+ <span class="k">if</span> <span class="nx">globbed</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span>
+ <span class="nx">globbed</span>
+ <span class="k">else</span>
+ <span class="nx">prereq</span>
+ <span class="p">)</span>
+ <span class="p">.</span><span class="nx">flatten</span><span class="p">()</span>
+ <span class="p">.</span><span class="nx">value</span><span class="p">()</span>
- <span class="nx">rule</span><span class="p">.</span><span class="nx">prereqs</span><span class="p">.</span><span class="nx">forEach</span> <span class="nf">(prereq) -&gt;</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <p>If a prereq already exists, we use it. Targets must therefore
+ <span class="nx">rule</span><span class="p">.</span><span class="nx">prereqs</span><span class="p">.</span><span class="nx">forEach</span> <span class="nf">(prereq) -&gt;</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>If a prereq already exists, we use it. Targets must therefore
always be defined prior to being referenced as prerequisites in other
rules.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">graph</span><span class="p">.</span><span class="nx">node</span> <span class="nx">prereq</span>
- <span class="nv">input = </span><span class="nx">graph</span><span class="p">.</span><span class="nx">node</span> <span class="nx">prereq</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>There's a special case when a RecipeNode's recipe has outputs. When
+ <span class="nv">input = </span><span class="nx">graph</span><span class="p">.</span><span class="nx">node</span> <span class="nx">prereq</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>There's a special case when a RecipeNode's recipe has outputs. When
other RecipeNode targets have one as a prereq its dependency is on
those FileNode outputs and not the RecipeNode itself.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">input</span> <span class="k">instanceof</span> <span class="nx">RecipeNode</span>
<span class="nv">inputsOutputs = </span> <span class="nx">graph</span><span class="p">.</span><span class="nx">arcs</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="nx">input</span><span class="p">).</span><span class="nx">to</span><span class="p">().</span><span class="nx">ofType</span><span class="p">(</span><span class="nx">FileNode</span><span class="p">)</span>
<span class="k">if</span> <span class="o">not</span> <span class="nx">inputsOutputs</span><span class="p">.</span><span class="nx">isEmpty</span><span class="p">()</span>
<span class="nx">inputsOutputs</span><span class="p">.</span><span class="nx">forEach</span> <span class="nf">(inputsOutput) -&gt;</span>
<span class="nx">graph</span><span class="p">.</span><span class="nx">arc</span> <span class="nx">inputsOutput</span><span class="p">.</span><span class="nx">name</span><span class="p">,</span> <span class="nx">target</span><span class="p">.</span><span class="nx">name</span>
<span class="k">return</span>
- <span class="nx">graph</span><span class="p">.</span><span class="nx">arc</span> <span class="nx">input</span><span class="p">.</span><span class="nx">name</span><span class="p">,</span> <span class="nx">target</span><span class="p">.</span><span class="nx">name</span>
- <span class="k">else</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>see if there's an expansion for it</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">globbed = </span><span class="nx">globSync</span> <span class="nx">prereq</span>
- <span class="k">if</span> <span class="nx">globbed</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span>
- <span class="nx">globbed</span><span class="p">.</span><span class="nx">forEach</span> <span class="nf">(file) -&gt;</span>
- <span class="nv">input = </span><span class="k">new</span> <span class="nx">FileNode</span> <span class="nx">file</span>
- <span class="nx">graph</span><span class="p">.</span><span class="nx">node</span> <span class="nx">input</span>
- <span class="nx">graph</span><span class="p">.</span><span class="nx">arc</span> <span class="nx">input</span><span class="p">.</span><span class="nx">name</span><span class="p">,</span> <span class="nx">target</span><span class="p">.</span><span class="nx">name</span>
- <span class="k">else</span>
- <span class="nv">input = </span><span class="k">new</span> <span class="nx">FileNode</span> <span class="nx">prereq</span>
- <span class="nx">graph</span><span class="p">.</span><span class="nx">node</span> <span class="nx">input</span>
- <span class="nx">graph</span><span class="p">.</span><span class="nx">arc</span> <span class="nx">input</span><span class="p">.</span><span class="nx">name</span><span class="p">,</span> <span class="nx">target</span><span class="p">.</span><span class="nx">name</span>
+ <span class="k">else</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</a> </div> <p>see if there's an expansion for it</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">input = </span><span class="k">new</span> <span class="nx">FileNode</span> <span class="nx">prereq</span>
+ <span class="nx">graph</span><span class="p">.</span><span class="nx">node</span> <span class="nx">input</span>
+ <span class="nx">graph</span><span class="p">.</span><span class="nx">arc</span> <span class="nx">input</span><span class="p">.</span><span class="nx">name</span><span class="p">,</span> <span class="nx">target</span><span class="p">.</span><span class="nx">name</span>
<span class="nv">outputs = </span><span class="nx">rule</span><span class="p">.</span><span class="nx">recipe</span><span class="p">.</span><span class="nx">outputs</span><span class="p">.</span><span class="nx">call</span> <span class="nx">rule</span>
<span class="nx">outputs</span><span class="p">.</span><span class="nx">forEach</span> <span class="nf">(output) -&gt;</span>
<span class="nv">output = </span><span class="k">new</span> <span class="nx">FileNode</span> <span class="nx">output</span>
<span class="nx">graph</span><span class="p">.</span><span class="nx">node</span> <span class="nx">output</span>
<span class="nx">graph</span><span class="p">.</span><span class="nx">arc</span> <span class="nx">target</span><span class="p">.</span><span class="nx">name</span><span class="p">,</span> <span class="nx">output</span><span class="p">.</span><span class="nx">name</span>
- <span class="k">this</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</a> </div> <h3>Rule Graph Elements</h3> </td> <td class="code"> <div class="highlight"><pre><span class="k">class</span> <span class="nx">Rule</span>
+ <span class="k">this</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">&#182;</a> </div> <h3>Rule Graph Elements</h3> </td> <td class="code"> <div class="highlight"><pre><span class="k">class</span> <span class="nx">Rule</span>
<span class="nv">constructor: </span><span class="nf">(@target, @prereqs, @recipe) -&gt;</span>
<span class="k">if</span> <span class="nx">_</span><span class="p">(</span><span class="nx">@recipe</span><span class="p">).</span><span class="nx">isFunction</span><span class="p">()</span>
<span class="vi">@recipe = </span><span class="k">new</span> <span class="nx">Recipe</span> <span class="nx">@recipe</span>
<span class="vi">@prereqs = </span><span class="nx">@prereqs</span><span class="p">.</span><span class="nx">reverse</span><span class="p">()</span> <span class="c1"># Because we push they&#39;ll get reversed again</span>
<span class="k">class</span> <span class="nx">Recipe</span>
- <span class="nv">constructor: </span><span class="p">(</span><span class="vi">@exec = </span><span class="p">(</span><span class="o">-&gt;</span><span class="p">),</span> <span class="vi">@outputs = </span><span class="p">(</span><span class="o">-&gt;</span><span class="p">[]))</span> <span class="o">-&gt;</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">&#182;</a> </div> <h3>Additional Graph Nodes</h3> </td> <td class="code"> <div class="highlight"><pre><span class="k">class</span> <span class="nx">RecipeNode</span> <span class="k">extends</span> <span class="nx">Node</span>
+ <span class="nv">constructor: </span><span class="p">(</span><span class="vi">@exec = </span><span class="p">(</span><span class="o">-&gt;</span><span class="p">),</span> <span class="vi">@outputs = </span><span class="p">(</span><span class="o">-&gt;</span><span class="p">[]))</span> <span class="o">-&gt;</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</a> </div> <h3>Additional Graph Nodes</h3> </td> <td class="code"> <div class="highlight"><pre><span class="k">class</span> <span class="nx">RecipeNode</span> <span class="k">extends</span> <span class="nx">Node</span>
<span class="nv">constructor: </span><span class="nf">(@name, @recipe) -&gt;</span>
<span class="nv">equals: </span><span class="nf">(node) -&gt;</span>
<span class="k">super</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">RecipeNode</span>
<span class="nv">clone: </span><span class="nf">(node) -&gt;</span> <span class="k">new</span> <span class="nx">RecipeNode</span> <span class="nx">@name</span><span class="p">,</span> <span class="nx">@recipe</span>
<span class="nv">prereqs: </span><span class="nf">(graph) -&gt;</span> <span class="nx">graph</span><span class="p">.</span><span class="nx">arcs</span><span class="p">.</span><span class="nx">to</span><span class="p">(</span><span class="nx">graph</span><span class="p">.</span><span class="nx">node</span> <span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">).</span><span class="nx">from</span><span class="p">().</span><span class="nx">ofType</span> <span class="nx">FileNode</span>
- <span class="nv">shouldRun: </span><span class="nf">(graph) -&gt;</span> <span class="kc">true</span>
+ <span class="nv">outputs: </span><span class="nf">(graph) -&gt;</span> <span class="nx">graph</span><span class="p">.</span><span class="nx">arcs</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="nx">graph</span><span class="p">.</span><span class="nx">node</span> <span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">).</span><span class="nx">to</span><span class="p">().</span><span class="nx">ofType</span> <span class="nx">FileNode</span>
+ <span class="nv">shouldRun: </span><span class="nf">(graph) -&gt;</span>
+ <span class="nv">prereqs = </span><span class="k">this</span><span class="p">.</span><span class="nx">prereqs</span> <span class="nx">graph</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">&#182;</a> </div> <p>Recipes without prereqs always run</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">prereqs</span><span class="p">.</span><span class="nx">isEmpty</span><span class="p">()</span> <span class="k">then</span> <span class="k">return</span> <span class="kc">true</span>
+
+ <span class="nv">outputs = </span><span class="k">this</span><span class="p">.</span><span class="nx">outputs</span> <span class="nx">graph</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">&#182;</a> </div> <p>Recipes without file outputs always run</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">outputs</span><span class="p">.</span><span class="nx">isEmpty</span><span class="p">()</span> <span class="k">then</span> <span class="k">return</span> <span class="kc">true</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">&#182;</a> </div> <p>There are file inputs and outputs. If there is the same number of inputs
+as outputs we take a special case and compare them 1 by 1. If there are
+a different number of inputs and outputs we check to see if the greatest
+modified time of the inputs is greater than the oldest output. If so we
+should run.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">prereqs</span><span class="p">.</span><span class="nx">count</span><span class="p">()</span> <span class="o">==</span> <span class="nx">outputs</span><span class="p">.</span><span class="nx">count</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p>TODO: special case</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">return</span> <span class="kc">true</span>
+ <span class="k">else</span>
+ <span class="nv">prereqMax = </span><span class="nx">_</span><span class="p">(</span><span class="nx">prereqs</span><span class="p">.</span><span class="nx">items</span><span class="p">).</span><span class="nx">max</span> <span class="nf">(fileNode) -&gt;</span> <span class="nx">fileNode</span><span class="p">.</span><span class="nx">mtime</span> <span class="o">||</span> <span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">()</span>
+ <span class="nv">outputMin = </span><span class="nx">_</span><span class="p">(</span><span class="nx">outputs</span><span class="p">.</span><span class="nx">items</span><span class="p">).</span><span class="nx">min</span> <span class="nf">(fileNode) -&gt;</span> <span class="nx">fileNode</span><span class="p">.</span><span class="nx">mtime</span> <span class="o">||</span> <span class="mi">0</span>
+ <span class="k">return</span> <span class="nx">prereqMax</span><span class="p">.</span><span class="nx">mtime</span> <span class="o">&gt;</span> <span class="nx">outputMin</span><span class="p">.</span><span class="nx">mtime</span>
+
<span class="nv">run: </span><span class="nf">(context, options) -&gt;</span> <span class="nx">@recipe</span><span class="p">.</span><span class="nx">exec</span><span class="p">.</span><span class="nx">call</span> <span class="nx">context</span><span class="p">,</span> <span class="nx">options</span>
<span class="k">class</span> <span class="nx">FileNode</span> <span class="k">extends</span> <span class="nx">Node</span>
<span class="nv">constructor: </span><span class="nf">(@name) -&gt;</span>
+ <span class="k">try</span>
+ <span class="vi">@stats = </span><span class="nx">fs</span><span class="p">.</span><span class="nx">statSync</span> <span class="nx">@name</span>
+ <span class="vi">@mtime = </span><span class="nx">@stats</span><span class="p">.</span><span class="nx">mtime</span>
+ <span class="k">catch</span> <span class="nb">Error</span>
+ <span class="vi">@stats = </span><span class="p">{}</span>
+ <span class="vi">@mtime = </span><span class="kc">undefined</span>
<span class="nv">equals: </span><span class="nf">(node) -&gt;</span>
<span class="k">super</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">FileNode</span>
- <span class="nv">clone: </span><span class="nf">(node) -&gt;</span> <span class="k">new</span> <span class="nx">FileNode</span> <span class="nx">@name</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</a> </div> <h3>Exports</h3> </td> <td class="code"> <div class="highlight"><pre><span class="nx">_</span><span class="p">(</span><span class="nx">exports</span><span class="p">).</span><span class="nx">extend</span> <span class="p">{</span> <span class="nx">RuleGraph</span><span class="p">,</span> <span class="nx">Rule</span><span class="p">,</span> <span class="nx">RecipeNode</span><span class="p">,</span> <span class="nx">FileNode</span><span class="p">,</span> <span class="nx">Recipe</span> <span class="p">}</span>
+ <span class="nv">clone: </span><span class="nf">(node) -&gt;</span> <span class="k">new</span> <span class="nx">FileNode</span> <span class="nx">@name</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <h3>Exports</h3> </td> <td class="code"> <div class="highlight"><pre><span class="nx">_</span><span class="p">(</span><span class="nx">exports</span><span class="p">).</span><span class="nx">extend</span> <span class="p">{</span> <span class="nx">RuleGraph</span><span class="p">,</span> <span class="nx">Rule</span><span class="p">,</span> <span class="nx">RecipeNode</span><span class="p">,</span> <span class="nx">FileNode</span><span class="p">,</span> <span class="nx">Recipe</span> <span class="p">}</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
View
5 src/dag.coffee
@@ -1,4 +1,4 @@
-# **dag** is a simple library for constructing and operating on
+# **dag** is a simple library for working with
# [directed acyclic graphs](http://en.wikipedia.org/wiki/Directed_acyclic_graph).
# Its primary purpose is to support command execution pipelines for **icing**.
#
@@ -17,7 +17,7 @@
# *Disclaimer: dag's intention is not to be a complete or robust
# DAG library. Nor is it meant to be highly performant, just simple.*
-# **Dependencies**
+# **Dependencies**
_ = require 'underscore'
#### Graph
@@ -181,6 +181,7 @@ class List
isEmpty: -> @items.length == 0
pop: -> do @items.pop
shift: -> do @items.shift
+ count: -> @items.length
pluck: (property) ->
_(@items).pluck property
View
2 src/icing.coffee
@@ -84,7 +84,7 @@ global.task = (target, description, prereqs=undefined, recipe=undefined) ->
recipeNode = {}
runNextRecipeCallback = ( ok = true, report = {} ) ->
if not ok
- console.error "===== #{report.rule.target} Failed ====="
+ console.error "===== #{report.target} Failed ====="
console.error report.message
process.exit 1
View
59 src/rules.coffee
@@ -22,6 +22,7 @@
_ = require 'underscore'
assert = require 'assert'
{ globSync } = require 'glob'
+fs = require 'fs'
class RuleGraph extends Graph
recipeNodesTo: (target) ->
@@ -37,6 +38,19 @@ class RuleGraph extends Graph
target = new RecipeNode rule.target, rule.recipe
graph.node target
+ # Glob Prereqs
+ rule.prereqs = _(rule.prereqs)
+ .chain()
+ .map( (prereq) ->
+ globbed = globSync prereq
+ if globbed.length > 0
+ globbed
+ else
+ prereq
+ )
+ .flatten()
+ .value()
+
rule.prereqs.forEach (prereq) ->
# If a prereq already exists, we use it. Targets must therefore
# always be defined prior to being referenced as prerequisites in other
@@ -52,19 +66,11 @@ class RuleGraph extends Graph
inputsOutputs.forEach (inputsOutput) ->
graph.arc inputsOutput.name, target.name
return
- graph.arc input.name, target.name
else
# see if there's an expansion for it
- globbed = globSync prereq
- if globbed.length > 0
- globbed.forEach (file) ->
- input = new FileNode file
- graph.node input
- graph.arc input.name, target.name
- else
- input = new FileNode prereq
- graph.node input
- graph.arc input.name, target.name
+ input = new FileNode prereq
+ graph.node input
+ graph.arc input.name, target.name
outputs = rule.recipe.outputs.call rule
outputs.forEach (output) ->
@@ -91,15 +97,42 @@ class RecipeNode extends Node
super(node) && node instanceof RecipeNode
clone: (node) -> new RecipeNode @name, @recipe
prereqs: (graph) -> graph.arcs.to(graph.node this.name).from().ofType FileNode
- shouldRun: (graph) -> true
+ outputs: (graph) -> graph.arcs.from(graph.node this.name).to().ofType FileNode
+ shouldRun: (graph) ->
+ prereqs = this.prereqs graph
+ # Recipes without prereqs always run
+ if prereqs.isEmpty() then return true
+
+ outputs = this.outputs graph
+ # Recipes without file outputs always run
+ if outputs.isEmpty() then return true
+
+ # There are file inputs and outputs. If there is the same number of inputs
+ # as outputs we take a special case and compare them 1 by 1. If there are
+ # a different number of inputs and outputs we check to see if the greatest
+ # modified time of the inputs is greater than the oldest output. If so we
+ # should run.
+ if prereqs.count() == outputs.count()
+ # TODO: special case
+ return true
+ else
+ prereqMax = _(prereqs.items).max (fileNode) -> fileNode.mtime || Date.now()
+ outputMin = _(outputs.items).min (fileNode) -> fileNode.mtime || 0
+ return prereqMax.mtime > outputMin.mtime
+
run: (context, options) -> @recipe.exec.call context, options
class FileNode extends Node
constructor: (@name) ->
+ try
+ @stats = fs.statSync @name
+ @mtime = @stats.mtime
+ catch Error
+ @stats = {}
+ @mtime = undefined
equals: (node) ->
super(node) && node instanceof FileNode
clone: (node) -> new FileNode @name
-
#### Exports
_(exports).extend { RuleGraph, Rule, RecipeNode, FileNode, Recipe }

0 comments on commit 5819eab

Please sign in to comment.
Something went wrong with that request. Please try again.