.gitignore 0000664 0000000 0000000 00000000447 15161264430 0013055 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
composer.phar
phpunit.xml
.htaccess 0000664 0000000 0000000 00000000437 15161264430 0012662 0 ustar 00root root 0000000 0000000
Options -MultiViews SymLinksIfOwnerMatch
RewriteEngine On
#RewriteBase /path/to/gitlist/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L,NC]
order allow,deny
deny from all
.travis.yml 0000664 0000000 0000000 00000000234 15161264430 0013170 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
INSTALL.md 0000664 0000000 0000000 00000004301 15161264430 0012506 0 ustar 00root root 0000000 0000000 # GitList Installation
* 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 read/write permissions to your web server user:
```
cd /var/www/gitlist
mkdir cache
chmod 777 cache
```
That's it, installation complete!
## Webserver configuration
Apache is the "default" webserver for GitList. You will find the configuration inside the `.htaccess` file. However, nginx and lighttpd are also supported.
### nginx server.conf
```
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;
}
}
```
### lighttpd
```
# GitList is located in /var/www/gitlist
server.document-root = "/var/www"
url.rewrite-once = (
"^/gitlist/web/.+" => "$0",
"^/gitlist/favicon\.ico$" => "$0",
"^/gitlist(/[^\?]*)(\?.*)?" => "/gitlist/index.php$1$2"
)
```
### hiawatha
```
UrlToolkit {
ToolkitID = gitlist
RequestURI isfile Return
# If you have example.com/gitlist/ ; Otherwise remove "/gitlist" below
Match ^/gitlist/.* Rewrite /gitlist/index.php
Match ^/gitlist/.*\.ini DenyAccess
}
```
LICENSE.txt 0000664 0000000 0000000 00000002705 15161264430 0012707 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 00000012015 15161264430 0012336 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://gitlist-khornberg.rhcloud.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
* 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
## Installation
* 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.
* In case GitList isn't accessed through the root of the website, open .htaccess and edit RewriteBase (for example, /gitlist/ if GitList is accessed through http://localhost/gitlist/).
* Create the cache folder and give read/write permissions to your web server user:
```
cd /var/www/gitlist
mkdir cache
chmod 777 cache
```
That's it, installation complete! If you're having problems, check the [Troubleshooting](https://github.com/klaussilveira/gitlist/wiki/Troubleshooting) page.
## Development
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! :)
boot.php 0000664 0000000 0000000 00000000663 15161264430 0012541 0 ustar 00root root 0000000 0000000 mount('', new GitList\Controller\MainController());
$app->mount('', new GitList\Controller\BlobController());
$app->mount('', new GitList\Controller\CommitController());
$app->mount('', new GitList\Controller\TreeController());
$app->mount('', new GitList\Controller\NetworkController());
return $app;
build.xml 0000664 0000000 0000000 00000010110 15161264430 0012672 0 ustar 00root root 0000000 0000000
cache/ 0000775 0000000 0000000 00000000000 15161264430 0012123 5 ustar 00root root 0000000 0000000 cache/.gitkeep 0000664 0000000 0000000 00000000000 15161264430 0013542 0 ustar 00root root 0000000 0000000 composer.json 0000664 0000000 0000000 00000001100 15161264430 0013572 0 ustar 00root root 0000000 0000000 {
"name": "klaussilveira/gitlist",
"require": {
"silex/silex": "1.0.*@dev",
"twig/twig": "1.12.*",
"symfony/twig-bridge": "2.2.*",
"symfony/filesystem": "2.2.*",
"klaussilveira/gitter": "0.2.*"
},
"require-dev": {
"symfony/browser-kit": "2.2.*",
"symfony/css-selector": "2.2.*",
"phpunit/phpunit": "3.7.*",
"phpmd/phpmd": "1.4.*",
"phploc/phploc": "1.7.*"
},
"minimum-stability": "dev",
"autoload": {
"psr-0": {
"GitList": "src/"
}
}
}
composer.lock 0000664 0000000 0000000 00000145303 15161264430 0013567 0 ustar 00root root 0000000 0000000 {
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
],
"hash": "3b87a5ccc4819475fffa9f49284e65a6",
"packages": [
{
"name": "klaussilveira/gitter",
"version": "0.2.0",
"source": {
"type": "git",
"url": "https://github.com/klaussilveira/gitter.git",
"reference": "0.2.0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/klaussilveira/gitter/zipball/0.2.0",
"reference": "0.2.0",
"shasum": ""
},
"require": {
"php": ">=5.3.0",
"symfony/process": ">=2.2"
},
"require-dev": {
"phpunit/phpunit": ">=3.7.1",
"symfony/filesystem": ">=2.2"
},
"type": "library",
"autoload": {
"psr-0": {
"Gitter": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Klaus Silveira",
"email": "klaussilveira@php.net",
"homepage": "http://www.klaussilveira.com/",
"role": "Developer"
}
],
"description": "Gitter allows you to interact in an object oriented manner with Git repositories.",
"homepage": "https://github.com/klaussilveira/gitter",
"keywords": [
"git",
"vcs"
],
"time": "2013-06-01 13:32:37"
},
{
"name": "pimple/pimple",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/fabpot/Pimple.git",
"reference": "v1.0.2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fabpot/Pimple/zipball/v1.0.2",
"reference": "v1.0.2",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Pimple": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Pimple is a simple Dependency Injection Container for PHP 5.3",
"homepage": "http://pimple.sensiolabs.org",
"keywords": [
"container",
"dependency injection"
],
"time": "2013-03-08 08:21:40"
},
{
"name": "psr/log",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log",
"reference": "1.0.0"
},
"dist": {
"type": "zip",
"url": "https://github.com/php-fig/log/archive/1.0.0.zip",
"reference": "1.0.0",
"shasum": ""
},
"type": "library",
"autoload": {
"psr-0": {
"Psr\\Log\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"keywords": [
"log",
"psr",
"psr-3"
],
"time": "2012-12-21 11:40:51"
},
{
"name": "silex/silex",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/fabpot/Silex.git",
"reference": "803f809cdaa409e5769b24db952655d7e9187677"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fabpot/Silex/zipball/803f809cdaa409e5769b24db952655d7e9187677",
"reference": "803f809cdaa409e5769b24db952655d7e9187677",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"pimple/pimple": "1.*",
"symfony/event-dispatcher": ">=2.1,<2.3-dev",
"symfony/http-foundation": ">=2.1,<2.3-dev",
"symfony/http-kernel": ">=2.1,<2.3-dev",
"symfony/routing": ">=2.1,<2.3-dev"
},
"require-dev": {
"doctrine/dbal": ">=2.2.0,<2.4.0-dev",
"swiftmailer/swiftmailer": "4.2.*",
"symfony/browser-kit": ">=2.1,<2.3-dev",
"symfony/config": ">=2.1,<2.3-dev",
"symfony/css-selector": ">=2.1,<2.3-dev",
"symfony/dom-crawler": ">=2.1,<2.3-dev",
"symfony/finder": ">=2.1,<2.3-dev",
"symfony/form": ">=2.1.4,<2.3-dev",
"symfony/locale": ">=2.1,<2.3-dev",
"symfony/monolog-bridge": ">=2.1,<2.3-dev",
"symfony/options-resolver": ">=2.1,<2.3-dev",
"symfony/process": ">=2.1,<2.3-dev",
"symfony/security": ">=2.1,<2.3-dev",
"symfony/serializer": ">=2.1,<2.3-dev",
"symfony/translation": ">=2.1,<2.3-dev",
"symfony/twig-bridge": ">=2.1,<2.3-dev",
"symfony/validator": ">=2.1,<2.3-dev",
"twig/twig": ">=1.8.0,<2.0-dev"
},
"suggest": {
"symfony/browser-kit": ">=2.1,<2.3-dev",
"symfony/css-selector": ">=2.1,<2.3-dev",
"symfony/dom-crawler": ">=2.1,<2.3-dev",
"symfony/form": "To make use of the FormServiceProvider, >= 2.1.4 is required"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Silex": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Igor Wiedler",
"email": "igor@wiedler.ch",
"homepage": "http://wiedler.ch/igor/"
}
],
"description": "The PHP micro-framework based on the Symfony2 Components",
"homepage": "http://silex.sensiolabs.org",
"keywords": [
"microframework"
],
"time": "2013-04-01 08:47:32"
},
{
"name": "symfony/event-dispatcher",
"version": "2.2.x-dev",
"target-dir": "Symfony/Component/EventDispatcher",
"source": {
"type": "git",
"url": "https://github.com/symfony/EventDispatcher.git",
"reference": "v2.2.0-RC3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.2.0-RC3",
"reference": "v2.2.0-RC3",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"symfony/dependency-injection": ">=2.0,<3.0"
},
"suggest": {
"symfony/dependency-injection": "2.2.*",
"symfony/http-kernel": "2.2.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\EventDispatcher\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"description": "Symfony EventDispatcher Component",
"homepage": "http://symfony.com",
"time": "2013-02-11 11:26:43"
},
{
"name": "symfony/filesystem",
"version": "2.2.x-dev",
"target-dir": "Symfony/Component/Filesystem",
"source": {
"type": "git",
"url": "https://github.com/symfony/Filesystem.git",
"reference": "v2.2.0-RC3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Filesystem/zipball/v2.2.0-RC3",
"reference": "v2.2.0-RC3",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\Filesystem\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"description": "Symfony Filesystem Component",
"homepage": "http://symfony.com",
"time": "2013-01-17 15:25:59"
},
{
"name": "symfony/http-foundation",
"version": "2.2.x-dev",
"target-dir": "Symfony/Component/HttpFoundation",
"source": {
"type": "git",
"url": "https://github.com/symfony/HttpFoundation.git",
"reference": "9a87bc5856de55ebbc8b3e66c3c686e6aef35ba7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/9a87bc5856de55ebbc8b3e66c3c686e6aef35ba7",
"reference": "9a87bc5856de55ebbc8b3e66c3c686e6aef35ba7",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\HttpFoundation\\": ""
},
"classmap": [
"Symfony/Component/HttpFoundation/Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"description": "Symfony HttpFoundation Component",
"homepage": "http://symfony.com",
"time": "2013-04-01 08:05:23"
},
{
"name": "symfony/http-kernel",
"version": "2.2.x-dev",
"target-dir": "Symfony/Component/HttpKernel",
"source": {
"type": "git",
"url": "https://github.com/symfony/HttpKernel.git",
"reference": "3bfc8fda577fb671b2d9395a59fbc87f449fa61f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/HttpKernel/zipball/3bfc8fda577fb671b2d9395a59fbc87f449fa61f",
"reference": "3bfc8fda577fb671b2d9395a59fbc87f449fa61f",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"psr/log": ">=1.0,<2.0",
"symfony/event-dispatcher": ">=2.1,<3.0",
"symfony/http-foundation": ">=2.2,<2.3-dev"
},
"require-dev": {
"symfony/browser-kit": "2.2.*",
"symfony/class-loader": ">=2.1,<3.0",
"symfony/config": ">=2.0,<3.0",
"symfony/console": "2.2.*",
"symfony/dependency-injection": ">=2.0,<3.0",
"symfony/finder": ">=2.0,<3.0",
"symfony/process": ">=2.0,<3.0",
"symfony/routing": ">=2.2,<2.3-dev",
"symfony/stopwatch": ">=2.2,<2.3-dev"
},
"suggest": {
"symfony/browser-kit": "2.2.*",
"symfony/class-loader": "2.2.*",
"symfony/config": "2.2.*",
"symfony/console": "2.2.*",
"symfony/dependency-injection": "2.2.*",
"symfony/finder": "2.2.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\HttpKernel\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"description": "Symfony HttpKernel Component",
"homepage": "http://symfony.com",
"time": "2013-03-23 10:43:44"
},
{
"name": "symfony/process",
"version": "dev-master",
"target-dir": "Symfony/Component/Process",
"source": {
"type": "git",
"url": "https://github.com/symfony/Process.git",
"reference": "46b24c5905096914d467b769027e36433c7b5421"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Process/zipball/46b24c5905096914d467b769027e36433c7b5421",
"reference": "46b24c5905096914d467b769027e36433c7b5421",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\Process\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"description": "Symfony Process Component",
"homepage": "http://symfony.com",
"time": "2013-03-23 08:06:49"
},
{
"name": "symfony/routing",
"version": "2.2.x-dev",
"target-dir": "Symfony/Component/Routing",
"source": {
"type": "git",
"url": "https://github.com/symfony/Routing.git",
"reference": "6fea997908607f18a970a3848ec89c8e775255f3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Routing/zipball/6fea997908607f18a970a3848ec89c8e775255f3",
"reference": "6fea997908607f18a970a3848ec89c8e775255f3",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"doctrine/common": ">=2.2,<3.0",
"psr/log": ">=1.0,<2.0",
"symfony/config": ">=2.2,<2.3-dev",
"symfony/yaml": ">=2.0,<3.0"
},
"suggest": {
"doctrine/common": "~2.2",
"symfony/config": "2.2.*",
"symfony/yaml": "2.2.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\Routing\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"description": "Symfony Routing Component",
"homepage": "http://symfony.com",
"time": "2013-03-23 12:03:22"
},
{
"name": "symfony/twig-bridge",
"version": "2.2.x-dev",
"target-dir": "Symfony/Bridge/Twig",
"source": {
"type": "git",
"url": "https://github.com/symfony/TwigBridge.git",
"reference": "50bbc4a10d34a71325b58940c4887726b8a30841"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/TwigBridge/zipball/50bbc4a10d34a71325b58940c4887726b8a30841",
"reference": "50bbc4a10d34a71325b58940c4887726b8a30841",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"twig/twig": ">=1.11.0,<2.0"
},
"require-dev": {
"symfony/form": "2.2.*",
"symfony/http-kernel": ">=2.2,<2.3-dev",
"symfony/routing": ">=2.2,<2.3-dev",
"symfony/security": ">=2.0,<2.3-dev",
"symfony/templating": ">=2.1,<3.0",
"symfony/translation": ">=2.0,<2.3-dev",
"symfony/yaml": ">=2.0,<3.0"
},
"suggest": {
"symfony/form": "2.2.*",
"symfony/http-kernel": "2.2.*",
"symfony/routing": "2.2.*",
"symfony/security": "2.2.*",
"symfony/templating": "2.2.*",
"symfony/translation": "2.2.*",
"symfony/yaml": "2.2.*"
},
"type": "symfony-bridge",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Bridge\\Twig\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"description": "Symfony Twig Bridge",
"homepage": "http://symfony.com",
"time": "2013-03-15 10:14:31"
},
{
"name": "twig/twig",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/fabpot/Twig.git",
"reference": "399916916533589c95dc04e1afd4aeefa34928ad"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fabpot/Twig/zipball/399916916533589c95dc04e1afd4aeefa34928ad",
"reference": "399916916533589c95dc04e1afd4aeefa34928ad",
"shasum": ""
},
"require": {
"php": ">=5.2.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.12-dev"
}
},
"autoload": {
"psr-0": {
"Twig_": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Armin Ronacher",
"email": "armin.ronacher@active-4.com"
}
],
"description": "Twig, the flexible, fast, and secure template language for PHP",
"homepage": "http://twig.sensiolabs.org",
"keywords": [
"templating"
],
"time": "2013-04-01 08:27:18"
}
],
"packages-dev": [
{
"name": "pdepend/pdepend",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/pdepend/pdepend.git",
"reference": "85b3d7f2d2c6105a76daea0f5a0aee7c7a140b25"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pdepend/pdepend/zipball/85b3d7f2d2c6105a76daea0f5a0aee7c7a140b25",
"reference": "85b3d7f2d2c6105a76daea0f5a0aee7c7a140b25",
"shasum": ""
},
"require": {
"php": ">=5.2.3"
},
"bin": [
"src/bin/pdepend"
],
"type": "library",
"notification-url": "https://packagist.org/downloads/",
"description": "Official version of pdepend to be handled with Composer",
"time": "2013-01-25 15:09:33"
},
{
"name": "phploc/phploc",
"version": "1.7.4",
"source": {
"type": "git",
"url": "git://github.com/sebastianbergmann/phploc.git",
"reference": "1.7.4"
},
"dist": {
"type": "zip",
"url": "https://github.com/sebastianbergmann/phploc/archive/1.7.4.zip",
"reference": "1.7.4",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"symfony/finder": "2.1.x-dev",
"zetacomponents/console-tools": "dev-master"
},
"bin": [
"composer/bin/phploc"
],
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "A tool for quickly measuring the size of a PHP project.",
"homepage": "https://github.com/sebastianbergmann/phploc",
"time": "2012-11-10 12:45:44"
},
{
"name": "phpmd/phpmd",
"version": "1.4.1",
"source": {
"type": "git",
"url": "git://github.com/phpmd/phpmd.git",
"reference": "1.4.1"
},
"dist": {
"type": "zip",
"url": "https://github.com/phpmd/phpmd/archive/1.4.1.zip",
"reference": "1.4.1",
"shasum": ""
},
"require": {
"pdepend/pdepend": "*",
"php": ">=5.3.0"
},
"bin": [
"src/bin/phpmd"
],
"type": "library",
"notification-url": "https://packagist.org/downloads/",
"include-path": [
"../../pdepend/pdepend/src/main/php",
"src/main/php"
],
"description": "Official version of PHPMD handled with Composer.",
"time": "2012-12-14 12:25:09"
},
{
"name": "phpunit/php-code-coverage",
"version": "1.2.x-dev",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "1.2.9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.9",
"reference": "1.2.9",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"phpunit/php-file-iterator": ">=1.3.0@stable",
"phpunit/php-text-template": ">=1.1.1@stable",
"phpunit/php-token-stream": ">=1.1.3@stable"
},
"suggest": {
"ext-dom": "*",
"ext-xdebug": ">=2.0.5"
},
"type": "library",
"autoload": {
"classmap": [
"PHP/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
"homepage": "https://github.com/sebastianbergmann/php-code-coverage",
"keywords": [
"coverage",
"testing",
"xunit"
],
"time": "2013-02-26 18:55:56"
},
{
"name": "phpunit/php-file-iterator",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "2deb24c65ea78e126daa8d45b2089ddc29ec1d26"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2deb24c65ea78e126daa8d45b2089ddc29ec1d26",
"reference": "2deb24c65ea78e126daa8d45b2089ddc29ec1d26",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"autoload": {
"classmap": [
"File/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "FilterIterator implementation that filters files based on a list of suffixes.",
"homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
"keywords": [
"filesystem",
"iterator"
],
"time": "2013-01-07 10:47:05"
},
{
"name": "phpunit/php-text-template",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-text-template.git",
"reference": "1eeef106193d2f8c539728e566bb4793071a9e18"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/1eeef106193d2f8c539728e566bb4793071a9e18",
"reference": "1eeef106193d2f8c539728e566bb4793071a9e18",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"autoload": {
"classmap": [
"Text/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Simple template engine.",
"homepage": "https://github.com/sebastianbergmann/php-text-template/",
"keywords": [
"template"
],
"time": "2013-01-07 10:56:17"
},
{
"name": "phpunit/php-timer",
"version": "1.0.x-dev",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
"reference": "ecf7920b27003a9412b07dad79dbb5ad1249e6c3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/ecf7920b27003a9412b07dad79dbb5ad1249e6c3",
"reference": "ecf7920b27003a9412b07dad79dbb5ad1249e6c3",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"autoload": {
"classmap": [
"PHP/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Utility class for timing",
"homepage": "https://github.com/sebastianbergmann/php-timer/",
"keywords": [
"timer"
],
"time": "2013-01-30 06:08:51"
},
{
"name": "phpunit/php-token-stream",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "c25dd88e1592e66dee2553c99ef244203d5a1b98"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c25dd88e1592e66dee2553c99ef244203d5a1b98",
"reference": "c25dd88e1592e66dee2553c99ef244203d5a1b98",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": ">=5.3.3"
},
"type": "library",
"autoload": {
"classmap": [
"PHP/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Wrapper around PHP's tokenizer extension.",
"homepage": "https://github.com/sebastianbergmann/php-token-stream/",
"keywords": [
"tokenizer"
],
"time": "2013-01-07 10:56:35"
},
{
"name": "phpunit/phpunit",
"version": "3.7.x-dev",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "3.7.19"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.19",
"reference": "3.7.19",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-pcre": "*",
"ext-reflection": "*",
"ext-spl": "*",
"php": ">=5.3.3",
"phpunit/php-code-coverage": ">=1.2.1,<1.3.0",
"phpunit/php-file-iterator": ">=1.3.1",
"phpunit/php-text-template": ">=1.1.1",
"phpunit/php-timer": ">=1.0.2,<1.1.0",
"phpunit/phpunit-mock-objects": ">=1.2.0,<1.3.0",
"symfony/yaml": ">=2.0.0,<2.3.0"
},
"require-dev": {
"pear-pear/pear": "1.9.4"
},
"suggest": {
"ext-json": "*",
"ext-simplexml": "*",
"ext-tokenizer": "*",
"phpunit/php-invoker": ">=1.1.0,<1.2.0"
},
"bin": [
"composer/bin/phpunit"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.7.x-dev"
}
},
"autoload": {
"classmap": [
"PHPUnit/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
"",
"../../symfony/yaml/"
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "The PHP Unit Testing framework.",
"homepage": "http://www.phpunit.de/",
"keywords": [
"phpunit",
"testing",
"xunit"
],
"time": "2013-03-25 11:45:06"
},
{
"name": "phpunit/phpunit-mock-objects",
"version": "1.2.x-dev",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
"reference": "d49b5683200b5db9b1c64cb06f52f50d147891c4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/d49b5683200b5db9b1c64cb06f52f50d147891c4",
"reference": "d49b5683200b5db9b1c64cb06f52f50d147891c4",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"phpunit/php-text-template": ">=1.1.1@stable"
},
"suggest": {
"ext-soap": "*"
},
"type": "library",
"autoload": {
"classmap": [
"PHPUnit/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Mock Object library for PHPUnit",
"homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
"keywords": [
"mock",
"xunit"
],
"time": "2013-02-05 07:46:41"
},
{
"name": "symfony/browser-kit",
"version": "2.2.x-dev",
"target-dir": "Symfony/Component/BrowserKit",
"source": {
"type": "git",
"url": "https://github.com/symfony/BrowserKit.git",
"reference": "d55e7ffd7f10bead48adb03b208bc67bd53926bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/BrowserKit/zipball/d55e7ffd7f10bead48adb03b208bc67bd53926bb",
"reference": "d55e7ffd7f10bead48adb03b208bc67bd53926bb",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"symfony/dom-crawler": ">=2.0,<3.0"
},
"require-dev": {
"symfony/css-selector": ">=2.0,<3.0",
"symfony/process": ">=2.0,<3.0"
},
"suggest": {
"symfony/process": "2.2.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\BrowserKit\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"description": "Symfony BrowserKit Component",
"homepage": "http://symfony.com",
"time": "2013-03-15 10:14:31"
},
{
"name": "symfony/css-selector",
"version": "2.2.x-dev",
"target-dir": "Symfony/Component/CssSelector",
"source": {
"type": "git",
"url": "https://github.com/symfony/CssSelector.git",
"reference": "v2.2.0-RC3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/CssSelector/zipball/v2.2.0-RC3",
"reference": "v2.2.0-RC3",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\CssSelector\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"description": "Symfony CssSelector Component",
"homepage": "http://symfony.com",
"time": "2013-01-17 15:25:59"
},
{
"name": "symfony/dom-crawler",
"version": "dev-master",
"target-dir": "Symfony/Component/DomCrawler",
"source": {
"type": "git",
"url": "https://github.com/symfony/DomCrawler.git",
"reference": "09f0cd5980511ee77c2e8142405ccd5c867506b9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/DomCrawler/zipball/09f0cd5980511ee77c2e8142405ccd5c867506b9",
"reference": "09f0cd5980511ee77c2e8142405ccd5c867506b9",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"symfony/css-selector": ">=2.0,<3.0"
},
"suggest": {
"symfony/css-selector": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.4-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\DomCrawler\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"description": "Symfony DomCrawler Component",
"homepage": "http://symfony.com",
"time": "2013-05-27 14:49:42"
},
{
"name": "symfony/finder",
"version": "2.1.x-dev",
"target-dir": "Symfony/Component/Finder",
"source": {
"type": "git",
"url": "https://github.com/symfony/Finder.git",
"reference": "v2.1.9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Finder/zipball/v2.1.9",
"reference": "v2.1.9",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"autoload": {
"psr-0": {
"Symfony\\Component\\Finder": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"description": "Symfony Finder Component",
"homepage": "http://symfony.com",
"time": "2013-03-06 19:26:55"
},
{
"name": "symfony/yaml",
"version": "2.2.x-dev",
"target-dir": "Symfony/Component/Yaml",
"source": {
"type": "git",
"url": "https://github.com/symfony/Yaml.git",
"reference": "3f6d4ab3fd8226ab4ba0be9fc8a238f4338b79ab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Yaml/zipball/3f6d4ab3fd8226ab4ba0be9fc8a238f4338b79ab",
"reference": "3f6d4ab3fd8226ab4ba0be9fc8a238f4338b79ab",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\Yaml\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"description": "Symfony Yaml Component",
"homepage": "http://symfony.com",
"time": "2013-03-23 07:49:54"
},
{
"name": "zetacomponents/base",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/zetacomponents/Base.git",
"reference": "642f63a8a72c32996f1aaf8a317fdf746bc32ce7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zetacomponents/Base/zipball/642f63a8a72c32996f1aaf8a317fdf746bc32ce7",
"reference": "642f63a8a72c32996f1aaf8a317fdf746bc32ce7",
"shasum": ""
},
"require-dev": {
"zetacomponents/unit-test": "*"
},
"type": "library",
"autoload": {
"classmap": [
"src"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Sergey Alexeev"
},
{
"name": "Sebastian Bergmann"
},
{
"name": "Jan Borsodi"
},
{
"name": "Raymond Bosman"
},
{
"name": "Frederik Holljen"
},
{
"name": "Kore Nordmann"
},
{
"name": "Derick Rethans"
},
{
"name": "Vadym Savchuk"
},
{
"name": "Tobias Schlitt"
},
{
"name": "Alexandru Stanoi"
}
],
"description": "The Base package provides the basic infrastructure that all packages rely on. Therefore every component relies on this package.",
"homepage": "https://github.com/zetacomponents",
"time": "2012-05-21 11:21:36"
},
{
"name": "zetacomponents/console-tools",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/zetacomponents/ConsoleTools.git",
"reference": "90156abef01e4215fda8b9740f77c322f126fb02"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zetacomponents/ConsoleTools/zipball/90156abef01e4215fda8b9740f77c322f126fb02",
"reference": "90156abef01e4215fda8b9740f77c322f126fb02",
"shasum": ""
},
"require": {
"zetacomponents/base": "*"
},
"require-dev": {
"zetacomponents/unit-test": "*"
},
"type": "library",
"autoload": {
"classmap": [
"src"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Sergey Alexeev"
},
{
"name": "Sebastian Bergmann"
},
{
"name": "Jan Borsodi"
},
{
"name": "Raymond Bosman"
},
{
"name": "Frederik Holljen"
},
{
"name": "Kore Nordmann"
},
{
"name": "Derick Rethans"
},
{
"name": "Vadym Savchuk"
},
{
"name": "Tobias Schlitt"
},
{
"name": "Alexandru Stanoi"
}
],
"description": "A set of classes to do different actions with the console (also called shell). It can render a progress bar, tables and a status bar and contains a class for parsing command line options.",
"homepage": "https://github.com/zetacomponents",
"time": "2012-05-21 09:55:34"
}
],
"aliases": [
],
"minimum-stability": "dev",
"stability-flags": {
"silex/silex": 20
},
"platform": [
],
"platform-dev": [
]
}
config.ini-example 0000664 0000000 0000000 00000001644 15161264430 0014464 0 ustar 00root root 0000000 0000000 [git]
client = '/usr/bin/git' ; Your git executable path
default_branch = 'master' ; Default branch when HEAD is detached
repositories[] = '/home/git/repositories/' ; Path to your repositories
; If you wish to add more repositories, just add a new line
; WINDOWS USERS
;client = '"C:\Program Files (x86)\Git\bin\git.exe"' ; Your git executable path
;repositories[] = 'C:\Path\to\Repos\' ; Path to your repositories
; You can hide repositories from GitList, just copy this for each repository you want to hide
; hidden[] = '/home/git/repositories/BetaTest'
[app]
debug = false
cache = true
; If you need to specify custom filetypes for certain extensions, do this here
[filetypes]
; extension = type
; dist = xml
; If you need to set file types as binary or not, do this here
[binary_filetypes]
; extension = true
; svh = false
; map = true
; set the timezone
[Date]
; timezone = UTC
index.php 0000664 0000000 0000000 00000001354 15161264430 0012703 0 ustar 00root root 0000000 0000000 get('Date', 'timezone')) {
date_default_timezone_set($config->get('Date', 'timezone'));
}
$app = require 'boot.php';
$app->run();
phpunit.xml.dist 0000664 0000000 0000000 00000001350 15161264430 0014232 0 ustar 00root root 0000000 0000000
./tests/
pkg_builder/ 0000775 0000000 0000000 00000000000 15161264430 0013347 5 ustar 00root root 0000000 0000000 pkg_builder/Makefile 0000664 0000000 0000000 00000010511 15161264430 0015005 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
pkg_builder/README.md 0000664 0000000 0000000 00000001553 15161264430 0014632 0 ustar 00root root 0000000 0000000 # GitList Builder: Tools to build gitlist package
## Status
### Ready to build
* Core Deb Packages:
```
$ make build_deb
```
* Core Rpm Packages:
```
$ make build_rpm
```
### Not Ready (Comming soon)
Packages to install configuration files:
* make apache_deb
* make apache_rpm
* make nginx_deb
* make nginx_rpm
## Dependencies
* To use this package builder you may need to install some development packages like: dpkg-dev or evem rpm;
* A tarball of a stable release;
## Instructions
To use this builder just download the lastest stable release into this directory and build using the make functions avaible in make help
## How to build
The packages can be generated by running Makefile functions like:
```
$ make build_deb
$ make build_rpm
```
## Structure
Core package is a simple source package while a configuration package requires all the dependencies.
pkg_builder/tools/ 0000775 0000000 0000000 00000000000 15161264430 0014507 5 ustar 00root root 0000000 0000000 pkg_builder/tools/gitlist.spec 0000664 0000000 0000000 00000001105 15161264430 0017037 0 ustar 00root root 0000000 0000000 Name: %{name}
Summary: %{summary}
Version: %{version}
Release: %{release}
URL: %{url}
License: %{license}
Group: %{group}
Vendor: %{vendor}
Packager: %{user}
Prefix: %{prefix}
BuildArch: noarch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
Source0: %{name}.tar
%description
%{summary}
%prep
%setup -c
%build
%install
%{__rm} -rf %{buildroot}
%{__mkdir} -p %{buildroot}%{prefix}
%{__cp} -Ra * %{buildroot}%{prefix}
%clean
rm -rf %{buildroot}
%files
%defattr(0755,root,root)
%{prefix}/*
%changelog
* Thu Jan 21 2013 Bruno Gurgel
- Initial
pkg_builder/tools/release.info 0000664 0000000 0000000 00000000031 15161264430 0016776 0 ustar 00root root 0000000 0000000 release=0.3
name=gitlist
src/ 0000775 0000000 0000000 00000000000 15161264430 0011647 5 ustar 00root root 0000000 0000000 src/GitList/ 0000775 0000000 0000000 00000000000 15161264430 0013226 5 ustar 00root root 0000000 0000000 src/GitList/Application.php 0000664 0000000 0000000 00000006144 15161264430 0016207 0 ustar 00root root 0000000 0000000 path = realpath($root);
$this['debug'] = $config->get('app', 'debug');
$this['filetypes'] = $config->getSection('filetypes');
$this['cache.archives'] = $this->getCachePath() . 'archives';
// Register services
$this->register(new TwigServiceProvider(), array(
'twig.path' => $this->getViewPath(),
'twig.options' => $config->get('app', 'cache') ?
array('cache' => $this->getCachePath() . 'views') : array(),
));
$repositories = $config->get('git', 'repositories');
$this->register(new GitServiceProvider(), array(
'git.client' => $config->get('git', 'client'),
'git.repos' => $repositories,
'ini.file' => "config.ini",
'git.hidden' => $config->get('git', 'hidden') ?
$config->get('git', 'hidden') : array(),
'git.default_branch' => $config->get('git', 'default_branch') ?
$config->get('git', 'default_branch') : 'master',
));
$this->register(new ViewUtilServiceProvider());
$this->register(new RepositoryUtilServiceProvider());
$this->register(new UrlGeneratorServiceProvider());
$this->register(new RoutingUtilServiceProvider());
$this['twig'] = $this->share($this->extend('twig', function ($twig, $app) {
$twig->addFilter('htmlentities', new \Twig_Filter_Function('htmlentities'));
$twig->addFilter('md5', new \Twig_Filter_Function('md5'));
return $twig;
}));
// Handle errors
$this->error(function (\Exception $e, $code) use ($app) {
if ($app['debug']) {
return;
}
return $app['twig']->render('error.twig', array(
'message' => $e->getMessage(),
));
});
}
public function getPath()
{
return $this->path . DIRECTORY_SEPARATOR;
}
public function setPath($path)
{
$this->path = $path;
return $this;
}
public function getCachePath()
{
return $this->path . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR;
}
public function getViewPath()
{
return $this->path . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR;
}
}
src/GitList/Config.php 0000664 0000000 0000000 00000003337 15161264430 0015152 0 ustar 00root root 0000000 0000000 validateOptions();
return $config;
}
public function __construct($data = array())
{
$this->data = $data;
}
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()
{
$repositories = $this->get('git', 'repositories');
$atLeastOneOk = false;
$atLeastOneWrong = false;
foreach ($repositories as $directory) {
if (!$directory || !is_dir($directory)) {
$atLeastOneWrong = true;
} else {
$atLeastOneOk = true;
}
}
if (!$atLeastOneOk) {
die("Please, edit the config file and provide your repositories directory");
}
if ($atLeastOneWrong) {
die("One or more of the supplied repository paths appears to be wrong. Please, check the config file");
}
}
}
src/GitList/Controller/ 0000775 0000000 0000000 00000000000 15161264430 0015351 5 ustar 00root root 0000000 0000000 src/GitList/Controller/BlobController.php 0000664 0000000 0000000 00000005606 15161264430 0021013 0 ustar 00root root 0000000 0000000 get('{repo}/blob/{commitishPath}', function ($repo, $commitishPath) use ($app) {
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
list($branch, $file) = $app['util.routing']
->parseCommitishPathParam($commitishPath, $repo);
list($branch, $file) = $app['util.repository']->extractRef($repository, $branch, $file);
$blob = $repository->getBlob("$branch:\"$file\"");
$breadcrumbs = $app['util.view']->getBreadcrumbs($file);
$fileType = $app['util.repository']->getFileType($file);
if ($fileType !== 'image' && $app['util.repository']->isBinary($file)) {
return $app->redirect($app['url_generator']->generate('blob_raw', array(
'repo' => $repo,
'commitishPath' => $commitishPath,
)));
}
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('repo', $app['util.routing']->getRepositoryRegex())
->assert('commitishPath', '.+')
->bind('blob');
$route->get('{repo}/raw/{commitishPath}', function ($repo, $commitishPath) use ($app) {
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
list($branch, $file) = $app['util.routing']
->parseCommitishPathParam($commitishPath, $repo);
list($branch, $file) = $app['util.repository']->extractRef($repository, $branch, $file);
$blob = $repository->getBlob("$branch:\"$file\"")->output();
$headers = array();
if ($app['util.repository']->isBinary($file)) {
$headers['Content-Disposition'] = 'attachment; filename="' . $file . '"';
$headers['Content-Type'] = 'application/octet-stream';
} else {
$headers['Content-Type'] = 'text/plain';
}
return new Response($blob, 200, $headers);
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('commitishPath', $app['util.routing']->getCommitishPathRegex())
->bind('blob_raw');
return $route;
}
}
src/GitList/Controller/CommitController.php 0000664 0000000 0000000 00000011617 15161264430 0021364 0 ustar 00root root 0000000 0000000 get('{repo}/commits/{commitishPath}', function ($repo, $commitishPath) use ($app) {
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
if ($commitishPath === null) {
$commitishPath = $repository->getHead();
}
list($branch, $file) = $app['util.routing']
->parseCommitishPathParam($commitishPath, $repo);
list($branch, $file) = $app['util.repository']->extractRef($repository, $branch, $file);
$type = $file ? "$branch -- \"$file\"" : $branch;
$pager = $app['util.view']->getPager($app['request']->get('page'), $repository->getTotalCommits($type));
$commits = $repository->getPaginatedCommits($type, $pager['current']);
$categorized = array();
foreach ($commits as $commit) {
$date = $commit->getDate();
$date = $date->format('m/d/Y');
$categorized[$date][] = $commit;
}
$template = $app['request']->isXmlHttpRequest() ? 'commits_list.twig' : 'commits.twig';
return $app['twig']->render($template, array(
'page' => 'commits',
'pager' => $pager,
'repo' => $repo,
'branch' => $branch,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
'commits' => $categorized,
'file' => $file,
));
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('commitishPath', $app['util.routing']->getCommitishPathRegex())
->value('commitishPath', null)
->bind('commits');
$route->post('{repo}/commits/{branch}/search', function (Request $request, $repo, $branch = '') use ($app) {
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
$query = $request->get('query');
$commits = $repository->searchCommitLog($request->get('query'));
$categorized = array();
foreach ($commits as $commit) {
$date = $commit->getDate();
$date = $date->format('m/d/Y');
$categorized[$date][] = $commit;
}
return $app['twig']->render('searchcommits.twig', array(
'repo' => $repo,
'branch' => $branch,
'file' => '',
'commits' => $categorized,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
'query' => $query
));
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', $app['util.routing']->getBranchRegex())
->bind('searchcommits');
$route->get('{repo}/commit/{commit}', function ($repo, $commit) use ($app) {
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
$commit = $repository->getCommit($commit);
$branch = $repository->getHead();
return $app['twig']->render('commit.twig', array(
'branch' => $branch,
'repo' => $repo,
'commit' => $commit,
));
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('commit', '[a-f0-9^]+')
->bind('commit');
$route->get('{repo}/blame/{commitishPath}', function ($repo, $commitishPath) use ($app) {
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
list($branch, $file) = $app['util.routing']
->parseCommitishPathParam($commitishPath, $repo);
list($branch, $file) = $app['util.repository']->extractRef($repository, $branch, $file);
$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', $app['util.routing']->getRepositoryRegex())
->assert('commitishPath', $app['util.routing']->getCommitishPathRegex())
->bind('blame');
return $route;
}
}
src/GitList/Controller/MainController.php 0000664 0000000 0000000 00000005222 15161264430 0021013 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('/refresh', function(Request $request) use ($app ) {
# Go back to calling page
return $app->redirect($request->headers->get('Referer'));
})->bind('refresh');
$route->get('{repo}/stats/{branch}', function($repo, $branch) use ($app) {
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
if ($branch === null) {
$branch = $repository->getHead();
}
$stats = $repository->getStatistics($branch);
$authors = $repository->getAuthorStatistics($branch);
return $app['twig']->render('stats.twig', array(
'repo' => $repo,
'branch' => $branch,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
'stats' => $stats,
'authors' => $authors,
));
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', $app['util.routing']->getBranchRegex())
->value('branch', null)
->bind('stats');
$route->get('{repo}/{branch}/rss/', function($repo, $branch) use ($app) {
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
if ($branch === null) {
$branch = $repository->getHead();
}
$commits = $repository->getPaginatedCommits($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', $app['util.routing']->getRepositoryRegex())
->assert('branch', $app['util.routing']->getBranchRegex())
->value('branch', null)
->bind('rss');
return $route;
}
}
src/GitList/Controller/NetworkController.php 0000664 0000000 0000000 00000011402 15161264430 0021555 0 ustar 00root root 0000000 0000000 get('{repo}/network/{commitishPath}/{page}.json',
function ($repo, $commitishPath, $page) use ($app) {
/** @var $repository Repository */
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
if ($commitishPath === null) {
$commitishPath = $repository->getHead();
}
$pager = $app['util.view']->getPager($page, $repository->getTotalCommits($commitishPath));
$commits = $repository->getPaginatedCommits($commitishPath, $pager['current']);
$jsonFormattedCommits = array();
foreach ($commits as $commit) {
$detailsUrl = $app['url_generator']->generate(
'commit',
array(
'repo' => $repo,
'commit' => $commit->getHash()
)
);
$jsonFormattedCommits[$commit->getHash()] = array(
'hash' => $commit->getHash(),
'parentsHash' => $commit->getParentsHash(),
'date' => $commit->getDate()->format('U'),
'message' => htmlentities($commit->getMessage()),
'details' => $detailsUrl,
'author' => array(
'name' => $commit->getAuthor()->getName(),
'email' => $commit->getAuthor()->getEmail(),
// due to the lack of a inbuilt javascript md5 mechanism, build the full avatar url on the php side
'image' => 'http://gravatar.com/avatar/' . md5(
strtolower($commit->getAuthor()->getEmail())
) . '?s=40'
)
);
}
$nextPageUrl = null;
if ($pager['last'] !== $pager['current']) {
$nextPageUrl = $app['url_generator']->generate(
'networkData',
array(
'repo' => $repo,
'commitishPath' => $commitishPath,
'page' => $pager['next']
)
);
}
// when no commits are given, return an empty response - issue #369
if( count($commits) === 0 ) {
return $app->json( array(
'repo' => $repo,
'commitishPath' => $commitishPath,
'nextPage' => null,
'start' => null,
'commits' => $jsonFormattedCommits
), 200
);
}
return $app->json( array(
'repo' => $repo,
'commitishPath' => $commitishPath,
'nextPage' => $nextPageUrl,
'start' => $commits[0]->getHash(),
'commits' => $jsonFormattedCommits
), 200
);
}
)->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('commitishPath', $app['util.routing']->getCommitishPathRegex())
->value('commitishPath', null)
->assert('page', '\d+')
->value('page', '0')
->bind('networkData');
$route->get(
'{repo}/network/{commitishPath}',
function ($repo, $commitishPath) use ($app) {
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
if ($commitishPath === null) {
$commitishPath = $repository->getHead();
}
list($branch, $file) = $app['util.routing']->parseCommitishPathParam($commitishPath, $repo);
list($branch, $file) = $app['util.repository']->extractRef($repository, $branch, $file);
return $app['twig']->render(
'network.twig',
array(
'repo' => $repo,
'branch' => $branch,
'commitishPath' => $commitishPath,
)
);
}
)->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('commitishPath', $app['util.routing']->getCommitishPathRegex())
->value('commitishPath', null)
->bind('network');
return $route;
}
}
src/GitList/Controller/TreeController.php 0000664 0000000 0000000 00000012327 15161264430 0021032 0 ustar 00root root 0000000 0000000 get('{repo}/tree/{commitishPath}/', $treeController = function ($repo, $commitishPath = '') use ($app) {
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
if (!$commitishPath) {
$commitishPath = $repository->getHead();
}
list($branch, $tree) = $app['util.routing']->parseCommitishPathParam($commitishPath, $repo);
list($branch, $tree) = $app['util.repository']->extractRef($repository, $branch, $tree);
$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($repository, $branch),
));
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('commitishPath', $app['util.routing']->getCommitishPathRegex())
->bind('tree');
$route->post('{repo}/tree/{branch}/search', function (Request $request, $repo, $branch = '', $tree = '') use ($app) {
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
if (!$branch) {
$branch = $repository->getHead();
}
$query = $request->get('query');
$breadcrumbs = array(array('dir' => 'Search results for: ' . $query, 'path' => ''));
$results = $repository->searchTree($query, $branch);
return $app['twig']->render('search.twig', array(
'results' => $results,
'repo' => $repo,
'branch' => $branch,
'path' => $tree,
'breadcrumbs' => $breadcrumbs,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
));
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', $app['util.routing']->getBranchRegex())
->bind('search');
# Intentionally before next statement, because order appears
# to be important, and the other statement got precedence previously.
$route->get('{repo}/{format}ball/{branch}', function($repo, $format, $branch) use ($app) {
$repository = $app['git']->getRepositoryFromName($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', $app['util.routing']->getRepositoryRegex())
->assert('branch', $app['util.routing']->getBranchRegex())
->bind('archive');
$route->get('{repo}/{branch}/', function($repo, $branch) use ($app, $treeController) {
return $treeController($repo, $branch);
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', $app['util.routing']->getBranchRegex())
->bind('branch');
$route->get('{repo}/', function($repo) use ($app, $treeController) {
return $treeController($repo);
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->bind('repository');
return $route;
}
}
src/GitList/Exception/ 0000775 0000000 0000000 00000000000 15161264430 0015164 5 ustar 00root root 0000000 0000000 src/GitList/Exception/BlankDataException.php 0000664 0000000 0000000 00000000141 15161264430 0021371 0 ustar 00root root 0000000 0000000 setDefaultBranch($options['default_branch']);
$this->setHidden($options['hidden']);
}
public function getRepositoryFromName($paths, $repo)
{
$repositories = $this->getRepositories($paths);
$path = $repositories[$repo]['path'];
return $this->getRepository($path);
}
/**
* Searches for valid repositories on the specified path
*
* @param array $paths Array of paths where repositories will be searched
* @return array Found repositories, containing their name, path and description
*/
public function getRepositories($paths)
{
$allRepositories = array();
foreach ($paths as $path) {
$repositories = $this->recurseDirectory($path);
if (empty($repositories)) {
throw new \RuntimeException('There are no GIT repositories in ' . $path);
}
$allRepositories = array_merge($allRepositories, $repositories);
}
$allRepositories = array_unique($allRepositories, SORT_REGULAR);
asort($allRepositories);
return $allRepositories;
}
private function recurseDirectory($path, $topLevel = true)
{
$dir = new \DirectoryIterator($path);
$repositories = array();
foreach ($dir as $file) {
if ($file->isDot()) {
continue;
}
if (strrpos($file->getFilename(), '.') === 0) {
continue;
}
if (!$file->isReadable()) {
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 = null;
}
if (!$topLevel) {
$repoName = $file->getPathInfo()->getFilename() . '/' . $file->getFilename();
} else {
$repoName = $file->getFilename();
}
$repositories[$repoName] = array(
'name' => $repoName,
'path' => $file->getPathname(),
'description' => $description
);
continue;
} else {
$repositories = array_merge($repositories, $this->recurseDirectory($file->getPathname(), false));
}
}
}
return $repositories;
}
/**
* Set default branch as a string.
*
* @param string $branch Name of branch to use when repo's HEAD is detached.
*/
protected function setDefaultBranch($branch)
{
$this->defaultBranch = $branch;
return $this;
}
/**
* Return name of default branch as a string.
*/
public function getDefaultBranch()
{
return $this->defaultBranch;
}
/**
* 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;
return $this;
}
/**
* Overloads the parent::createRepository method for the correct Repository class instance
*
* {@inheritdoc}
*/
public function createRepository($path, $bare = null)
{
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($bare);
}
/**
* Overloads the parent::getRepository method for the correct Repository class instance
*
* {@inheritdoc}
*/
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);
}
return new Repository($path, $this);
}
}
src/GitList/Git/Repository.php 0000664 0000000 0000000 00000026677 15161264430 0016663 0 ustar 00root root 0000000 0000000 getClient()->run($this, "show $commitHash");
$logs = explode("\n", $logs);
return strpos($logs[0], 'commit') === 0;
}
/**
* Get the current branch, returning a default value when HEAD is detached.
*/
public function getHead($default = null)
{
$client = $this->getClient();
return parent::getHead($client->getDefaultBranch());
}
/**
* Show the data from a specific commit
*
* @param string $commitHash Hash of the specific commit to read data
* @return array Commit data
*/
public function getCommit($commitHash)
{
$logs = $this->getClient()->run($this,
"show --pretty=format:\"- %H"
. "%h%T%P"
. "%an%ae"
. "%at%cn%ce"
. "%ct"
. ""
. ""
. "
\" $commitHash"
);
$xmlEnd = strpos($logs, '') + 7;
$commitInfo = substr($logs, 0, $xmlEnd);
$commitData = substr($logs, $xmlEnd);
$logs = explode("\n", $commitData);
// Read commit metadata
$format = new PrettyFormat;
$data = $format->parse($commitInfo);
$commit = new Commit;
$commit->importData($data[0]);
if ($commit->getParentsHash()) {
$command = 'diff ' . $commitHash . '~1..' . $commitHash;
$logs = explode("\n", $this->getClient()->run($this, $command));
}
$commit->setDiffs($this->readDiffLogs($logs));
return $commit;
}
/**
* 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 --root -sl $file");
$logs = explode("\n", $logs);
$i = 0;
$previousCommit = '';
foreach ($logs as $log) {
if ($log == '') {
continue;
}
preg_match_all("/([a-zA-Z0-9]{40})\s+.*?([0-9]+)\)(.+)/", $log, $match);
$currentCommit = $match[1][0];
if ($currentCommit != $previousCommit) {
++$i;
$blame[$i] = array(
'line' => '',
'commit' => $currentCommit,
'commitShort' => substr($currentCommit, 0, 8)
);
}
$blame[$i]['line'] .= PHP_EOL . $match[3][0];
$previousCommit = $currentCommit;
}
return $blame;
}
/**
* Read diff logs and generate a collection of diffs
*
* @param array $logs Array of log rows
* @return array Array of diffs
*/
public function readDiffLogs(array $logs)
{
$diffs = array();
$lineNumOld = 0;
$lineNumNew = 0;
foreach ($logs as $log) {
# Skip empty lines
if ($log == "") {
continue;
}
if ('diff' === substr($log, 0, 4)) {
if (isset($diff)) {
$diffs[] = $diff;
}
$diff = new Diff;
if (preg_match('/^diff --[\S]+ a\/?(.+) b\/?/', $log, $name)) {
$diff->setFile($name[1]);
}
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]}");
}
}
if (!empty($log)) {
switch ($log[0]) {
case "@":
// Set the line numbers
preg_match('/@@ -([0-9]+)/', $log, $matches);
$lineNumOld = $matches[1] - 1;
$lineNumNew = $matches[1] - 1;
break;
case "-":
$lineNumOld++;
break;
case "+":
$lineNumNew++;
break;
default:
$lineNumOld++;
$lineNumNew++;
}
} else {
$lineNumOld++;
$lineNumNew++;
}
if (isset($diff)) {
$diff->addLine($log, $lineNumOld, $lineNumNew);
}
}
if (isset($diff)) {
$diffs[] = $diff;
}
return $diffs;
}
/**
* Show the repository commit log with pagination
*
* @access public
* @return array Commit log
*/
public function getPaginatedCommits($file = null, $page = 0)
{
$page = 15 * $page;
$pager = "--skip=$page --max-count=15";
$command =
"log $pager --pretty=format:\"- %H"
. "%h%T%P"
. "%an%ae"
. "%at%cn"
. "%ce"
. "%ct"
. "
\"";
if ($file) {
$command .= " $file";
}
try {
$logs = $this->getPrettyFormat($command);
} catch (\RuntimeException $e) {
return array();
}
foreach ($logs as $log) {
$commit = new Commit;
$commit->importData($log);
$commits[] = $commit;
}
return $commits;
}
public function searchCommitLog($query)
{
$query = escapeshellarg($query);
$command =
"log --grep={$query} --pretty=format:\"- %H"
. "%h%T%P"
. "%an%ae"
. "%at%cn"
. "%ce"
. "%ct"
. "
\"";
try {
$logs = $this->getPrettyFormat($command);
} catch (\RuntimeException $e) {
return array();
}
foreach ($logs as $log) {
$commit = new Commit;
$commit->importData($log);
$commits[] = $commit;
}
return $commits;
}
public function searchTree($query, $branch)
{
$query = escapeshellarg($query);
try {
$results = $this->getClient()->run($this, "grep -I --line-number {$query} $branch");
} catch (\RuntimeException $e) {
return false;
}
$results = explode("\n", $results);
foreach ($results as $result) {
if ($result == '') {
continue;
}
preg_match_all('/([\w-._]+):([^:]+):([0-9]+):(.+)/', $result, $matches, PREG_SET_ORDER);
$data['branch'] = $matches[0][1];
$data['file'] = $matches[0][2];
$data['line'] = $matches[0][3];
$data['match'] = $matches[0][4];
$searchResults[] = $data;
}
return $searchResults;
}
public function getAuthorStatistics($branch)
{
$logs = $this->getClient()->run($this, 'log --pretty=format:"%an||%ae" ' . $branch);
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;
}
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) {
$extension = substr($file[4], $pos);
if (($pos = strrpos($extension, '/')) === false) {
$data['extensions'][] = $extension;
}
}
}
$data['extensions'] = array_count_values($data['extensions']);
arsort($data['extensions']);
return $data;
}
/**
* 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");
}
/**
* Return true if $path exists in $branch; return false otherwise.
*
* @param string $commitish Commitish reference; branch, tag, SHA1, etc.
* @param string $path Path whose existence we want to verify.
*
* GRIPE Arguably belongs in Gitter, as it's generally useful functionality.
* Also, this really may not be the best way to do this.
*/
public function pathExists($commitish, $path)
{
$output = $this->getClient()->run($this, "ls-tree $commitish '$path'");
if (strlen($output) > 0) {
return true;
}
return false;
}
}
src/GitList/Provider/ 0000775 0000000 0000000 00000000000 15161264430 0015020 5 ustar 00root root 0000000 0000000 src/GitList/Provider/GitServiceProvider.php 0000664 0000000 0000000 00000001464 15161264430 0021315 0 ustar 00root root 0000000 0000000 share(function () use ($app) {
return new Repository($app);
});
}
public function boot(Application $app)
{
}
}
src/GitList/Provider/RoutingUtilServiceProvider.php 0000664 0000000 0000000 00000001101 15161264430 0023043 0 ustar 00root root 0000000 0000000 share(function () use ($app) {
return new Routing($app);
});
}
public function boot(Application $app)
{
}
}
src/GitList/Provider/ViewUtilServiceProvider.php 0000664 0000000 0000000 00000001043 15161264430 0022333 0 ustar 00root root 0000000 0000000 share(function () {
return new View;
});
}
public function boot(Application $app)
{
}
}
src/GitList/Util/ 0000775 0000000 0000000 00000000000 15161264430 0014143 5 ustar 00root root 0000000 0000000 src/GitList/Util/Repository.php 0000664 0000000 0000000 00000015053 15161264430 0017037 0 ustar 00root root 0000000 0000000 'php',
'c' => 'clike',
'h' => 'clike',
'cpp' => 'clike',
'm' => 'clike',
'mm' => 'clike',
'ino' => 'clike',
'cs' => 'text/x-csharp',
'java' => 'text/x-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',
'scala' => 'text/x-scala',
'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',
);
protected static $binaryTypes = array(
'exe', 'com', 'so', 'la', 'o', 'dll', 'pyc',
'jpg', 'jpeg', 'bmp', 'gif', 'png', 'xmp', 'pcx', 'svgz', 'ttf', 'tiff', 'oet',
'gz', 'tar', 'rar', 'zip', '7z', 'jar', 'class',
'odt', 'ods', 'pdf', 'doc', 'docx', 'dot', 'xls', 'xlsx',
);
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';
}
/**
* Returns whether the file is binary.
*
* @param string $file
*
* @return boolean
*/
public function isBinary($file)
{
if (($pos = strrpos($file, '.')) !== false) {
$fileType = substr($file, $pos + 1);
} else {
return false;
}
if (in_array($fileType, self::$binaryTypes)) {
return true;
}
if (!empty($this->app['binary_filetypes']) && array_key_exists($fileType, $this->app['binary_filetypes'])) {
return $this->app['binary_filetypes'][$fileType];
}
return false;
}
public function getReadme($repository, $branch = null)
{
$files = $repository->getTree($branch)->output();
if ($branch === null) {
$branch = $repository->getHead();
}
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();
}
/**
* Returns an Array where the first value is the tree-ish and the second is the path
*
* @param \GitList\Git\Repository $repository
* @param string $branch
* @param string $tree
* @return array
*/
public function extractRef($repository, $branch = '', $tree = '')
{
$branch = trim($branch, '/');
$tree = trim($tree, '/');
$input = $branch . '/' . $tree;
// If the ref appears to be a SHA, just split the string
if (preg_match("/^([[:alnum:]]{40})(.+)/", $input, $matches)) {
$branch = $matches[1];
} else {
// Otherwise, attempt to detect the ref using a list of the project's branches and tags
$validRefs = array_merge((array) $repository->getBranches(), (array) $repository->getTags());
foreach ($validRefs as $key => $ref) {
if (!preg_match(sprintf("#^%s/#", preg_quote($ref, '#')), $input)) {
unset($validRefs[$key]);
}
}
// No exact ref match, so just try our best
if (count($validRefs) > 1) {
preg_match('/([^\/]+)(.*)/', $input, $matches);
$branch = preg_replace('/^\/|\/$/', '', $matches[1]);
} else {
// Extract branch name
$branch = array_shift($validRefs);
}
}
return array($branch, $tree);
}
}
src/GitList/Util/Routing.php 0000664 0000000 0000000 00000010775 15161264430 0016315 0 ustar 00root root 0000000 0000000 app = $app;
}
/* @brief Return $commitish, $path parsed from $commitishPath, based on
* what's in $repo. Raise a 404 if $branchpath does not represent a
* valid branch and path.
*
* A helper for parsing routes that use commit-ish names and paths
* separated by /, since route regexes are not enough to get that right.
*/
public function parseCommitishPathParam($commitishPath, $repo)
{
$app = $this->app;
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
$commitish = null;
$path = null;
$slashPosition = strpos($commitishPath, '/');
if (strlen($commitishPath) >= 40 &&
($slashPosition === false ||
$slashPosition === 40)) {
// We may have a commit hash as our commitish.
$hash = substr($commitishPath, 0, 40);
if ($repository->hasCommit($hash)) {
$commitish = $hash;
}
}
if ($commitish === null) {
$branches = $repository->getBranches();
$tags = $repository->getTags();
if ($tags !== null && count($tags) > 0) {
$branches = array_merge($branches, $tags);
}
$matchedBranch = null;
$matchedBranchLength = 0;
foreach ($branches as $branch) {
if (strpos($commitishPath, $branch) === 0 &&
strlen($branch) > $matchedBranchLength) {
$matchedBranch = $branch;
$matchedBranchLength = strlen($matchedBranch);
}
}
if ($matchedBranch === null) {
throw new EmptyRepositoryException('This repository is currently empty. There are no commits.');
}
$commitish = $matchedBranch;
}
$commitishLength = strlen($commitish);
$path = substr($commitishPath, $commitishLength);
if (strpos($path, '/') === 0) {
$path = substr($path, 1);
}
return array($commitish, $path);
}
public function getBranchRegex()
{
static $branchRegex = null;
if ($branchRegex === null) {
$branchRegex = '(?!/|.*([/.]\.|//|@\{|\\\\))[^\040\177 ~^:?*\[]+(?app;
$self = $this;
$quotedPaths = array_map(
function ($repo) use ($app, $self) {
$repoName = $repo['name'];
//Windows
if ($self->isWindows()){
$repoName = str_replace('\\', '\\\\',$repoName);
}
return $repoName;
},
$this->app['git']->getRepositories($this->app['git.repos'])
);
usort(
$quotedPaths,
function ($a, $b) {
return strlen($b) - strlen($a);
}
);
$regex = implode('|', $quotedPaths);
}
return $regex;
}
public function isWindows()
{
switch (PHP_OS) {
case 'WIN32':
case 'WINNT':
case 'Windows':
return true;
default:
return false;
}
}
/**
* Strips the base path from a full repository path
*
* @param string $repoPath Full path to the repository
* @return string Relative path to the repository from git.repositories
*/
public function getRelativePath($repoPath)
{
if (strpos($repoPath, $this->app['git.repos']) === 0) {
$relativePath = substr($repoPath, strlen($this->app['git.repos']));
return ltrim(strtr($relativePath, '\\', '/'), '/');
} else {
throw new \InvalidArgumentException(
sprintf("Path '%s' does not match configured repository directory", $repoPath)
);
}
}
}
src/GitList/Util/View.php 0000664 0000000 0000000 00000002407 15161264430 0015571 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,
);
}
}
tests/ 0000775 0000000 0000000 00000000000 15161264430 0012222 5 ustar 00root root 0000000 0000000 tests/InterfaceTest.php 0000664 0000000 0000000 00000036167 15161264430 0015510 0 ustar 00root root 0000000 0000000 mkdir(self::$tmpdir);
if (!is_writable(self::$tmpdir)) {
$this->markTestSkipped('There are no write permissions in order to create test repositories.');
}
$options['path'] = getenv('GIT_CLIENT') ?: '/usr/bin/git';
$options['hidden'] = array(self::$tmpdir . '/hiddenrepo');
$options['default_branch'] = 'master';
$options['ini.file'] = "config.ini";
$cacheDir = self::$tmpdir . DIRECTORY_SEPARATOR . 'cache';
$fs->mkdir($cacheDir);
$git = new Client($options);
self::$gitPath = $options['path'];
// GitTest repository fixture
$git->createRepository(self::$tmpdir . 'GitTest');
$repository = $git->getRepository(self::$tmpdir . 'GitTest');
file_put_contents(self::$tmpdir . 'GitTest/README.md', "## GitTest\nGitTest is a *test* repository!");
file_put_contents(self::$tmpdir . 'GitTest/test.php', "setConfig('user.name', 'Luke Skywalker');
$repository->setConfig('user.email', 'luke@rebel.org');
$repository->addAll();
$repository->commit("Initial commit");
$repository->createBranch('issue12');
$repository->createBranch('issue42');
$repository->createBranch('branch/name/wiith/slashes');
// foobar repository fixture
$git->createRepository(self::$tmpdir . 'foobar');
$repository = $git->getRepository(self::$tmpdir . 'foobar');
file_put_contents(self::$tmpdir . 'foobar/bar.json', "{\n\"name\": \"foobar\"\n}");
file_put_contents(self::$tmpdir . 'foobar/.git/description', 'This is a test repo!');
$fs->mkdir(self::$tmpdir . 'foobar/myfolder');
$fs->mkdir(self::$tmpdir . 'foobar/testfolder');
file_put_contents(self::$tmpdir . 'foobar/myfolder/mytest.php',
"setConfig('user.name', 'Luke Skywalker');
$repository->setConfig('user.email', 'luke@rebel.org');
$repository->addAll();
$repository->commit("First commit");
// Nested repository fixture
$nested_dir = self::$tmpdir . 'nested/';
$fs->mkdir($nested_dir);
$git->createRepository($nested_dir . 'NestedRepo');
$repository = $git->getRepository($nested_dir . 'NestedRepo');
file_put_contents($nested_dir . 'NestedRepo/.git/description', 'This is a NESTED test repo!');
file_put_contents($nested_dir . 'NestedRepo/README.txt', 'NESTED TEST REPO README');
$repository->setConfig('user.name', 'Luke Skywalker');
$repository->setConfig('user.email', 'luke@rebel.org');
$repository->addAll();
$repository->commit("First commit");
$repository->createBranch("testing");
$repository->checkout("testing");
file_put_contents($nested_dir . 'NestedRepo/README.txt', 'NESTED TEST BRANCH README');
$repository->addAll();
$repository->commit("Changing branch");
$repository->checkout("master");
// master-less repository fixture
$git->createRepository(self::$tmpdir . 'develop');
$repository = $git->getRepository(self::$tmpdir . 'develop');
$repository->setConfig('user.name', 'Luke Skywalker');
$repository->setConfig('user.email', 'luke@rebel.org');
file_put_contents(self::$tmpdir . 'develop/README.md', "## develop\ndevelop is a *test* repository!");
$repository->addAll();
$repository->commit("First commit");
$repository->createBranch("develop");
$repository = $repository->checkout('develop');
file_put_contents(self::$tmpdir . 'develop/test.php', "setConfig('user.name', 'Luke Skywalker');
$repository->setConfig('user.email', 'luke@rebel.org');
$repository->addAll();
$repository->commit("Initial commit");
// Detached HEAD repository fixture
$git->createRepository(self::$tmpdir . 'detached-head');
$repository = $git->getRepository(self::$tmpdir . 'detached-head');
$repository->setConfig('user.name', 'Luke Skywalker');
$repository->setConfig('user.email', 'luke@rebel.org');
file_put_contents(self::$tmpdir . 'detached-head/README.md', "## detached head\ndetached-head is a *test* repository!");
$repository->addAll();
$repository->commit("First commit");
$repository->checkout('HEAD');
}
public function createApplication()
{
$config = new GitList\Config;
$config->set('app', 'debug', true);
$config->set('app', 'debug', false);
$config->set('git', 'client', self::$gitPath);
$config->set('git', 'default_branch', 'master');
$config->set('git', 'repositories', array(self::$tmpdir));
$app = require 'boot.php';
return $app;
}
public function testInitialPage()
{
$client = $this->createClient();
$crawler = $client->request('GET', '/');
$this->assertTrue($client->getResponse()->isOk());
$this->assertCount(1, $crawler->filter('title:contains("GitList")'));
$this->assertCount(1, $crawler->filter('div.repository-header a:contains("GitTest")'));
$this->assertEquals('/GitTest/', $crawler->filter('.repository-header a')->eq(0)->attr('href'));
$this->assertEquals('/GitTest/master/rss/', $crawler->filter('.repository-header a')->eq(1)->attr('href'));
$this->assertCount(1, $crawler->filter('div.repository-header a:contains("detached-head")'));
$this->assertEquals('/detached-head/', $crawler->filter('.repository-header a')->eq(2)->attr('href'));
$this->assertEquals('/detached-head/master/rss/', $crawler->filter('.repository-header a')->eq(3)->attr('href'));
$this->assertCount(1, $crawler->filter('div.repository-header a:contains("develop")'));
$this->assertEquals('/develop/', $crawler->filter('.repository-header a')->eq(4)->attr('href'));
$this->assertEquals('/develop/master/rss/', $crawler->filter('.repository-header a')->eq(5)->attr('href'));
$this->assertCount(1, $crawler->filter('div.repository-header:contains("foobar")'));
$this->assertCount(1, $crawler->filter('div.repository-body:contains("This is a test repo!")'));
$this->assertEquals('/foobar/', $crawler->filter('.repository-header a')->eq(6)->attr('href'));
$this->assertEquals('/foobar/master/rss/', $crawler->filter('.repository-header a')->eq(7)->attr('href'));
$this->assertCount(1, $crawler->filter('div.repository-header a:contains("nested/NestedRepo")'));
$this->assertEquals('/nested/NestedRepo/', $crawler->filter('.repository-header a')->eq(8)->attr('href'));
$this->assertEquals('/nested/NestedRepo/master/rss/', $crawler->filter('.repository-header a')->eq(9)->attr('href'));
$this->assertCount(1, $crawler->filter('div.repository-body:contains("This is a NESTED test repo!")'));
}
public function testRepositoryPage()
{
$client = $this->createClient();
$crawler = $client->request('GET', '/GitTest/');
$this->assertTrue($client->getResponse()->isOk());
$this->assertCount(1, $crawler->filter('.tree tr:contains("README.md")'));
$this->assertCount(1, $crawler->filter('.tree tr:contains("test.php")'));
$this->assertCount(1, $crawler->filter('.md-header:contains("README.md")'));
$this->assertEquals("## GitTest\nGitTest is a *test* repository!", $crawler->filter('#md-content')->eq(0)->text());
$this->assertEquals('/GitTest/blob/master/README.md', $crawler->filter('.tree tr td')->eq(0)->filter('a')->eq(0)->attr('href'));
$this->assertEquals('/GitTest/blob/master/test.php', $crawler->filter('.tree tr td')->eq(3)->filter('a')->eq(0)->attr('href'));
$this->assertEquals('branch/name/wiith/slashes', $crawler->filter('.dropdown-menu li')->eq(1)->text());
$this->assertEquals('issue12', $crawler->filter('.dropdown-menu li')->eq(2)->text());
$this->assertEquals('issue42', $crawler->filter('.dropdown-menu li')->eq(3)->text());
$this->assertEquals('master', $crawler->filter('.dropdown-menu li')->eq(4)->text());
$crawler = $client->request('GET', '/foobar/');
$this->assertTrue($client->getResponse()->isOk());
$this->assertCount(1, $crawler->filter('.tree tr:contains("myfolder")'));
$this->assertCount(1, $crawler->filter('.tree tr:contains("testfolder")'));
$this->assertCount(1, $crawler->filter('.tree tr:contains("bar.json")'));
$this->assertEquals('/foobar/tree/master/myfolder/', $crawler->filter('.tree tr td')->eq(0)->filter('a')->eq(0)->attr('href'));
$this->assertEquals('/foobar/tree/master/testfolder/', $crawler->filter('.tree tr td')->eq(3)->filter('a')->eq(0)->attr('href'));
$this->assertEquals('/foobar/blob/master/bar.json', $crawler->filter('.tree tr td')->eq(6)->filter('a')->eq(0)->attr('href'));
$this->assertCount(0, $crawler->filter('.md-header'));
$this->assertEquals('master', $crawler->filter('.dropdown-menu li')->eq(1)->text());
}
public function testBlobPage()
{
$client = $this->createClient();
$crawler = $client->request('GET', '/GitTest/blob/master/test.php');
$this->assertTrue($client->getResponse()->isOk());
$this->assertCount(1, $crawler->filter('.breadcrumb .active:contains("test.php")'));
$this->assertEquals('/GitTest/raw/master/test.php',
$crawler->filter('.source-header .btn-group a')->eq(0)->attr('href'));
$this->assertEquals('/GitTest/blame/master/test.php',
$crawler->filter('.source-header .btn-group a')->eq(1)->attr('href'));
$this->assertEquals('/GitTest/commits/master/test.php',
$crawler->filter('.source-header .btn-group a')->eq(2)->attr('href'));
}
public function testRawPage()
{
$client = $this->createClient();
$crawler = $client->request('GET', '/GitTest/raw/master/test.php');
$this->assertTrue($client->getResponse()->isOk());
$this->assertEquals("getResponse()->getContent());
}
public function testBlamePage()
{
$client = $this->createClient();
$crawler = $client->request('GET', '/GitTest/blame/master/test.php');
$this->assertTrue($client->getResponse()->isOk());
$this->assertCount(1, $crawler->filter('.source-header .meta:contains("test.php")'));
$this->assertRegexp('/\/GitTest\/commit\/[a-zA-Z0-9%]+/',
$crawler->filter('.blame-view .commit')->eq(0)->filter('a')->attr('href'));
$crawler = $client->request('GET', '/foobar/blame/master/bar.json');
$this->assertTrue($client->getResponse()->isOk());
$this->assertCount(1, $crawler->filter('.source-header .meta:contains("bar.json")'));
$this->assertRegexp('/\/foobar\/commit\/[a-zA-Z0-9%]+/',
$crawler->filter('.blame-view .commit')->eq(0)->filter('a')->attr('href'));
}
public function testHistoryPage()
{
$client = $this->createClient();
$crawler = $client->request('GET', '/GitTest/commits/master/test.php');
$this->assertTrue($client->getResponse()->isOk());
$this->assertEquals('Initial commit', $crawler->filter('.table tbody tr td h4')->eq(0)->text());
$crawler = $client->request('GET', '/GitTest/commits/master/README.md');
$this->assertTrue($client->getResponse()->isOk());
$this->assertEquals('Initial commit', $crawler->filter('.table tbody tr td h4')->eq(0)->text());
$crawler = $client->request('GET', '/foobar/commits/master/bar.json');
$this->assertTrue($client->getResponse()->isOk());
$this->assertEquals('First commit', $crawler->filter('.table tbody tr td h4')->eq(0)->text());
}
public function testCommitsPage()
{
$client = $this->createClient();
$crawler = $client->request('GET', '/GitTest/commits');
$this->assertTrue($client->getResponse()->isOk());
$this->assertEquals('Initial commit', $crawler->filter('.table tbody tr td h4')->eq(0)->text());
$crawler = $client->request('GET', '/foobar/commits');
$this->assertTrue($client->getResponse()->isOk());
$this->assertEquals('First commit', $crawler->filter('.table tbody tr td h4')->eq(0)->text());
}
public function testStatsPage()
{
$client = $this->createClient();
$crawler = $client->request('GET', '/GitTest/stats');
$this->assertTrue($client->getResponse()->isOk());
$this->assertRegexp('/.php: 1 files/', $crawler->filter('.table tbody')->eq(0)->text());
$this->assertRegexp('/.md: 1 files/', $crawler->filter('.table tbody')->eq(0)->text());
$this->assertRegexp('/Total files: 2/', $crawler->filter('.table tbody')->eq(0)->text());
$this->assertRegexp('/Luke Skywalker: 1 commits/', $crawler->filter('.table tbody')->eq(0)->text());
}
public function testRssPage()
{
$client = $this->createClient();
$client->request('GET', '/GitTest/master/rss/');
$response = $client->getResponse();
$this->assertTrue($response->isOk());
$this->assertRegexp('/Latest commits in GitTest:master/', $client->getResponse()->getContent());
$this->assertRegexp('/Initial commit/', $client->getResponse()->getContent());
}
public function testNestedRepoPage()
{
$client = $this->createClient();
$client->request('GET', '/nested/NestedRepo/');
$response = $client->getResponse();
$this->assertTrue($response->isOk());
$this->assertRegexp('/NESTED TEST REPO README/', $client->getResponse()->getContent());
}
public function testDevelopRepo()
{
$client = $this->createClient();
$crawler = $client->request('GET', '/develop/');
$this->assertTrue($client->getResponse()->isOk());
}
public function testNestedRepoBranch()
{
$client = $this->createClient();
$crawler = $client->request('GET', '/nested/NestedRepo/testing/');
$this->assertTrue($client->getResponse()->isOk());
$this->assertRegexp('/NESTED TEST BRANCH README/', $client->getResponse()->getContent());
}
public static function tearDownAfterClass()
{
$fs = new Filesystem();
$fs->remove(self::$tmpdir);
}
}
views/ 0000775 0000000 0000000 00000000000 15161264430 0012215 5 ustar 00root root 0000000 0000000 views/blame.twig 0000664 0000000 0000000 00000001275 15161264430 0014176 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 15161264430 0015375 0 ustar 00root root 0000000 0000000