.gitignore 0000664 0000000 0000000 00000000414 15161025004 0013037 0 ustar 00root root 0000000 0000000 cache/
vendor/
build/
*.diff
*.err
*.orig
*.log
*.rej
*.swo
*.swp
*.zip
*.vi
*~
*.sass-cache
.DS_Store
._*
Thumbs.db
.cache
.project
.settings
.tmproj
*.esproj
nbproject
*.sublime-project
*.sublime-workspace
.hg
.svn
.CVS
.idea
node_modules
config.ini
cache.properties .htaccess 0000664 0000000 0000000 00000000336 15161025004 0012650 0 ustar 00root root 0000000 0000000
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
order allow,deny
deny from all
.travis.yml 0000664 0000000 0000000 00000000234 15161025004 0013160 0 ustar 00root root 0000000 0000000 language: php
before_script:
- curl -s http://getcomposer.org/installer | php
- php composer.phar install --dev
php:
- 5.3
- 5.4
script: phpunit
LICENSE.txt 0000664 0000000 0000000 00000002705 15161025004 0012677 0 ustar 00root root 0000000 0000000 Copyright (c) 2012, Klaus Silveira and contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of GitList nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
README.md 0000664 0000000 0000000 00000012005 15161025004 0012325 0 ustar 00root root 0000000 0000000 # GitList: an elegant and modern git repository viewer
[](http://travis-ci.org/klaussilveira/gitlist)
GitList is an elegant and modern web interface for interacting with multiple git repositories. It allows you to browse repositories using your favorite browser, viewing files under different revisions, commit history, diffs. It also generates RSS feeds for each repository, allowing you to stay up-to-date with the latest changes anytime, anywhere. GitList was written in PHP, on top of the [Silex](http://silex.sensiolabs.org/) microframework and powered by the Twig template engine. This means that GitList is easy to install and easy to customize. Also, the GitList gorgeous interface was made possible due to [Bootstrap](http://twitter.github.com/bootstrap/).
## Features
* Multiple repository support
* Multiple branch support
* Multiple tag support
* Commit history, blame, diff
* RSS feeds
* Syntax highlighting
* Repository statistics
## Screenshots
[](http://cloud.github.com/downloads/klaussilveira/gitlist/1.jpg)
[](http://cloud.github.com/downloads/klaussilveira/gitlist/2.jpg)
[](http://cloud.github.com/downloads/klaussilveira/gitlist/3.jpg)
[](http://cloud.github.com/downloads/klaussilveira/gitlist/4.jpg)
[](http://cloud.github.com/downloads/klaussilveira/gitlist/5.jpg)
You can also see a live demo [here](http://git.gofedora.com).
## Authors and contributors
* [Klaus Silveira](http://www.klaussilveira.com) (Creator, developer)
## License
[New BSD license](http://www.opensource.org/licenses/bsd-license.php)
## Todo
* improve the current test code coverage
* test the interface
* error handling can be greatly improved during parsing
* submodule support
* multilanguage support
## Requirements
In order to run GitList on your server, you'll need:
* git
* Apache with mod_rewrite enabled or nginx
* PHP 5.3.3
## Installing
* Download GitList from [gitlist.org](http://gitlist.org/) and decompress to your `/var/www/gitlist` folder, or anywhere else you want to place GitList.
* Rename the `config.ini-example` file to `config.ini`.
* Open up the `config.ini` and configure your installation. You'll have to provide where your repositories are located and the base GitList URL (in our case, http://localhost/gitlist).
* Create the cache folder and give the correct permissions:
```
cd /var/www/gitlist
mkdir cache
chmod 777 cache
```
That's it, installation complete! If you're having problems, check this [tutorial](http://gofedora.com/insanely-awesome-web-interface-git-repos/) by Kulbir Saini or the [Troubleshooting](https://github.com/klaussilveira/gitlist/wiki/Troubleshooting) page.
## Building
GitList uses [Composer](http://getcomposer.org/) to manage dependencies and [Ant](http://ant.apache.org/) to build the project. In order to run all the targets in the build script, you will need [PHPUnit](http://www.phpunit.de/), [phpcpd](https://github.com/sebastianbergmann/phpcpd), [phploc](https://github.com/sebastianbergmann/phploc), [PHPMD](http://phpmd.org/) and [PHP_Depend](http://pdepend.org).
Once you have all the dependencies set, you can clone the repository and run Ant:
```
git clone https://github.com/klaussilveira/gitlist.git
ant
```
If you just want to get the project dependencies, instead of building everything:
```
git clone https://github.com/klaussilveira/gitlist.git
curl -s http://getcomposer.org/installer | php
php composer.phar install
```
If you have Composer in your path, things get easier. But you know the drill.
## Contributing
If you are a developer, we need your help. GitList is a young project and we have lot's of stuff to do. Some developers are contributing with new features, others with bug fixes. But you can also dedicate yourself to refactoring the current codebase and improving what we already have. This is very important, we want GitList to be a state-of-the-art application, and we need your help for that.
* Stay tuned to possible bugs, suboptimal code, duplicated code, overcomplicated expressions and unused code with [PHPMD](http://ci.gitlist.org:8080/job/GitList%20\(master\)/9/pmdResult/?) in our CI server
* Try to fix any [violations](http://ci.gitlist.org:8080/job/GitList%20\(master\)/violations/) reported
* Improve the [test coverage](http://ci.gitlist.org:8080/job/GitList%20\(master\)/9/cloverphp-report/) by creating unit and functional tests
## Further information
If you want to know more about customizing GitList, check the [Customization](https://github.com/klaussilveira/gitlist/wiki/Customizing) page on the wiki. Also, if you're having problems with GitList, check the [Troubleshooting](https://github.com/klaussilveira/gitlist/wiki/Troubleshooting) page. Don't forget to report issues and suggest new features! :)
build.xml 0000664 0000000 0000000 00000006475 15161025004 0012705 0 ustar 00root root 0000000 0000000
composer.json 0000664 0000000 0000000 00000000433 15161025004 0013572 0 ustar 00root root 0000000 0000000 {
"require": {
"silex/silex": "1.0.*",
"twig/twig": "1.8.*",
"symfony/twig-bridge": "2.1.*",
"symfony/filesystem": "2.1.*"
},
"minimum-stability": "dev",
"autoload": {
"psr-0": {
"GitList": "lib/"
}
}
}
composer.lock 0000664 0000000 0000000 00000007144 15161025004 0013557 0 ustar 00root root 0000000 0000000 {
"hash": "c79508061cbc4f6754d227089129fa14",
"packages": [
{
"package": "pimple/pimple",
"version": "dev-master",
"alias-pretty-version": "1.0.x-dev",
"alias-version": "1.0.9999999.9999999-dev"
},
{
"package": "pimple/pimple",
"version": "dev-master",
"source-reference": "d2cfa2f02f50abef65c238747c753a5f6786f6be",
"commit-date": "1341139100"
},
{
"package": "silex/silex",
"version": "dev-master",
"alias-pretty-version": "1.0.x-dev",
"alias-version": "1.0.9999999.9999999-dev"
},
{
"package": "silex/silex",
"version": "dev-master",
"source-reference": "18e248a277adb061602d2bcabe96011db1c76ec0",
"commit-date": "1342208524"
},
{
"package": "symfony/event-dispatcher",
"version": "dev-master",
"alias-pretty-version": "2.1.x-dev",
"alias-version": "2.1.9999999.9999999-dev"
},
{
"package": "symfony/event-dispatcher",
"version": "dev-master",
"source-reference": "b99b49760016467099f010aff7a5098861d49e09",
"commit-date": "1342207366"
},
{
"package": "symfony/filesystem",
"version": "dev-master",
"alias-pretty-version": "2.1.x-dev",
"alias-version": "2.1.9999999.9999999-dev"
},
{
"package": "symfony/filesystem",
"version": "dev-master",
"source-reference": "7d1b311f8c37136bd99510c069878d72ecff1897",
"commit-date": "1342207366"
},
{
"package": "symfony/http-foundation",
"version": "dev-master",
"alias-pretty-version": "2.1.x-dev",
"alias-version": "2.1.9999999.9999999-dev"
},
{
"package": "symfony/http-foundation",
"version": "dev-master",
"source-reference": "498c2da9c3fecefc7e3b0add73621f3feb337ddd",
"commit-date": "1342207366"
},
{
"package": "symfony/http-kernel",
"version": "dev-master",
"alias-pretty-version": "2.1.x-dev",
"alias-version": "2.1.9999999.9999999-dev"
},
{
"package": "symfony/http-kernel",
"version": "dev-master",
"source-reference": "efedca5d30added6a21fc6ae8356617ad1c80de7",
"commit-date": "1342271095"
},
{
"package": "symfony/routing",
"version": "dev-master",
"alias-pretty-version": "2.1.x-dev",
"alias-version": "2.1.9999999.9999999-dev"
},
{
"package": "symfony/routing",
"version": "dev-master",
"source-reference": "6bca82c3ea0d42d750de4f49b22020dfd047dc0f",
"commit-date": "1342207366"
},
{
"package": "symfony/twig-bridge",
"version": "dev-master",
"alias-pretty-version": "2.1.x-dev",
"alias-version": "2.1.9999999.9999999-dev"
},
{
"package": "symfony/twig-bridge",
"version": "dev-master",
"source-reference": "944be0979f02e929b61d0a6633dd51bef0f5c618",
"commit-date": "1342260629"
},
{
"package": "twig/twig",
"version": "v1.8.3"
}
],
"packages-dev": null,
"aliases": [
],
"minimum-stability": "dev",
"stability-flags": [
]
}
config.ini-example 0000664 0000000 0000000 00000000622 15161025004 0014447 0 ustar 00root root 0000000 0000000 [git]
client = '/usr/bin/git' ; Your git executable path
repositories = '/var/www/projects/' ; Path to your repositories
; You can hide repositories from GitList, just copy this for each repository you want to hide
; hidden[] = '/var/www/projects/BetaTest'
[app]
debug = false
; If you need to specify custom filetypes for certain extensions, do this here
[filetypes]
; extension = type
; dist = xml index.php 0000664 0000000 0000000 00000001231 15161025004 0012665 0 ustar 00root root 0000000 0000000 set('git', 'repositories', rtrim($config->get('git', 'repositories'), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR);
// Startup and configure Silex application
$app = new GitList\Application($config, __DIR__);
// Mount the controllers
$app->mount('', new GitList\Controller\MainController());
$app->mount('', new GitList\Controller\BlobController());
$app->mount('', new GitList\Controller\CommitController());
$app->mount('', new GitList\Controller\TreeController());
$app->run();
lib/ 0000775 0000000 0000000 00000000000 15161025004 0011616 5 ustar 00root root 0000000 0000000 lib/GitList/ 0000775 0000000 0000000 00000000000 15161025004 0013175 5 ustar 00root root 0000000 0000000 lib/GitList/Application.php 0000664 0000000 0000000 00000004134 15161025004 0016153 0 ustar 00root root 0000000 0000000 get('app', 'debug');
$this['filetypes'] = $config->getSection('filetypes');
$this['cache.archives'] = $root . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'archives';
// Register services
$this->register(new TwigServiceProvider(), array(
'twig.path' => $root . DIRECTORY_SEPARATOR . 'views',
'twig.options' => array('cache' => $root . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'views'),
));
$this->register(new GitServiceProvider(), array(
'git.client' => $config->get('git', 'client'),
'git.repos' => $config->get('git', 'repositories'),
'git.hidden' => $config->get('git', 'hidden') ? $config->get('git', 'hidden') : array(),
));
$this->register(new ViewUtilServiceProvider());
$this->register(new RepositoryUtilServiceProvider());
$this->register(new UrlGeneratorServiceProvider());
$this['twig'] = $this->share($this->extend('twig', function($twig, $app) {
$twig->addFilter('md5', new \Twig_Filter_Function('md5'));
return $twig;
}));
// Handle errors
$this->error(function (\Exception $e, $code) use ($app) {
return $app['twig']->render('error.twig', array(
'message' => $e->getMessage(),
));
});
}
}
lib/GitList/Component/ 0000775 0000000 0000000 00000000000 15161025004 0015137 5 ustar 00root root 0000000 0000000 lib/GitList/Component/Git/ 0000775 0000000 0000000 00000000000 15161025004 0015662 5 ustar 00root root 0000000 0000000 lib/GitList/Component/Git/Client.php 0000664 0000000 0000000 00000012571 15161025004 0017617 0 ustar 00root root 0000000 0000000 setPath($options['path']);
$this->setHidden($options['hidden']);
}
/**
* Creates a new repository on the specified path
*
* @param string $path Path where the new repository will be created
* @return Repository Instance of Repository
*/
public function createRepository($path)
{
if (file_exists($path . '/.git/HEAD') && !file_exists($path . '/HEAD')) {
throw new \RuntimeException('A GIT repository already exists at ' . $path);
}
$repository = new Repository($path, $this);
return $repository->create();
}
/**
* Opens a repository at the specified path
*
* @param string $path Path where the repository is located
* @return Repository Instance of Repository
*/
public function getRepository($path)
{
if (!file_exists($path) || !file_exists($path . '/.git/HEAD') && !file_exists($path . '/HEAD')) {
throw new \RuntimeException('There is no GIT repository at ' . $path);
}
if (in_array($path, $this->getHidden())) {
throw new \RuntimeException('You don\'t have access to this repository');
}
return new Repository($path, $this);
}
/**
* Searches for valid repositories on the specified path
*
* @param string $path Path where repositories will be searched
* @return array Found repositories, containing their name, path and description
*/
public function getRepositories($path)
{
$repositories = $this->recurseDirectory($path);
if (empty($repositories)) {
throw new \RuntimeException('There are no GIT repositories in ' . $path);
}
sort($repositories);
return $repositories;
}
private function recurseDirectory($path)
{
$dir = new \DirectoryIterator($path);
$repositories = array();
foreach ($dir as $file) {
if ($file->isDot()) {
continue;
}
if (($pos = strrpos($file->getFilename(), '.')) === 0) {
continue;
}
if ($file->isDir()) {
$isBare = file_exists($file->getPathname() . '/HEAD');
$isRepository = file_exists($file->getPathname() . '/.git/HEAD');
if ($isRepository || $isBare) {
if (in_array($file->getPathname(), $this->getHidden())) {
continue;
}
if ($isBare) {
$description = $file->getPathname() . '/description';
} else {
$description = $file->getPathname() . '/.git/description';
}
if (file_exists($description)) {
$description = file_get_contents($description);
} else {
$description = 'There is no repository description file. Please, create one to remove this message.';
}
$repositories[] = array('name' => $file->getFilename(), 'path' => $file->getPathname(), 'description' => $description);
continue;
}
}
}
return $repositories;
}
/**
* Execute a git command on the repository being manipulated
*
* This method will start a new process on the current machine and
* run git commands. Once the command has been run, the method will
* return the command line output.
*
* @param Repository $repository Repository where the command will be run
* @param string $command Git command to be run
* @return string Returns the command output
*/
public function run(Repository $repository, $command)
{
$descriptors = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w"));
$process = proc_open($this->getPath() . ' ' . $command, $descriptors, $pipes, $repository->getPath());
if (!is_resource($process)) {
throw new \RuntimeException('Unable to execute command: ' . $command);
}
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
if (!empty($stderr)) {
throw new \RuntimeException($stderr);
}
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
proc_close($process);
return $stdout;
}
/**
* Get the current Git binary path
*
* @return string Path where the Git binary is located
*/
protected function getPath()
{
return $this->path;
}
/**
* Set the current Git binary path
*
* @param string $path Path where the Git binary is located
*/
protected function setPath($path)
{
$this->path = $path;
}
/**
* Get hidden repository list
*
* @return array List of repositories to hide
*/
protected function getHidden()
{
return $this->hidden;
}
/**
* Set the hidden repository list
*
* @param array $hidden List of repositories to hide
*/
protected function setHidden($hidden)
{
$this->hidden = $hidden;
}
}
lib/GitList/Component/Git/Commit/ 0000775 0000000 0000000 00000000000 15161025004 0017112 5 ustar 00root root 0000000 0000000 lib/GitList/Component/Git/Commit/Author.php 0000664 0000000 0000000 00000001026 15161025004 0021064 0 ustar 00root root 0000000 0000000 setName($name);
$this->setEmail($email);
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function getEmail()
{
return $this->email;
}
public function setEmail($email)
{
$this->email = $email;
}
}
lib/GitList/Component/Git/Commit/Commit.php 0000664 0000000 0000000 00000005273 15161025004 0021062 0 ustar 00root root 0000000 0000000 setHash($data['hash']);
$this->setShortHash($data['short_hash']);
$this->setTreeHash($data['tree']);
$this->setParentHash($data['parent']);
$this->setAuthor(
new Author($data['author'], $data['author_email'])
);
$this->setDate(
new \DateTime('@' . $data['date'])
);
$this->setCommiter(
new Author($data['commiter'], $data['commiter_email'])
);
$this->setCommiterDate(
new \DateTime('@' . $data['commiter_date'])
);
$this->setMessage($data['message']);
}
public function getHash()
{
return $this->hash;
}
public function setHash($hash)
{
$this->hash = $hash;
}
public function getShortHash()
{
return $this->shortHash;
}
public function setShortHash($shortHash)
{
$this->shortHash = $shortHash;
}
public function getTreeHash()
{
return $this->treeHash;
}
public function setTreeHash($treeHash)
{
$this->treeHash = $treeHash;
}
public function getParentHash()
{
return $this->parentHash;
}
public function setParentHash($parentHash)
{
$this->parentHash = $parentHash;
}
public function getAuthor()
{
return $this->author;
}
public function setAuthor($author)
{
$this->author = $author;
}
public function getDate()
{
return $this->date;
}
public function setDate($date)
{
$this->date = $date;
}
public function getCommiter()
{
return $this->commiter;
}
public function setCommiter($commiter)
{
$this->commiter = $commiter;
}
public function getCommiterDate()
{
return $this->commiterDate;
}
public function setCommiterDate($commiterDate)
{
$this->commiterDate = $commiterDate;
}
public function getMessage()
{
return $this->message;
}
public function setMessage($message)
{
$this->message = $message;
}
public function getDiffs()
{
return $this->diffs;
}
public function setDiffs($diffs)
{
$this->diffs = $diffs;
}
public function getChangedFiles()
{
return sizeof($this->diffs);
}
}
lib/GitList/Component/Git/Model/ 0000775 0000000 0000000 00000000000 15161025004 0016722 5 ustar 00root root 0000000 0000000 lib/GitList/Component/Git/Model/Blob.php 0000664 0000000 0000000 00000002313 15161025004 0020310 0 ustar 00root root 0000000 0000000 setClient($client);
$this->setRepository($repository);
$this->setHash($hash);
}
public function output()
{
$data = $this->getClient()->run($this->getRepository(), 'show ' . $this->getHash());
return $data;
}
public function getMode()
{
return $this->mode;
}
public function setMode($mode)
{
$this->mode = $mode;
}
public function getHash()
{
return $this->hash;
}
public function setHash($hash)
{
$this->hash = $hash;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function getSize()
{
return $this->size;
}
public function setSize($size)
{
$this->size = $size;
}
}
lib/GitList/Component/Git/Model/Diff.php 0000664 0000000 0000000 00000001673 15161025004 0020312 0 ustar 00root root 0000000 0000000 lines[] = new Line($line);
}
public function getLines()
{
return $this->lines;
}
public function setIndex($index)
{
$this->index = $index;
}
public function getIndex()
{
return $this->index;
}
public function setOld($old)
{
$this->old = $old;
}
public function getOld()
{
return $this->old;
}
public function setNew($new)
{
$this->new = $new;
}
public function getNew()
{
return $this->new;
}
public function setFile($file)
{
$this->file = $file;
}
public function getFile()
{
return $this->file;
}
}
lib/GitList/Component/Git/Model/Line.php 0000664 0000000 0000000 00000001427 15161025004 0020326 0 ustar 00root root 0000000 0000000 setType('chunk');
}
if ($data[0] == '-') {
$this->setType('old');
}
if ($data[0] == '+') {
$this->setType('new');
}
}
$this->setLine($data);
}
public function getLine()
{
return $this->line;
}
public function setLine($line)
{
$this->line = $line;
}
public function getType()
{
return $this->type;
}
public function setType($type)
{
$this->type = $type;
}
}
lib/GitList/Component/Git/Model/Symlink.php 0000664 0000000 0000000 00000001074 15161025004 0021063 0 ustar 00root root 0000000 0000000 mode;
}
public function setMode($mode)
{
$this->mode = $mode;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function getPath()
{
return $this->path;
}
public function setPath($path)
{
$this->path = $path;
}
}
lib/GitList/Component/Git/Model/Tree.php 0000664 0000000 0000000 00000010514 15161025004 0020333 0 ustar 00root root 0000000 0000000 setClient($client);
$this->setRepository($repository);
$this->setHash($hash);
}
public function parse()
{
$data = $this->getClient()->run($this->getRepository(), 'ls-tree -l ' . $this->getHash());
$lines = explode("\n", $data);
$files = array();
$root = array();
foreach ($lines as $key => $line) {
if (empty($line)) {
unset($lines[$key]);
continue;
}
$files[] = preg_split("/[\s]+/", $line, 5);
}
foreach ($files as $file) {
if ($file[1] == 'commit') {
// submodule
continue;
}
if ($file[0] == '120000') {
$show = $this->getClient()->run($this->getRepository(), 'show ' . $file[2]);
$tree = new Symlink;
$tree->setMode($file[0]);
$tree->setName($file[4]);
$tree->setPath($show);
$root[] = $tree;
continue;
}
if ($file[1] == 'blob') {
$blob = new Blob($file[2], $this->getClient(), $this->getRepository());
$blob->setMode($file[0]);
$blob->setName($file[4]);
$blob->setSize($file[3]);
$root[] = $blob;
continue;
}
$tree = new Tree($file[2], $this->getClient(), $this->getRepository());
$tree->setMode($file[0]);
$tree->setName($file[4]);
$root[] = $tree;
}
$this->data = $root;
}
public function output()
{
$files = $folders = array();
foreach ($this as $node) {
if ($node instanceof Blob) {
$file['type'] = 'blob';
$file['name'] = $node->getName();
$file['size'] = $node->getSize();
$file['mode'] = $node->getMode();
$file['hash'] = $node->getHash();
$files[] = $file;
continue;
}
if ($node instanceof Tree) {
$folder['type'] = 'folder';
$folder['name'] = $node->getName();
$folder['size'] = '';
$folder['mode'] = $node->getMode();
$folder['hash'] = $node->getHash();
$folders[] = $folder;
continue;
}
if ($node instanceof Symlink) {
$folder['type'] = 'symlink';
$folder['name'] = $node->getName();
$folder['size'] = '';
$folder['mode'] = $node->getMode();
$folder['hash'] = '';
$folder['path'] = $node->getPath();
$folders[] = $folder;
}
}
// Little hack to make folders appear before files
$files = array_merge($folders, $files);
return $files;
}
public function valid()
{
return isset($this->data[$this->position]);
}
public function hasChildren()
{
return is_array($this->data[$this->position]);
}
public function next()
{
$this->position++;
}
public function current()
{
return $this->data[$this->position];
}
public function getChildren()
{
return $this->data[$this->position];
}
public function rewind()
{
$this->position = 0;
}
public function key()
{
return $this->position;
}
public function getMode()
{
return $this->mode;
}
public function setMode($mode)
{
$this->mode = $mode;
}
public function getHash()
{
return $this->hash;
}
public function setHash($hash)
{
$this->hash = $hash;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
}
lib/GitList/Component/Git/Repository.php 0000664 0000000 0000000 00000035624 15161025004 0020564 0 ustar 00root root 0000000 0000000 setPath($path);
$this->setClient($client);
}
public function setClient(Client $client)
{
$this->client = $client;
}
public function getClient()
{
return $this->client;
}
public function create()
{
mkdir($this->getPath());
$this->getClient()->run($this, 'init');
return $this;
}
public function getConfig($key)
{
$key = $this->getClient()->run($this, 'config ' . $key);
return trim($key);
}
public function setConfig($key, $value)
{
$this->getClient()->run($this, "config $key \"$value\"");
return $this;
}
/**
* Add untracked files
*
* @access public
* @param mixed $files Files to be added to the repository
*/
public function add($files = '.')
{
if (is_array($files)) {
$files = implode(' ', $files);
}
$this->getClient()->run($this, "add $files");
return $this;
}
/**
* Add all untracked files
*
* @access public
*/
public function addAll()
{
$this->getClient()->run($this, "add -A");
return $this;
}
/**
* Commit changes to the repository
*
* @access public
* @param string $message Description of the changes made
*/
public function commit($message)
{
$this->getClient()->run($this, "commit -m '$message'");
return $this;
}
/**
* Checkout a branch
*
* @access public
* @param string $branch Branch to be checked out
*/
public function checkout($branch)
{
$this->getClient()->run($this, "checkout $branch");
return $this;
}
/**
* Pull repository changes
*
* @access public
*/
public function pull()
{
$this->getClient()->run($this, "pull");
return $this;
}
/**
* Update remote references
*
* @access public
* @param string $repository Repository to be pushed
* @param string $refspec Refspec for the push
*/
public function push($repository = null, $refspec = null)
{
$command = "push";
if ($repository) {
$command .= " $repository";
}
if ($refspec) {
$command .= " $refspec";
}
$this->getClient()->run($this, $command);
return $this;
}
/**
* Show a list of the repository branches
*
* @access public
* @return array List of branches
*/
public function getBranches()
{
$branches = $this->getClient()->run($this, "branch");
$branches = explode("\n", $branches);
$branches = array_filter(preg_replace('/[\*\s]/', '', $branches));
return $branches;
}
/**
* Show the current repository branch
*
* @access public
* @return string Current repository branch
*/
public function getCurrentBranch()
{
$branches = $this->getClient()->run($this, "branch");
$branches = explode("\n", $branches);
foreach ($branches as $branch) {
if ($branch[0] == '*') {
return substr($branch, 2);
}
}
}
/**
* Check if a specified branch exists
*
* @access public
* @param string $branch Branch to be checked
* @return boolean True if the branch exists
*/
public function hasBranch($branch)
{
$branches = $this->getBranches();
$status = in_array($branch, $branches);
return $status;
}
/**
* Create a new repository branch
*
* @access public
* @param string $branch Branch name
*/
public function createBranch($branch)
{
$this->getClient()->run($this, "branch $branch");
}
/**
* Show a list of the repository tags
*
* @access public
* @return array List of tags
*/
public function getTags()
{
$tags = $this->getClient()->run($this, "tag");
$tags = explode("\n", $tags);
if (empty($tags[0])) {
return NULL;
}
return $tags;
}
/**
* Show the amount of commits on the repository
*
* @access public
* @return integer Total number of commits
*/
public function getTotalCommits($file = null)
{
$command = "rev-list --all";
if ($file) {
$command .= " $file";
}
$command .= " | wc -l";
$commits = $this->getClient()->run($this, $command);
return $commits;
}
/**
* Show the repository commit log
*
* @access public
* @return array Commit log
*/
public function getCommits($file = null, $page = 0)
{
$page = 15 * $page;
$pager = "--skip=$page --max-count=15";
$command = 'log ' . $pager . ' --pretty=format:\'"%h": {"hash": "%H", "short_hash": "%h", "tree": "%T", "parent": "%P", "author": "%an", "author_email": "%ae", "date": "%at", "commiter": "%cn", "commiter_email": "%ce", "commiter_date": "%ct", "message": "%f"}\'';
if ($file) {
$command .= " $file";
}
$logs = $this->getClient()->run($this, $command);
if (empty($logs)) {
throw new \RuntimeException('No commit log available');
}
$logs = str_replace("\n", ',', $logs);
$logs = json_decode("{ $logs }", true);
foreach ($logs as $log) {
$log['message'] = str_replace('-', ' ', $log['message']);
$commit = new Commit;
$commit->importData($log);
$commits[] = $commit;
}
return $commits;
}
public function getRelatedCommits($hash)
{
$logs = $this->getClient()->run($this, 'log --pretty=format:\'"%h": {"hash": "%H", "short_hash": "%h", "tree": "%T", "parent": "%P", "author": "%an", "author_email": "%ae", "date": "%at", "commiter": "%cn", "commiter_email": "%ce", "commiter_date": "%ct", "message": "%f"}\'');
if (empty($logs)) {
throw new \RuntimeException('No commit log available');
}
$logs = str_replace("\n", ',', $logs);
$logs = json_decode("{ $logs }", true);
foreach ($logs as $log) {
$log['message'] = str_replace('-', ' ', $log['message']);
$logTree = $this->getClient()->run($this, 'diff-tree -t -r ' . $log['hash']);
$lines = explode("\n", $logTree);
array_shift($lines);
$files = array();
foreach ($lines as $key => $line) {
if (empty($line)) {
unset($lines[$key]);
continue;
}
$files[] = preg_split("/[\s]+/", $line);
}
// Now let's find the commits who have our hash within them
foreach ($files as $file) {
if ($file[1] == 'commit') {
continue;
}
if ($file[3] == $hash) {
$commit = new Commit;
$commit->importData($log);
$commits[] = $commit;
break;
}
}
}
return $commits;
}
public function getCommit($commit)
{
$logs = $this->getClient()->run($this, 'show --pretty=format:\'{"hash": "%H", "short_hash": "%h", "tree": "%T", "parent": "%P", "author": "%an", "author_email": "%ae", "date": "%at", "commiter": "%cn", "commiter_email": "%ce", "commiter_date": "%ct", "message": "%f"}\' ' . $commit);
if (empty($logs)) {
throw new \RuntimeException('No commit log available');
}
$logs = explode("\n", $logs);
// Read commit metadata
$data = json_decode($logs[0], true);
$data['message'] = str_replace('-', ' ', $data['message']);
$commit = new Commit;
$commit->importData($data);
unset($logs[0]);
if (empty($logs[1])) {
throw new \RuntimeException('No commit log available');
}
// Read diff logs
foreach ($logs as $log) {
if ('diff' === substr($log, 0, 4)) {
if (isset($diff)) {
$diffs[] = $diff;
}
$diff = new Diff;
preg_match('/^diff --[\S]+ (a\/)?([\S]+)( b\/)?/', $log, $name);
$diff->setFile($name[2]);
continue;
}
if ('index' === substr($log, 0, 5)) {
$diff->setIndex($log);
continue;
}
if ('---' === substr($log, 0, 3)) {
$diff->setOld($log);
continue;
}
if ('+++' === substr($log, 0, 3)) {
$diff->setNew($log);
continue;
}
// Handle binary files properly.
if ('Binary' === substr($log, 0, 6)) {
$m = array();
if (preg_match('/Binary files (.+) and (.+) differ/', $log, $m)) {
$diff->setOld($m[1]);
$diff->setNew(" {$m[2]}");
}
}
$diff->addLine($log);
}
if (isset($diff)) {
$diffs[] = $diff;
}
$commit->setDiffs($diffs);
return $commit;
}
public function getAuthorStatistics()
{
$logs = $this->getClient()->run($this, 'log --pretty=format:\'%an||%ae\' ' . $this->getHead());
if (empty($logs)) {
throw new \RuntimeException('No statistics available');
}
$logs = explode("\n", $logs);
$logs = array_count_values($logs);
arsort($logs);
foreach ($logs as $user => $count) {
$user = explode('||', $user);
$data[] = array('name' => $user[0], 'email' => $user[1], 'commits' => $count);
}
return $data;
}
/**
* Get the current HEAD.
*
* @return string the name of the HEAD branch.
*/
public function getHead()
{
if (file_exists($this->getPath() . '/.git/HEAD')) {
$file = @file_get_contents($this->getPath() . '/.git/HEAD');
} elseif (file_exists($this->getPath() . '/HEAD')) {
$file = @file_get_contents($this->getPath() . '/HEAD');
} else {
return 'master';
}
// Find first existing branch
foreach (explode("\n", $file) as $line) {
$m = array();
if (preg_match('#ref:\srefs/heads/(.+)#', $line, $m)) {
if ($this->hasBranch($m[1])) {
return $m[1];
}
}
}
// Default to something sane if in a detached HEAD state.
$branches = $this->getBranches();
if (!empty($branches)) {
return current($branches);
}
return 'master';
}
public function getStatistics($branch)
{
// Calculate amount of files, extensions and file size
$logs = $this->getClient()->run($this, 'ls-tree -r -l ' . $branch);
$lines = explode("\n", $logs);
$files = array();
$data['extensions'] = array();
$data['size'] = 0;
$data['files'] = 0;
foreach ($lines as $key => $line) {
if (empty($line)) {
unset($lines[$key]);
continue;
}
$files[] = preg_split("/[\s]+/", $line);
}
foreach ($files as $file) {
if ($file[1] == 'blob') {
$data['files']++;
}
if (is_numeric($file[3])) {
$data['size'] += $file[3];
}
if (($pos = strrpos($file[4], '.')) !== FALSE) {
$data['extensions'][] = substr($file[4], $pos);
}
}
$data['extensions'] = array_count_values($data['extensions']);
arsort($data['extensions']);
return $data;
}
/**
* Extract the tree hash for a given branch or tree reference
*
* @param string $branch
* @return string
*/
public function getBranchTree($branch)
{
$hash = $this->getClient()->run($this, "log --pretty='%T' --max-count=1 $branch");
$hash = trim($hash, "\r\n ");
return $hash ? : false;
}
/**
* Create a TAR or ZIP archive of a git tree
*
* @param string $tree Tree-ish reference
* @param string $output Output File name
* @param string $format Archive format
*/
public function createArchive($tree, $output, $format = 'zip')
{
$fs = new Filesystem;
$fs->mkdir(dirname($output));
$this->getClient()->run($this, "archive --format=$format --output=$output $tree");
}
/**
* Get the Tree for the provided folder
*
* @param string $tree Folder that will be parsed
* @return Tree Instance of Tree for the provided folder
*/
public function getTree($tree)
{
$tree = new Tree($tree, $this->getClient(), $this);
$tree->parse();
return $tree;
}
/**
* Get the Blob for the provided file
*
* @param string $blob File that will be parsed
* @return Blob Instance of Blob for the provided file
*/
public function getBlob($blob)
{
return new Blob($blob, $this->getClient(), $this);
}
/**
* Blames the provided file and parses the output
*
* @param string $file File that will be blamed
* @return array Commits hashes containing the lines
*/
public function getBlame($file)
{
$blame = array();
$logs = $this->getClient()->run($this, "blame -s $file");
$logs = explode("\n", $logs);
$i = 0;
$previous_commit = '';
foreach ($logs as $log) {
if ($log == '') {
continue;
}
preg_match_all("/([a-zA-Z0-9^]{8})\s+.*?([0-9]+)\)(.+)/", $log, $match);
$current_commit = $match[1][0];
if ($current_commit != $previous_commit) {
++$i;
$blame[$i] = array('line' => '', 'commit' => $current_commit);
}
$blame[$i]['line'] .= PHP_EOL . $match[3][0];
$previous_commit = $current_commit;
}
return $blame;
}
/**
* Get the current Repository path
*
* @return string Path where the repository is located
*/
public function getPath()
{
return $this->path;
}
/**
* Set the current Repository path
*
* @param string $path Path where the repository is located
*/
public function setPath($path)
{
$this->path = $path;
}
}
lib/GitList/Component/Git/ScopeAware.php 0000664 0000000 0000000 00000000717 15161025004 0020431 0 ustar 00root root 0000000 0000000 client = $client;
}
public function getClient()
{
return $this->client;
}
public function getRepository()
{
return $this->repository;
}
public function setRepository($repository)
{
$this->repository = $repository;
}
}
lib/GitList/Config.php 0000664 0000000 0000000 00000002207 15161025004 0015114 0 ustar 00root root 0000000 0000000 data = parse_ini_file('config.ini', true);
$this->validateOptions();
}
public function get($section, $option)
{
if (!array_key_exists($section, $this->data)) {
return false;
}
if (!array_key_exists($option, $this->data[$section])) {
return false;
}
return $this->data[$section][$option];
}
public function getSection($section)
{
if (!array_key_exists($section, $this->data)) {
return false;
}
return $this->data[$section];
}
public function set($section, $option, $value)
{
$this->data[$section][$option] = $value;
}
protected function validateOptions()
{
if (!$this->get('git', 'repositories') || !is_dir($this->get('git', 'repositories'))) {
die("Please, edit the config.ini file and provide your repositories directory");
}
}
} lib/GitList/Controller/ 0000775 0000000 0000000 00000000000 15161025004 0015320 5 ustar 00root root 0000000 0000000 lib/GitList/Controller/BlobController.php 0000664 0000000 0000000 00000003465 15161025004 0020763 0 ustar 00root root 0000000 0000000 get('{repo}/blob/{branch}/{file}', function($repo, $branch, $file) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$blob = $repository->getBlob("$branch:'$file'");
$breadcrumbs = $app['util.view']->getBreadcrumbs($file);
$fileType = $app['util.repository']->getFileType($file);
return $app['twig']->render('file.twig', array(
'file' => $file,
'fileType' => $fileType,
'blob' => $blob->output(),
'repo' => $repo,
'branch' => $branch,
'breadcrumbs' => $breadcrumbs,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
));
})->assert('file', '.+')
->assert('repo', '[\w-._]+')
->assert('branch', '[\w-._]+')
->bind('blob');
$route->get('{repo}/raw/{branch}/{file}', function($repo, $branch, $file) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$blob = $repository->getBlob("$branch:'$file'")->output();
return new Response($blob, 200, array('Content-Type' => 'text/plain'));
})->assert('file', '.+')
->assert('repo', '[\w-._]+')
->assert('branch', '[\w-._]+')
->bind('blob_raw');
return $route;
}
} lib/GitList/Controller/CommitController.php 0000664 0000000 0000000 00000005604 15161025004 0021332 0 ustar 00root root 0000000 0000000 get('{repo}/commits/{branch}/{file}', function($repo, $branch, $file) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$type = $file ? "$branch -- $file" : $branch;
$pager = $app['util.view']->getPager($app['request']->get('page'), $repository->getTotalCommits($type));
$commits = $repository->getCommits($type, $pager['current']);
foreach ($commits as $commit) {
$date = $commit->getDate();
$date = $date->format('m/d/Y');
$categorized[$date][] = $commit;
}
return $app['twig']->render('commits.twig', array(
'pager' => $pager,
'repo' => $repo,
'branch' => $branch,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
'commits' => $categorized,
'file' => $file,
));
})->assert('repo', '[\w-._]+')
->assert('branch', '[\w-._]+')
->assert('file', '.+')
->value('branch', 'master')
->value('file', '')
->bind('commits');
$route->get('{repo}/commit/{commit}/', function($repo, $commit) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$commit = $repository->getCommit($commit);
return $app['twig']->render('commit.twig', array(
'branch' => 'master',
'repo' => $repo,
'commit' => $commit,
));
})->assert('repo', '[\w-._]+')
->assert('commit', '[a-f0-9]+')
->bind('commit');
$route->get('{repo}/blame/{branch}/{file}', function($repo, $branch, $file) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$blames = $repository->getBlame("$branch -- $file");
return $app['twig']->render('blame.twig', array(
'file' => $file,
'repo' => $repo,
'branch' => $branch,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
'blames' => $blames,
));
})->assert('repo', '[\w-._]+')
->assert('file', '.+')
->assert('branch', '[\w-._]+')
->bind('blame');
return $route;
}
} lib/GitList/Controller/MainController.php 0000664 0000000 0000000 00000004061 15161025004 0020762 0 ustar 00root root 0000000 0000000 get('/', function() use ($app) {
$repositories = $app['git']->getRepositories($app['git.repos']);
return $app['twig']->render('index.twig', array(
'repositories' => $repositories,
));
})->bind('homepage');
$route->get('{repo}/stats/{branch}', function($repo, $branch) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$stats = $repository->getStatistics($branch);
$authors = $repository->getAuthorStatistics();
return $app['twig']->render('stats.twig', array(
'repo' => $repo,
'branch' => $branch,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
'stats' => $stats,
'authors' => $authors,
));
})->assert('repo', '[\w-._]+')
->assert('branch', '[\w-._]+')
->value('branch', 'master')
->bind('stats');
$route->get('{repo}/{branch}/rss/', function($repo, $branch) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$commits = $repository->getCommits($branch);
$html = $app['twig']->render('rss.twig', array(
'repo' => $repo,
'branch' => $branch,
'commits' => $commits,
));
return new Response($html, 200, array('Content-Type' => 'application/rss+xml'));
})->assert('repo', '[\w-._]+')
->assert('branch', '[\w-._]+')
->bind('rss');
return $route;
}
} lib/GitList/Controller/TreeController.php 0000664 0000000 0000000 00000007126 15161025004 0021002 0 ustar 00root root 0000000 0000000 get('{repo}/tree/{branch}/{tree}/', $treeController = function($repo, $branch = '', $tree = '') use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
if (!$branch) {
$branch = $repository->getHead();
}
$files = $repository->getTree($tree ? "$branch:'$tree'/" : $branch);
$breadcrumbs = $app['util.view']->getBreadcrumbs($tree);
$parent = null;
if (($slash = strrpos($tree, '/')) !== false) {
$parent = substr($tree, 0, $slash);
} elseif (!empty($tree)) {
$parent = '';
}
return $app['twig']->render('tree.twig', array(
'files' => $files->output(),
'repo' => $repo,
'branch' => $branch,
'path' => $tree ? $tree . '/' : $tree,
'parent' => $parent,
'breadcrumbs' => $breadcrumbs,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
'readme' => $app['util.repository']->getReadme($repo, $branch),
));
})->assert('repo', '[\w-._]+')
->assert('branch', '[\w-._]+')
->assert('tree', '.+')
->bind('tree');
$route->get('{repo}/{branch}/', function($repo, $branch) use ($app, $treeController) {
return $treeController($repo, $branch);
})->assert('repo', '[\w-._]+')
->assert('branch', '[\w-._]+')
->bind('branch');
$route->get('{repo}/', function($repo) use ($app, $treeController) {
return $treeController($repo);
})->assert('repo', '[\w-._]+')
->bind('repository');
$route->get('{repo}/{format}ball/{branch}', function($repo, $format, $branch) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$tree = $repository->getBranchTree($branch);
if (false === $tree) {
return $app->abort(404, 'Invalid commit or tree reference: ' . $branch);
}
$file = $app['cache.archives'] . DIRECTORY_SEPARATOR
. $repo . DIRECTORY_SEPARATOR
. substr($tree, 0, 2) . DIRECTORY_SEPARATOR
. substr($tree, 2)
. '.'
. $format;
if (!file_exists($file)) {
$repository->createArchive($tree, $file, $format);
}
return new StreamedResponse(function () use ($file) {
readfile($file);
}, 200, array(
'Content-type' => ('zip' === $format) ? 'application/zip' : 'application/x-tar',
'Content-Description' => 'File Transfer',
'Content-Disposition' => 'attachment; filename="'.$repo.'-'.substr($tree, 0, 6).'.'.$format.'"',
'Content-Transfer-Encoding' => 'binary',
));
})->assert('format', '(zip|tar)')
->assert('repo', '[\w-._]+')
->assert('branch', '[\w-._]+')
->bind('archive');
return $route;
}
} lib/GitList/Exception/ 0000775 0000000 0000000 00000000000 15161025004 0015133 5 ustar 00root root 0000000 0000000 lib/GitList/Exception/BlankDataException.php 0000664 0000000 0000000 00000000132 15161025004 0021340 0 ustar 00root root 0000000 0000000 share(function () use ($app) {
return new Repository($app);
});
}
public function boot(Application $app)
{
}
}
lib/GitList/Provider/ViewUtilServiceProvider.php 0000664 0000000 0000000 00000001043 15161025004 0022302 0 ustar 00root root 0000000 0000000 share(function () {
return new View;
});
}
public function boot(Application $app)
{
}
}
lib/GitList/Util/ 0000775 0000000 0000000 00000000000 15161025004 0014112 5 ustar 00root root 0000000 0000000 lib/GitList/Util/Repository.php 0000664 0000000 0000000 00000010131 15161025004 0016776 0 ustar 00root root 0000000 0000000 'php',
'c' => 'clike',
'h' => 'clike',
'cpp' => 'clike',
'm' => 'clike',
'mm' => 'clike',
'cs' => 'text/x-csharp',
'java' => 'java',
'clj' => 'clojure',
'coffee' => 'coffeescript',
'css' => 'css',
'diff' => 'diff',
'ecl' => 'ecl',
'el' => 'erlang',
'go' => 'go',
'groovy' => 'groovy',
'hs' => 'haskell',
'lhs' => 'haskell',
'jsp' => 'htmlembedded',
'asp' => 'htmlembedded',
'aspx' => 'htmlembedded',
'html' => 'htmlmixed',
'tpl' => 'htmlmixed',
'js' => 'javascript',
'json' => 'javascript',
'less' => 'less',
'lua' => 'lua',
'md' => 'markdown',
'markdown' => 'markdown',
'sql' => 'mysql',
'pl' => 'perl',
'pm' => 'perl',
'pas' => 'pascal',
'ini' => 'properties',
'cfg' => 'properties',
'nt' => 'ntriples',
'py' => 'python',
'rb' => 'ruby',
'rst' => 'rst',
'r' => 'r',
'sh' => 'shell',
'ss' => 'scheme',
'scm' => 'scheme',
'sls' => 'scheme',
'sps' => 'scheme',
'rs' => 'rust',
'st' => 'smalltalk',
'tex' => 'stex',
'vbs' => 'vbscript',
'v' => 'verilog',
'xml' => 'xml',
'xsd' => 'xml',
'xsl' => 'xml',
'xul' => 'xml',
'xlf' => 'xml',
'xliff' => 'xml',
'xaml' => 'xml',
'wxs' => 'xml',
'wxl' => 'xml',
'wxi' => 'xml',
'wsdl' => 'xml',
'svg' => 'xml',
'rss' => 'xml',
'rdf' => 'xml',
'plist' => 'xml',
'mxml' => 'xml',
'kml' => 'xml',
'glade' => 'xml',
'xq' => 'xquery',
'xqm' => 'xquery',
'xquery' => 'xquery',
'xqy' => 'xquery',
'yml' => 'yaml',
'yaml' => 'yaml',
'png' => 'image',
'jpg' => 'image',
'gif' => 'image',
'jpeg' => 'image',
'bmp' => 'image',
'csproj' => 'xml',
);
public function __construct(Application $app)
{
$this->app = $app;
}
/**
* Returns the file type based on filename by treating the extension
*
* The file type is used by CodeMirror, a Javascript-based IDE implemented in
* GitList, to properly highlight the blob syntax (if it's a source-code)
*
* @param string $file File name
* @return mixed File type
*/
public function getFileType($file)
{
if (($pos = strrpos($file, '.')) !== FALSE) {
$fileType = substr($file, $pos + 1);
} else {
return 'text';
}
if (isset($this->defaultFileTypes[$fileType])) {
return $this->defaultFileTypes[$fileType];
}
if (!empty($this->app['filetypes'])) {
if (isset($this->app['filetypes'][$fileType])) {
return $this->app['filetypes'][$fileType];
}
}
return 'text';
}
public function getReadme($repo, $branch = 'master')
{
$repository = $this->app['git']->getRepository($this->app['git.repos'] . $repo);
$files = $repository->getTree($branch)->output();
foreach ($files as $file) {
if (preg_match('/^readme*/i', $file['name'])) {
return array(
'filename' => $file['name'],
'content' => $repository->getBlob("$branch:'{$file['name']}'")->output()
);
}
}
return array();
}
}
lib/GitList/Util/View.php 0000664 0000000 0000000 00000002406 15161025004 0015537 0 ustar 00root root 0000000 0000000 $path) {
$breadcrumbs[] = array(
'dir' => $path,
'path' => implode('/', array_slice($paths, 0, $i + 1)),
);
}
return $breadcrumbs;
}
public function getPager($pageNumber, $totalCommits)
{
$pageNumber = (empty($pageNumber)) ? 0 : $pageNumber;
$lastPage = intval($totalCommits / 15);
// If total commits are integral multiple of 15, the lastPage will be commits/15 - 1.
$lastPage = ($lastPage * 15 == $totalCommits) ? $lastPage - 1 : $lastPage;
$nextPage = $pageNumber + 1;
$previousPage = $pageNumber - 1;
return array('current' => $pageNumber,
'next' => $nextPage,
'previous' => $previousPage,
'last' => $lastPage,
'total' => $totalCommits,
);
}
}
nginx/ 0000775 0000000 0000000 00000000000 15161025004 0012173 5 ustar 00root root 0000000 0000000 nginx/server.conf 0000664 0000000 0000000 00000002033 15161025004 0014346 0 ustar 00root root 0000000 0000000 server {
server_name MYSERVER;
access_log /var/log/nginx/MYSERVER.access_log main;
error_log /var/log/nginx/MYSERVER.error_log debug_http;
root /var/www/DIR;
index index.php;
# auth_basic "Restricted";
# auth_basic_user_file rhtpasswd;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location ~* ^/index.php.*$ {
fastcgi_pass 127.0.0.1:9000;
include fastcgi.conf;
}
location / {
try_files $uri @gitlist;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
add_header Vary "Accept-Encoding";
expires max;
try_files $uri @gitlist;
tcp_nodelay off;
tcp_nopush on;
}
# location ~* \.(git|svn|patch|htaccess|log|route|plist|inc|json|pl|po|sh|ini|sample|kdev4)$ {
# deny all;
# }
location @gitlist {
rewrite ^/.*$ /index.php;
}
}
phpunit.xml.dist 0000664 0000000 0000000 00000001276 15161025004 0014231 0 ustar 00root root 0000000 0000000
./tests/
pkg_builder/ 0000775 0000000 0000000 00000000000 15161025004 0013337 5 ustar 00root root 0000000 0000000 pkg_builder/Makefile 0000664 0000000 0000000 00000010511 15161025004 0014775 0 ustar 00root root 0000000 0000000 # Main Info
NAME = gitlist
DESCRIPTION = "An elegant and modern git repository viewer"
LICENSE = New BSD
GROUP = gitlist
VENDOR = gitlist.org
URL = "http://www.gitlist.org"
#BUILD Info
PREFIX = /usr/share
PROJROOT = "$(shell pwd)"
SRCROOT = "$(shell pwd)/gitlist"
UPSTREAM_VERSION = $(shell cat tools/release.info | head -n1 | cut -d"=" -f2)
BUILD_STAMP = $(shell date +"%Y%m%d%H%M%S")
#Packager Info
PACKAGER = $(shell git config user.name)
PACKAGER_MAIL = $(shell git config user.email)
#Debian Package Info
PACKAGE-VERSION= 1
DEBIAN_BUILD_ROOT = ${PROJROOT}/debian/
PROJECT_DEBIAN_LIKE_NAME=$(shell cat tools/release.info | grep name | cut -d"=" -f2)
DEBIAN_NAME=$(PROJECT_DEBIAN_LIKE_NAME)$(shell echo "_")$(UPSTREAM_VERSION)-${PACKAGE-VERSION}$(shell echo "_all.deb")
DEBIAN_VERSION =
# Generating control file
define control
Package: $(PROJECT_DEBIAN_LIKE_NAME)
Version: $(UPSTREAM_VERSION)-${PACKAGE-VERSION}
Architecture: all
Section: web
Priority: optional
Maintainer: "${PACKAGER} <${PACKAGER_MAIL}>"
Description: ${DESCRIPTION}
endef
export control
all:
@echo "... $(UPSTREAM_VERSION)"
@echo "... $(PACKAGER)"
@echo "... $(PACKAGER_MAIL)"
@echo "... $(DEBIAN_NAME)"
help:
@echo "To use this make file just:"
@echo "Download the gitlist tarball and stract it into a folder called gitlist"
@echo "make [build_deb|build_rpm|build(apache|nginx|lighthttp)]"
clean_deb:
@echo "Cleaning . . ."
@rm -rf ${DEBIAN_BUILD_ROOT}/*.deb
@rm -rf ${PROJROOT}/debian
prepare_deb: clean_deb
@echo "############################### - Building DEB"
@mkdir ${DEBIAN_BUILD_ROOT} -pv
@mkdir ${DEBIAN_BUILD_ROOT}/DEBIAN -pv
@mkdir ${DEBIAN_BUILD_ROOT}${PREFIX}/${PROJECT_DEBIAN_LIKE_NAME} -pv
copy_deb_files: prepare_deb
@echo "$$control" > ${DEBIAN_BUILD_ROOT}/DEBIAN/control
copy_deb: copy_deb_files
@echo Sync files
@rsync -avz ${SRCROOT} ${DEBIAN_BUILD_ROOT}${PREFIX}/
md5sum_deb: copy_deb
@cd debian; find . -type f ! -regex '.*\.hg.*' ! -regex '.*?debian-binary.*' ! -regex '.*?DEBIAN.*' | xargs -d "\n" md5sum > DEBIAN/md5sums
deb_uniq: md5sum_deb
@mkdir ${PROJROOT}/pkg -p
@dpkg -b debian $(DEBIAN_NAME);
@mv $(DEBIAN_NAME) ${PROJROOT}/pkg/
@rm debian -rf
@echo '### Wrote $(DEBIAN_NAME) in ${PROJROOT}/pkg/ . . . . . Success'
build_deb: deb_uniq
#### RPM STUFF
RPM_NAME=$(PROJECT_DEBIAN_LIKE_NAME)$(shell echo "_")$(UPSTREAM_VERSION)-${PACKAGE-VERSION}$(shell echo "_all.rpm")
DIST_DIR = dist
TAR_DIR = tar
RPM_DIR = rpm
RPM_DIRS = SPECS RPMS SOURCES BUILD
clean_rpm:
@echo Cleaning temporary dirs...
@rm -rf $(TAR_DIR)
@rm -rf $(RPM_DIR)
@rm -rf $(DIST_DIR)
rpm_init: clean_rpm
@echo Creating directories...
@echo $(DIST_DIR)
@mkdir -p $(DIST_DIR)
@for dir in $(RPM_DIRS); do \
echo $(RPM_DIR)/$$dir; \
mkdir -p $(RPM_DIR)/$$dir; \
done
rpm_preptar: rpm_init
@echo Copying files to generate tar...
@echo creating directory: $(TAR_DIR)/
@mkdir $(TAR_DIR)/ -p
@rsync -avz --exclude ".git" --exclude ".gitignore" --exclude "builder" gitlist $(TAR_DIR)/
rpm_tar: rpm_preptar
@echo Generating tarball...
@cd $(PROJROOT)/$(TAR_DIR); \
tar cf $(PROJROOT)/$(RPM_DIR)/SOURCES/$(NAME).tar .
rpm: rpm_tar
@echo Calling rpmbuild...
@echo Vesion: $(VERSION)
@cp tools/$(NAME).spec $(RPM_DIR)/SPECS/
@cd $(PROJROOT)/$(RPM_DIR)/SPECS ; \
rpmbuild -bb \
--buildroot="$(PROJROOT)/$(RPM_DIR)/BUILD/$(NAME)" \
--define "_topdir $(PROJROOT)/$(RPM_DIR)" \
--define "name $(NAME)" \
--define "summary "$(DESCRIPTION)"" \
--define "version $(UPSTREAM_VERSION)" \
--define "release $(PACKAGE-VERSION)" \
--define "url _$(URL)_" \
--define "license $(LICENSE)" \
--define "group $(GROUP)" \
--define "vendor $(VENDOR)" \
--define "packager $(PACKAGER)" \
--define "prefix $(PREFIX)" \
--define "source_dir $(PROJROOT)/$(RPM_DIR)/SOURCES" \
$(NAME).spec
@echo Copying generated RPM to dist dir...
@mkdir ${PROJROOT}/pkg -p
@cp $(PROJROOT)/$(RPM_DIR)/RPMS/noarch/*.rpm $(PROJROOT)/pkg
@rm -rf $(TAR_DIR)
@rm -rf $(RPM_DIR)
@rm -rf $(DIST_DIR)
build_rpm: rpm
tests/ 0000775 0000000 0000000 00000000000 15161025004 0012212 5 ustar 00root root 0000000 0000000 tests/ClientTest.php 0000664 0000000 0000000 00000006502 15161025004 0015004 0 ustar 00root root 0000000 0000000 markTestSkipped('There are no write permissions in order to create test repositories.');
}
$options['path'] = getenv('GIT_CLIENT') ?: '/usr/bin/git';
$options['hidden'] = array(ClientTest::PATH . '/hiddenrepo');
$this->client = new Client($options);
}
/**
* @expectedException RuntimeException
*/
public function testIsNotFindingRepositories()
{
$this->client->getRepositories(ClientTest::PATH . '/testrepo');
}
/**
* @expectedException RuntimeException
*/
public function testIsNotAbleToGetUnexistingRepository()
{
$this->client->getRepository(ClientTest::PATH . '/testrepo');
}
/**
* @expectedException RuntimeException
*/
public function testIsNotAbleToGetUnexistingRepositories()
{
$this->client->getRepositories('/tmp');
}
public function testIsCreatingRepository()
{
$repository = $this->client->createRepository(ClientTest::PATH . '/testrepo');
$this->assertRegExp("/nothing to commit/", $repository->getClient()->run($repository, 'status'));
}
/**
* @expectedException RuntimeException
*/
public function testIsNotAbleToCreateRepositoryDueToExistingOne()
{
$this->client->createRepository(ClientTest::PATH . '/testrepo');
}
public function testIsListingRepositories()
{
$this->client->createRepository(ClientTest::PATH . '/anothertestrepo');
$this->client->createRepository(ClientTest::PATH . '/bigbadrepo');
$repositories = $this->client->getRepositories(ClientTest::PATH);
$this->assertEquals($repositories[0]['name'], 'anothertestrepo');
$this->assertEquals($repositories[1]['name'], 'bigbadrepo');
$this->assertEquals($repositories[2]['name'], 'testrepo');
}
public function testIsNotListingHiddenRepositories()
{
$this->client->createRepository(ClientTest::PATH . '/hiddenrepo');
$repositories = $this->client->getRepositories(ClientTest::PATH);
$this->assertEquals($repositories[0]['name'], 'anothertestrepo');
$this->assertEquals($repositories[1]['name'], 'bigbadrepo');
$this->assertEquals($repositories[2]['name'], 'testrepo');
$this->assertFalse(isset($repositories[3]));
}
/**
* @expectedException RuntimeException
*/
public function testIsNotOpeningHiddenRepositories()
{
$this->client->getRepository(ClientTest::PATH . '/hiddenrepo');
}
/**
* @expectedException RuntimeException
*/
public function testIsCatchingGitCommandErrors()
{
$repository = $this->client->getRepository(ClientTest::PATH . '/testrepo');
$repository->getClient()->run($repository, 'wrong');
}
public static function tearDownAfterClass()
{
$fs = new Filesystem();
$fs->remove(ClientTest::PATH);
}
}
tests/RepositoryTest.php 0000664 0000000 0000000 00000041075 15161025004 0015751 0 ustar 00root root 0000000 0000000 markTestSkipped('There are no write permissions in order to create test repositories.');
}
$options['path'] = getenv('GIT_CLIENT') ?: '/usr/bin/git';
$options['hidden'] = array();
$this->client = new Client($options);
}
public function testIsCreatingRepositoryFixtures()
{
$a = $this->client->createRepository(RepositoryTest::PATH . '/testrepo');
$b = $this->client->createRepository(RepositoryTest::PATH . '/anothertestrepo');
$c = $this->client->createRepository(RepositoryTest::PATH . '/bigbadrepo');
$this->assertRegExp("/nothing to commit/", $a->getClient()->run($a, 'status'));
$this->assertRegExp("/nothing to commit/", $b->getClient()->run($b, 'status'));
$this->assertRegExp("/nothing to commit/", $c->getClient()->run($c, 'status'));
}
public function testIsConfiguratingRepository()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
$repository->setConfig('user.name', 'Luke Skywalker');
$repository->setConfig('user.email', 'luke@rebel.org');
$this->assertEquals($repository->getConfig('user.name'), 'Luke Skywalker');
$this->assertEquals($repository->getConfig('user.email'), 'luke@rebel.org');
}
public function testIsAdding()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
file_put_contents(RepositoryTest::PATH . '/testrepo/test_file.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
$repository->add('test_file.txt');
$this->assertRegExp("/new file: test_file.txt/", $repository->getClient()->run($repository, 'status'));
}
/**
* @depends testIsAdding
*/
public function testIsAddingDot()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
file_put_contents(RepositoryTest::PATH . '/testrepo/test_file1.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
file_put_contents(RepositoryTest::PATH . '/testrepo/test_file2.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
file_put_contents(RepositoryTest::PATH . '/testrepo/test_file3.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
$repository->add();
$this->assertRegExp("/new file: test_file1.txt/", $repository->getClient()->run($repository, 'status'));
$this->assertRegExp("/new file: test_file2.txt/", $repository->getClient()->run($repository, 'status'));
$this->assertRegExp("/new file: test_file3.txt/", $repository->getClient()->run($repository, 'status'));
}
/**
* @depends testIsAddingDot
*/
public function testIsAddingAll()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
file_put_contents(RepositoryTest::PATH . '/testrepo/test_file4.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
file_put_contents(RepositoryTest::PATH . '/testrepo/test_file5.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
file_put_contents(RepositoryTest::PATH . '/testrepo/test_file6.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
$repository->addAll();
$this->assertRegExp("/new file: test_file4.txt/", $repository->getClient()->run($repository, 'status'));
$this->assertRegExp("/new file: test_file5.txt/", $repository->getClient()->run($repository, 'status'));
$this->assertRegExp("/new file: test_file6.txt/", $repository->getClient()->run($repository, 'status'));
}
/**
* @depends testIsAddingAll
*/
public function testIsAddingArrayOfFiles()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
file_put_contents(RepositoryTest::PATH . '/testrepo/test_file7.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
file_put_contents(RepositoryTest::PATH . '/testrepo/test_file8.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
file_put_contents(RepositoryTest::PATH . '/testrepo/test_file9.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
$repository->add(array('test_file7.txt', 'test_file8.txt', 'test_file9.txt'));
$this->assertRegExp("/new file: test_file7.txt/", $repository->getClient()->run($repository, 'status'));
$this->assertRegExp("/new file: test_file8.txt/", $repository->getClient()->run($repository, 'status'));
$this->assertRegExp("/new file: test_file9.txt/", $repository->getClient()->run($repository, 'status'));
}
/**
* @depends testIsAddingArrayOfFiles
*/
public function testIsCommiting()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
$repository->commit("The truth unveiled");
$this->assertRegExp("/The truth unveiled/", $repository->getClient()->run($repository, 'log'));
}
public function testIsCreatingBranches()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
$repository->createBranch('issue12');
$repository->createBranch('issue42');
$branches = $repository->getBranches();
$this->assertContains('issue12', $branches);
$this->assertContains('issue42', $branches);
$this->assertContains('master', $branches);
}
public function testIsGettingCurrentBranch()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
$branch = $repository->getCurrentBranch();
$this->assertTrue($branch === 'master');
}
/**
* @depends testIsCommiting
*/
public function testIsGettingCommits()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
$commits = $repository->getCommits();
foreach ($commits as $commit) {
$this->assertInstanceOf('GitList\Component\Git\Commit\Commit', $commit);
$this->assertTrue($commit->getMessage() === 'The truth unveiled');
$this->assertInstanceOf('GitList\Component\Git\Commit\Author', $commit->getAuthor());
$this->assertEquals($commit->getAuthor()->getName(), 'Luke Skywalker');
$this->assertEquals($commit->getAuthor()->getEmail(), 'luke@rebel.org');
$this->assertEquals($commit->getCommiter()->getName(), 'Luke Skywalker');
$this->assertEquals($commit->getCommiter()->getEmail(), 'luke@rebel.org');
$this->assertEquals($commit->getParentHash(), '');
$this->assertInstanceOf('DateTime', $commit->getDate());
$this->assertInstanceOf('DateTime', $commit->getCommiterDate());
$this->assertRegExp('/[a-f0-9]+/', $commit->getHash());
$this->assertRegExp('/[a-f0-9]+/', $commit->getShortHash());
$this->assertRegExp('/[a-f0-9]+/', $commit->getTreeHash());
}
}
/**
* @depends testIsGettingCommits
*/
public function testIsGettingCommitsFromSpecificFile()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
$commits = $repository->getCommits('test_file4.txt');
foreach ($commits as $commit) {
$this->assertInstanceOf('GitList\Component\Git\Commit\Commit', $commit);
$this->assertTrue($commit->getMessage() === 'The truth unveiled');
$this->assertInstanceOf('GitList\Component\Git\Commit\Author', $commit->getAuthor());
$this->assertEquals($commit->getAuthor()->getName(), 'Luke Skywalker');
$this->assertEquals($commit->getAuthor()->getEmail(), 'luke@rebel.org');
}
}
public function testIsGettingTree()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
$files = $repository->getTree('master');
foreach ($files as $file) {
$this->assertInstanceOf('GitList\Component\Git\Model\Blob', $file);
$this->assertRegExp('/test_file[0-9]*.txt/', $file->getName());
$this->assertEquals($file->getSize(), '55');
$this->assertEquals($file->getMode(), '100644');
$this->assertRegExp('/[a-f0-9]+/', $file->getHash());
}
}
public function testIsGettingTreeOutput()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
$files = $repository->getTree('master')->output();
foreach ($files as $file) {
$this->assertEquals('blob', $file['type']);
$this->assertRegExp('/test_file[0-9]*.txt/', $file['name']);
$this->assertEquals($file['size'], '55');
$this->assertEquals($file['mode'], '100644');
$this->assertRegExp('/[a-f0-9]+/', $file['hash']);
}
}
public function testIsGettingTreesWithinTree()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
// Creating folders
mkdir(RepositoryTest::PATH . '/testrepo/MyFolder');
mkdir(RepositoryTest::PATH . '/testrepo/MyTest');
mkdir(RepositoryTest::PATH . '/testrepo/MyFolder/Tests');
// Populating created folders
file_put_contents(RepositoryTest::PATH . '/testrepo/MyFolder/crazy.php', 'Lorem ipsum dolor sit amet');
file_put_contents(RepositoryTest::PATH . '/testrepo/MyFolder/skywalker.php', 'Lorem ipsum dolor sit amet');
file_put_contents(RepositoryTest::PATH . '/testrepo/MyTest/fortytwo.php', 'Lorem ipsum dolor sit amet');
file_put_contents(RepositoryTest::PATH . '/testrepo/MyFolder/Tests/web.php', 'Lorem ipsum dolor sit amet');
file_put_contents(RepositoryTest::PATH . '/testrepo/MyFolder/Tests/cli.php', 'Lorem ipsum dolor sit amet');
// Adding and commiting
$repository->addAll();
$repository->commit("Creating folders for testIsGettingTreesWithinTrees");
// Checking tree
$files = $repository->getTree('master')->output();
$this->assertEquals('folder', $files[0]['type']);
$this->assertEquals('MyFolder', $files[0]['name']);
$this->assertEquals('', $files[0]['size']);
$this->assertEquals('040000', $files[0]['mode']);
$this->assertEquals('4143e982237f3bdf56b5350f862c334054aad69e', $files[0]['hash']);
$this->assertEquals('folder', $files[1]['type']);
$this->assertEquals('MyTest', $files[1]['name']);
$this->assertEquals('', $files[1]['size']);
$this->assertEquals('040000', $files[1]['mode']);
$this->assertEquals('632240595eabd59e4217d196d6c12efb81f9c011', $files[1]['hash']);
$this->assertEquals('blob', $files[2]['type']);
$this->assertEquals('test_file.txt', $files[2]['name']);
$this->assertEquals('55', $files[2]['size']);
$this->assertEquals('100644', $files[2]['mode']);
$this->assertEquals('a773bfc0fda6f878e3d17d78c667d18297c8831f', $files[2]['hash']);
}
public function testIsGettingBlobsWithinTrees()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
$files = $repository->getTree('master:MyFolder/')->output();
$this->assertEquals('folder', $files[0]['type']);
$this->assertEquals('Tests', $files[0]['name']);
$this->assertEquals('', $files[0]['size']);
$this->assertEquals('040000', $files[0]['mode']);
$this->assertEquals('8542f67d011ff2ea5ec49a729ba81a52935676d1', $files[0]['hash']);
$this->assertEquals('blob', $files[1]['type']);
$this->assertEquals('crazy.php', $files[1]['name']);
$this->assertEquals('26', $files[1]['size']);
$this->assertEquals('100644', $files[1]['mode']);
$this->assertEquals('d781006b2d05cc31751954a0fb920c990e825aad', $files[1]['hash']);
$this->assertEquals('blob', $files[2]['type']);
$this->assertEquals('skywalker.php', $files[2]['name']);
$this->assertEquals('26', $files[2]['size']);
$this->assertEquals('100644', $files[2]['mode']);
$this->assertEquals('d781006b2d05cc31751954a0fb920c990e825aad', $files[2]['hash']);
}
public function testIsGettingBlobOutput()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
$blob = $repository->getBlob('master:MyFolder/crazy.php')->output();
$this->assertEquals('Lorem ipsum dolor sit amet', $blob);
$blob = $repository->getBlob('master:test_file4.txt')->output();
$this->assertEquals('Your mother is so ugly, glCullFace always returns TRUE.', $blob);
}
public function testIsGettingStatistics()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
$stats = $repository->getStatistics('master');
$this->assertEquals('10', $stats['extensions']['.txt']);
$this->assertEquals('5', $stats['extensions']['.php']);
$this->assertEquals('680', $stats['size']);
$this->assertEquals('15', $stats['files']);
}
public function testIsGettingAuthorStatistics()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
$stats = $repository->getAuthorStatistics();
$this->assertEquals('Luke Skywalker', $stats[0]['name']);
$this->assertEquals('luke@rebel.org', $stats[0]['email']);
$this->assertEquals('2', $stats[0]['commits']);
$repository->setConfig('user.name', 'Princess Leia');
$repository->setConfig('user.email', 'sexyleia@republic.com');
file_put_contents(RepositoryTest::PATH . '/testrepo/MyFolder/crazy.php', 'Lorem ipsum dolor sit AMET');
$repository->addAll();
$repository->commit("Fixing AMET case");
$stats = $repository->getAuthorStatistics();
$this->assertEquals('Luke Skywalker', $stats[0]['name']);
$this->assertEquals('luke@rebel.org', $stats[0]['email']);
$this->assertEquals('2', $stats[0]['commits']);
$this->assertEquals('Princess Leia', $stats[1]['name']);
$this->assertEquals('sexyleia@republic.com', $stats[1]['email']);
$this->assertEquals('1', $stats[1]['commits']);
}
public function testIsGettingSymlinksWithinTrees()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
$fs = new Filesystem();
$fs->touch(RepositoryTest::PATH . '/testrepo/original_file.txt');
$fs->symlink(RepositoryTest::PATH . '/testrepo/original_file.txt', RepositoryTest::PATH . '/testrepo/link.txt');
$repository->addAll();
$repository->commit("Testing symlinks");
$files = $repository->getTree('master');
foreach ($files as $file) {
if ($file instanceof GitList\Component\Git\Model\Symlink) {
$this->assertEquals($file->getPath(), RepositoryTest::PATH . '/testrepo/original_file.txt');
$this->assertEquals($file->getName(), 'link.txt');
$this->assertEquals($file->getMode(), '120000');
return;
}
}
$this->fail('No symlink found inside tree');
}
public function testIsGettingSymlinksWithinTreesOutput()
{
$repository = $this->client->getRepository(RepositoryTest::PATH . '/testrepo');
$fs = new Filesystem();
$fs->touch(RepositoryTest::PATH . '/testrepo/original_file.txt');
$fs->symlink(RepositoryTest::PATH . '/testrepo/original_file.txt', RepositoryTest::PATH . '/testrepo/link.txt');
$repository->addAll();
$repository->commit("Testing symlinks");
$files = $repository->getTree('master')->output();
foreach ($files as $file) {
if ($file['type'] == 'symlink') {
$this->assertEquals($file['path'], RepositoryTest::PATH . '/testrepo/original_file.txt');
$this->assertEquals($file['name'], 'link.txt');
$this->assertEquals($file['mode'], '120000');
return;
}
}
$this->fail('No symlink found inside tree output');
}
public static function tearDownAfterClass()
{
$fs = new Filesystem();
$fs->remove(RepositoryTest::PATH);
}
}
views/ 0000775 0000000 0000000 00000000000 15161025004 0012205 5 ustar 00root root 0000000 0000000 views/blame.twig 0000664 0000000 0000000 00000001266 15161025004 0014166 0 ustar 00root root 0000000 0000000 {% extends 'layout_page.twig' %}
{% set page = 'commits' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: [{dir: 'Blame', path:''}]} %}
{% endblock %}
views/branch_menu.twig 0000664 0000000 0000000 00000001165 15161025004 0015365 0 ustar 00root root 0000000 0000000