Skip to content
This repository
Browse code

NEW Allow debugging of config cyclic errors

It is possible to specify before and after rules on config fragments
that conflict - A before B and B before A isnt possible to solve.

This used to just throw an error with no way to debug. Now if you
specify debug as a GET parameter and the site is not in live mode
youll get a basic dump of the remaining DAG graph
  • Loading branch information...
commit 6009cfadc2e310b723a8c091cd9d94db968fe07e 1 parent e0b8f15
Hamish Friedlander authored August 27, 2012
65  core/DAG.php
@@ -4,7 +4,7 @@
4 4
  * A Directed Acyclic Graph - used for doing topological sorts on dependencies, such as the before/after conditions
5 5
  * in config yaml fragments
6 6
  */
7  
-class SS_DAG {
  7
+class SS_DAG implements IteratorAggregate {
8 8
 	/** @var array|null - The nodes/vertices in the graph. Should be a numeric sequence of items (no string keys, no gaps). */
9 9
 	protected $data;
10 10
 
@@ -68,7 +68,68 @@ function sort() {
68 68
 			$dag = $withedges;
69 69
 		}
70 70
 
71  
-		if ($dag) throw new Exception("DAG has cyclic requirements");
  71
+		if ($dag) {
  72
+			$remainder = new SS_DAG($data); $remainder->dag = $dag;
  73
+			throw new SS_DAG_CyclicException("DAG has cyclic requirements", $remainder);
  74
+		}
72 75
 		return $sorted;
73 76
 	}
  77
+
  78
+	function getIterator() {
  79
+		return new SS_DAG_Iterator($this->data, $this->dag);
  80
+	}
  81
+}
  82
+
  83
+class SS_DAG_CyclicException extends Exception {
  84
+
  85
+	public $dag;
  86
+
  87
+	function __construct($message, $dag) {
  88
+		$this->dag = $dag;
  89
+		parent::__construct($message);
  90
+	}
  91
+
  92
+}
  93
+
  94
+class SS_DAG_Iterator implements Iterator {
  95
+
  96
+	protected $data;
  97
+	protected $dag;
  98
+
  99
+	protected $dagkeys;
  100
+	protected $i;
  101
+
  102
+	function __construct($data, $dag) {
  103
+		$this->data = $data;
  104
+		$this->dag = $dag;
  105
+		$this->rewind();
  106
+	}
  107
+
  108
+	function key() {
  109
+		return $this->i;
  110
+	}
  111
+
  112
+	function current() {
  113
+		$res = array();
  114
+
  115
+		$res['from'] = $this->data[$this->i];
  116
+
  117
+		$res['to'] = array();
  118
+		foreach ($this->dag[$this->i] as $to) $res['to'][] = $this->data[$to];
  119
+
  120
+		return $res;
  121
+	}
  122
+
  123
+	function next() {
  124
+		$this->i = array_shift($this->dagkeys);
  125
+	}
  126
+
  127
+	function rewind() {
  128
+		$this->dagkeys = array_keys($this->dag);
  129
+		$this->next();
  130
+	}
  131
+
  132
+	function valid() {
  133
+		return $this->i !== null;
  134
+	}
74 135
 }
25  core/manifest/ConfigManifest.php
@@ -268,7 +268,30 @@ protected function sortYamlFragments() {
268 268
 			}
269 269
 		}
270 270
 
271  
-		$this->yamlConfigFragments = $dag->sort();
  271
+		try {
  272
+			$this->yamlConfigFragments = $dag->sort();
  273
+		}
  274
+		catch (SS_DAG_CyclicException $e) {
  275
+
  276
+			if (!Director::isLive() && isset($_REQUEST['debug'])) {
  277
+				$res = '<h1>Remaining config fragment graph</h1>';
  278
+				$res .= '<dl>';
  279
+
  280
+				foreach ($e->dag as $node) {
  281
+					$res .= "<dt>{$node['from']['module']}/{$node['from']['file']}#{$node['from']['name']} marked to come after</dt><dd><ul>";
  282
+					foreach ($node['to'] as $to) {
  283
+						$res .= "<li>{$to['module']}/{$to['file']}#{$to['name']}</li>";
  284
+					}
  285
+					$res .= "</ul></dd>";
  286
+				}
  287
+
  288
+				$res .= '</dl>';
  289
+				echo $res;
  290
+			}
  291
+
  292
+			throw $e;
  293
+		}
  294
+
272 295
 	}
273 296
 	
274 297
 	/**

0 notes on commit 6009cfa

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