$path);
}
}
}
}
$action = 'index';
$template = 'index';
$page['title'] = 'MLD Git';
if (isset($_REQUEST['a'])) {
$action = strtolower($_REQUEST['a']);
}
$page['action'] = $action;
/*
* index - list of projects
*/
if ($action === 'index') {
$template = 'index';
$page['title'] .= ' - List of projects';
foreach (array_keys($conf['projects']) as $p) {
$page['projects'][] = get_project_info($p);
}
}
/*
* archive - send a tree as an archive to client
* @param p project
* @param h tree hash
* @param hb OPTIONAL base commit (trees can be part of multiple commits, this
* one denotes which commit the user navigated from)
* @param t type, "targz" or "zip"
* @param n OPTIONAL name suggestion
*/
elseif ($action === 'archive') {
$project = validate_project($_REQUEST['p']);
$info = get_project_info($project);
$tree = validate_hash($_REQUEST['h']);
$type = $_REQUEST['t'];
if (isset($_REQUEST['hb'])) {
$hb = validate_hash($_REQUEST['hb']);
$describe = git_describe($project, $hb);
}
// Archive prefix
$archive_prefix = '';
if (isset($info['archive_prefix'])) {
$archive_prefix = "{$info['archive_prefix']}";
}
elseif (isset($conf['archive_prefix'])) {
$archive_prefix = "{$conf['archive_prefix']}";
}
$archive_prefix = str_replace(array('{PROJECT}', '{DESCRIBE}'), array($project, $describe), $archive_prefix);
// Basename
$basename = "$project-tree-". substr($tree, 0, 7);
$basename = $archive_prefix;
if (isset($_REQUEST['n'])) {
$basename = "$basename-$_REQUEST[n]-". substr($tree, 0, 6);
}
$prefix_option = '';
if (isset($archive_prefix)) {
$prefix_option = "--prefix={$archive_prefix}/";
}
if ($type === 'targz') {
header("Content-Type: application/x-tar-gz");
header("Content-Transfer-Encoding: binary");
header("Content-Disposition: attachment; filename=\"$basename.tar.gz\";");
run_git_passthru($project, "archive --format=tar $prefix_option $tree |gzip");
}
elseif ($type === 'zip') {
header("Content-Type: application/x-zip");
header("Content-Transfer-Encoding: binary");
header("Content-Disposition: attachment; filename=\"$basename.zip\";");
run_git_passthru($project, "archive --format=zip $prefix_option $tree");
}
else {
die('Invalid archive type requested');
}
die();
}
/*
* blob - send a blob to browser with filename suggestion
* @param p project
* @param h blob hash
* @param n filename
*/
elseif ($action === 'blob') {
$project = validate_project($_REQUEST['p']);
$hash = validate_hash($_REQUEST['h']);
$name = $_REQUEST['n'];
header('Content-type: application/octet-stream');
header("Content-Disposition: attachment; filename=$name"); // FIXME needs quotation
run_git_passthru($project, "cat-file blob $hash");
die();
}
/*
* co - git checkout. These requests come from mod_rewrite, see the .htaccess file.
* @param p project
* @param r path
*/
elseif ($action === 'co') {
if (!$conf['allow_checkout']) { die('Checkout not allowed'); }
// For debugging
debug("Project: $_REQUEST[p] Request: $_REQUEST[r]");
// eg. info/refs, HEAD
$p = validate_project($_REQUEST['p']); // project
$r = $_REQUEST['r']; // path
$gitdir = $conf['projects'][$p]['repo'];
$filename = $gitdir .'/'. $r;
// make sure the request is legit (no reading of other files besides those under git projects)
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 || preg_match('!^objects/pack/pack-[0-9a-f]{40}\.(idx|pack)$!', $r)) {
if (file_exists($filename)) {
debug('OK, sending');
readfile($filename);
} else {
debug('Not found');
header('HTTP/1.0 404 Not Found');
}
} else {
debug("Denied");
}
die();
}
/*
* commit - view commit information
* @param p project
* @param h commit hash
*/
elseif ($action === 'commit') {
$template = 'commit';
$page['project'] = validate_project($_REQUEST['p']);
$page['title'] .= " - $page[project] - Commit";
$page['commit_id'] = validate_hash($_REQUEST['h']);
$page['subtitle'] = "Commit ". substr($page['commit_id'], 0, 6);
$info = git_get_commit_info($page['project'], $page['commit_id']);
$page['author_name'] = $info['author_name'];
$page['author_mail'] = $info['author_mail'];
$page['author_datetime'] = $info['author_datetime'];
$page['author_datetime_local'] = $info['author_datetime_local'];
$page['committer_name'] = $info['committer_name'];
$page['committer_mail'] = $info['committer_mail'];
$page['committer_datetime'] = $info['committer_datetime'];
$page['committer_datetime_local'] = $info['committer_datetime_local'];
$page['tree_id'] = $info['tree'];
$page['parents'] = $info['parents'];
$page['message'] = $info['message'];
$page['message_firstline'] = $info['message_firstline'];
$page['message_full'] = $info['message_full'];
$page['affected_files'] = git_get_changed_paths($page['project'], $page['commit_id']);
}
/*
* commitdiff - view diff of a commit
* @param p project
* @param h commit hash
*/
elseif ($action === 'commitdiff') {
$template = 'commitdiff';
$page['project'] = validate_project($_REQUEST['p']);
$page['title'] .= " - $page[project] - Commitdiff";
$hash = validate_hash($_REQUEST['h']);
$page['commit_id'] = $hash;
$page['subtitle'] = "Commitdiff ". substr($page['commit_id'], 0, 6);
$info = git_get_commit_info($page['project'], $hash);
$page['tree_id'] = $info['tree'];
$page['message'] = $info['message'];
$page['message_firstline'] = $info['message_firstline'];
$page['message_full'] = $info['message_full'];
$page['author_name'] = $info['author_name'];
$page['author_mail'] = $info['author_mail'];
$page['author_datetime'] = $info['author_datetime'];
$text = fix_encoding(git_diff($page['project'], "$hash^", $hash));
list($page['files'], $page['diffdata']) = format_diff($text);
//$page['diffdata'] = format_diff($text);
}
elseif ($action === 'patch') {
$project = validate_project($_REQUEST['p']);
$hash = validate_hash($_REQUEST['h']);
$filename = "$project-". substr($hash, 0, 7) .".patch";
//header("Content-Type: text/x-diff");
header("Content-Type: application/octet-stream");
header("Content-Transfer-Encoding: binary");
// TODO git-style filename
header("Content-Disposition: attachment; filename=\"$filename\";");
run_git_passthru($project, "format-patch --stdout $hash^..$hash");
die();
}
/*
* rss-log - RSS feed of project changes
* @param p project
* @param h OPTIONAL commit id to start showing log from
*/
elseif ($action === 'rss-log') {
$page['project'] = validate_project($_REQUEST['p']);
$ext_url = 'http://'. $_SERVER['HTTP_HOST'] . dirname($_SERVER['SCRIPT_NAME']) .'/';
$page['rss_title'] = "Log for $page[project]";
$page['rss_link'] = $ext_url . makelink(array('a' => 'summary', 'p' => $page['project']));
$page['rss_description'] = "Git log for project $page[project], generated by ViewGit.";
$page['rss_pubDate'] = rss_pubdate(time());
$page['rss_ttl'] = $conf['rss_ttl'];
$page['rss_items'] = array();
$diffstat = strstr($conf['rss_item_description'], '{DIFFSTAT}');
if (isset($_REQUEST['h'])) {
$page['ref'] = validate_hash($_REQUEST['h']);
} else {
$page['ref'] = 'HEAD';
}
$revs = git_get_rev_list($page['project'], 0, $conf['rss_max_items'], $page['ref']);
foreach ($revs as $rev) {
$info = git_get_commit_info($page['project'], $rev);
$link = $ext_url . makelink(array('a' => 'commit', 'p' => $page['project'], 'h' => $rev));
if ($diffstat) {
$info['diffstat'] = git_diffstat($page['project'], $rev);
}
$page['rss_items'][] = array(
'title' => rss_item_format($conf['rss_item_title'], $info),
'guid' => $link,
'link' => $link,
'description' => rss_item_format($conf['rss_item_description'], $info),
'pubdate' => rss_pubdate($info['author_utcstamp']),
);
}
require('templates/rss.php');
die();
}
/*
* search - search project history
* @param p project
* @param h branch
* @param st search type: commit,grep,author,committer,pickaxe
* @param s string to search for
*/
elseif ($action === 'search') {
$template = 'shortlog';
$page['project'] = validate_project($_REQUEST['p']);
$info = git_get_commit_info($page['project']);
$page['commit_id'] = $info['h'];
$page['tree_id'] = $info['tree'];
$branch = validate_hash($_REQUEST['h']);
$type = $_REQUEST['st'];
$string = $_REQUEST['s'];
$page['search_t'] = $type;
$page['search_s'] = $string;
$commits = git_search_commits($page['project'], $branch, $type, $string);
$shortlog = array();
foreach ($commits as $c) {
$info = git_get_commit_info($page['project'], $c);
$shortlog[] = array(
'author' => $info['author_name'],
'date' => strftime($conf['datetime'], $info['author_utcstamp']),
'message' => $info['message'],
'commit_id' => $info['h'],
'tree' => $info['tree'],
'refs' => array(),
);
}
$page['shortlog_no_more'] = true;
$page['shortlog'] = $shortlog;
}
/*
* shortlog - project shortlog entries
* @param p project
* @param h OPTIONAL commit id to start showing log from
*/
elseif ($action === 'shortlog') {
$template = 'shortlog';
$page['project'] = validate_project($_REQUEST['p']);
$page['title'] .= " - $page[project] - Shortlog";
$page['subtitle'] = "Shortlog";
if (isset($_REQUEST['h'])) {
$page['ref'] = validate_hash($_REQUEST['h']);
} else {
$page['ref'] = 'HEAD';
}
if (isset($_REQUEST['pg'])) {
$page['pg'] = intval($_REQUEST['pg']);
} else {
$page['pg'] = 0;
}
$info = git_get_commit_info($page['project'], $page['ref']);
$page['commit_id'] = $info['h'];
$page['tree_id'] = $info['tree'];
$page['shortlog'] = handle_shortlog($page['project'], $page['ref'], $page['pg']);
}
elseif ($action === 'summary') {
$template = 'summary';
$page['project'] = validate_project($_REQUEST['p']);
$page['title'] .= " - $page[project] - Summary";
$page['subtitle'] = "Summary";
$info = git_get_commit_info($page['project']);
$page['commit_id'] = $info['h'];
$page['tree_id'] = $info['tree'];
$page['shortlog'] = handle_shortlog($page['project']);
$page['tags'] = handle_tags($page['project'], $conf['summary_tags']);
$page['ref'] = 'HEAD';
$heads = git_get_heads($page['project']);
$page['heads'] = array();
foreach ($heads as $h) {
$info = git_get_commit_info($page['project'], $h['h']);
$page['heads'][] = array(
'date' => strftime($conf['datetime'], $info['author_utcstamp']),
'h' => $h['h'],
'fullname' => $h['fullname'],
'name' => $h['name'],
);
}
}
elseif ($action === 'tags') {
$template = 'tags';
$page['project'] = validate_project($_REQUEST['p']);
$page['title'] .= " - $page[project] - Tags";
$info = git_get_commit_info($page['project']);
$page['commit_id'] = $info['h'];
$page['tree_id'] = $info['tree'];
$page['tags'] = handle_tags($page['project']);
}
/*
* Shows a tree, with list of directories/files, links to them and download
* links to archives.
*
* @param p project
* @param h tree hash
* @param hb OPTIONAL base commit (trees can be part of multiple commits, this
* one denotes which commit the user navigated from)
* @param f OPTIONAL path the user has followed to view this tree
*/
elseif ($action === 'tree') {
$template = 'tree';
$page['project'] = validate_project($_REQUEST['p']);
if (isset($_REQUEST['h'])) {
$page['tree_id'] = validate_hash($_REQUEST['h']);
}
/*
else {
// TODO walk the tree
$page['tree_id'] = 'HEAD';
}
*/
$page['title'] .= " - $page[project] - Tree";
// 'hb' optionally contains the commit_id this tree is related to
if (isset($_REQUEST['hb'])) {
$page['commit_id'] = validate_hash($_REQUEST['hb']);
}
else {
// for the header
$info = git_get_commit_info($page['project']);
$page['commit_id'] = $info['h'];
}
$page['path'] = '';
if (isset($_REQUEST['f'])) {
$page['path'] = $_REQUEST['f']; // TODO validate?
}
// get path info for the header
$page['pathinfo'] = git_get_path_info($page['project'], $page['commit_id'], $page['path']);
if (!isset($page['tree_id'])) {
// Take the last hash from the tree
if (count($page['pathinfo']) > 0) {
$page['tree_id'] = $page['pathinfo'][count($page['pathinfo']) - 1]['hash'];
} else {
$page['tree_id'] = 'HEAD';
}
}
$page['subtitle'] = "Tree ". substr($page['tree_id'], 0, 6);
$page['entries'] = git_ls_tree($page['project'], $page['tree_id']);
}
/*
* View a blob as inline, embedded on the page.
* @param p project
* @param h blob hash
* @param hb OPTIONAL base commit
*/
elseif ($action === 'viewblob') {
$template = 'blob';
$page['project'] = validate_project($_REQUEST['p']);
$page['hash'] = validate_hash($_REQUEST['h']);
$page['title'] .= " - $page[project] - Blob";
if (isset($_REQUEST['hb'])) {
$page['commit_id'] = validate_hash($_REQUEST['hb']);
}
else {
$page['commit_id'] = 'HEAD';
}
$page['subtitle'] = "Blob ". substr($page['hash'], 0, 6);
$page['path'] = '';
if (isset($_REQUEST['f'])) {
$page['path'] = $_REQUEST['f']; // TODO validate?
}
// For the header's pagenav
$info = git_get_commit_info($page['project'], $page['commit_id']);
$page['commit_id'] = $info['h'];
$page['tree_id'] = $info['tree'];
$page['pathinfo'] = git_get_path_info($page['project'], $page['commit_id'], $page['path']);
$page['data'] = fix_encoding(join("\n", run_git($page['project'], "cat-file blob $page[hash]")));
$page['lastlog'] = git_get_commit_info($page['project'], 'HEAD', $page['path']);
// GeSHi support
if ($conf['geshi'] && strpos($page['path'], '.')) {
$old_mask = error_reporting(E_ALL ^ E_NOTICE);
require_once($conf['geshi_path']);
$parts = explode('.', $page['path']);
$ext = array_pop($parts);
$geshi = new Geshi($page['data']);
$lang = $geshi->get_language_name_from_extension($ext);
if (strlen($lang) > 0) {
$geshi->set_language($lang);
if (is_int($conf['geshi_line_numbers'])) {
if ($conf['geshi_line_numbers'] == 0) {
$geshi->enable_line_numbers(GESHI_NORMAL_LINE_NUMBERS);
}
else {
$geshi->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS, $conf['geshi_line_numbers']);
}
}
$page['html_data'] = $geshi->parse_code();
}
error_reporting($old_mask);
}
}
elseif (in_array($action, array_keys(VGPlugin::$plugin_actions))) {
VGPlugin::$plugin_actions[$action]->action($action);
die();
}
else {
die('Invalid action');
}
require 'templates/header.php';
require "templates/$template.php";
require 'templates/footer.php';