.gitignore 0000664 0000000 0000000 00000000433 15161103626 0013047 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
.htaccess 0000664 0000000 0000000 00000000412 15161103626 0012652 0 ustar 00root root 0000000 0000000
Options -MultiViews
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 15161103626 0013167 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 15161103626 0012505 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 15161103626 0012706 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 00000012034 15161103626 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://git.gofedora.com).
## Authors and contributors
* [Klaus Silveira](http://www.klaussilveira.com) (Creator, developer)
## License
[New BSD license](http://www.opensource.org/licenses/bsd-license.php)
## Todo
* improve the current test code coverage
* test the interface
* error handling can be greatly improved during parsing
* submodule support
* multilanguage support
## Requirements
In order to run GitList on your server, you'll need:
* git
* Apache with mod_rewrite enabled or nginx
* PHP 5.3.3
## Installing
* Download GitList from [gitlist.org](http://gitlist.org/) and decompress to your `/var/www/gitlist` folder, or anywhere else you want to place GitList.
* Rename the `config.ini-example` file to `config.ini`.
* Open up the `config.ini` and configure your installation. You'll have to provide where your repositories are located and the base GitList URL (in our case, http://localhost/gitlist).
* Create the cache folder and give 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 this [tutorial](http://gofedora.com/insanely-awesome-web-interface-git-repos/) by Kulbir Saini or the [Troubleshooting](https://github.com/klaussilveira/gitlist/wiki/Troubleshooting) page.
## Building
GitList uses [Composer](http://getcomposer.org/) to manage dependencies and [Ant](http://ant.apache.org/) to build the project. In order to run all the targets in the build script, you will need [PHPUnit](http://www.phpunit.de/), [phpcpd](https://github.com/sebastianbergmann/phpcpd), [phploc](https://github.com/sebastianbergmann/phploc), [PHPMD](http://phpmd.org/) and [PHP_Depend](http://pdepend.org).
Once you have all the dependencies set, you can clone the repository and run Ant:
```
git clone https://github.com/klaussilveira/gitlist.git
ant
```
If you just want to get the project dependencies, instead of building everything:
```
git clone https://github.com/klaussilveira/gitlist.git
curl -s http://getcomposer.org/installer | php
php composer.phar install
```
If you have Composer in your path, things get easier. But you know the drill.
## Contributing
If you are a developer, we need your help. GitList is a young project and we have lot's of stuff to do. Some developers are contributing with new features, others with bug fixes. But you can also dedicate yourself to refactoring the current codebase and improving what we already have. This is very important, we want GitList to be a state-of-the-art application, and we need your help for that.
* Stay tuned to possible bugs, suboptimal code, duplicated code, overcomplicated expressions and unused code with [PHPMD](http://ci.gitlist.org:8080/job/GitList%20\(master\)/9/pmdResult/?) in our CI server
* Try to fix any [violations](http://ci.gitlist.org:8080/job/GitList%20\(master\)/violations/) reported
* Improve the [test coverage](http://ci.gitlist.org:8080/job/GitList%20\(master\)/9/cloverphp-report/) by creating unit and functional tests
## Further information
If you want to know more about customizing GitList, check the [Customization](https://github.com/klaussilveira/gitlist/wiki/Customizing) page on the wiki. Also, if you're having problems with GitList, check the [Troubleshooting](https://github.com/klaussilveira/gitlist/wiki/Troubleshooting) page. Don't forget to report issues and suggest new features! :)
boot.php 0000664 0000000 0000000 00000001073 15161103626 0012534 0 ustar 00root root 0000000 0000000 set('git', 'repositories', rtrim($config->get('git', 'repositories'), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR);
// Startup and configure Silex application
$app = new GitList\Application($config, __DIR__);
// Mount the controllers
$app->mount('', new GitList\Controller\MainController());
$app->mount('', new GitList\Controller\BlobController());
$app->mount('', new GitList\Controller\CommitController());
$app->mount('', new GitList\Controller\TreeController());
return $app;
build.xml 0000664 0000000 0000000 00000006477 15161103626 0012716 0 ustar 00root root 0000000 0000000
cache/ 0000775 0000000 0000000 00000000000 15161103626 0012122 5 ustar 00root root 0000000 0000000 cache/.gitkeep 0000664 0000000 0000000 00000000000 15161103626 0013541 0 ustar 00root root 0000000 0000000 composer.json 0000664 0000000 0000000 00000000665 15161103626 0013610 0 ustar 00root root 0000000 0000000 {
"require": {
"silex/silex": "1.0.*",
"twig/twig": "1.9.*",
"symfony/twig-bridge": "2.1.*",
"symfony/filesystem": "2.1.*",
"klaussilveira/gitter": "dev-master"
},
"require-dev": {
"symfony/browser-kit": "2.1.*",
"symfony/css-selector": "2.1.*"
},
"minimum-stability": "dev",
"autoload": {
"psr-0": {
"GitList": "src/"
}
}
}
composer.lock 0000664 0000000 0000000 00000051420 15161103626 0013562 0 ustar 00root root 0000000 0000000 {
"hash": "b1fc3d7e61707618f68e5cf940e97081",
"packages": [
{
"name": "klaussilveira/gitter",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/klaussilveira/gitter",
"reference": "1c9b6e4dde81d21acffe99d9f4559ed3bc59f947"
},
"dist": {
"type": "zip",
"url": "https://github.com/klaussilveira/gitter/zipball/1c9b6e4dde81d21acffe99d9f4559ed3bc59f947",
"reference": "1c9b6e4dde81d21acffe99d9f4559ed3bc59f947",
"shasum": ""
},
"require": {
"php": ">=5.3.0",
"symfony/process": ">=2.1"
},
"require-dev": {
"symfony/filesystem": ">=2.1"
},
"time": "1351643953",
"type": "library",
"installation-source": "source",
"autoload": {
"psr-0": {
"Gitter": "lib/"
}
},
"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"
]
},
{
"name": "pimple/pimple",
"version": "dev-master",
"source": {
"type": "git",
"url": "git://github.com/fabpot/Pimple.git",
"reference": "b9f27b8dc18c08f00627dec02359b46a24791dc3"
},
"dist": {
"type": "zip",
"url": "https://github.com/fabpot/Pimple/zipball/b9f27b8dc18c08f00627dec02359b46a24791dc3",
"reference": "b9f27b8dc18c08f00627dec02359b46a24791dc3",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-0": {
"Pimple": "lib/"
}
},
"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": [
"dependency injection",
"container"
],
"time": "1347278988"
},
{
"name": "silex/silex",
"version": "dev-master",
"source": {
"type": "git",
"url": "git://github.com/fabpot/Silex.git",
"reference": "69d710011ee8f9fa286854fcf636a07ad76b570b"
},
"dist": {
"type": "zip",
"url": "https://github.com/fabpot/Silex/zipball/69d710011ee8f9fa286854fcf636a07ad76b570b",
"reference": "69d710011ee8f9fa286854fcf636a07ad76b570b",
"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": {
"monolog/monolog": ">=1.0.0,<1.2-dev",
"twig/twig": ">=1.8.0,<2.0-dev",
"swiftmailer/swiftmailer": "4.2.*",
"doctrine/dbal": ">=2.2.0,<2.4.0-dev",
"symfony/security": ">=2.1,<2.3-dev",
"symfony/config": ">=2.1,<2.3-dev",
"symfony/locale": ">=2.1,<2.3-dev",
"symfony/form": ">=2.1,<2.3-dev",
"symfony/browser-kit": ">=2.1,<2.3-dev",
"symfony/css-selector": ">=2.1,<2.3-dev",
"symfony/finder": ">=2.1,<2.3-dev",
"symfony/monolog-bridge": ">=2.1,<2.3-dev",
"symfony/process": ">=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",
"symfony/serializer": ">=2.1,<2.3-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"
},
"time": "1351540898",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-0": {
"Silex": "src/"
}
},
"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"
]
},
{
"name": "symfony/event-dispatcher",
"version": "dev-master",
"target-dir": "Symfony/Component/EventDispatcher",
"source": {
"type": "git",
"url": "https://github.com/symfony/EventDispatcher",
"reference": "24a1039d52b6b9f533cb73dcb96c7748262db686"
},
"dist": {
"type": "zip",
"url": "https://github.com/symfony/EventDispatcher/zipball/24a1039d52b6b9f533cb73dcb96c7748262db686",
"reference": "24a1039d52b6b9f533cb73dcb96c7748262db686",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"symfony/dependency-injection": "2.2.*"
},
"suggest": {
"symfony/dependency-injection": "2.2.*",
"symfony/http-kernel": "2.2.*"
},
"time": "1349553479",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-0": {
"Symfony\\Component\\EventDispatcher\\": ""
}
},
"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"
},
{
"name": "symfony/filesystem",
"version": "2.1.x-dev",
"target-dir": "Symfony/Component/Filesystem",
"source": {
"type": "git",
"url": "https://github.com/symfony/Filesystem",
"reference": "v2.1.3"
},
"dist": {
"type": "zip",
"url": "https://github.com/symfony/Filesystem/zipball/v2.1.3",
"reference": "v2.1.3",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.1-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-0": {
"Symfony\\Component\\Filesystem": ""
}
},
"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": "1350717030"
},
{
"name": "symfony/http-foundation",
"version": "dev-master",
"target-dir": "Symfony/Component/HttpFoundation",
"source": {
"type": "git",
"url": "https://github.com/symfony/HttpFoundation",
"reference": "707e289629a10fde825bc4ba90aba743f79b173c"
},
"dist": {
"type": "zip",
"url": "https://github.com/symfony/HttpFoundation/zipball/707e289629a10fde825bc4ba90aba743f79b173c",
"reference": "707e289629a10fde825bc4ba90aba743f79b173c",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"time": "1351508251",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-0": {
"Symfony\\Component\\HttpFoundation\\": ""
},
"classmap": [
"Symfony/Component/HttpFoundation/Resources/stubs"
]
},
"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"
},
{
"name": "symfony/http-kernel",
"version": "dev-master",
"target-dir": "Symfony/Component/HttpKernel",
"source": {
"type": "git",
"url": "https://github.com/symfony/HttpKernel",
"reference": "4dcb0bf602788342fb80c28c6e28be818839d417"
},
"dist": {
"type": "zip",
"url": "https://github.com/symfony/HttpKernel/zipball/4dcb0bf602788342fb80c28c6e28be818839d417",
"reference": "4dcb0bf602788342fb80c28c6e28be818839d417",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"symfony/event-dispatcher": "2.2.*",
"symfony/http-foundation": "2.2.*"
},
"require-dev": {
"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.*",
"symfony/process": "2.2.*",
"symfony/routing": "2.2.*"
},
"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.*"
},
"time": "1351530455",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-0": {
"Symfony\\Component\\HttpKernel\\": ""
}
},
"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"
},
{
"name": "symfony/process",
"version": "dev-master",
"target-dir": "Symfony/Component/Process",
"source": {
"type": "git",
"url": "https://github.com/symfony/Process",
"reference": "b35a2a4fae02286df3275d7094a3d3d575122db8"
},
"dist": {
"type": "zip",
"url": "https://github.com/symfony/Process/zipball/b35a2a4fae02286df3275d7094a3d3d575122db8",
"reference": "b35a2a4fae02286df3275d7094a3d3d575122db8",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-0": {
"Symfony\\Component\\Process\\": ""
}
},
"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": "1351356874"
},
{
"name": "symfony/routing",
"version": "dev-master",
"target-dir": "Symfony/Component/Routing",
"source": {
"type": "git",
"url": "https://github.com/symfony/Routing",
"reference": "29792d8ac4ed7308acdeed4933cb6d91b7f6510f"
},
"dist": {
"type": "zip",
"url": "https://github.com/symfony/Routing/zipball/29792d8ac4ed7308acdeed4933cb6d91b7f6510f",
"reference": "29792d8ac4ed7308acdeed4933cb6d91b7f6510f",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"doctrine/common": ">=2.2,<2.4-dev",
"symfony/config": "2.2.*",
"symfony/yaml": "2.2.*",
"symfony/http-kernel": "2.2.*"
},
"suggest": {
"doctrine/common": ">=2.2,<2.4-dev",
"symfony/config": "2.2.*",
"symfony/yaml": "2.2.*"
},
"time": "1351466734",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-0": {
"Symfony\\Component\\Routing\\": ""
}
},
"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"
},
{
"name": "symfony/twig-bridge",
"version": "2.1.x-dev",
"target-dir": "Symfony/Bridge/Twig",
"source": {
"type": "git",
"url": "https://github.com/symfony/TwigBridge",
"reference": "v2.1.3"
},
"dist": {
"type": "zip",
"url": "https://github.com/symfony/TwigBridge/zipball/v2.1.3",
"reference": "v2.1.3",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"twig/twig": ">=1.9.1,<2.0-dev"
},
"require-dev": {
"symfony/form": "2.1.*",
"symfony/routing": "2.1.*",
"symfony/templating": "2.1.*",
"symfony/translation": "2.1.*",
"symfony/yaml": "2.1.*",
"symfony/security": "2.1.*"
},
"suggest": {
"symfony/form": "2.1.*",
"symfony/routing": "2.1.*",
"symfony/templating": "2.1.*",
"symfony/translation": "2.1.*",
"symfony/yaml": "2.1.*",
"symfony/security": "2.1.*"
},
"type": "symfony-bridge",
"extra": {
"branch-alias": {
"dev-master": "2.1-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-0": {
"Symfony\\Bridge\\Twig": ""
}
},
"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": "1349363877"
},
{
"name": "twig/twig",
"version": "v1.9.2",
"source": {
"type": "git",
"url": "git://github.com/fabpot/Twig.git",
"reference": "v1.9.2"
},
"dist": {
"type": "zip",
"url": "https://github.com/fabpot/Twig/zipball/v1.9.2",
"reference": "v1.9.2",
"shasum": ""
},
"require": {
"php": ">=5.2.4"
},
"time": "2012-08-25 10:32:57",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.9-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"Twig_": "lib/"
}
},
"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"
]
}
],
"packages-dev": null,
"aliases": [
],
"minimum-stability": "dev",
"stability-flags": {
"klaussilveira/gitter": 20
}
} config.ini-example 0000664 0000000 0000000 00000001024 15161103626 0014453 0 ustar 00root root 0000000 0000000 [git]
client = '/usr/bin/git' ; Your git executable path
repositories = '/var/www/projects/' ; Path to your repositories
; You can hide repositories from GitList, just copy this for each repository you want to hide
; hidden[] = '/var/www/projects/BetaTest'
[app]
debug = false
; If you need to specify custom filetypes for certain extensions, do this here
[filetypes]
; extension = type
; dist = xml
; If you need to set file types as binary or not, do this here
[binary_filetypes]
; extension = true
; svh = false
; map = true
index.php 0000664 0000000 0000000 00000000741 15161103626 0012701 0 ustar 00root root 0000000 0000000 run();
phpunit.xml.dist 0000664 0000000 0000000 00000001350 15161103626 0014231 0 ustar 00root root 0000000 0000000
./tests/
src/ 0000775 0000000 0000000 00000000000 15161103626 0011646 5 ustar 00root root 0000000 0000000 src/GitList/ 0000775 0000000 0000000 00000000000 15161103626 0013225 5 ustar 00root root 0000000 0000000 src/GitList/Application.php 0000664 0000000 0000000 00000004420 15161103626 0016201 0 ustar 00root root 0000000 0000000 get('app', 'debug');
$this['filetypes'] = $config->getSection('filetypes');
$this['cache.archives'] = $root . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'archives';
// Register services
$this->register(new TwigServiceProvider(), array(
'twig.path' => $root . DIRECTORY_SEPARATOR . 'views',
'twig.options' => array('cache' => $root . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'views'),
));
$this->register(new GitServiceProvider(), array(
'git.client' => $config->get('git', 'client'),
'git.repos' => $config->get('git', 'repositories'),
'git.hidden' => $config->get('git', 'hidden') ? $config->get('git', 'hidden') : array(),
));
$this->register(new ViewUtilServiceProvider());
$this->register(new RepositoryUtilServiceProvider());
$this->register(new UrlGeneratorServiceProvider());
$this->register(new RoutingUtilServiceProvider());
$this['twig'] = $this->share($this->extend('twig', function($twig, $app) {
$twig->addFilter('md5', new \Twig_Filter_Function('md5'));
return $twig;
}));
// Handle errors
$this->error(function (\Exception $e, $code) use ($app) {
if ($app['debug']) {
return;
}
return $app['twig']->render('error.twig', array(
'message' => $e->getMessage(),
));
});
}
}
src/GitList/Config.php 0000664 0000000 0000000 00000002363 15161103626 0015147 0 ustar 00root root 0000000 0000000 data = $data;
$this->validateOptions();
}
public function get($section, $option)
{
if (!array_key_exists($section, $this->data)) {
return false;
}
if (!array_key_exists($option, $this->data[$section])) {
return false;
}
return $this->data[$section][$option];
}
public function getSection($section)
{
if (!array_key_exists($section, $this->data)) {
return false;
}
return $this->data[$section];
}
public function set($section, $option, $value)
{
$this->data[$section][$option] = $value;
}
protected function validateOptions()
{
if (!$this->get('git', 'repositories') || !is_dir($this->get('git', 'repositories'))) {
die("Please, edit the config file and provide your repositories directory");
}
}
}
src/GitList/Controller/ 0000775 0000000 0000000 00000000000 15161103626 0015350 5 ustar 00root root 0000000 0000000 src/GitList/Controller/BlobController.php 0000664 0000000 0000000 00000005414 15161103626 0021007 0 ustar 00root root 0000000 0000000 get('{repo}/blob/{branch}/{file}', function($repo, $branch, $file) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
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,
'branch' => $branch,
'file' => $file,
)));
}
return $app['twig']->render('file.twig', array(
'file' => $file,
'fileType' => $fileType,
'blob' => $blob->output(),
'repo' => $repo,
'branch' => $branch,
'breadcrumbs' => $breadcrumbs,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
));
})->assert('file', '.+')
->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', '[\w-._\/]+')
->bind('blob');
$route->get('{repo}/raw/{branch}/{file}', function($repo, $branch, $file) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
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-Transfer-Encoding'] = 'application/octet-stream';
$headers['Content-Transfer-Encoding'] = 'binary';
} else {
$headers['Content-Transfer-Encoding'] = 'text/plain';
}
return new Response($blob, 200, $headers);
})->assert('file', '.+')
->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', '[\w-._\/]+')
->bind('blob_raw');
return $route;
}
}
src/GitList/Controller/CommitController.php 0000664 0000000 0000000 00000010672 15161103626 0021363 0 ustar 00root root 0000000 0000000 get('{repo}/commits/{branch}/{file}', function($repo, $branch, $file) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
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('branch', '[\w-._\/]+')
->assert('file', '.+')
->value('branch', 'master')
->value('file', '')
->bind('commits');
$route->post('{repo}/commits/{branch}/search', function(Request $request, $repo, $branch = '') use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$query = $request->get('query');
$commits = $repository->searchCommitLog($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', '[\w-._\/]+')
->bind('searchcommits');
$route->get('{repo}/commit/{commit}', function($repo, $commit) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$commit = $repository->getCommit($commit);
return $app['twig']->render('commit.twig', array(
'branch' => 'master',
'repo' => $repo,
'commit' => $commit,
));
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('commit', '[a-f0-9^]+')
->bind('commit');
$route->get('{repo}/blame/{branch}/{file}', function($repo, $branch, $file) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
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('file', '.+')
->assert('branch', '[\w-._\/]+')
->bind('blame');
return $route;
}
}
src/GitList/Controller/MainController.php 0000664 0000000 0000000 00000004514 15161103626 0021015 0 ustar 00root root 0000000 0000000 get('/', function() use ($app) {
$repositories = array_map(
function ($repo) use ($app) {
$repo['relativePath'] = $app['util.routing']->getRelativePath($repo['path']);
return $repo;
},
$app['git']->getRepositories($app['git.repos'])
);
return $app['twig']->render('index.twig', array(
'repositories' => $repositories,
));
})->bind('homepage');
$route->get('{repo}/stats/{branch}', function($repo, $branch) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$stats = $repository->getStatistics($branch);
$authors = $repository->getAuthorStatistics();
return $app['twig']->render('stats.twig', array(
'repo' => $repo,
'branch' => $branch,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
'stats' => $stats,
'authors' => $authors,
));
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', '[\w-._\/]+')
->value('branch', 'master')
->bind('stats');
$route->get('{repo}/{branch}/rss/', function($repo, $branch) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$commits = $repository->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', '[\w-._\/]+')
->bind('rss');
return $route;
}
}
src/GitList/Controller/TreeController.php 0000664 0000000 0000000 00000011534 15161103626 0021030 0 ustar 00root root 0000000 0000000 get('{repo}/tree/{branch}/{tree}/', $treeController = function($repo, $branch = '', $tree = '') use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
if (!$branch) {
$branch = $repository->getHead();
}
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($repo, $branch),
));
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', '[\w-._\/]+')
->assert('tree', '.+')
->bind('tree');
$route->post('{repo}/tree/{branch}/search', function(Request $request, $repo, $branch = '', $tree = '') use ($app) {
$repository = $app['git']->getRepository($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', '[\w-._\/]+')
->bind('search');
$route->get('{repo}/{branch}/', function($repo, $branch) use ($app, $treeController) {
return $treeController($repo, $branch);
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', '[\w-._\/]+')
->bind('branch');
$route->get('{repo}/', function($repo) use ($app, $treeController) {
return $treeController($repo);
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->bind('repository');
$route->get('{repo}/{format}ball/{branch}', function($repo, $format, $branch) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$tree = $repository->getBranchTree($branch);
if (false === $tree) {
return $app->abort(404, 'Invalid commit or tree reference: ' . $branch);
}
$file = $app['cache.archives'] . DIRECTORY_SEPARATOR
. $repo . DIRECTORY_SEPARATOR
. substr($tree, 0, 2) . DIRECTORY_SEPARATOR
. substr($tree, 2)
. '.'
. $format;
if (!file_exists($file)) {
$repository->createArchive($tree, $file, $format);
}
return new StreamedResponse(function () use ($file) {
readfile($file);
}, 200, array(
'Content-type' => ('zip' === $format) ? 'application/zip' : 'application/x-tar',
'Content-Description' => 'File Transfer',
'Content-Disposition' => 'attachment; filename="'.$repo.'-'.substr($tree, 0, 6).'.'.$format.'"',
'Content-Transfer-Encoding' => 'binary',
));
})->assert('format', '(zip|tar)')
->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', '[\w-._\/]+')
->bind('archive');
return $route;
}
}
src/GitList/Exception/ 0000775 0000000 0000000 00000000000 15161103626 0015163 5 ustar 00root root 0000000 0000000 src/GitList/Exception/BlankDataException.php 0000664 0000000 0000000 00000000133 15161103626 0021371 0 ustar 00root root 0000000 0000000 create($bare);
}
/**
* Opens a repository at the specified path
*
* @param string $path Path where the repository is located
* @return Repository Instance of Repository
*/
public function getRepository($path)
{
if (!file_exists($path) || !file_exists($path . '/.git/HEAD') && !file_exists($path . '/HEAD')) {
throw new \RuntimeException('There is no GIT repository at ' . $path);
}
if (in_array($path, $this->getHidden())) {
throw new \RuntimeException('You don\'t have access to this repository');
}
return new Repository($path, $this);
}
}
src/GitList/Git/Repository.php 0000664 0000000 0000000 00000015675 15161103626 0016656 0 ustar 00root root 0000000 0000000 getClient()->run($this, "show --pretty=format:\"- %H%h%T%P%an%ae%at%cn%ce%ct
\" $commitHash");
$logs = explode("\n", $logs);
// Read commit metadata
$format = new PrettyFormat;
$data = $format->parse($logs[0]);
$commit = new Commit;
$commit->importData($data[0]);
unset($logs[0]);
if (empty($logs[1])) {
$logs = explode("\n", $this->getClient()->run($this, 'diff ' . $commitHash . '~1..' . $commitHash));
}
$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;
}
/**
* 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()
{
$logs = $this->getClient()->run($this, 'log --pretty=format:"%an||%ae" ' . $this->getHead());
if (empty($logs)) {
throw new \RuntimeException('No statistics available');
}
$logs = explode("\n", $logs);
$logs = array_count_values($logs);
arsort($logs);
foreach ($logs as $user => $count) {
$user = explode('||', $user);
$data[] = array('name' => $user[0], 'email' => $user[1], 'commits' => $count);
}
return $data;
}
public function getStatistics($branch)
{
// Calculate amount of files, extensions and file size
$logs = $this->getClient()->run($this, 'ls-tree -r -l ' . $branch);
$lines = explode("\n", $logs);
$files = array();
$data['extensions'] = array();
$data['size'] = 0;
$data['files'] = 0;
foreach ($lines as $key => $line) {
if (empty($line)) {
unset($lines[$key]);
continue;
}
$files[] = preg_split("/[\s]+/", $line);
}
foreach ($files as $file) {
if ($file[1] == 'blob') {
$data['files']++;
}
if (is_numeric($file[3])) {
$data['size'] += $file[3];
}
if (($pos = strrpos($file[4], '.')) !== FALSE) {
$data['extensions'][] = substr($file[4], $pos);
}
}
$data['extensions'] = array_count_values($data['extensions']);
arsort($data['extensions']);
return $data;
}
/**
* 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");
}
}
src/GitList/Provider/ 0000775 0000000 0000000 00000000000 15161103626 0015017 5 ustar 00root root 0000000 0000000 src/GitList/Provider/GitServiceProvider.php 0000664 0000000 0000000 00000001271 15161103626 0021310 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 15161103626 0023042 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 15161103626 0022332 0 ustar 00root root 0000000 0000000 share(function () {
return new View;
});
}
public function boot(Application $app)
{
}
}
src/GitList/Util/ 0000775 0000000 0000000 00000000000 15161103626 0014142 5 ustar 00root root 0000000 0000000 src/GitList/Util/Repository.php 0000664 0000000 0000000 00000015142 15161103626 0017035 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($repo, $branch = 'master')
{
$repository = $this->app['git']->getRepository($this->app['git.repos'] . $repo);
$files = $repository->getTree($branch)->output();
foreach ($files as $file) {
if (preg_match('/^readme*/i', $file['name'])) {
return array(
'filename' => $file['name'],
'content' => $repository->getBlob("$branch:\"{$file['name']}\"")->output()
);
}
}
return array();
}
/**
* 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
$valid_refs = array_merge((array) $repository->getBranches(), (array) $repository->getTags());
foreach ($valid_refs as $k => $v) {
if (!preg_match(sprintf("#^%s/#", preg_quote($v, '#')), $input)) {
unset($valid_refs[$k]);
}
}
// No exact ref match, so just try our best
if (count($valid_refs) > 1) {
preg_match('/([^\/]+)(.*)/', $input, $matches);
$branch = preg_replace('/^\/|\/$/', '', $matches[1]);
} else {
// Extract branch name
$branch = array_shift($valid_refs);
}
}
$tree = trim(str_replace($branch, "", $input), "/");
return array($branch, $tree);
}
}
src/GitList/Util/Routing.php 0000664 0000000 0000000 00000002644 15161103626 0016310 0 ustar 00root root 0000000 0000000 app = $app;
}
public function getRepositoryRegex()
{
static $regex = null;
if ($regex === null) {
$app = $this->app;
$quotedPaths = array_map(
function ($repo) use ($app) {
return preg_quote($app['util.routing']->getRelativePath($repo['path']), '#');
},
$this->app['git']->getRepositories($this->app['git.repos'])
);
usort($quotedPaths, function ($a, $b) { return strlen($b) - strlen($a); });
$regex = implode('|', $quotedPaths);
}
return $regex;
}
/**
* 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($relativePath, '/');
} else {
throw new \InvalidArgumentException(
sprintf("Path '%s' does not match configured repository directory", $repoPath)
);
}
}
}
src/GitList/Util/View.php 0000664 0000000 0000000 00000002407 15161103626 0015570 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 15161103626 0012221 5 ustar 00root root 0000000 0000000 tests/InterfaceTest.php 0000664 0000000 0000000 00000030324 15161103626 0015474 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');
$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");
}
public function createApplication()
{
$config = new \GitList\Config(array(
'git' => array(
'client' => self::$gitPath,
'repositories' => self::$tmpdir,
),
'app' => array(
'debug' => true,
),
));
$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: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->assertEquals('/nested/NestedRepo/', $crawler->filter('.repository-header a')->eq(2)->attr('href'));
$this->assertEquals('/nested/NestedRepo/master/rss/', $crawler->filter('.repository-header a')->eq(3)->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(4)->attr('href'));
$this->assertEquals('/foobar/master/rss/', $crawler->filter('.repository-header a')->eq(5)->attr('href'));
}
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('.readme-header:contains("README.md")'));
$this->assertEquals("## GitTest\nGitTest is a *test* repository!", $crawler->filter('#readme-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('.readme-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();
$crawler = $client->request('GET', '/GitTest/master/rss/');
$this->assertTrue($client->getResponse()->isOk());
$this->assertRegexp('/Latest commits in GitTest:master/', $client->getResponse()->getContent());
$this->assertRegexp('/Initial commit/', $client->getResponse()->getContent());
}
public function testNestedRepoPage()
{
$client = $this->createClient();
$crawler = $client->request('GET', '/nested/NestedRepo/');
$this->assertTrue($client->getResponse()->isOk());
$this->assertRegexp('/NESTED TEST REPO README/', $client->getResponse()->getContent());
}
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 15161103626 0012214 5 ustar 00root root 0000000 0000000 views/blame.twig 0000664 0000000 0000000 00000001275 15161103626 0014175 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 15161103626 0015374 0 ustar 00root root 0000000 0000000