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);