. */ class difftree { private $difftree_data = null; public function push_difftree_data($data) { $this->difftree_data = $data; } public function generate_difftree($project, $commit, $patch_link) { $difftree = new ContentProvider('commit', 'difftree'); if($this->difftree_data) $tree = $this->difftree_data; else $tree = GitCommand::get_commit_changes($project['path'], $commit['id'], $commit['parent']); $entry_count = 0; if(count($commit['parent']) > 1) $difftree->set('class', ' combined'); else $difftree->set('class', ''); $difftree->set('tree_count', ''); foreach($tree as $entry) { $entry_count++; $difftree->append('tree', $this->tree_entry($entry_count, (($entry_count % 2) ? 'dark' : 'light'), $commit, $entry, $patch_link)); } if($entry_count == 0) $difftree->set('tree', ''); else if($entry_count > 10) $difftree->set('tree_count', new ContentProvider('commit', 'tree_count', array('count' => $entry_count))); return $difftree; } private function tree_entry($diffid, $class, $commit, $entry, $patch_link) { $tree = new ContentProvider('commit', 'tree'); $tree->set('class', $class); $tree->set('hash', $commit['id']); $tree->set('file', $entry['file']); if(count($commit['parent']) > 1) { if(preg_match('/^[0]{40}$/', $entry['to_id'])) //file doesn't exist in the result (child) commit $tree->set('file', $entry['file']); else $tree->set('file', new ContentProvider('commit', 'tree_file_link', array('file' => $entry['file']))); $tree->set('specials', ''); if($patch_link) $tree->append('merge', new ContentProvider('commit', 'tree_merge_patch_link', array("patch_marker" => "patch".$diffid))); $has_history = false; $not_deleted = false; for($i = 0; $i < count($commit['parent']); $i++) { $status = $entry['status'][$i]; $merge = null; $has_history = ($has_history || ($status != 'A')); $not_deleted = ($not_deleted || ($status != 'D')); switch($status) { case 'A': //Added $merge = new ContentProvider('commit', 'tree_merge_new'); break; case 'D': //Deleted $merge = new ContentProvider('commit', 'tree_merge'); $merge->set('class', ''); $blob_link = new ContentProvider('commit', 'tree_merge_blob', array('hash' => $commit['parent'][$i], 'file' => $entry['file'])); $merge->set('links', array($blob_link, ' | ')); break; default: $merge = new ContentProvider('commit', 'tree_merge'); if($entry['from_id'][$i] == $entry['to_id']) { $merge->set('class', ' nochange'); $merge->set('links', ' | '); } else { $merge->set('class', ''); $merge->set('links', new ContentProvider('commit', 'tree_merge_diff', array('hash' => $commit['id'], 'parent' => $commit['parent'][$i], 'file' => $entry['file'], 'id' => ($i + 1)))); } } $tree->append('merge', $merge); } $tree->set('links', ''); if($not_deleted) { $tree->append('links', new ContentProvider('commit', 'tree_merge_blob', array('hash' => $commit['id'], 'file' => $entry['file']))); if($has_history) $tree->append('links', ' | '); } if($has_history) $tree->append('links', new ContentProvider('commit', 'tree_merge_history', array('hash' => $commit['id'], 'file' => $entry['file']))); } else { $tree->set('file', new ContentProvider('commit', 'tree_file_link', array('file' => $entry['file']))); $tree->set('merge', ''); $from_type = Tools::get_filetype($entry['from_mode']); $to_type = Tools::get_filetype($entry['to_mode']); $from_mode = (Tools::is_regular_file($entry['from_mode']) ? Tools::get_file_permissions($entry['from_mode']) : null); $to_mode = (Tools::is_regular_file($entry['to_mode']) ? Tools::get_file_permissions($entry['to_mode']) : null); $link_placeholders = array( "hash" => $commit['id'], "file" => $entry['file'], "parent" => (count($commit['parent']) ? $commit['parent'][0] : ""), ); if($patch_link) $tree->append('links', new ContentProvider('commit', 'tree_patch_link', array("patch_marker" => "patch".$diffid))); switch($entry['status']) { case 'A': //Added $tree->set('specials', new ContentProvider('commit', (Tools::is_regular_file($entry['to_mode']) ? 'tree_new_file' : 'tree_new'), array('type' => $to_type, 'mode' => $to_mode))); $tree->append('links', new ContentProvider('commit', 'tree_new_links', $link_placeholders)); break; case 'D': //Deleted $tree->set('specials', new ContentProvider('commit', 'tree_deleted', array('type' => $from_type))); $tree->append('links', new ContentProvider('commit', 'tree_deleted_links', $link_placeholders)); break; case 'M': //Modified case 'T': //Type changed if($entry['from_mode'] != $entry['to_mode']) { $modified = new ContentProvider('commit', 'tree_changed'); $tree->set('specials', $modified); if($from_type != $to_type) $modified->append('changes', new ContentProvider('commit', 'tree_changed_type', array('from' => $from_type, 'to' => $to_type))); if($from_mode != $to_mode && $to_mode) { if($from_mode) $modified->append('changes', new ContentProvider('commit', 'tree_changed_mode', array('from' => $from_mode, 'to' => $to_mode))); else $modified->append('changes', new ContentProvider('commit', 'tree_changed_mode_to', array('to' => $to_mode))); } } else $tree->set('specials', ''); if(!$patch_link && $entry['from_id'] != $entry['to_id']) $tree->append('links', new ContentProvider('commit', 'tree_changed_links_diff', $link_placeholders)); $tree->append('links', new ContentProvider('commit', 'tree_changed_links', $link_placeholders)); break; case 'R': //Renamed case 'C': //Copied $actions = array('R' => 'tree_moved', 'C' => 'tree_copied'); $move = new ContentProvider('commit', $actions[$entry['status']]); $tree->set('specials', $move); $tree->set('file', $entry['to_file']); $move->set('file', $entry['from_file']); $move->set('hash', $commit['parent'][0]); $move->set('similarity', $entry['similarity']); if($from_mode != $to_mode) $move->set('mode', new ContentProvider('commit', 'tree_moved_mode', array('mode' => $to_mode))); else $move->set('mode', ''); if($entry['from_id'] != $entry['to_id']) $tree->append('links', new ContentProvider('commit', 'tree_moved_links_diff', $link_placeholders)); $tree->append('links', new ContentProvider('commit', 'tree_moved_links', $link_placeholders)); break; default: } } return $tree; } } class page_commit { private $page, $phpgitweb; private $commitid; public function main($phpgitweb, $project) { $this->phpgitweb = $phpgitweb; if(!$project) return new ContentProvider('main', 'err400'); $project['refs'] = $phpgitweb->get_project_loader()->getProjectRefs($project); $phpgitweb->append_header_nav("commit", null, true); $phpgitweb->append_title("commit"); $commit_loader = new CommitLoader($project); if(array_key_exists('h', $_GET)) $commitid = $_GET['h']; else $commitid = "HEAD"; $commit = $commit_loader->load($commitid); if(!$commit) return new ContentProvider('main', 'err404_object'); ContentProvider::overall_set('project_head', $commit['id']); $this->page = new ContentProvider('commit', 'main'); $this->page->set('hash', $commit['id']); $this->page->set('author', htmlentities($commit['author'])); $this->page->set('author_mail', htmlentities($commit['author_mail'])); $this->page->set('author_date', gmdate('r', $commit['author_time'])); $author_local_time = $commit['author_time'] + Tools::parseTimeZone($commit['author_timezone']); if(gmdate('H', $author_local_time) < 6) $this->page->set('author_local_date', ''.gmdate('H:i', $author_local_time).''); else $this->page->set('author_local_date', gmdate('H:i', $author_local_time)); $this->page->set('author_timezone', $commit['author_timezone']); $this->page->set('committer', htmlentities($commit['committer'])); $this->page->set('committer_mail', htmlentities($commit['committer_mail'])); $this->page->set('committer_date', gmdate('r', $commit['committer_time'])); $committer_local_time = $commit['committer_time'] + Tools::parseTimeZone($commit['committer_timezone']); if(gmdate('H', $committer_local_time) < 6) $this->page->set('committer_local_date', ''.gmdate('H:i', $committer_local_time).''); else $this->page->set('committer_local_date', gmdate('H:i', $committer_local_time)); $this->page->set('committer_timezone', $commit['committer_timezone']); $this->page->set('message', htmlentities(Tools::chop_text($commit['text'], 80, 5))); $this->page->set('full_message', htmlentities($commit['text'])); $this->page->set('tree_hash', $commit['tree']); foreach($commit['parent'] as $parent) { $this->page->append('parents', new ContentProvider('commit', 'parent', array('hash' => $parent, 'head' => $commit['id']))); } if(count($commit['parent']) == 0) $this->page->set('parents', ''); $refs = new ContentProvider('commit', 'commit_refs'); $found = false; foreach($project['refs'] as $ref => $rhash) { if(strtolower($rhash) == strtolower($commit['id'])) { $refexp = explode('/', $ref, 3); $reftype = $refexp[1]; if($reftype == 'heads') $reftype = 'head'; else if($reftype == 'remotes') $reftype = 'remote'; else if($reftype == 'tags') $reftype = 'tag'; $refs->append('refs', new ContentProvider('commit', 'commit_ref_'.$reftype, array("name" => $refexp[2], "ref_link" => $ref))); $found = true; } } $this->page->set('refs', ($found ? $refs : "")); $difftree = new difftree(); $this->page->set('difftree', $difftree->generate_difftree($project, $commit, false)); return $this->page; } } ?>