Use load strategies on head list
Use load strategies on head list

--- a/include/git/HeadList.class.php
+++ b/include/git/HeadList.class.php
@@ -9,6 +9,42 @@
  */
 class GitPHP_HeadList extends GitPHP_RefList
 {
+	/**
+	 * Data load strategy
+	 *
+	 * @var GitPHP_HeadListLoadStrategy_Interface
+	 */
+	protected $strategy;
+
+	/**
+	 * Constructor
+	 *
+	 * @param GitPHP_Project $project project
+	 * @param GitPHP_HeadListLoadStrategy_Interface $strategy load strategy
+	 */
+	public function __construct($project, GitPHP_HeadListLoadStrategy_Interface $strategy)
+	{
+		parent::__construct($project);
+
+		if (!$strategy)
+			throw new Exception('Head list load strategy is required');
+
+		$this->SetStrategy($strategy);
+	}
+
+	/**
+	 * Set the load strategy
+	 *
+	 * @param GitPHP_HeadListLoadStrategy_Interface $strategy load strategy
+	 */
+	public function SetStrategy(GitPHP_HeadListLoadStrategy_Interface $strategy)
+	{
+		if (!$strategy)
+			return;
+
+		$this->strategy = $strategy;
+	}
+
 	/**
 	 * Gets the heads
 	 *
@@ -35,10 +71,7 @@
 	{
 		$this->dataLoaded = true;
 
-		if ($this->compat)
-			$this->refs = $this->ReadRefListGit('heads');
-		else
-			$this->refs = $this->ReadRefListRaw('heads');
+		$this->refs = $this->strategy->Load($this);
 	}
 
 	/**
@@ -69,46 +102,7 @@
 	 */
 	public function GetOrderedHeads($order, $count = 0)
 	{
-		if (!$this->dataLoaded)
-			$this->LoadData();
-
-		if ($this->compat) {
-			$ordered = $this->GetOrderedRefsGit('heads', $order, $count);
-			$heads = array();
-			foreach ($ordered as $head) {
-				if (isset($this->refs[$head])) {
-					$heads[] = $this->project->GetObjectManager()->GetHead($head, $this->refs[$head]);
-				}
-			}
-			return $heads;
-		} else {
-			return $this->GetOrderedHeadsRaw($order, $count);
-		}
-	}
-
-	/**
-	 * Get heads in a specific order using raw objects
-	 *
-	 * @param string $order order to use
-	 * @param int $count limit the number of results
-	 * @return GitPHP_Head[] array of heads
-	 */
-	private function GetOrderedHeadsRaw($order, $count = 0)
-	{
-		$heads = array();
-		foreach ($this->refs as $head => $hash) {
-			$heads[] = $this->project->GetObjectManager()->GetHead($head, $hash);
-		}
-
-		/* TODO add different orders */
-		if ($order == '-committerdate') {
-			usort($heads, array('GitPHP_Head', 'CompareAge'));
-		}
-
-		if (($count > 0) && (count($heads) > $count)) {
-			$heads = array_slice($heads, 0, $count);
-		}
-		return $heads;
+		return $this->strategy->LoadOrdered($this, $order, $count);
 	}
 
 	/**

--- /dev/null
+++ b/include/git/HeadListLoadStrategy.interface.php
@@ -1,1 +1,13 @@
+<?php
+/**
+ * Marker interface for head list load strategies
+ *
+ * @author Christopher Han <xiphux@gmail.com>
+ * @copyright Copyright (c) 2012 Christopher Han
+ * @package GitPHP
+ * @subpackage Git
+ */
+interface GitPHP_HeadListLoadStrategy_Interface extends GitPHP_RefListLoadStrategy_Interface
+{
+}
 

--- /dev/null
+++ b/include/git/HeadListLoad_Git.class.php
@@ -1,1 +1,50 @@
+<?php
+/**
+ * Head list load strategy using git exe
+ *
+ * @author Christopher Han <xiphux@gmail.com>
+ * @copyright Copyright (c) 2012 Christopher Han
+ * @package GitPHP
+ * @subpackage Git
+ */
+class GitPHP_HeadListLoad_Git extends GitPHP_RefListLoad_Git implements GitPHP_HeadListLoadStrategy_Interface
+{
+	/**
+	 * Loads the head list
+	 *
+	 * @param GitPHP_HeadList $headList head list
+	 * @return array array of head hashes
+	 */
+	public function Load($headList)
+	{
+		return $this->GetRefs($headList, 'heads');
+	}
 
+	/** 
+	 * Loads sorted heads
+	 *
+	 * @param GitPHP_HeadList $headList head list
+	 * @param string $order list order
+	 * @param integer $count number to load
+	 */
+	public function LoadOrdered($headList, $order, $count = 0)
+	{
+		if (!$headList)
+			return;
+
+		$ordered = $this->GetOrderedRefs($headList, 'heads', $order, $count);
+
+		if (!$ordered)
+			return;
+
+		$headObjs = array();
+		foreach ($ordered as $head) {
+			if ($headList->Exists($head)) {
+				$headObjs[] = $headList->GetHead($head);
+			}
+		}
+
+		return $headObjs;
+	}
+}
+

--- /dev/null
+++ b/include/git/HeadListLoad_Raw.class.php
@@ -1,1 +1,52 @@
+<?php
+/**
+ * Head list load strategy using raw objects
+ *
+ * @author Christopher Han <xiphux@gmail.com>
+ * @copyright Copyright (c) 2012 Christopher Han
+ * @package GitPHP
+ * @subpackage Git
+ */
+class GitPHP_HeadListLoad_Raw extends GitPHP_RefListLoad_Raw implements GitPHP_HeadListLoadStrategy_Interface
+{
+	/**
+	 * Loads the head list
+	 *
+	 * @param GitPHP_HeadList $headList head list
+	 * @return array array of head hashes
+	 */
+	public function Load($headList)
+	{
+		return $this->GetRefs($headList, 'heads');
+	}
 
+	/** 
+	 * Loads sorted heads
+	 *
+	 * @param GitPHP_HeadList $headList head list
+	 * @param string $order list order
+	 * @param integer $count number to load
+	 */
+	public function LoadOrdered($headList, $order, $count = 0)
+	{
+		if (!$headList)
+			return;
+
+		if (empty($order))
+			return;
+
+		$heads = $headList->GetHeads();
+
+		/* TODO add different orders */
+		if ($order == '-committerdate') {
+			usort($heads, array('GitPHP_Head', 'CompareAge'));
+		}
+
+		if (($count > 0) && (count($heads) > $count)) {
+			$heads = array_slice($heads, 0, $count);
+		}
+
+		return $heads;
+	}
+}
+

--- /dev/null
+++ b/include/git/RefListLoadStrategy.interface.php
@@ -1,1 +1,29 @@
+<?php
+/**
+ * Interface for ref list load strategies
+ *
+ * @author Christopher Han <xiphux@gmail.com>
+ * @copyright Copyright (c) 2012 Christopher Han
+ * @package GitPHP
+ * @subpackage Git
+ */
+interface GitPHP_RefListLoadStrategy_Interface
+{
+	/**
+	 * Loads the ref list
+	 *
+	 * @param GitPHP_RefList $refList ref list
+	 * @return array array of refs
+	 */
+	public function Load($refList);
 
+	/** 
+	 * Loads sorted refs
+	 *
+	 * @param GitPHP_RefList $refList ref list
+	 * @param string $order list order
+	 * @param integer $count number to load
+	 */
+	public function LoadOrdered($refList, $order, $count = 0);
+}
+

--- /dev/null
+++ b/include/git/RefListLoad_Git.class.php
@@ -1,1 +1,108 @@
+<?php
+/**
+ * Ref list load strategy using git exe
+ *
+ * @author Christopher Han <xiphux@gmail.com>
+ * @copyright Copyright (c) 2012 Christopher Han
+ * @package GitPHP
+ * @subpackage Git
+ */
+abstract class GitPHP_RefListLoad_Git
+{
+	/**
+	 * Executable
+	 *
+	 * @var GitPHP_GitExe
+	 */
+	protected $exe;
 
+	/**
+	 * Constructor
+	 *
+	 * @param GitPHP_GitExe $exe git executable
+	 */
+	public function __construct($exe)
+	{
+		if (!$exe)
+			throw new Exception('Git exe is required');
+
+		$this->exe = $exe;
+	}
+
+	/**
+	 * Loads the ref list for a ref type
+	 *
+	 * @param GitPHP_RefList $refList ref list
+	 * @param string $type ref type
+	 * @return array array of refs
+	 */
+	protected function GetRefs($refList, $type)
+	{
+		if (!$refList)
+			return;
+
+		if (empty($type))
+			return;
+
+		$args = array();
+		$args[] = '--' . $type;
+		$ret = $this->exe->Execute($refList->GetProject()->GetPath(), GIT_SHOW_REF, $args);
+
+		$lines = explode("\n", $ret);
+
+		$refs = array();
+
+		foreach ($lines as $line) {
+			if (preg_match('/^([0-9a-fA-F]{40}) refs\/' . $type . '\/([^^]+)(\^{})?$/', $line, $regs)) {
+				$refs[$regs[2]] = $regs[1];
+			}
+		}
+
+		return $refs;
+	}
+
+	/**
+	 * Get refs in a specific order
+	 *
+	 * @param GitPHP_RefList $refList ref list
+	 * @param string $type type of ref
+	 * @param string $order order to use
+	 * @param int $count limit the number of results
+	 * @return array array of refs
+	 */
+	protected function GetOrderedRefs($refList, $type, $order, $count = 0)
+	{
+		if (!$refList)
+			return;
+
+		if (empty($type) || empty($order))
+			return null;
+
+		$args = array();
+		$args[] = '--sort=' . $order;
+		$args[] = '--format="%(refname)"';
+		if ($count > 0) {
+			$args[] = '--count=' . $count;
+		}
+		$args[] = '--';
+		$args[] = 'refs/' . $type;
+		$ret = $this->exe->Execute($refList->GetProject()->GetPath(), GIT_FOR_EACH_REF, $args);
+
+		$lines = explode("\n", $ret);
+
+		$prefix = 'refs/' . $type . '/';
+		$prefixLen = strlen($prefix);
+
+		$refs = array();
+
+		foreach ($lines as $ref) {
+			$ref = substr($ref, $prefixLen);
+			if (!empty($ref))
+				$refs[] = $ref;
+		}
+
+		return $refs;
+	}
+
+}
+

--- /dev/null
+++ b/include/git/RefListLoad_Raw.class.php
@@ -1,1 +1,64 @@
+<?php
+/**
+ * Ref list load strategy using raw git objects
+ *
+ * @author Christopher Han <xiphux@gmail.com>
+ * @copyright Copyright (c) 2012 Christopher Han
+ * @package GitPHP
+ * @subpackage Git
+ */
+abstract class GitPHP_RefListLoad_Raw
+{
+	/**
+	 * Loads the ref list for a ref type
+	 *
+	 * @param GitPHP_RefList $refList ref list
+	 * @param string $type ref type
+	 * @return array array of refs
+	 */
+	protected function GetRefs(GitPHP_RefList $refList, $type)
+	{
+		if (!$refList)
+			return;
 
+		if (empty($type))
+			return;
+
+		$refs = array();
+
+		$prefix = 'refs/' . $type;
+		$fullPath = $refList->GetProject()->GetPath() . '/' . $prefix;
+		$fullPathLen = strlen($fullPath) + 1;
+
+		/* loose files */
+		$refFiles = GitPHP_Util::ListDir($fullPath);
+		for ($i = 0; $i < count($refFiles); ++$i) {
+			$ref = substr($refFiles[$i], $fullPathLen);
+			
+			if (empty($ref) || isset($refs[$ref]))
+				continue;
+
+			$hash = trim(file_get_contents($refFiles[$i]));
+			if (preg_match('/^[0-9A-Fa-f]{40}$/', $hash)) {
+				$refs[$ref] = $hash;
+			}
+		}
+
+		/* packed refs */
+		if (file_exists($refList->GetProject()->GetPath() . '/packed-refs')) {
+			$packedRefs = explode("\n", file_get_contents($refList->GetProject()->GetPath() . '/packed-refs'));
+
+			foreach ($packedRefs as $ref) {
+
+				if (preg_match('/^([0-9A-Fa-f]{40}) refs\/' . $type . '\/(.+)$/', $ref, $regs)) {
+					if (!isset($refs[$regs[2]])) {
+						$refs[$regs[2]] = $regs[1];
+					}
+				}
+			}
+		}
+
+		return $refs;
+	}
+}
+

--- a/include/git/projectlist/ProjectListBase.class.php
+++ b/include/git/projectlist/ProjectListBase.class.php
@@ -235,7 +235,13 @@
 
 		$compat = $project->GetCompat();
 
-		$headList = new GitPHP_HeadList($project);
+		$headListStrategy = null;
+		if ($compat) {
+			$headListStrategy = new GitPHP_HeadListLoad_Git(GitPHP_GitExe::GetInstance());
+		} else {
+			$headListStrategy = new GitPHP_HeadListLoad_Raw();
+		}
+		$headList = new GitPHP_HeadList($project, $headListStrategy);
 		$headList->SetCompat($compat);
 		$project->SetHeadList($headList);
 

comments