Start getting log off of project object, unify log/shortlog controller logic
Start getting log off of project object, unify log/shortlog controller logic

--- a/include/controller/Controller_Log.class.php
+++ b/include/controller/Controller_Log.class.php
@@ -11,7 +11,6 @@
  */
 
 require_once(GITPHP_INCLUDEDIR . 'util.age_string.php');
-require_once(GITPHP_INCLUDEDIR . 'gitutil.git_read_revlist.php');
 require_once(GITPHP_INCLUDEDIR . 'gitutil.read_info_ref.php');
 
 /**
@@ -96,102 +95,18 @@
 	 */
 	protected function LoadData()
 	{
-		if (isset($this->params['short']) && ($this->params['short'] === true)) {
-			$this->LoadDataShort();
-			return;
+		$this->tpl->assign('hash', $this->project->GetCommit($this->params['hash']));
+		$this->tpl->assign('head', $this->project->GetHeadCommit());
+		$this->tpl->assign('page',$this->params['page']);
+
+		$revlist = $this->project->GetLog($this->params['hash'], 101, ($this->params['page'] * 100));
+		if ($revlist) {
+			if (count($revlist) > 100) {
+				$this->tpl->assign('hasmore', true);
+				$revlist = array_slice($revlist, 0, 100);
+			}
+			$this->tpl->assign('revlist', $revlist);
 		}
-		$head = $this->project->GetHeadCommit()->GetHash();
-		$refs = read_info_ref();
-		$this->tpl->assign("hash",$this->params['hash']);
-		$this->tpl->assign("head",$head);
-
-		if ($this->params['page'])
-			$this->tpl->assign("page",$this->params['page']);
-
-		$revlist = git_read_revlist($this->params['hash'], 101, ($this->params['page'] * 100));
-
-		$revlistcount = count($revlist);
-		$this->tpl->assign("revlistcount",$revlistcount);
-
-		if (!$revlist) {
-			$this->tpl->assign("norevlist",TRUE);
-			$co = $this->project->GetCommit($this->params['hash']);
-			$this->tpl->assign("lastchange", age_string($co->GetAge()));
-		}
-
-		$commitlines = array();
-		$commitcount = min(100,$revlistcount);
-		for ($i = 0; $i < $commitcount; ++$i) {
-			$commit = $revlist[$i];
-			if (isset($commit) && strlen($commit) > 1) {
-				$commitline = array();
-				$co = $this->project->GetCommit($commit);
-				$commitline["project"] = $this->project->GetProject();
-				$commitline["commit"] = $commit;
-				if (isset($refs[$commit]))
-					$commitline["commitref"] = $refs[$commit];
-				$commitline["agestring"] = age_string($co->GetAge());
-				$commitline["title"] = $co->GetTitle();
-				$commitline["authorname"] = $co->GetAuthorName();
-				$commitline["authorepoch"] = $co->GetAuthorEpoch();
-				$commitline["comment"] = $co->GetComment();
-				$commitlines[] = $commitline;
-				unset($co);
-			}
-		}
-		$this->tpl->assign("commitlines",$commitlines);
-	}
-
-	/**
-	 * LoadDataShort
-	 *
-	 * Load data for shortlog
-	 * TODO: temporary until templates get cleaned up more
-	 */
-	private function LoadDataShort()
-	{
-		$head = $this->project->GetHeadCommit();;
-		$refs = read_info_ref();
-		$this->tpl->assign("hash",$this->params['hash']);
-		$this->tpl->assign("head",$head->GetHash());
-
-		if ($page)
-			$this->tpl->assign("page",$page);
-
-		$revlist = git_read_revlist($this->params['hash'], 101, ($page * 100));
-
-		$revlistcount = count($revlist);
-		$this->tpl->assign("revlistcount",$revlistcount);
-
-		$commitlines = array();
-		$commitcount = min(100,count($revlist));
-		for ($i = 0; $i < $commitcount; ++$i) {
-			$commit = $revlist[$i];
-			if (strlen(trim($commit)) > 0) {
-				$commitline = array();
-				if (isset($refs[$commit]))
-					$commitline["commitref"] = $refs[$commit];
-				$co = $this->project->GetCommit($commit);
-				$commitline["commit"] = $commit;
-				$age = $co->GetAge();
-				if ($age > 60*60*24*7*2) {
-					$commitline["agestringdate"] = date('Y-m-d', $co->GetCommitterEpoch());
-					$commitline["agestringage"] = age_string($age);
-				} else {
-					$commitline["agestringdate"] = age_string($age);
-					$commitline["agestringage"] = date('Y-m-d', $co->GetCommitterEpoch());
-				}
-				$commitline["authorname"] = $co->GetAuthorName();
-				$titleshort = $co->GetTitle(GITPHP_TRIM_LENGTH);
-				$title = $co->GetTitle();
-				$commitline["title_short"] = $titleshort;
-				if (strlen($titleshort) < strlen($title))
-					$commitline["title"] = $title;
-				$commitlines[] = $commitline;
-				unset($co);
-			}
-		}
-		$this->tpl->assign("commitlines",$commitlines);
 	}
 
 }

--- a/include/git/GitExe.class.php
+++ b/include/git/GitExe.class.php
@@ -100,7 +100,7 @@
 	 *
 	 * Gets the binary for this executable
 	 *
-	 * @return string $param
+	 * @return string binary
 	 * @access public
 	 */
 	public function GetBinary()
@@ -108,5 +108,46 @@
 		return $this->binary;
 	}
 
+	/**
+	 * GetVersion
+	 *
+	 * Gets the version of the git binary
+	 *
+	 * @return string version
+	 * @access public
+	 */
+	public function GetVersion()
+	{
+		$versionCommand = $this->binary . ' --version';
+		$ret = trim(shell_exec($versionCommand));
+		if (preg_match('/^git version ([0-9\.]+)$/i', $ret, $regs)) {
+			return $regs[1];
+		}
+		return '';
+	}
+
+	/**
+	 * CanSkip
+	 *
+	 * Tests if this version of git can skip through the revision list
+	 *
+	 * @access public
+	 * @return boolean true if we can skip
+	 */
+	public function CanSkip()
+	{
+		$version = $this->GetVersion();
+		if (!empty($version)) {
+			$splitver = explode('.', $version);
+
+			/* Skip only appears in git >= 1.5.0 */
+			if (($splitver[0] < 1) || (($splitver[0] == 1) && ($splitver[1] < 5))) {
+				return false;
+			}
+		}
+
+		return true;
+	}
+
 }
 

--- a/include/git/Project.class.php
+++ b/include/git/Project.class.php
@@ -570,6 +570,76 @@
 
 	}
 
+	/**
+	 * GetLogHash
+	 *
+	 * Gets log entries as an array of hashes
+	 *
+	 * @access public
+	 * @param string $hash hash to start the log at
+	 * @param integer $count number of entries to get
+	 * @param integer $skip number of entries to skip
+	 * @return array array of hashes
+	 */
+	public function GetLogHash($hash, $count = 50, $skip = 0)
+	{
+		if ($count < 1)
+			return;
+
+		$exe = new GitPHP_GitExe($this);
+
+		$canSkip = true;
+		
+		if ($skip > 0)
+			$canSkip = $exe->CanSkip();
+
+		$args = array();
+
+		if ($canSkip) {
+			$args[] = '--max-count=' . $count;
+			if ($skip > 0) {
+				$args[] = '--skip=' . $skip;
+			}
+		} else {
+			$args[] = '--max-count=' . ($count + $skip);
+		}
+
+		$args[] = $hash;
+
+		$revlist = explode("\n", $exe->Execute(GIT_REV_LIST, $args));
+
+		if (!$revlist[count($revlist)-1]) {
+			/* the last newline creates a null entry */
+			array_splice($revlist, -1, 1);
+		}
+
+		if (($skip > 0) && (!$exe->CanSkip())) {
+			return array_slice($revlist, $skip, $count);
+		}
+
+		return $revlist;
+	}
+
+	/**
+	 * GetLog
+	 *
+	 * Gets log entries as an array of commit objects
+	 *
+	 * @access public
+	 * @param string $hash hash to start the log at
+	 * @param integer $count number of entries to get
+	 * @param integer $skip number of entries to skip
+	 * @return array array of commit objects
+	 */
+	public function GetLog($hash, $count = 50, $skip = 0)
+	{
+		$log = $this->GetLogHash($hash, $count, $skip);
+		$len = count($log);
+		for ($i = 0; $i < $len; ++$i) {
+			$log[$i] = $this->GetCommit($log[$i]);
+		}
+		return $log;
+	}
 
 }
 

--- a/templates/header.tpl
+++ b/templates/header.tpl
@@ -39,7 +39,7 @@
             <div class="search">
               <input type="hidden" name="p" value="{$project->GetProject()}" />
               <input type="hidden" name="a" value="search" />
-              <input type ="hidden" name="h" value="{if $hashbase}{$hashbase}{elseif $hash}{$hash}{else}HEAD{/if}" />
+              <input type ="hidden" name="h" value="{if $hashbase}{$hashbase}{elseif $hash instanceof GitPHP_Commit}{$hash->GetHash()}{elseif $hash}{$hash}{else}HEAD{/if}" />
               <select name="st">
                 <option {if $searchtype == 'commit'}selected="selected"{/if} value="commit">commit</option>
                 <option {if $searchtype == 'author'}selected="selected"{/if} value="author">author</option>

--- a/templates/log.tpl
+++ b/templates/log.tpl
@@ -10,61 +10,67 @@
 
  {* Nav *}
  <div class="page_nav">
-   <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=summary">summary</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=shortlog&h={$hash}">shortlog</a> | log | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commit&h={$hash}">commit</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commitdiff&h={$hash}">commitdiff</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=tree&h={$hash}&hb={$hash}">tree</a>
+   <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=summary">summary</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=shortlog&h={$hash->GetHash()}">shortlog</a> | log | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commit&h={$hash->GetHash()}">commit</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commitdiff&h={$hash->GetHash()}">commitdiff</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=tree&h={$hash->GetHash()}&hb={$hash->GetHash()}">tree</a>
    <br />
-   {if ($hash != $head) || $page}
+   {if ($hash->GetHash() != $head->GetHash()) || ($page > 0)}
      <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=log">HEAD</a>
    {else}
      HEAD
    {/if}
    &sdot; 
    {if $page > 0}
-     <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=log&h={$hash}&pg={$page-1}" accesskey="p" title="Alt-p">prev</a>
+     <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=log&h={$hash->GetHash()}&pg={$page-1}" accesskey="p" title="Alt-p">prev</a>
    {else}
      prev
    {/if}
    &sdot; 
-   {if $revlistcount > 100}
-     <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=log&h={$hash}&pg={$page+1}" accesskey="n" title="Alt-n">next</a>
+   {if $hasmore}
+     <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=log&h={$hash->GetHash()}&pg={$page+1}" accesskey="n" title="Alt-n">next</a>
    {else}
      next
    {/if}
    <br />
  </div>
- {if $norevlist}
+ {foreach from=$revlist item=rev}
+   <div class="title">
+     <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commit&h={$rev->GetHash()}" class="title"><span class="age">{$rev->GetAge()|agestring}</span>{$rev->GetTitle()}</a>
+     <span class="refs">
+     {foreach from=$rev->GetHeads() item=revhead}
+       <span class="head">
+	   <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=shortlog&h=refs/heads/{$revhead->GetName()}">{$revhead->GetName()}</a>
+	 </span>
+     {/foreach}
+     {foreach from=$rev->GetTags() item=revtag}
+       <span class="tag">
+	   <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=tag&h={$revtag->GetName()}">{$revtag->GetName()}</a>
+	 </span>
+     {/foreach}
+     </span>
+   </div>
+   <div class="title_text">
+     <div class="log_link">
+       <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commit&h={$rev->GetHash()}">commit</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commitdiff&h={$rev->GetHash()}">commitdiff</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=tree&h={$rev->GetHash()}&hb={$rev->GetHash()}">tree</a>
+       <br />
+     </div>
+     <em>{$rev->GetAuthorName()} [{$rev->GetAuthorEpoch()|date_format:"%a, %d %b %Y %H:%M:%S %z"}]</em><br />
+   </div>
+   <div class="log_body">
+     {foreach from=$rev->GetComment() item=line}
+       {$line}<br />
+     {/foreach}
+     {if count($rev->GetComment()) > 0}
+       <br />
+     {/if}
+   </div>
+ {foreachelse}
    <div class="title">
      <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=summary" class="title">&nbsp</a>
    </div>
    <div class="page_body">
-     Last change {$lastchange}.
+     Last change {$hash->GetAge()|agestring}.
      <br /><br />
    </div>
- {/if}
- {* Display each commit *}
- {section name=log loop=$commitlines}
-   <div class="title">
-     <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commit&h={$commitlines[log].commit}" class="title"><span class="age">{$commitlines[log].agestring}</span>{$commitlines[log].title}
-       {if $commitlines[log].commitref}
-         <span class="tag">{$commitlines[log].commitref}</span>
-       {/if}
-     </a>
-   </div>
-   <div class="title_text">
-     <div class="log_link">
-       <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commit&h={$commitlines[log].commit}">commit</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commitdiff&h={$commitlines[log].commit}">commitdiff</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=tree&h={$commitlines[log].commit}&hb={$commitlines[log].commit}">tree</a>
-       <br />
-     </div>
-     <em>{$commitlines[log].authorname} [{$commitlines[log].authorepoch|date_format:"%a, %d %b %Y %H:%M:%S %z"}]</em><br />
-   </div>
-   <div class="log_body">
-     {foreach from=$commitlines[log].comment item=line}
-       {$line}<br />
-     {/foreach}
-     {if count($commitlines[log].comment) > 0}
-       <br />
-     {/if}
-   </div>
- {/section}
+ {/foreach}
 
  {include file='footer.tpl'}
 

--- a/templates/shortlog.tpl
+++ b/templates/shortlog.tpl
@@ -10,22 +10,22 @@
 
  {* Nav *}
  <div class="page_nav">
-   <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=summary">summary</a> | shortlog | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=log&h={$hash}">log</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commit&h={$hash}">commit</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commitdiff&h={$hash}">commitdiff</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=tree&h={$hash}&hb={$hash}">tree</a>
+   <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=summary">summary</a> | shortlog | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=log&h={$hash->GetHash()}">log</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commit&h={$hash->GetHash()}">commit</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commitdiff&h={$hash->GetHash()}">commitdiff</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=tree&h={$hash->GetHash()}&hb={$hash->GetHash()}">tree</a>
    <br />
-   {if ($hash != $head) || $page}
+   {if ($hash->GetHash() != $head->GetHash()) || ($page > 0)}
      <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=shortlog">HEAD</a>
    {else}
      HEAD
    {/if}
      &sdot; 
    {if $page > 0}
-     <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=shortlog&h={$hash}&pg={$page-1}" accesskey="p" title="Alt-p">prev</a>
+     <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=shortlog&h={$hash->GetHash()}&pg={$page-1}" accesskey="p" title="Alt-p">prev</a>
    {else}
      prev
    {/if}
      &sdot; 
-   {if $revlistcount > 100}
-     <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=shortlog&h={$hash}&pg={$page+1}" accesskey="n" title="Alt-n">next</a>
+   {if $hasmore}
+     <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=shortlog&h={$hash->GetHash()}&pg={$page+1}" accesskey="n" title="Alt-n">next</a>
    {else}
      next
    {/if}
@@ -35,26 +35,33 @@
    <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=summary" class="title">&nbsp;</a>
  </div>
  <table cellspacing="0">
-   {* Display each log entry *}
-   {section name=log loop=$commitlines}
+   {foreach from=$revlist item=rev}
      <tr class="{cycle values="light,dark"}">
-       <td title="{$commitlines[log].agestringage}"><em>{$commitlines[log].agestringdate}</em></td>
-       <td><em>{$commitlines[log].authorname}</em></td>
+       <td title="{if $rev->GetAge() > 60*60*24*7*2}{$rev->GetAge()|agestring}{else}{$rev->GetCommitterEpoch()|date_format:"%F"}{/if}"><em>{if $rev->GetAge() > 60*60*24*7*2}{$rev->GetCommitterEpoch()|date_format:"%F"}{else}{$rev->GetAge()|agestring}{/if}</em></td>
+       <td><em>{$rev->GetAuthorName()}</em></td>
        <td>
-         <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commit&h={$commitlines[log].commit}" class="list" {if $commitlines[log].title}title="{$commitlines[log].title}"{/if}><strong>{$commitlines[log].title_short}
-         {if $commitlines[log].commitref}
-           <span class="tag">{$commitlines[log].commitref}</span>
-         {/if}
-         </strong>
+         <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commit&h={$rev->GetHash()}" class="list" {if strlen($rev->GetTitle()) > 50}title="{$rev->GetTitle()}"{/if}><strong>{$rev->GetTitle(50)}</strong></a>
+	 <span class="refs">
+	 {foreach from=$rev->GetHeads() item=revhead}
+	   <span class="head">
+	     <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=shortlog&h=refs/heads/{$revhead->GetName()}">{$revhead->GetName()}</a>
+	   </span>
+	 {/foreach}
+	 {foreach from=$rev->GetTags() item=revtag}
+	   <span class="tag">
+	     <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=tag&h={$revtag->GetName()}">{$revtag->GetName()}</a>
+	   </span>
+	 {/foreach}
+	 </span>
        </td>
-       <td class="link"><a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commit&h={$commitlines[log].commit}">commit</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commitdiff&h={$commitlines[log].commit}">commitdiff</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=tree&h={$commitlines[log].commit}&hb={$commitlines[log].commit}">tree</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=snapshot&h={$commitlines[log].commit}">snapshot</a>
+       <td class="link"><a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commit&h={$rev->GetHash()}">commit</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=commitdiff&h={$rev->GetHash()}">commitdiff</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=tree&h={$rev->GetHash()}&hb={$rev->GetHash()}">tree</a> | <a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=snapshot&h={$rev->GetHash()}">snapshot</a>
        </td>
      </tr>
-   {/section}
+   {/foreach}
 
-   {if $revlistcount > 100}
+   {if $hasmore}
      <tr>
-       <td><a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=shortlog&h={$hash}&pg={$page+1}" title="Alt-n">next</a></td>
+       <td><a href="{$SCRIPT_NAME}?p={$project->GetProject()}&a=shortlog&h={$hash->GetHash()}&pg={$page+1}" title="Alt-n">next</a></td>
      </tr>
    {/if}
  </table>

comments