From c05b7cf631ccbdf044118221128f8b5a9d9bd89e Mon Sep 17 00:00:00 2001 From: Sven Slootweg Date: Sat, 5 May 2012 18:22:35 +0200 Subject: [PATCH] Cleaned up --- lib/binary.class.php | 61 ----- lib/git.class.php | 438 --------------------------------- lib/git_blob.class.php | 45 ---- lib/git_commit.class.php | 174 ------------- lib/git_commit_stamp.class.php | 45 ---- lib/git_object.class.php | 154 ------------ lib/git_tree.class.php | 267 -------------------- lib/glip.php | 24 -- test.php | 3 - 9 files changed, 1211 deletions(-) delete mode 100644 lib/binary.class.php delete mode 100644 lib/git.class.php delete mode 100644 lib/git_blob.class.php delete mode 100644 lib/git_commit.class.php delete mode 100644 lib/git_commit_stamp.class.php delete mode 100644 lib/git_object.class.php delete mode 100644 lib/git_tree.class.php delete mode 100644 lib/glip.php delete mode 100644 test.php diff --git a/lib/binary.class.php b/lib/binary.class.php deleted file mode 100644 index 06f360a..0000000 --- a/lib/binary.class.php +++ /dev/null @@ -1,61 +0,0 @@ -. - */ - -final class Binary -{ - static public function uint16($str, $pos=0) - { - return ord($str{$pos+0}) << 8 | ord($str{$pos+1}); - } - - static public function uint32($str, $pos=0) - { - $a = unpack('Nx', substr($str, $pos, 4)); - return $a['x']; - } - - static public function nuint32($n, $str, $pos=0) - { - $r = array(); - for ($i = 0; $i < $n; $i++, $pos += 4) - $r[] = Binary::uint32($str, $pos); - return $r; - } - - static public function fuint32($f) { return Binary::uint32(fread($f, 4)); } - static public function nfuint32($n, $f) { return Binary::nuint32($n, fread($f, 4*$n)); } - - static public function git_varint($str, &$pos=0) - { - $r = 0; - $c = 0x80; - for ($i = 0; $c & 0x80; $i += 7) - { - $c = ord($str{$pos++}); - $r |= (($c & 0x7F) << $i); - } - return $r; - } -} - diff --git a/lib/git.class.php b/lib/git.class.php deleted file mode 100644 index 8828fa8..0000000 --- a/lib/git.class.php +++ /dev/null @@ -1,438 +0,0 @@ -. - */ - -require_once('binary.class.php'); -require_once('git_object.class.php'); -require_once('git_blob.class.php'); -require_once('git_commit.class.php'); -require_once('git_commit_stamp.class.php'); -require_once('git_tree.class.php'); - -/** - * @relates Git - * @brief Convert a SHA-1 hash from hexadecimal to binary representation. - * - * @param $hex (string) The hash in hexadecimal representation. - * @returns (string) The hash in binary representation. - */ -function sha1_bin($hex) -{ - return pack('H40', $hex); -} - -/** - * @relates Git - * @brief Convert a SHA-1 hash from binary to hexadecimal representation. - * - * @param $bin (string) The hash in binary representation. - * @returns (string) The hash in hexadecimal representation. - */ -function sha1_hex($bin) -{ - return bin2hex($bin); -} - -class Git -{ - public $dir; - - const OBJ_NONE = 0; - const OBJ_COMMIT = 1; - const OBJ_TREE = 2; - const OBJ_BLOB = 3; - const OBJ_TAG = 4; - const OBJ_OFS_DELTA = 6; - const OBJ_REF_DELTA = 7; - - static public function getTypeID($name) - { - if ($name == 'commit') - return Git::OBJ_COMMIT; - else if ($name == 'tree') - return Git::OBJ_TREE; - else if ($name == 'blob') - return Git::OBJ_BLOB; - else if ($name == 'tag') - return Git::OBJ_TAG; - throw new Exception(sprintf('unknown type name: %s', $name)); - } - - static public function getTypeName($type) - { - if ($type == Git::OBJ_COMMIT) - return 'commit'; - else if ($type == Git::OBJ_TREE) - return 'tree'; - else if ($type == Git::OBJ_BLOB) - return 'blob'; - else if ($type == Git::OBJ_TAG) - return 'tag'; - throw new Exception(sprintf('no string representation of type %d', $type)); - } - - public function __construct($dir) - { - $this->dir = realpath($dir); - if ($this->dir === FALSE || !@is_dir($this->dir)) - throw new Exception(sprintf('not a directory: %s', $dir)); - - $this->packs = array(); - $dh = opendir(sprintf('%s/objects/pack', $this->dir)); - if ($dh !== FALSE) { - while (($entry = readdir($dh)) !== FALSE) - if (preg_match('#^pack-([0-9a-fA-F]{40})\.idx$#', $entry, $m)) - $this->packs[] = sha1_bin($m[1]); - closedir($dh); - } - } - - /** - * @brief Tries to find $object_name in the fanout table in $f at $offset. - * - * @returns array The range where the object can be located (first possible - * location and past-the-end location) - */ - protected function readFanout($f, $object_name, $offset) - { - if ($object_name{0} == "\x00") - { - $cur = 0; - fseek($f, $offset); - $after = Binary::fuint32($f); - } - else - { - fseek($f, $offset + (ord($object_name{0}) - 1)*4); - $cur = Binary::fuint32($f); - $after = Binary::fuint32($f); - } - - return array($cur, $after); - } - - /** - * @brief Try to find an object in a pack. - * - * @param $object_name (string) name of the object (binary SHA1) - * @returns (array) an array consisting of the name of the pack (string) and - * the byte offset inside it, or NULL if not found - */ - protected function findPackedObject($object_name) - { - foreach ($this->packs as $pack_name) - { - $index = fopen(sprintf('%s/objects/pack/pack-%s.idx', $this->dir, sha1_hex($pack_name)), 'rb'); - flock($index, LOCK_SH); - - /* check version */ - $magic = fread($index, 4); - if ($magic != "\xFFtOc") - { - /* version 1 */ - /* read corresponding fanout entry */ - list($cur, $after) = $this->readFanout($index, $object_name, 0); - - $n = $after-$cur; - if ($n == 0) - continue; - - /* - * TODO: do a binary search in [$offset, $offset+24*$n) - */ - fseek($index, 4*256 + 24*$cur); - for ($i = 0; $i < $n; $i++) - { - $off = Binary::fuint32($index); - $name = fread($index, 20); - if ($name == $object_name) - { - /* we found the object */ - fclose($index); - return array($pack_name, $off); - } - } - } - else - { - /* version 2+ */ - $version = Binary::fuint32($index); - if ($version == 2) - { - list($cur, $after) = $this->readFanout($index, $object_name, 8); - - if ($cur == $after) - continue; - - fseek($index, 8 + 4*255); - $total_objects = Binary::fuint32($index); - - /* look up sha1 */ - fseek($index, 8 + 4*256 + 20*$cur); - for ($i = $cur; $i < $after; $i++) - { - $name = fread($index, 20); - if ($name == $object_name) - break; - } - if ($i == $after) - continue; - - fseek($index, 8 + 4*256 + 24*$total_objects + 4*$i); - $off = Binary::fuint32($index); - if ($off & 0x80000000) - { - /* packfile > 2 GB. Gee, you really want to handle this - * much data with PHP? - */ - throw new Exception('64-bit packfiles offsets not implemented'); - } - - fclose($index); - return array($pack_name, $off); - } - else - throw new Exception('unsupported pack index format'); - } - fclose($index); - } - /* not found */ - return NULL; - } - - /** - * @brief Apply the git delta $delta to the byte sequence $base. - * - * @param $delta (string) the delta to apply - * @param $base (string) the sequence to patch - * @returns (string) the patched byte sequence - */ - protected function applyDelta($delta, $base) - { - $pos = 0; - - $base_size = Binary::git_varint($delta, $pos); - $result_size = Binary::git_varint($delta, $pos); - - $r = ''; - while ($pos < strlen($delta)) - { - $opcode = ord($delta{$pos++}); - if ($opcode & 0x80) - { - /* copy a part of $base */ - $off = 0; - if ($opcode & 0x01) $off = ord($delta{$pos++}); - if ($opcode & 0x02) $off |= ord($delta{$pos++}) << 8; - if ($opcode & 0x04) $off |= ord($delta{$pos++}) << 16; - if ($opcode & 0x08) $off |= ord($delta{$pos++}) << 24; - $len = 0; - if ($opcode & 0x10) $len = ord($delta{$pos++}); - if ($opcode & 0x20) $len |= ord($delta{$pos++}) << 8; - if ($opcode & 0x40) $len |= ord($delta{$pos++}) << 16; - if ($len == 0) $len = 0x10000; - $r .= substr($base, $off, $len); - } - else - { - /* take the next $opcode bytes as they are */ - $r .= substr($delta, $pos, $opcode); - $pos += $opcode; - } - } - return $r; - } - - /** - * @brief Unpack an object from a pack. - * - * @param $pack (resource) open .pack file - * @param $object_offset (integer) offset of the object in the pack - * @returns (array) an array consisting of the object type (int) and the - * binary representation of the object (string) - */ - protected function unpackObject($pack, $object_offset) - { - fseek($pack, $object_offset); - - /* read object header */ - $c = ord(fgetc($pack)); - $type = ($c >> 4) & 0x07; - $size = $c & 0x0F; - for ($i = 4; $c & 0x80; $i += 7) - { - $c = ord(fgetc($pack)); - $size |= (($c & 0x7F) << $i); - } - - /* compare sha1_file.c:1608 unpack_entry */ - if ($type == Git::OBJ_COMMIT || $type == Git::OBJ_TREE || $type == Git::OBJ_BLOB || $type == Git::OBJ_TAG) - { - /* - * We don't know the actual size of the compressed - * data, so we'll assume it's less than - * $object_size+512. - * - * FIXME use PHP stream filter API as soon as it behaves - * consistently - */ - $data = gzuncompress(fread($pack, $size+512), $size); - } - else if ($type == Git::OBJ_OFS_DELTA) - { - /* 20 = maximum varint length for offset */ - $buf = fread($pack, $size+512+20); - - /* - * contrary to varints in other places, this one is big endian - * (and 1 is added each turn) - * see sha1_file.c (get_delta_base) - */ - $pos = 0; - $offset = -1; - do - { - $offset++; - $c = ord($buf{$pos++}); - $offset = ($offset << 7) + ($c & 0x7F); - } - while ($c & 0x80); - - $delta = gzuncompress(substr($buf, $pos), $size); - unset($buf); - - $base_offset = $object_offset - $offset; - assert($base_offset >= 0); - list($type, $base) = $this->unpackObject($pack, $base_offset); - - $data = $this->applyDelta($delta, $base); - } - else if ($type == Git::OBJ_REF_DELTA) - { - $base_name = fread($pack, 20); - list($type, $base) = $this->getRawObject($base_name); - - // $size is the length of the uncompressed delta - $delta = gzuncompress(fread($pack, $size+512), $size); - - $data = $this->applyDelta($delta, $base); - } - else - throw new Exception(sprintf('object of unknown type %d', $type)); - - return array($type, $data); - } - - /** - * @brief Fetch an object in its binary representation by name. - * - * Throws an exception if the object cannot be found. - * - * @param $object_name (string) name of the object (binary SHA1) - * @returns (array) an array consisting of the object type (int) and the - * binary representation of the object (string) - */ - protected function getRawObject($object_name) - { - static $cache = array(); - /* FIXME allow limiting the cache to a certain size */ - - if (isset($cache[$object_name])) - return $cache[$object_name]; - $sha1 = sha1_hex($object_name); - $path = sprintf('%s/objects/%s/%s', $this->dir, substr($sha1, 0, 2), substr($sha1, 2)); - if (file_exists($path)) - { - list($hdr, $object_data) = explode("\0", gzuncompress(file_get_contents($path)), 2); - - sscanf($hdr, "%s %d", $type, $object_size); - $object_type = Git::getTypeID($type); - $r = array($object_type, $object_data); - } - else if ($x = $this->findPackedObject($object_name)) - { - list($pack_name, $object_offset) = $x; - - $pack = fopen(sprintf('%s/objects/pack/pack-%s.pack', $this->dir, sha1_hex($pack_name)), 'rb'); - flock($pack, LOCK_SH); - - /* check magic and version */ - $magic = fread($pack, 4); - $version = Binary::fuint32($pack); - if ($magic != 'PACK' || $version != 2) - throw new Exception('unsupported pack format'); - - $r = $this->unpackObject($pack, $object_offset); - fclose($pack); - } - else - throw new Exception(sprintf('object not found: %s', sha1_hex($object_name))); - $cache[$object_name] = $r; - return $r; - } - - /** - * @brief Fetch an object in its PHP representation. - * - * @param $name (string) name of the object (binary SHA1) - * @returns (GitObject) the object - */ - public function getObject($name) - { - list($type, $data) = $this->getRawObject($name); - $object = GitObject::create($this, $type); - $object->unserialize($data); - assert($name == $object->getName()); - return $object; - } - - /** - * @brief Look up a branch. - * - * @param $branch (string) The branch to look up, defaulting to @em master. - * @returns (string) The tip of the branch (binary sha1). - */ - public function getTip($branch='master') - { - $subpath = sprintf('refs/heads/%s', $branch); - $path = sprintf('%s/%s', $this->dir, $subpath); - if (file_exists($path)) - return sha1_bin(file_get_contents($path)); - $path = sprintf('%s/packed-refs', $this->dir); - if (file_exists($path)) - { - $head = NULL; - $f = fopen($path, 'rb'); - flock($f, LOCK_SH); - while ($head === NULL && ($line = fgets($f)) !== FALSE) - { - if ($line{0} == '#') - continue; - $parts = explode(' ', trim($line)); - if (count($parts) == 2 && $parts[1] == $subpath) - $head = sha1_bin($parts[0]); - } - fclose($f); - if ($head !== NULL) - return $head; - } - throw new Exception(sprintf('no such branch: %s', $branch)); - } -} - diff --git a/lib/git_blob.class.php b/lib/git_blob.class.php deleted file mode 100644 index da6983e..0000000 --- a/lib/git_blob.class.php +++ /dev/null @@ -1,45 +0,0 @@ -. - */ - -require_once('git_object.class.php'); - -class GitBlob extends GitObject -{ - /** - * @brief The data contained in this blob. - */ - public $data = NULL; - - public function __construct($repo) - { - parent::__construct($repo, Git::OBJ_BLOB); - } - - public function _unserialize($data) - { - $this->data = $data; - } - - public function _serialize() - { - return $this->data; - } -} - diff --git a/lib/git_commit.class.php b/lib/git_commit.class.php deleted file mode 100644 index 0252a36..0000000 --- a/lib/git_commit.class.php +++ /dev/null @@ -1,174 +0,0 @@ -. - */ - -require_once('git_object.class.php'); -require_once('git_commit_stamp.class.php'); - -class GitCommit extends GitObject -{ - /** - * @brief (string) The tree referenced by this commit, as binary sha1 - * string. - */ - public $tree; - - /** - * @brief (array of string) Parent commits of this commit, as binary sha1 - * strings. - */ - public $parents; - - /** - * @brief (GitCommitStamp) The author of this commit. - */ - public $author; - - /** - * @brief (GitCommitStamp) The committer of this commit. - */ - public $committer; - - /** - * @brief (string) Commit summary, i.e. the first line of the commit message. - */ - public $summary; - - /** - * @brief (string) Everything after the first line of the commit message. - */ - public $detail; - - public function __construct($repo) - { - parent::__construct($repo, Git::OBJ_COMMIT); - } - - public function _unserialize($data) - { - $lines = explode("\n", $data); - unset($data); - $meta = array('parent' => array()); - while (($line = array_shift($lines)) != '') - { - $parts = explode(' ', $line, 2); - if (!isset($meta[$parts[0]])) - $meta[$parts[0]] = array($parts[1]); - else - $meta[$parts[0]][] = $parts[1]; - } - - $this->tree = sha1_bin($meta['tree'][0]); - $this->parents = array_map('sha1_bin', $meta['parent']); - $this->author = new GitCommitStamp; - $this->author->unserialize($meta['author'][0]); - $this->committer = new GitCommitStamp; - $this->committer->unserialize($meta['committer'][0]); - - $this->summary = array_shift($lines); - $this->detail = implode("\n", $lines); - - $this->history = NULL; - } - - public function _serialize() - { - $s = ''; - $s .= sprintf("tree %s\n", sha1_hex($this->tree)); - foreach ($this->parents as $parent) - $s .= sprintf("parent %s\n", sha1_hex($parent)); - $s .= sprintf("author %s\n", $this->author->serialize()); - $s .= sprintf("committer %s\n", $this->committer->serialize()); - $s .= "\n".$this->summary."\n".$this->detail; - return $s; - } - - /** - * @brief Get commit history in topological order. - * - * @returns (array of GitCommit) - */ - public function getHistory() - { - if ($this->history) - return $this->history; - - /* count incoming edges */ - $inc = array(); - - $queue = array($this); - while (($commit = array_shift($queue)) !== NULL) - { - foreach ($commit->parents as $parent) - { - if (!isset($inc[$parent])) - { - $inc[$parent] = 1; - $queue[] = $this->repo->getObject($parent); - } - else - $inc[$parent]++; - } - } - - $queue = array($this); - $r = array(); - while (($commit = array_pop($queue)) !== NULL) - { - array_unshift($r, $commit); - foreach ($commit->parents as $parent) - { - if (--$inc[$parent] == 0) - $queue[] = $this->repo->getObject($parent); - } - } - - $this->history = $r; - return $r; - } - - /** - * @brief Get the tree referenced by this commit. - * - * @returns The GitTree referenced by this commit. - */ - public function getTree() - { - return $this->repo->getObject($this->tree); - } - - /** - * @copybrief GitTree::find() - * - * This is a convenience function calling GitTree::find() on the commit's - * tree. - * - * @copydetails GitTree::find() - */ - public function find($path) - { - return $this->getTree()->find($path); - } - - static public function treeDiff($a, $b) - { - return GitTree::treeDiff($a ? $a->getTree() : NULL, $b ? $b->getTree() : NULL); - } -} - diff --git a/lib/git_commit_stamp.class.php b/lib/git_commit_stamp.class.php deleted file mode 100644 index 9bc075b..0000000 --- a/lib/git_commit_stamp.class.php +++ /dev/null @@ -1,45 +0,0 @@ -. - */ - -class GitCommitStamp -{ - public $name; - public $email; - public $time; - public $offset; - - public function unserialize($data) - { - assert(preg_match('/^(.+?)\s+<(.+?)>\s+(\d+)\s+([+-]\d{4})$/', $data, $m)); - $this->name = $m[1]; - $this->email = $m[2]; - $this->time = intval($m[3]); - $off = intval($m[4]); - $this->offset = ($off/100) * 3600 + ($off%100) * 60; - } - - public function serialize() - { - if ($this->offset%60) - throw new Exception('cannot serialize sub-minute timezone offset'); - return sprintf('%s <%s> %d %+05d', $this->name, $this->email, $this->time, ($this->offset/3600)*100 + ($this->offset/60)%60); - } -} - diff --git a/lib/git_object.class.php b/lib/git_object.class.php deleted file mode 100644 index c4c67c3..0000000 --- a/lib/git_object.class.php +++ /dev/null @@ -1,154 +0,0 @@ -. - */ - -class GitObject -{ - /** - * @brief (Git) The repository this object belongs to. - */ - public $repo; - protected $type; - protected $name = NULL; - - /** - * @brief Get the object's cached SHA-1 hash value. - * - * @returns (string) The hash value (binary sha1). - */ - public function getName() { return $this->name; } - - /** - * @brief Get the object's type. - * - * @returns (integer) One of Git::OBJ_COMMIT, Git::OBJ_TREE or - * GIT::OBJ_BLOB. - */ - public function getType() { return $this->type; } - - /** - * @brief Create a GitObject of the specified type. - * - * @param $repo (Git) The repository the object belongs to. - * @param $type (integer) Object type (one of Git::OBJ_COMMIT, - * Git::OBJ_TREE, Git::OBJ_BLOB). - * @returns A new GitCommit, GitTree or GitBlob object respectively. - */ - static public function create($repo, $type) - { - if ($type == Git::OBJ_COMMIT) - return new GitCommit($repo); - if ($type == Git::OBJ_TREE) - return new GitTree($repo); - if ($type == Git::OBJ_BLOB) - return new GitBlob($repo); - throw new Exception(sprintf('unhandled object type %d', $type)); - } - - /** - * @brief Internal function to calculate the hash value of a git object of the - * current type with content $data. - * - * @param $data (string) The data to hash. - * @returns (string) The hash value (binary sha1). - */ - protected function hash($data) - { - $hash = hash_init('sha1'); - hash_update($hash, Git::getTypeName($this->type)); - hash_update($hash, ' '); - hash_update($hash, strlen($data)); - hash_update($hash, "\0"); - hash_update($hash, $data); - return hash_final($hash, TRUE); - } - - /** - * @brief Internal constructor for use from derived classes. - * - * Never use this function except from a derived class. Use the - * constructor of a derived class, create() or Git::getObject() instead. - */ - public function __construct($repo, $type) - { - $this->repo = $repo; - $this->type = $type; - } - - /** - * @brief Populate this object with values from its string representation. - * - * Note that the types of $this and the serialized object in $data have to - * match. - * - * @param $data (string) The serialized representation of an object, as - * it would be stored by git. - */ - public function unserialize($data) - { - $this->name = $this->hash($data); - $this->_unserialize($data); - } - - /** - * @brief Get the string representation of an object. - * - * @returns The serialized representation of the object, as it would be - * stored by git. - */ - public function serialize() - { - return $this->_serialize(); - } - - /** - * @brief Update the SHA-1 name of an object. - * - * You need to call this function after making changes to attributes in - * order to have getName() return the correct hash. - */ - public function rehash() - { - $this->name = $this->hash($this->serialize()); - } - - /** - * @brief Write this object in its serialized form to the git repository - * given at creation time. - */ - public function write() - { - $sha1 = sha1_hex($this->name); - $path = sprintf('%s/objects/%s/%s', $this->repo->dir, substr($sha1, 0, 2), substr($sha1, 2)); - if (file_exists($path)) - return FALSE; - $dir = dirname($path); - if (!is_dir($dir)) - mkdir(dirname($path), 0770); - $f = fopen($path, 'ab'); - flock($f, LOCK_EX); - ftruncate($f, 0); - $data = $this->serialize(); - $data = Git::getTypeName($this->type).' '.strlen($data)."\0".$data; - fwrite($f, gzcompress($data)); - fclose($f); - return TRUE; - } -} - diff --git a/lib/git_tree.class.php b/lib/git_tree.class.php deleted file mode 100644 index f7a0495..0000000 --- a/lib/git_tree.class.php +++ /dev/null @@ -1,267 +0,0 @@ -. - */ - -class GitTreeError extends Exception {} -class GitTreeInvalidPathError extends GitTreeError {} - -require_once('git_object.class.php'); - -class GitTree extends GitObject -{ - public $nodes = array(); - - public function __construct($repo) - { - parent::__construct($repo, Git::OBJ_TREE); - } - - public function _unserialize($data) - { - $this->nodes = array(); - $start = 0; - while ($start < strlen($data)) - { - $node = new stdClass; - - $pos = strpos($data, "\0", $start); - list($node->mode, $node->name) = explode(' ', substr($data, $start, $pos-$start), 2); - $node->mode = intval($node->mode, 8); - $node->is_dir = !!($node->mode & 040000); - $node->is_submodule = ($node->mode == 57344); - $node->object = substr($data, $pos+1, 20); - $start = $pos+21; - - $this->nodes[$node->name] = $node; - } - unset($data); - } - - protected static function nodecmp(&$a, &$b) - { - return strcmp($a->name, $b->name); - } - - public function _serialize() - { - $s = ''; - /* git requires nodes to be sorted */ - uasort($this->nodes, array('GitTree', 'nodecmp')); - foreach ($this->nodes as $node) - $s .= sprintf("%s %s\0%s", base_convert($node->mode, 10, 8), $node->name, $node->object); - return $s; - } - - /** - * @brief Find the tree or blob at a certain path. - * - * @throws GitTreeInvalidPathError The path was found to be invalid. This - * can happen if you are trying to treat a file like a directory (i.e. - * @em foo/bar where @em foo is a file). - * - * @param $path (string) The path to look for, relative to this tree. - * @returns The GitTree or GitBlob at the specified path, or NULL if none - * could be found. - */ - public function find($path) - { - if (!is_array($path)) - $path = explode('/', $path); - - while ($path && !$path[0]) - array_shift($path); - if (!$path) - return $this->getName(); - - if (!isset($this->nodes[$path[0]])) - return NULL; - $cur = $this->nodes[$path[0]]->object; - - array_shift($path); - while ($path && !$path[0]) - array_shift($path); - - if (!$path) - return $cur; - else - { - $cur = $this->repo->getObject($cur); - if (!($cur instanceof GitTree)) - throw new GitTreeInvalidPathError; - return $cur->find($path); - } - } - - /** - * @brief Recursively list the contents of a tree. - * - * @returns (array mapping string to string) An array where the keys are - * paths relative to the current tree, and the values are SHA-1 names of - * the corresponding blobs in binary representation. - */ - public function listRecursive() - { - $r = array(); - - foreach ($this->nodes as $node) - { - if ($node->is_dir) - { - if ($node->is_submodule) - { - $r[$node->name. ':submodule'] = $node->object; - } - else - { - $subtree = $this->repo->getObject($node->object); - foreach ($subtree->listRecursive() as $entry => $blob) - { - $r[$node->name . '/' . $entry] = $blob; - } - } - } - else - { - $r[$node->name] = $node->object; - } - } - - return $r; - } - - /** - * @brief Updates a node in this tree. - * - * Missing directories in the path will be created automatically. - * - * @param $path (string) Path to the node, relative to this tree. - * @param $mode Git mode to set the node to. 0 if the node shall be - * cleared, i.e. the tree or blob shall be removed from this path. - * @param $object (string) Binary SHA-1 hash of the object that shall be - * placed at the given path. - * - * @returns (array of GitObject) An array of GitObject%s that were newly - * created while updating the specified node. Those need to be written to - * the repository together with the modified tree. - */ - public function updateNode($path, $mode, $object) - { - if (!is_array($path)) - $path = explode('/', $path); - $name = array_shift($path); - if (count($path) == 0) - { - /* create leaf node */ - if ($mode) - { - $node = new stdClass; - $node->mode = $mode; - $node->name = $name; - $node->object = $object; - $node->is_dir = !!($mode & 040000); - - $this->nodes[$node->name] = $node; - } - else - unset($this->nodes[$name]); - - return array(); - } - else - { - /* descend one level */ - if (isset($this->nodes[$name])) - { - $node = $this->nodes[$name]; - if (!$node->is_dir) - throw new GitTreeInvalidPathError; - $subtree = clone $this->repo->getObject($node->object); - } - else - { - /* create new tree */ - $subtree = new GitTree($this->repo); - - $node = new stdClass; - $node->mode = 040000; - $node->name = $name; - $node->is_dir = TRUE; - - $this->nodes[$node->name] = $node; - } - $pending = $subtree->updateNode($path, $mode, $object); - - $subtree->rehash(); - $node->object = $subtree->getName(); - - $pending[] = $subtree; - return $pending; - } - } - - const TREEDIFF_A = 0x01; - const TREEDIFF_B = 0x02; - - const TREEDIFF_REMOVED = self::TREEDIFF_A; - const TREEDIFF_ADDED = self::TREEDIFF_B; - const TREEDIFF_CHANGED = 0x03; - - static public function treeDiff($a_tree, $b_tree) - { - $a_blobs = $a_tree ? $a_tree->listRecursive() : array(); - $b_blobs = $b_tree ? $b_tree->listRecursive() : array(); - - $a_files = array_keys($a_blobs); - $b_files = array_keys($b_blobs); - - $changes = array(); - - sort($a_files); - sort($b_files); - $a = $b = 0; - while ($a < count($a_files) || $b < count($b_files)) - { - if ($a < count($a_files) && $b < count($b_files)) - $cmp = strcmp($a_files[$a], $b_files[$b]); - else - $cmp = 0; - if ($b >= count($b_files) || $cmp < 0) - { - $changes[$a_files[$a]] = self::TREEDIFF_REMOVED; - $a++; - } - else if ($a >= count($a_files) || $cmp > 0) - { - $changes[$b_files[$b]] = self::TREEDIFF_ADDED; - $b++; - } - else - { - if ($a_blobs[$a_files[$a]] != $b_blobs[$b_files[$b]]) - $changes[$a_files[$a]] = self::TREEDIFF_CHANGED; - - $a++; - $b++; - } - } - - return $changes; - } -} - diff --git a/lib/glip.php b/lib/glip.php deleted file mode 100644 index a414f36..0000000 --- a/lib/glip.php +++ /dev/null @@ -1,24 +0,0 @@ -. - */ - -$old_include_path = set_include_path(dirname(__FILE__)); -require_once('git.class.php'); -set_include_path($old_include_path); - diff --git a/test.php b/test.php deleted file mode 100644 index 197837d..0000000 --- a/test.php +++ /dev/null @@ -1,3 +0,0 @@ -