1<?php
2/**
3 * DokuGource Plugin: extract gource log from the wiki
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Etienne Meleard <etienne.meleard@free.fr>
7 *
8 * 2010/05/19 : Creation
9 */
10
11// must be run within Dokuwiki
12if(!defined('DOKU_INC')) die();
13
14if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
15require_once(DOKU_PLUGIN.'action.php');
16
17class action_plugin_dokugource extends DokuWiki_Action_Plugin {
18	var $colors = array();
19	var $log = array();
20
21	// return some info
22	function getInfo() {
23		return confToHash(dirname(__FILE__).'/INFO');
24	}
25
26	/**
27	 * Register plugin hooks
28	 */
29	function register(&$controller) {
30		$controller->register_hook('IO_WIKIPAGE_WRITE', 'AFTER', $this, 'gourcecolor');
31		$controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'evalgourcerequest');
32	}
33
34	/**
35	 * Get gourcecolor
36	 * @param &$event dokuwiki event object
37	 * @param $args handler arguments
38	 */
39    function gourcecolor(&$event, $args) {
40		global $conf;
41		global $ID;
42		if(preg_match('`~~gourcecolor(<|:|>)#?([0-9a-z]{3}([0-9a-z]{3})?)~~`i', $event->data[0][1], $m)) {
43			$c = strtoupper($m[2]);
44			if(strlen($c) == 3) {
45				$c = str_split($c);
46				$c = $c[0].$c[0].$c[1].$c[1].$c[2].$c[2];
47			}
48			$ns = $event->data[1].':'.(($m[1] == '<') ? '' : $event->data[2]);
49			$ls = preg_split('`\n+`', trim(@file_get_contents($conf['metadir'].'/gource.colors')));
50			if($fp = fopen($conf['metadir'].'/gource.colors', 'w')) {
51				foreach($ls as $l) {
52					if(!$l) continue;
53					if(array_shift(preg_split('`\s+`', $l, 2)) != $ns) fwrite($fp, $l."\n");
54				}
55				fwrite($fp, $ns.' '.$c."\n");
56				fclose($fp);
57			}
58		}
59    }
60
61    /**
62     * Eval if a gource log is requiered
63	 * @param &$event dokuwiki event object
64	 * @param $args handler arguments
65     */
66    function evalgourcerequest(&$event, $args) {
67		global $conf;
68		global $ID;
69
70		// get autorisation
71		if(!isset($_GET['dokugource_key']) || empty($_GET['dokugource_key'])) return;
72		if(!preg_match('`^[a-z0-9]{8,64}$`i', $_GET['dokugource_key'])) die();
73		$key = $_GET['dokugource_key'];
74
75		$ns = $ID;
76		if($ns) {
77			$ns = str_replace('/', ':', trim($ns, '/:'));
78			if(!@is_dir($conf['datadir'].'/'.str_replace(':', '/', $ns).'/')) {
79				if(@is_file($conf['datadir'].'/'.str_replace(':', '/', $ns).'.txt')) {
80					$ns = preg_replace('`^(.*)\:[^\:]+$`', '$1', $ns);
81				}
82			}
83		}
84		$ns = trim($ns, '/:');
85
86		$auto = preg_split('`\n+`', @file_get_contents(DOKU_CONF.'/gource.cnf.php'));
87		array_shift($auto);
88		$autons = false;
89		foreach($auto as $l) {
90			if(preg_match('`^'.$key.'(\s+(.*))?$`', $l, $m)) {
91				$autons = trim($m[2], '/:');
92			}
93		}
94		if($autons === false) die();
95		if(substr($ns, 0, strlen($autons)) != $autons) die();
96
97		$from = (isset($_GET['dokugource_from']) && !empty($_GET['dokugource_from'])) ? (int)$_GET['dokugource_from'] : 0;
98
99		$this->colors = array();
100		foreach(preg_split('`\n+`', trim(@file_get_contents($conf['metadir'].'/gource.colors'))) as $l) {
101			if(!$l) continue;
102			$l = preg_split('`\s+`', $l, 2);
103			$this->colors[$l[0]] = $l[1];
104		}
105
106		$strip = explode(':', $ns);
107		array_pop($strip);
108		$strip = count($strip) ? strlen(implode(':', $strip)) : 0;
109		$this->crawl($conf['metadir'].($ns ? '/'.str_replace(':', '/', $ns) : ''), $strip, $from);
110		sort($this->log);
111
112		header('Content-Type: text/plain; charset=utf-8');
113		echo trim(implode("\n", $this->log)."\nDone\n");
114		exit();
115    }
116
117	function color($p) {
118		$ns = preg_replace('`^(.*\:)[^\:]+$`', '$1', $p);
119		if(isset($this->colors[$p])) return $this->colors[$p];
120		if(isset($this->colors[$ns])) return $this->colors[$ns];
121
122		$this->colors[$p] = sprintf('%02X%02X%02X', rand(0, 255), rand(0, 255), rand(0, 255));
123		return $this->colors[$p];
124	}
125
126	function crawl($p, $strip, $from) {
127		if(!@is_dir($p)) return;
128		foreach(scandir($p) as $i) {
129			if($i == '.' || $i == '..') continue;
130			if(is_file($p.'/'.$i)) if(preg_match('`\.changes$`', $i)) {
131				foreach(preg_split('`\n+`', trim(@file_get_contents($p.'/'.$i))) as $l) {
132					if(!$l) continue;
133					if(preg_match('`^\s*([0-9]+)\s+([^\s]+)\s+([a-z]{1,3})\s+([^\s]+)\s+([^\s]+)`i', $l, $m)) {
134						if((int)$m[1] < $from) continue;
135						if(preg_match('`(C|cc|sc)`i', $m[3])) {
136							$m[3] = 'A';
137						}elseif(preg_match('`(D|dc|hc)`i', $m[3])) {
138							$m[3] = 'D';
139						}else{
140							$m[3] = 'M';
141						}
142						$id = str_replace(':', '/', $m[4]);
143						if($strip) $id = trim(substr($id, $strip), '/:');
144						$this->log[] = $m[1].'|'.$m[5].'|'.$m[3].'|'.$id.'|'.$this->color($m[4]);
145					}
146				}
147			}
148
149			if(is_dir($p.'/'.$i)) $this->crawl($p.'/'.$i, $strip, $from);
150		}
151	}
152}
153