aboutsummaryrefslogtreecommitdiffstats
path: root/3rdparty/granite/git/tree.php
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/granite/git/tree.php')
-rw-r--r--3rdparty/granite/git/tree.php198
1 files changed, 198 insertions, 0 deletions
diff --git a/3rdparty/granite/git/tree.php b/3rdparty/granite/git/tree.php
new file mode 100644
index 00000000000..2de72274532
--- /dev/null
+++ b/3rdparty/granite/git/tree.php
@@ -0,0 +1,198 @@
+<?php
+/**
+ * Tree - provides a 'tree' object
+ *
+ * PHP version 5.3
+ *
+ * @category Git
+ * @package Granite
+ * @author Craig Roberts <craig0990@googlemail.com>
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+
+namespace Granite\Git;
+use \Granite\Git\Tree\Node as Node;
+
+/**
+ * Tree represents a full tree object, with nodes pointing to other tree objects
+ * and file blobs
+ *
+ * @category Git
+ * @package Granite
+ * @author Craig Roberts <craig0990@googlemail.com>
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+class Tree
+{
+
+ /**
+ * The SHA-1 id of the requested tree
+ */
+ private $sha;
+ /**
+ * The nodes/entries for the requested tree
+ */
+ private $nodes = array();
+ /**
+ * The path to the repository
+ */
+ private $path;
+
+ /**
+ * Reads a tree object by fetching the raw object
+ *
+ * @param string $path The path to the repository root
+ * @param string $sha The SHA-1 id of the requested object
+ */
+ public function __construct($path, $sha = NULL, $dbg = FALSE)
+ {
+ $this->path = $path;
+ if ($sha !== NULL) {
+ $object = Object\Raw::factory($path, $sha);
+ $this->sha = $sha;
+
+ if ($object->type() !== Object\Raw::OBJ_TREE) {
+ throw new \InvalidArgumentException(
+ "The object $sha is not a tree, type is " . $object->type()
+ );
+ }
+
+ $content = $object->content();
+ file_put_contents('/tmp/tree_from_real_repo'.time(), $content);
+ $nodes = array();
+
+ for ($i = 0; $i < strlen($content); $i = $data_start + 21) {
+ $data_start = strpos($content, "\0", $i);
+ $info = substr($content, $i, $data_start-$i);
+ list($mode, $name) = explode(' ', $info, 2);
+ // Read the object SHA-1 id
+ $sha = bin2hex(substr($content, $data_start + 1, 20));
+
+ $this->nodes[$name] = new Node($name, $mode, $sha);
+ }
+ }
+ }
+
+ /**
+ * Returns an array of Tree and Granite\Git\Blob objects,
+ * representing subdirectories and files
+ *
+ * @return array Array of Tree and Granite\Git\Blob objects
+ */
+ public function nodes($nodes = null)
+ {
+ if ($nodes == null) {
+ return $this->nodes;
+ }
+ $this->nodes = $nodes;
+ }
+
+ /**
+ * Adds a blob or a tree to the list of nodes
+ *
+ * @param string $name The basename (filename) of the blob or tree
+ * @param string $mode The mode of the blob or tree (see above)
+ * @param string $sha The SHA-1 id of the blob or tree to add
+ */
+ public function add($name, $mode, $sha)
+ {
+ $this->nodes[$name] = new Node($name, $mode, $sha);
+ uasort($this->nodes, array($this, '_sort'));
+ }
+
+ public function write()
+ {
+ $sha = $this->sha();
+ $path = $this->path
+ . 'objects'
+ . DIRECTORY_SEPARATOR
+ . substr($sha, 0, 2)
+ . DIRECTORY_SEPARATOR
+ . substr($sha, 2);
+ // FIXME: currently writes loose objects only
+ if (file_exists($path)) {
+ return FALSE;
+ }
+
+ if (!is_dir(dirname($path))) {
+ mkdir(dirname($path), 0777, TRUE);
+ }
+
+ $loose = fopen($path, 'wb');
+ $data = $this->_raw();
+ $data = 'tree ' . strlen($data) . "\0" . $data;
+ $write = fwrite($loose, gzcompress($data));
+ fclose($loose);
+
+ return ($write !== FALSE);
+ }
+
+ /**
+ * Returns the SHA-1 id of the Tree
+ *
+ * @return string SHA-1 id of the Tree
+ */
+ public function sha()
+ {
+ $data = $this->_raw();
+ $raw = 'tree ' . strlen($data) . "\0" . $data;
+ $this->sha = hash('sha1', $raw);
+ return $this->sha;
+ }
+
+ /**
+ * Generates the raw object content to be saved to disk
+ */
+ public function _raw()
+ {
+ uasort($this->nodes, array($this, '_sort'));
+ $data = '';
+ foreach ($this->nodes as $node)
+ {
+ $data .= base_convert($node->mode(), 10, 8) . ' ' . $node->name() . "\0";
+ $data .= pack('H40', $node->sha());
+ }
+ file_put_contents('/tmp/tree_made'.time(), $data);
+ return $data;
+ }
+
+ /**
+ * Sorts the node entries in a tree, general sort method adapted from original
+ * Git C code (see @see tag below).
+ *
+ * @return 1, 0 or -1 if the first entry is greater than, the same as, or less
+ * than the second, respectively.
+ * @see https://github.com/gitster/git/blob/master/read-cache.c Around line 352,
+ * the `base_name_compare` function
+ */
+ public function _sort(&$a, &$b)
+ {
+ $length = strlen($a->name()) < strlen($b->name()) ? strlen($a->name()) : strlen($b->name());
+
+ $cmp = strncmp($a->name(), $b->name(), $length);
+ if ($cmp) {
+ return $cmp;
+ }
+
+ $suffix1 = $a->name();
+ $suffix1 = (strlen($suffix1) > $length) ? $suffix1{$length} : FALSE;
+ $suffix2 = $b->name();
+ $suffix2 = (strlen($suffix2) > $length) ? $suffix2{$length} : FALSE;
+ if (!$suffix1 && $a->isDirectory()) {
+ $suffix1 = '/';
+ }
+ if (!$suffix2 && $b->isDirectory()) {
+ $suffix2 = '/';
+ }
+ if ($suffix1 < $suffix2) {
+ return -1;
+ } elseif ($suffix1 > $suffix2) {
+ return 1;
+ }
+
+ return 0;
+ }
+
+}