3 * The main "controller" file of ViewGit.
5 * All requests come to this file. You can think of it as the controller in the
6 * Model-View-Controller pattern. It reads config, processes user input,
7 * fetches required data using git commandline, and finally passes the data to
8 * templates to be shown to the user.
10 error_reporting(E_ALL
);
12 require_once('inc/config.php');
13 require_once('inc/functions.php');
15 if (isset($conf['projects_glob'])) {
16 foreach ($conf['projects_glob'] as $glob) {
17 foreach (glob($glob) as $path) {
18 // Get the last part of the path before .git
19 $name = preg_replace(array('#/?\.git$#', '#^.*/#'), array('', ''), $path);
21 // Workaround against name collisions; proj, proj1, proj2, ...
23 while (in_array($name . $i, array_keys($conf['projects']))) {
27 $conf['projects'][$name] = array('repo' => $path);
34 $page['title'] = 'ViewGit';
36 if (isset($_REQUEST['a'])) {
37 $action = strtolower($_REQUEST['a']);
39 $page['action'] = $action;
41 if ($action === 'index') {
43 $page['title'] = 'List of projects - ViewGit';
45 foreach (array_keys($conf['projects']) as $p) {
46 $page['projects'][] = get_project_info($p);
49 elseif ($action === 'archive') {
50 $project = validate_project($_REQUEST['p']);
51 $tree = validate_hash($_REQUEST['h']);
52 $type = $_REQUEST['t'];
54 $basename = "$project-tree-". substr($tree, 0, 7);
55 if (isset($_REQUEST['n'])) {
56 $basename = "$project-$_REQUEST[n]-". substr($tree, 0, 6);
59 if ($type === 'targz') {
60 header("Content-Type: application/x-tar-gz");
61 header("Content-Transfer-Encoding: binary");
62 header("Content-Disposition: attachment; filename=\"$basename.tar.gz\";");
63 run_git_passthru($project, "git archive --format=tar $tree |gzip");
65 elseif ($type === 'zip') {
66 header("Content-Type: application/x-zip");
67 header("Content-Transfer-Encoding: binary");
68 header("Content-Disposition: attachment; filename=\"$basename.zip\";");
69 run_git_passthru($project, "git archive --format=zip $tree");
72 die('Invalid archive type requested');
77 // blob: send a blob to browser with filename suggestion
78 elseif ($action === 'blob') {
79 $project = validate_project($_REQUEST['p']);
80 $hash = validate_hash($_REQUEST['h']);
81 $name = $_REQUEST['n'];
83 header('Content-type: application/octet-stream');
84 header("Content-Disposition: attachment; filename=$name"); // FIXME needs quotation
86 run_git_passthru($project, "git cat-file blob $hash");
92 elseif ($action === 'co') {
93 if (!$conf['allow_checkout']) { die('Checkout not allowed'); }
96 debug("Project: $_REQUEST[p] Request: $_REQUEST[r]");
98 // eg. info/refs, HEAD
99 $p = validate_project($_REQUEST['p']); // project
100 $r = $_REQUEST['r']; // path
102 $gitdir = $conf['projects'][$p]['repo'];
103 $filename = $gitdir .'/'. $r;
105 // make sure the request is legit (no reading of other files besides those under git projects)
106 if ($r === 'HEAD' ||
$r === 'info/refs' ||
preg_match('!^objects/info/(packs|http-alternates|alternates)$!', $r) > 0 ||
preg_match('!^objects/[0-9a-f]{2}/[0-9a-f]{38}$!', $r) > 0) {
107 if (file_exists($filename)) {
108 debug('OK, sending');
120 elseif ($action === 'commit') {
121 $template = 'commit';
122 $page['project'] = validate_project($_REQUEST['p']);
123 $page['title'] = "$page[project] - Commit - ViewGit";
124 $page['commit_id'] = validate_hash($_REQUEST['h']);
126 $info = git_get_commit_info($page['project'], $page['commit_id']);
128 $page['author_name'] = $info['author_name'];
129 $page['author_mail'] = $info['author_mail'];
130 $page['author_datetime'] = strftime($conf['datetime'], $info['author_utcstamp']);
131 $page['author_datetime_local'] = strftime($conf['datetime'], $info['author_stamp']) .' '. $info['author_timezone'];
132 $page['committer_name'] = $info['committer_name'];
133 $page['committer_mail'] = $info['committer_mail'];
134 $page['committer_datetime'] = strftime($conf['datetime'], $info['committer_utcstamp']);
135 $page['committer_datetime_local'] = strftime($conf['datetime'], $info['committer_stamp']) .' '. $info['committer_timezone'];
136 $page['tree_id'] = $info['tree'];
137 $page['parents'] = $info['parents'];
138 $page['message'] = $info['message'];
139 $page['message_firstline'] = $info['message_firstline'];
140 $page['message_full'] = $info['message_full'];
143 elseif ($action === 'commitdiff') {
144 $template = 'commitdiff';
145 $page['project'] = validate_project($_REQUEST['p']);
146 $page['title'] = "$page[project] - Commitdiff - ViewGit";
147 $hash = validate_hash($_REQUEST['h']);
148 $page['commit_id'] = $hash;
150 $info = git_get_commit_info($page['project'], $hash);
152 $page['tree_id'] = $info['tree'];
154 $page['message'] = $info['message'];
155 $page['message_firstline'] = $info['message_firstline'];
156 $page['message_full'] = $info['message_full'];
157 $page['author_name'] = $info['author_name'];
158 $page['author_mail'] = $info['author_mail'];
159 $page['author_datetime'] = strftime($conf['datetime'], $info['author_utcstamp']);
161 $text = join("\n", run_git($page['project'], "git diff $hash^..$hash"));
162 list($page['files'], $page['diffdata']) = format_diff($text);
163 //$page['diffdata'] = format_diff($text);
165 elseif ($action === 'rss-log') {
166 $page['project'] = validate_project($_REQUEST['p']);
168 $ext_url = 'http://'. $_SERVER['HTTP_HOST'] . dirname($_SERVER['SCRIPT_NAME']) .'/';
170 $page['rss_title'] = "Log for $page[project]";
171 $page['rss_link'] = $ext_url . makelink(array('a' => 'summary', 'p' => $page['project']));
172 $page['rss_description'] = "Git log for project $page[project], generated by ViewGit.";
173 $page['rss_pubDate'] = rss_pubdate(time());
174 $page['rss_ttl'] = $conf['rss_ttl'];
176 $page['rss_items'] = array();
178 $revs = git_get_rev_list($page['project'], $conf['rss_max_items']);
179 foreach ($revs as $rev) {
180 $info = git_get_commit_info($page['project'], $rev);
181 $link = $ext_url . makelink(array('a' => 'commit', 'p' => $page['project'], 'h' => $rev));
183 $page['rss_items'][] = array(
184 'title' => rss_item_format($conf['rss_item_title'], $info),
187 'description' => rss_item_format($conf['rss_item_description'], $info),
188 'pubdate' => rss_pubdate($info['author_stamp']),
192 require('templates/rss.php');
195 elseif ($action === 'shortlog') {
196 $template = 'shortlog';
197 $page['project'] = validate_project($_REQUEST['p']);
198 $page['title'] = "$page[project] - Shortlog - ViewGit";
199 if (isset($_REQUEST['h'])) {
200 $page['ref'] = validate_hash($_REQUEST['h']);
202 $page['ref'] = 'HEAD';
205 $info = git_get_commit_info($page['project'], $page['ref']);
206 $page['commit_id'] = $info['h'];
207 $page['tree_id'] = $info['tree'];
209 // TODO merge the logic with 'summary' below
210 $revs = git_get_rev_list($page['project'], $conf['summary_shortlog'], $page['ref']); // TODO pass first rev as parameter
211 foreach ($revs as $rev) {
212 $info = git_get_commit_info($page['project'], $rev);
213 $page['shortlog'][] = array(
214 'author' => $info['author_name'],
215 'date' => strftime($conf['datetime'], $info['author_utcstamp']),
216 'message' => $info['message'],
218 'tree' => $info['tree'],
222 elseif ($action === 'summary') {
223 $template = 'summary';
224 $page['project'] = validate_project($_REQUEST['p']);
225 $page['title'] = "$page[project] - Summary - ViewGit";
227 $info = git_get_commit_info($page['project']);
228 $page['commit_id'] = $info['h'];
229 $page['tree_id'] = $info['tree'];
231 $revs = git_get_rev_list($page['project'], $conf['summary_shortlog']);
232 foreach ($revs as $rev) {
233 $info = git_get_commit_info($page['project'], $rev);
234 $page['shortlog'][] = array(
235 'author' => $info['author_name'],
236 'date' => strftime($conf['datetime'], $info['author_utcstamp']),
237 'message' => $info['message'],
239 'tree' => $info['tree'],
243 $tags = git_get_tags($page['project']);
244 $page['tags'] = array();
245 foreach ($tags as $tag) {
246 $info = git_get_commit_info($page['project'], $tag['h']);
247 $page['tags'][] = array(
248 'stamp' => $info['author_utcstamp'],
249 'date' => strftime($conf['datetime'], $info['author_utcstamp']),
251 'fullname' => $tag['fullname'],
252 'name' => $tag['name'],
255 // sort tags newest first
256 // aka. two more reasons to hate PHP (figuring those out is your homework:)
257 $arr = $page['tags'];
258 usort($arr, create_function(
260 '$a = $x["stamp"]; $b = $y["stamp"]; return ($a == $b ? 0 : ($a > $b ? -1 : 1));'
262 // it's actually three, I lied.
263 $page['tags'] = $arr;
265 $heads = git_get_heads($page['project']);
266 $page['heads'] = array();
267 foreach ($heads as $h) {
268 $info = git_get_commit_info($page['project'], $h['h']);
269 $page['heads'][] = array(
270 'date' => strftime($conf['datetime'], $info['author_utcstamp']),
272 'fullname' => $h['fullname'],
273 'name' => $h['name'],
278 * Shows a tree, with list of directories/files, links to them and download
283 * @param hb OPTIONAL base commit (trees can be part of multiple commits, this
284 * one denotes which commit the user navigated from)
285 * @param f OPTIONAL path the user has followed to view this tree
287 elseif ($action === 'tree') {
289 $page['project'] = validate_project($_REQUEST['p']);
290 $page['tree_id'] = validate_hash($_REQUEST['h']);
291 $page['title'] = "$page[project] - Tree - ViewGit";
293 // 'hb' optionally contains the commit_id this tree is related to
294 if (isset($_REQUEST['hb'])) {
295 $page['commit_id'] = validate_hash($_REQUEST['hb']);
299 $info = git_get_commit_info($page['project']);
300 $page['commit_id'] = $info['h'];
304 if (isset($_REQUEST['f'])) {
305 $page['path'] = $_REQUEST['f']; // TODO validate?
308 // get path info for the header
309 $page['pathinfo'] = git_get_path_info($page['project'], $page['commit_id'], explode('/', $page['path']));
311 $page['entries'] = git_ls_tree($page['project'], $page['tree_id']);
314 * View a blob as inline, embedded on the page.
317 * @param hb OPTIONAL base commit
319 elseif ($action === 'viewblob') {
321 $page['project'] = validate_project($_REQUEST['p']);
322 $page['hash'] = validate_hash($_REQUEST['h']);
323 $page['title'] = "$page[project] - Blob - ViewGit";
324 if (isset($_REQUEST['hb'])) {
325 $page['commit_id'] = validate_hash($_REQUEST['hb']);
328 $page['commit_id'] = 'HEAD';
332 if (isset($_REQUEST['f'])) {
333 $page['path'] = $_REQUEST['f']; // TODO validate?
336 // For the header's pagenav
337 $info = git_get_commit_info($page['project'], $page['commit_id']);
338 $page['commit_id'] = $info['h'];
339 $page['tree_id'] = $info['tree'];
341 $page['pathinfo'] = git_get_path_info($page['project'], $page['commit_id'], explode('/', $page['path']));
343 $page['data'] = join("\n", run_git($page['project'], "git cat-file blob $page[hash]"));
346 die('Invalid action');
349 require 'templates/header.php';
350 require "templates/$template.php";
351 require 'templates/footer.php';