Updated todo.
[viewgit.git] / index.php
blob89f60af0016dc424fb57faf435d3f57a3db0bd5c
1 <?php
2 error_reporting(E_ALL);
4 require_once('inc/config.php');
6 function get_project_info($name)
8 global $conf;
10 $info = $conf['projects'][$name];
11 $info['name'] = $name;
12 $info['description'] = file_get_contents($info['repo'] .'/description');
14 return $info;
17 /**
18 * Get details of a commit: tree, parent, author/committer (name, mail, date), message
20 function git_get_commit_info($project, $hash)
22 $info = array();
23 $info['h'] = $hash;
24 $info['message_full'] = '';
26 $output = run_git($project, "git rev-list --header --max-count=1 $hash");
27 // tree <h>
28 // parent <h>
29 // author <name> "<"<mail>">" <stamp> <timezone>
30 // committer
31 // <empty>
32 // <message>
33 $pattern = '/^(author|committer) ([^<]+) <([^>]*)> ([0-9]+) (.*)$/';
34 foreach ($output as $line) {
35 if (substr($line, 0, 4) === 'tree') {
36 $info['tree'] = substr($line, 5);
38 elseif (substr($line, 0, 6) === 'parent') {
39 $info['parent'] = substr($line, 7);
41 elseif (preg_match($pattern, $line, $matches) > 0) {
42 $info[$matches[1] .'_name'] = $matches[2];
43 $info[$matches[1] .'_mail'] = $matches[3];
44 $info[$matches[1] .'_stamp'] = $matches[4];
45 $info[$matches[1] .'_timezone'] = $matches[5];
46 $info[$matches[1] .'_utcstamp'] = $matches[4] - ((intval($matches[5]) / 100.0) * 3600);
48 elseif (substr($line, 0, 4) === ' ') {
49 $info['message_full'] .= substr($line, 4) ."\n";
50 if (!isset($info['message'])) {
51 $info['message'] = substr($line, 4, 40);
56 return $info;
59 function git_get_heads($project)
61 $heads = array();
63 $output = run_git($project, 'git show-ref --heads');
64 foreach ($output as $line) {
65 $fullname = substr($line, 41);
66 $name = array_pop(explode('/', $fullname));
67 $heads[] = array('h' => substr($line, 0, 40), 'fullname' => "$fullname", 'name' => "$name");
70 return $heads;
73 function git_get_rev_list($project, $max_count = null)
75 $cmd = 'git rev-list HEAD';
76 if (!is_null($max_count)) {
77 $cmd = "git rev-list --max-count=$max_count HEAD";
80 return run_git($project, $cmd);
83 function git_get_tags($project)
85 $tags = array();
87 $output = run_git($project, 'git show-ref --tags');
88 foreach ($output as $line) {
89 $fullname = substr($line, 41);
90 $name = array_pop(explode('/', $fullname));
91 $tags[] = array('h' => substr($line, 0, 40), 'fullname' => $fullname, 'name' => $name);
93 return $tags;
96 function git_ls_tree($project, $tree)
98 $entries = array();
99 $output = run_git($project, "git ls-tree $tree");
100 // 100644 blob 493b7fc4296d64af45dac64bceac2d9a96c958c1 .gitignore
101 // 040000 tree 715c78b1011dc58106da2a1af2fe0aa4c829542f doc
102 foreach ($output as $line) {
103 $parts = preg_split('/\s+/', $line, 4);
104 $entries[] = array('name' => $parts[3], 'mode' => $parts[0], 'type' => $parts[1], 'hash' => $parts[2]);
107 return $entries;
110 function makelink($dict)
112 $params = array();
113 foreach ($dict as $k => $v) {
114 $params[] = rawurlencode($k) .'='. str_replace('%2F', '/', rawurlencode($v));
116 if (count($params) > 0) {
117 return '?'. htmlentities(join('&', $params));
119 return '';
123 * Executes a git command in the project repo.
124 * @return array of output lines
126 function run_git($project, $command)
128 global $conf;
130 $output = array();
131 $cmd = "GIT_DIR=". $conf['projects'][$project]['repo'] ." $command";
132 exec($cmd, &$output);
133 return $output;
137 * Executes a git command in the project repo, sending output directly to the
138 * client.
140 function run_git_passthru($project, $command)
142 global $conf;
144 $cmd = "GIT_DIR=". $conf['projects'][$project]['repo'] ." $command";
145 $result = 0;
146 passthru($cmd, &$result);
147 return $result;
151 * Makes sure the given project is valid. If it's not, this function will
152 * die().
153 * @return the project
155 function validate_project($project)
157 global $conf;
159 if (!in_array($project, array_keys($conf['projects']))) {
160 die('Invalid project');
162 return $project;
166 * Makes sure the given hash is valid. If it's not, this function will die().
167 * @return the hash
169 function validate_hash($hash)
171 if (strlen($hash) != 40 || !preg_match('/^[0-9a-z]*$/', $hash)) {
172 die('Invalid hash');
175 return $hash;
178 $action = 'index';
179 $template = '';
180 $page['title'] = 'ViewGit';
182 if (isset($_REQUEST['a'])) {
183 $action = strtolower($_REQUEST['a']);
185 $page['action'] = $action;
187 if ($action === 'index') {
188 $template = 'index';
189 $page['title'] = 'List of projects - ViewGit';
191 foreach (array_keys($conf['projects']) as $p) {
192 $page['projects'][] = get_project_info($p);
195 elseif ($action === 'archive') {
196 $project = validate_project($_REQUEST['p']);
197 $tree = validate_hash($_REQUEST['h']);
198 $type = $_REQUEST['t'];
200 // TODO check that the data passed is really valid
201 if ($type === 'targz') {
202 header("Content-Type: application/x-tar-gz");
203 header("Content-Transfer-Encoding: binary");
204 header("Content-Disposition: attachment; filename=\"$project-tree-$tree.tar.gz\";");
206 $data = join("\n", run_git($project, "git archive --format=tar $tree |gzip"));
207 header("Content-Length: ". strlen($data));
208 echo $data;
210 run_git_passthru($project, "git archive --format=tar $tree |gzip");
212 elseif ($type === 'zip') {
213 header("Content-Type: application/x-zip");
214 header("Content-Transfer-Encoding: binary");
215 header("Content-Disposition: attachment; filename=\"$project-tree-$tree.zip\";");
217 $data = join("\n", run_git($project, "git archive --format=zip $tree"));
218 header("Content-Length: ". strlen($data));
219 echo $data;
221 run_git_passthru($project, "git archive --format=zip $tree");
223 else {
224 die('Invalid archive type requested');
227 die();
229 elseif ($action === 'blob') {
230 $page['project'] = validate_project($_REQUEST['p']);
231 $page['hash'] = validate_hash($_REQUEST['h']);
233 header('Content-type: text/plain');
235 run_git_passthru($page['project'], "git cat-file blob $page[hash]");
236 die();
238 elseif ($action === 'commit') {
239 $template = 'commit';
240 $page['project'] = validate_project($_REQUEST['p']);
241 $page['commit_id'] = validate_hash($_REQUEST['h']);
243 $info = git_get_commit_info($page['project'], $page['commit_id']);
245 $page['author_name'] = $info['author_name'];
246 $page['author_mail'] = $info['author_mail'];
247 $page['author_datetime'] = strftime($conf['datetime'], $info['author_utcstamp']);
248 $page['committer_name'] = $info['committer_name'];
249 $page['committer_mail'] = $info['committer_mail'];
250 $page['committer_datetime'] = strftime($conf['datetime'], $info['committer_utcstamp']);
251 $page['tree'] = $info['tree'];
252 $page['parent'] = $info['parent'];
253 $page['message'] = $info['message'];
254 $page['message_full'] = $info['message_full'];
257 elseif ($action === 'summary') {
258 $template = 'summary';
259 $page['project'] = validate_project($_REQUEST['p']);
260 $page['title'] = "$page[project] - Summary - ViewGit";
262 $revs = git_get_rev_list($page['project'], $conf['summary_shortlog']);
263 foreach ($revs as $rev) {
264 $info = git_get_commit_info($page['project'], $rev);
265 $page['shortlog'][] = array(
266 'author' => $info['author_name'],
267 'date' => strftime($conf['datetime'], $info['author_utcstamp']),
268 'message' => $info['message'],
269 'commit_id' => $rev,
270 'tree' => $info['tree'],
274 $tags = git_get_tags($page['project']);
275 $page['tags'] = array();
276 foreach ($tags as $tag) {
277 $info = git_get_commit_info($page['project'], $tag['h']);
278 $page['tags'][] = array(
279 'date' => strftime($conf['datetime'], $info['author_utcstamp']),
280 'h' => $tag['h'],
281 'fullname' => $tag['fullname'],
282 'name' => $tag['name'],
286 $heads = git_get_heads($page['project']);
287 $page['heads'] = array();
288 foreach ($heads as $h) {
289 $info = git_get_commit_info($page['project'], $h['h']);
290 $page['heads'][] = array(
291 'date' => strftime($conf['datetime'], $info['author_utcstamp']),
292 'h' => $h['h'],
293 'fullname' => $h['fullname'],
294 'name' => $h['name'],
298 elseif ($action === 'tree') {
299 $template = 'tree';
300 $page['project'] = validate_project($_REQUEST['p']);
301 $page['tree'] = validate_hash($_REQUEST['h']);
302 $page['title'] = "$page[project] - Tree - ViewGit";
304 $page['entries'] = git_ls_tree($page['project'], $page['tree']);
306 else {
307 die('Invalid action');
310 require 'templates/header.php';
311 require "templates/$template.php";
312 require 'templates/footer.php';