update: correction quelques erreurs et mise en place du fil d'ariane

This commit is contained in:
Emmanuel ROY 2021-02-09 14:16:16 +01:00
parent 297de5a303
commit 2b9d7af69f
103 changed files with 6320 additions and 70 deletions

View file

@ -16,7 +16,7 @@ class Modele
//on recherche le pattern des tableau dans la valeur du paramètre
// dans le cas ou la déclaration se fait sur une seule ligne
if (preg_match("#{.*}#", $matches[2])) {
if (preg_match_all("#(?<capture>[0-9a-zA-ZÀÁÂÃÄÅàáâãäåÒÓÔÕÖØòóôõöøÈÉÊËèéêëÇçÌÍÎÏìíîïÙÚÛÜùúûüÿÑñ_+\-]*)#", $matches[2], $arrayMatches)) {
if (preg_match_all("#(?<capture>[0-9a-zA-ZÀÁÂÃÄÅàáâãäåÒÓÔÕÖØòóôõöøÈÉÊËèéêëÇçÌÍÎÏìíîïÙÚÛÜùúûüÿÑñ_+\- ']*)#", $matches[2], $arrayMatches)) {
$array = array();
foreach ($arrayMatches['capture'] as $val) {
if ($val != '') {

View file

@ -0,0 +1,6 @@
<?php
define('LDAP_USER','cn=name, ou=group, dc=domain, dc=tld');
define('LDAP_PASSWORD','password');
define('LDAP_URL',"ldap://ldap.domain.tld");
define('LDAP_PORT',"389");

View file

@ -2,5 +2,6 @@ name : index
page_title : Accueil de l'application
description : zatou stra bracadabla
engine : blade
params : params
ariane : {acceuil}
arianelink : {index}

View file

@ -51,13 +51,34 @@
</header>
<!-- end: Header -->
<!-- Subbar -->
<div id="sub-bar" class="fullwidth">
<div id="subbar" class="fullwidth">
<div class="container">
<span style="float:left;">Vous êtes connecté en tant que {{$_SESSION['user_login']}}</span>
<span style="float:right;"><a href="{{ \MVC\Classe\Url::link_rewrite( false, 'Logout', []) }}">Se Deconnecter</a></span>
</div>
</div>
<!-- end: Subbar -->
<!-- Breadcrumbs -->
@if (isset($ariane))
<div id="breadcrumbs" class="fullwidth">
<div class="container">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
@foreach($ariane as $value)
@if($value == end($ariane))
<li class="breadcrumb-item active" aria-current="page">{{$value}}</li>
@else
<li class="breadcrumb-item"><a href="{{\MVC\Classe\Url::link_rewrite(false,$arianelink[array_search($value,$ariane)])}}">{{$value}}</a></li>
@endif
@endforeach
</ol>
</nav>
</div>
</div>
@endif
<!-- end: BreadCrumbs -->
<section id="page-content">
<div class="container">

View file

@ -0,0 +1,119 @@
{% block body %}
<!-- Body Inner -->
<div class="body-inner">
<!-- Topbar -->
<div id="topbar" class="d-none d-xl-block d-lg-block topbar-transparent topbar-fullwidth dark"
style="background: rgba(0, 0, 0, 0.59);">
<div class="container">
<ul class="top-menu">
<li {% if name == 'docs_route' || name == 'docs_name_route' %} class="actual" {% endif %} ><a href="{{ \MVC\Classe\Url::link_rewrite( false, 'docs', []) }}">Documentation</a></li>
<li {% if name == 'depots' %} class="actual" {% endif %} ><a href="{{ \MVC\Classe\Url::link_rewrite( false, 'gitlist/SAND-FrameWork', []) }}">Dépot</a></li>
<li {% if name == 'donate' %} class="actual" {% endif %} ><a href="{{ \MVC\Classe\Url::link_rewrite( false, 'Donate', []) }}">Donate</a></li>
<li {% if name == 'cgu' %} class="actual" {% endif %} ><a href="{{ \MVC\Classe\Url::link_rewrite( false, 'CGU', []) }}"> CGU Terms</a></li>
<li {% if name == 'policy' %} class="actual" {% endif %} ><a href="{{ \MVC\Classe\Url::link_rewrite( false, 'Policy', []) }}">Policy</a></li>
</ul>
</div>
</div>
<!-- end: Topbar -->
<!-- Header -->
<header id="header" class="dark" data-transparent="true" data-fullwidth="true"
style="background: rgba(0, 0, 0, 0.59);">
<div class="header-inner">
<div class="container">
<!--Navigation Resposnive Trigger-->
<div id="mainMenu-trigger">
<a class="lines-button x"><span class="lines"></span></a>
</div>
<!--end: Navigation Resposnive Trigger-->
<!--Navigation-->
<div id="mainMenu">
<div class="container">
<!--Logo-->
<div id="logo">
<a href="#">
SAND Framework
</a>
</div>
<!--end: logo-->
<nav>
<ul>
<li {% if name == 'index' %} class="actual" {% endif %} ><a href="{{ \MVC\Classe\Url::link_rewrite( false, 'Index', []) }}">Index</a></li>
<li {% if name == 'admin' %} class="actual" {% endif %} ><a href="{{ \MVC\Classe\Url::link_rewrite( false, 'Admin', []) }}">Admin</a></li>
</ul>
</nav>
</div>
</div>
<!--end: Navigation-->
</div>
</div>
</header>
<!-- end: Header -->
<!-- Subbar -->
<div id="subbar" class="fullwidth">
<div class="container">
<span style="float:left;">Vous êtes connecté en tant que {{$_SESSION['user_login']}}</span>
<span style="float:right;"><a href="{{ \MVC\Classe\Url::link_rewrite( false, 'Logout', []) }}">Se Deconnecter</a></span>
</div>
</div>
<!-- end: Subbar -->
<section id="page-content">
<div class="container">
<!--Alerts-->
{% if $_SESSION['alerts'] is defined %}
{% foreach $_SESSION['alerts'] as alert %}
<div class="alert alert-{{alert.type}} alert-dismissible fade show" role="alert">
<strong>{{alert.title}}</strong> {{alert.message}}.
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endforeach %}
{% endif %}
<!--end: Alerts-->
{% block content %}{% endblock %}
</div>
</section>
<!-- Footer -->
<footer id="footer">
<div class="footer-content">
<div class="container">
<div class="row">
<div class="col-lg-3">
<div class="widget">
<div class="widget-title"></div>
<p class="mb-5">
<img src="{{ \MVC\Classe\Url::asset_rewrite('assets/img/1007698-ffeb3b.svg') }}" width="150">
</p>
</div>
</div>
<div class="col-lg-9">
<p>
SAND FrameWork is an CC-licensed or MIT-licenced open source project and completely free to use.
</p>
<p>
However, the amount of effort needed to maintain and develop new features for the project is not
sustainable without proper financial backing.
You can support its ongoing development by being a backer or a sponsor on
<a href="https://www.patreon.com/">Patreon campaign</a>
(recurring, with perks for different tiers), and get your company logo here.
</p>
<p>
Also, you can make a <a href="https://www.paypal.me/">one time donation via PayPal</a>.
</p>
</div>
</div>
</div>
<div class="copyright-content">
<div class="container">
<div class="copyright-text text-center">&copy; 2020-2021 Built with SAND Framework - Responsive SAND Template.</div>
</div>
</div>
</div>
</footer>
<!-- end: Footer -->
</div>
<!-- end: Body Inner -->
{% endblock %}}

View file

@ -0,0 +1,72 @@
<!DOCTYPE html>
<html>
<head>
{% block head %}
<title>{{page_title}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="author" content="" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" lang="fr" content="{{description}}"/>
<link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/manifest.json">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png">
<meta name="theme-color" content="#ffffff">
{% block top-css %}
<link rel="stylesheet" href="{{ \MVC\Classe\Url::asset_rewrite('assets/bootstrap-5.0.0-beta1-dist/css/bootstrap.min.css')}}">
<link rel="stylesheet" href="{{ \MVC\Classe\Url::asset_rewrite('assets/css/custom.css')}}">
{% endblock %}
{% endblock %}
</head>
<body>
{% block top-javascript %}{% endblock %}
{% block body %}{% endblock %}
{% block bottom-javascript %}
<script src="{{ \MVC\Classe\Url::asset_rewrite('assets/bootstrap-5.0.0-beta1-dist/js/bootstrap.min.js')}}"></script>
<script src="{{ \MVC\Classe\Url::asset_rewrite('assets/js/custom.js')}}"></script>
/*
SCRIPT JS permettant de ne valider qu'une seule fois un formulaire
ATTENTION tous les formulaires sont affecté
Lors d'une validation bootstrap personnalisé veuillez utilisé
la class do-resubmit sur le formulaire afin de permettre
l'activation supplémentaire du bouton.
*/
<script>
window.onload = function() {
let PreventAllforms = document.querySelectorAll("form");
Array.prototype.slice.call(PreventAllforms)
.forEach(function (PreventForm) {
PreventForm.onsubmit = submitted.bind(PreventForm);
});
}
function submitted(event) {
if (event.target.classList.contains('do-resubmit')) {
event.submitter.disabled = false;
}else{
event.submitter.disabled = true;
}
}
</script>
{% endblock %}
</body>
</html>

View file

@ -1,3 +1,4 @@
<!DOCTYPE html>
<html>
<head>
@ -43,6 +44,31 @@
@section('bottom-javascript')
<script src="{{ \MVC\Classe\Url::asset_rewrite('assets/bootstrap-5.0.0-beta1-dist/js/bootstrap.min.js')}}"></script>
<script src="{{ \MVC\Classe\Url::asset_rewrite('assets/js/custom.js')}}"></script>
/*
SCRIPT JS permettant de ne valider qu'une seule fois un formulaire
ATTENTION tous les formulaires sont affecté
Lors d'une validation bootstrap personnalisé veuillez utilisé
la class do-resubmit sur le formulaire afin de permettre
l'activation supplémentaire du bouton.
*/
<script>
window.onload = function() {
let PreventAllforms = document.querySelectorAll("form");
Array.prototype.slice.call(PreventAllforms)
.forEach(function (PreventForm) {
PreventForm.onsubmit = submitted.bind(PreventForm);
});
}
function submitted(event) {
if (event.target.classList.contains('do-resubmit')) {
event.submitter.disabled = false;
}else{
event.submitter.disabled = true;
}
}
</script>
@show
</body>

View file

@ -0,0 +1,14 @@
<IfModule mod_rewrite.c>
Options -MultiViews +SymLinksIfOwnerMatch
RewriteEngine On
#RewriteBase /path/to/gitlist/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L,NC]
</IfModule>
<Files config.ini>
order allow,deny
deny from all
</Files>

View file

@ -0,0 +1,96 @@
# 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 combined;
error_log /var/log/nginx/MYSERVER.error.log error;
root /var/www/DIR;
index index.php;
# auth_basic "Restricted";
# auth_basic_user_file .htpasswd;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location ~* ^/index.php.*$ {
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# if you're using php5-fpm via tcp
fastcgi_pass 127.0.0.1:9000;
# if you're using php5-fpm via socket
#fastcgi_pass unix:/var/run/php5-fpm.sock;
include /etc/nginx/fastcgi_params;
}
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
}
```

View file

@ -0,0 +1,9 @@
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.

View file

@ -0,0 +1,86 @@
<p align="left"><img src="logo/horizontal.png" alt=gitlist" height="120px"></p>
# GitList: an elegant git repository viewer
[![Build Status](https://secure.travis-ci.org/klaussilveira/gitlist.png)](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
![Screenshot 1](https://raw.githubusercontent.com/klaussilveira/gitlist/gh-pages/img/roller/1.png)
![Screenshot 2](https://raw.githubusercontent.com/klaussilveira/gitlist/gh-pages/img/roller/2.png)
![Screenshot 3](https://raw.githubusercontent.com/klaussilveira/gitlist/gh-pages/img/roller/3.png)
![Screenshot 4](https://raw.githubusercontent.com/klaussilveira/gitlist/gh-pages/img/roller/4.png)
![Screenshot 5](https://raw.githubusercontent.com/klaussilveira/gitlist/gh-pages/img/roller/5.png)
![Screenshot 6](https://raw.githubusercontent.com/klaussilveira/gitlist/gh-pages/img/roller/6.png)
![Screenshot 7](https://raw.githubusercontent.com/klaussilveira/gitlist/gh-pages/img/roller/7.png)
![Screenshot 8](https://raw.githubusercontent.com/klaussilveira/gitlist/gh-pages/img/roller/8.png)
![Screenshot 9](https://raw.githubusercontent.com/klaussilveira/gitlist/gh-pages/img/roller/9.png)
![Screenshot 10](https://raw.githubusercontent.com/klaussilveira/gitlist/gh-pages/img/roller/10.png)
## Requirements
In order to run GitList on your server, you'll need:
* PHP 5.3+
* git
* Webserver (Apache, nginx, lighttpd)
## 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.
* Do not download a branch or tag from GitHub, unless you want to use the development version. The version available for download at the website already has all dependencies bundled, so you don't have to use composer or any other tool
* 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.
## Authors and contributors
* [Klaus Silveira](http://www.klaussilveira.com) (Creator, developer)
## License
[New BSD license](http://www.opensource.org/licenses/bsd-license.php)
## Development
GitList uses [Composer](http://getcomposer.org/) to manage dependencies and [Ant](http://ant.apache.org/) to build the project.
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 lots 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
* Improve the test coverage 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! :)

View file

@ -0,0 +1,16 @@
<?php
define('MODULE_NAME','gitlist');
// Startup and configure Silex application
$app = new GitList\Application($config, __DIR__);
// Mount the controllers
$app->mount('', new GitList\Controller\MainController());
$app->mount('', new GitList\Controller\BlobController());
$app->mount('', new GitList\Controller\CommitController());
$app->mount('', new GitList\Controller\TreeController());
$app->mount('', new GitList\Controller\NetworkController());
$app->mount('', new GitList\Controller\TreeGraphController());
return $app;

View file

@ -0,0 +1,58 @@
[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 or add a regex (including delimiters), eg. hidden[] = '/(.+)\.git/'
; hidden[] = '/home/git/repositories/BetaTest'
[app]
debug = false
cache = true
theme = "default"
title = ""
[clone_button]
; ssh remote
show_ssh_remote = false ; display remote URL for SSH
ssh_host = '' ; host to use for cloning via HTTP (default: none => uses gitlist web host)
ssh_url_subdir = '' ; if cloning via SSH is triggered using special dir (e.g. ssh://example.com/git/repo.git)
; has to end with trailing slash
ssh_port = '' ; port to use for cloning via SSH (default: 22 => standard ssh port)
ssh_user = 'git' ; user to use for cloning via SSH
ssh_user_dynamic = false ; when enabled, ssh_user is set to $_SERVER['PHP_AUTH_USER']
; http remote
show_http_remote = false ; display remote URL for HTTP
http_host = '' ; host to use for cloning via HTTP (default: none => uses gitlist web host)
use_https = true ; generate URL with https://
http_url_subdir = 'git/' ; if cloning via HTTP is triggered using virtual dir (e.g. https://example.com/git/repo.git)
; has to end with trailing slash
http_user = '' ; user to use for cloning via HTTP (default: none)
http_user_dynamic = false ; when enabled, http_user is set to $_SERVER['PHP_AUTH_USER']
; 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
; format = 'd/m/Y H:i:s'
; custom avatar service
[avatar]
; url = '//gravatar.com/avatar/'
; query[] = 'd=identicon'

View file

@ -0,0 +1,30 @@
<?php
/**
* GitList: an elegant and modern git repository viewer
* http://gitlist.org
*/
if (!ini_get('date.timezone')) {
date_default_timezone_set('UTC');
}
if (php_sapi_name() == 'cli-server' && file_exists(substr($_SERVER['REQUEST_URI'], 1))) {
return false;
}
if (!is_writable(__DIR__ . DIRECTORY_SEPARATOR . 'cache')) {
die(sprintf('The "%s" folder must be writable for GitList to run.', __DIR__ . DIRECTORY_SEPARATOR . 'cache'));
}
require dirname(__FILE__).DIRECTORY_SEPARATOR.'vendor/autoload.php';
$config = GitList\Config::fromFile(dirname(__FILE__).DIRECTORY_SEPARATOR.'config.ini');
if ($config->get('date', 'timezone')) {
date_default_timezone_set($config->get('date', 'timezone'));
}
$app = require 'boot.php';
$app->run();

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="2165.567px" height="641.871px" viewBox="0 0 2165.567 641.871" enable-background="new 0 0 2165.567 641.871"
xml:space="preserve">
<g>
<g>
<path fill="#F05133" d="M575.515,304.458L340.734,69.677c-9.099-9.1-23.853-9.1-32.955,0.002l-36.356,36.354l75.334,75.334
c12.273-2.876,25.697,0.431,35.268,9.999c14.716,14.716,14.716,38.577,0,53.293c-14.716,14.716-38.578,14.716-53.291,0
c-9.571-9.568-12.877-22.997-10.001-35.271l-75.332-75.332L72.999,304.46c-9.1,9.097-9.1,23.853,0,32.952l234.781,234.78
c9.102,9.103,23.856,9.1,32.953,0l37.87-37.867L244.737,400.457l24.993-24.996l133.868,133.865l42.027-42.024L311.757,333.434
l24.996-24.995l133.868,133.867l42.024-42.027L378.781,266.412l24.999-24.996l133.865,133.867l37.87-37.87
C584.615,328.313,584.615,313.557,575.515,304.458z M247.981,378.705c-14.718,14.716-38.58,14.714-53.296,0
c-14.716-14.719-14.713-38.577,0-53.292c14.719-14.716,38.578-14.716,53.296,0C262.697,340.128,262.697,363.989,247.981,378.705z
M315.002,311.683c-14.716,14.716-38.577,14.716-53.291,0c-14.719-14.718-14.716-38.577,0-53.293
c14.716-14.716,38.575-14.716,53.291,0C329.718,273.106,329.718,296.967,315.002,311.683z"/>
<path fill="#FFFFFF" d="M328.735,191.367c5.146-5.146,11.42-8.452,18.022-9.999l-75.334-75.334l-28.021,28.023l75.332,75.332
C320.28,202.79,323.586,196.515,328.735,191.367z"/>
<path fill="#FFFFFF" d="M261.711,258.39c-14.716,14.716-14.719,38.575,0,53.293c14.713,14.716,38.575,14.716,53.291,0
c14.716-14.716,14.716-38.577,0-53.293C300.286,243.674,276.427,243.674,261.711,258.39z"/>
<rect x="296.53" y="370.195" transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 393.5369 938.7476)" fill="#FFFFFF" width="189.318" height="35.35"/>
<path fill="#FFFFFF" d="M330.224,220.88l-11.491-11.491c-2.876,12.273,0.431,25.703,10.001,35.271
c14.713,14.716,38.574,14.716,53.291,0c14.716-14.716,14.716-38.577,0-53.293c-9.571-9.568-22.995-12.875-35.268-9.999
l11.488,11.488L330.224,220.88z"/>
<path fill="#FFFFFF" d="M318.733,209.389l11.491,11.491l28.021-28.024l-11.488-11.488c-6.603,1.546-12.877,4.853-18.022,9.999
C323.586,196.515,320.28,202.79,318.733,209.389z"/>
<rect x="363.555" y="303.171" transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 555.3423 871.726)" fill="#FFFFFF" width="189.315" height="35.352"/>
<path fill="#FFFFFF" d="M194.685,325.413c-14.713,14.715-14.716,38.573,0,53.292c14.716,14.714,38.578,14.716,53.296,0
c14.716-14.716,14.716-38.577,0-53.292C233.263,310.697,209.404,310.697,194.685,325.413z"/>
<rect x="229.509" y="437.216" transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 231.7255 1005.7686)" fill="#FFFFFF" width="189.316" height="35.352"/>
</g>
<g>
<g>
<path fill="#F05133" d="M873.918,439.349v-8.16c-22.252,11.372-45.748,17.062-70.473,17.062c-21.514,0-41.483-3.959-59.901-11.87
c-18.423-7.91-34.437-18.729-48.034-32.454c-13.603-13.725-24.238-29.795-31.899-48.218
c-7.667-18.418-11.499-38.262-11.499-59.531c0-20.771,3.895-40.43,11.686-58.975c7.789-18.545,18.545-34.802,32.268-48.776
c13.725-13.966,29.794-24.972,48.221-33.009c18.418-8.033,38.26-12.057,59.53-12.057c22.749,0,44.324,4.885,64.725,14.651
c20.4,9.773,38.141,23.555,53.228,41.358l-63.056,41.914c-7.667-7.661-16.135-13.538-25.407-17.619
c-9.273-4.081-19.104-6.12-29.489-6.12c-10.884,0-20.955,2.167-30.228,6.491c-9.272,4.331-17.313,10.077-24.11,17.248
c-6.803,7.174-12.119,15.521-15.948,25.037c-3.837,9.522-5.749,19.599-5.749,30.228c0,10.635,1.912,20.771,5.749,30.416
c3.83,9.642,9.208,18.051,16.135,25.222c6.919,7.174,15.022,12.923,24.294,17.245c9.273,4.33,19.344,6.491,30.228,6.491
c11.621,0,22.684-2.594,33.196-7.788c10.508-5.191,19.347-12.484,26.521-21.885h-50.815v-69.359h126.483v162.459H873.918z"/>
<path fill="#F05133" d="M973.32,439.349V194.917h71.584v244.432H973.32z"/>
<path fill="#F05133" d="M1279.319,258.344h-63.057v181.005h-69.731V258.344h-63.056l-5.934-5.933v-57.494h207.711v57.494
L1279.319,258.344z"/>
<path fill="#F05133" d="M1308.244,439.349V151.522h79.746v216.611h151.333v71.216H1308.244z"/>
<path fill="#F05133" d="M1558.61,439.349V194.917h71.584v244.432H1558.61z"/>
<path fill="#F05133" d="M1770.021,447.137c-16.078,0-31.961-1.982-47.663-5.934c-15.704-3.953-30.727-9.395-45.065-16.321
c-0.249,0-0.62-0.122-1.113-0.371c-0.498-0.241-1.113-0.49-1.855-0.739c-1.24-0.742-2.166-1.544-2.781-2.413
c-0.62-0.864-0.926-1.541-0.926-2.039c0-0.244,1.356-2.903,4.078-7.976c2.719-5.064,5.937-10.813,9.644-17.248
c3.461-5.685,6.679-11.185,9.644-16.504c2.969-5.315,5.438-9.581,7.421-12.798c2.716,1.24,4.758,2.169,6.12,2.783
c1.354,0.62,2.654,1.298,3.895,2.04c10.878,5.44,21.754,9.644,32.638,12.611c10.879,2.966,22.256,4.449,34.125,4.449
c1.729,0,3.396,0,5.008,0c1.605,0,3.274-0.122,5.007-0.371c3.71,0,7.047-0.492,10.015-1.483c2.969-1.232,5.501-2.966,7.604-5.191
c2.099-2.227,3.152-5.565,3.152-10.015c0-3.212-1.24-5.75-3.71-7.604c-2.473-1.855-5.069-3.396-7.789-4.637
c-1.732-0.742-3.336-1.356-4.82-1.854c-4.208-1.726-8.474-3.025-12.798-3.895c-4.328-0.864-8.715-1.79-13.167-2.781
c-5.934-1.235-11.748-2.532-17.433-3.895c-5.692-1.356-11.255-2.781-16.69-4.266c-5.692-1.728-11.006-3.645-15.95-5.749
c-4.948-2.099-9.644-4.509-14.094-7.232c-9.153-5.684-16.448-13.167-21.884-22.439c-5.443-9.273-8.16-21.57-8.16-36.907
c0-10.878,2.346-21.386,7.047-31.528c4.693-9.887,10.691-17.99,17.99-24.294c7.29-6.305,15.393-11.312,24.295-15.022
c8.901-3.71,18.174-6.242,27.817-7.604c9.644-1.354,19.287-2.039,28.931-2.039c15.821,0,31.585,1.982,47.292,5.933
c15.699,3.959,31.093,10.635,46.179,20.029c-5.691,9.644-11.005,18.859-15.95,27.634c-4.948,8.78-10.264,17.99-15.948,27.634
c-12.611-6.426-24.422-11.434-35.422-15.022c-11.006-3.583-22.811-5.378-35.423-5.378c-2.476,0-5.257,0.063-8.347,0.185
c-3.092,0.13-5.934,0.685-8.53,1.671c-2.597,0.991-4.82,2.475-6.676,4.449c-1.854,1.982-2.781,4.823-2.781,8.531
c0,2.226,0.612,4.33,1.853,6.307c0.986,1.982,3.155,3.65,6.491,5.007c3.34,1.362,7.849,2.781,13.538,4.265
c5.438,1.484,11.437,2.909,17.99,4.266c6.548,1.362,13.289,3.03,20.216,5.007c6.92,1.733,13.966,3.772,21.143,6.121
c7.169,2.354,13.909,5.319,20.214,8.902c6.305,3.588,11.991,7.788,17.061,12.611c5.067,4.821,9.089,10.57,12.057,17.247
c2.224,4.947,3.768,10.264,4.637,15.948c0.863,5.689,1.297,11.255,1.297,16.689c0,16.322-3.279,29.674-9.828,40.059
c-6.556,10.386-15.087,18.676-25.594,24.853c-10.514,6.183-22.256,10.442-35.235,12.796
C1795.799,445.962,1782.876,447.137,1770.021,447.137z"/>
<path fill="#F05133" d="M2093.46,258.344h-63.056v181.005h-69.731V258.344h-63.057l-5.934-5.933v-57.494h207.711v57.494
L2093.46,258.344z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="1480px" height="1416px" viewBox="0 0 1480 1416" enable-background="new 0 0 1480 1416" xml:space="preserve">
<path fill="#F05133" d="M1341.738,668.538L779.462,106.262c-21.791-21.793-57.125-21.793-78.924,0.006l-87.07,87.064L793.887,373.75
c29.393-6.888,61.542,1.031,84.463,23.945c35.243,35.243,35.243,92.389,0,127.632c-35.243,35.244-92.389,35.244-127.625,0
c-22.921-22.914-30.84-55.076-23.952-84.47L546.36,260.445L138.262,668.544c-21.793,21.785-21.793,57.125,0,78.916l562.276,562.275
c21.799,21.8,57.133,21.792,78.918,0l90.695-90.688L549.558,898.446l59.856-59.863l320.601,320.594l100.651-100.645L710.065,737.932
l59.863-59.859l320.601,320.598l100.644-100.651L870.579,577.421l59.87-59.863l320.594,320.598l90.695-90.695
C1363.531,725.669,1363.531,690.329,1341.738,668.538z M557.327,846.353c-35.249,35.243-92.395,35.238-127.639,0
c-35.242-35.25-35.235-92.389,0-127.629c35.25-35.243,92.39-35.243,127.639,0C592.571,753.964,592.571,811.109,557.327,846.353z
M717.836,685.841c-35.243,35.244-92.389,35.244-127.626,0c-35.25-35.248-35.242-92.388,0-127.631
c35.243-35.244,92.383-35.244,127.626,0C753.078,593.453,753.078,650.599,717.836,685.841z"/>
<path fill="#FFFFFF" d="M590.21,558.21c-35.242,35.243-35.25,92.383,0,127.631c35.237,35.244,92.383,35.244,127.626,0
c35.242-35.242,35.242-92.388,0-127.631C682.593,522.966,625.453,522.966,590.21,558.21z"/>
<rect x="673.599" y="825.971" transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 922.9224 2118.8887)" fill="#FFFFFF" width="453.398" height="84.659"/>
<path fill="#FFFFFF" d="M878.35,397.695c-22.921-22.914-55.07-30.833-84.463-23.945L613.468,193.332l-67.107,67.113l180.412,180.412
c-6.888,29.394,1.031,61.556,23.952,84.47c35.236,35.244,92.382,35.244,127.625,0C913.593,490.084,913.593,432.938,878.35,397.695z"
/>
<polygon fill="#FFFFFF" points="870.579,577.421 1191.173,898.019 1251.043,838.155 930.449,517.558 "/>
<path fill="#FFFFFF" d="M429.688,718.724c-35.235,35.24-35.242,92.379,0,127.629c35.244,35.238,92.39,35.243,127.639,0
c35.244-35.243,35.244-92.389,0-127.629C522.078,683.48,464.938,683.48,429.688,718.724z"/>
<polygon fill="#FFFFFF" points="549.558,898.446 870.151,1219.047 930.015,1159.177 609.414,838.583 "/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View file

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="1344px" height="1225.566px" viewBox="0 0 1344 1225.566" enable-background="new 0 0 1344 1225.566" xml:space="preserve">
<path fill="#F05133" d="M1044.531,401.631L699.165,56.259c-13.387-13.387-35.089-13.387-48.481,0.003l-53.479,53.479
l110.818,110.821c18.055-4.233,37.798,0.632,51.876,14.707c21.649,21.647,21.649,56.748,0,78.397
c-21.647,21.647-56.742,21.647-78.392,0c-14.078-14.078-18.938-33.832-14.708-51.888L555.982,150.963L305.315,401.634
c-13.384,13.384-13.384,35.089,0,48.476l345.369,345.368c13.393,13.39,35.095,13.384,48.473,0l55.708-55.704L557.948,542.848
l36.765-36.768L791.635,703l61.826-61.818L656.539,444.256l36.771-36.77l196.922,196.922l61.821-61.824L755.128,345.662
l36.779-36.771l196.916,196.925l55.708-55.707C1057.917,436.723,1057.917,415.018,1044.531,401.631z M562.723,510.852
c-21.656,21.647-56.754,21.645-78.4,0c-21.647-21.649-21.647-56.747,0-78.395c21.646-21.649,56.744-21.649,78.4,0
C584.369,454.104,584.369,489.202,562.723,510.852z M661.311,412.258c-21.646,21.646-56.753,21.646-78.391,0
c-21.656-21.652-21.647-56.748,0-78.397c21.647-21.647,56.745-21.647,78.391,0C682.958,355.51,682.958,390.611,661.311,412.258z"/>
<path fill="#FFFFFF" d="M582.919,333.86c-21.647,21.649-21.656,56.745,0,78.397c21.638,21.646,56.745,21.646,78.391,0
c21.647-21.646,21.647-56.748,0-78.397C639.664,312.213,604.566,312.213,582.919,333.86z"/>
<rect x="634.139" y="498.33" transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 949.4833 1441.9585)" fill="#FFFFFF" width="278.492" height="52.003"/>
<path fill="#FFFFFF" d="M759.899,235.269c-14.078-14.075-33.821-18.94-51.876-14.707L597.205,109.74l-41.223,41.223L666.8,261.778
c-4.229,18.056,0.63,37.81,14.708,51.888c21.649,21.647,56.744,21.647,78.392,0C781.549,292.017,781.549,256.916,759.899,235.269z"
/>
<polygon fill="#FFFFFF" points="755.128,345.662 952.053,542.584 988.823,505.816 791.907,308.892 "/>
<path fill="#FFFFFF" d="M484.322,432.457c-21.647,21.647-21.647,56.745,0,78.395c21.646,21.645,56.744,21.647,78.4,0
c21.646-21.649,21.646-56.747,0-78.395C541.066,410.808,505.969,410.808,484.322,432.457z"/>
<polygon fill="#FFFFFF" points="557.948,542.848 754.864,739.773 791.635,703 594.712,506.08 "/>
<g>
<g>
<path fill="#F05133" d="M231.721,1150.067v-7.206c-19.649,10.042-40.404,15.065-62.235,15.065
c-19.002,0-36.642-3.495-52.903-10.48c-16.271-6.983-30.413-16.542-42.419-28.663c-12.016-12.121-21.408-26.313-28.173-42.584
c-6.772-16.264-10.154-33.792-10.154-52.577c0-18.346,3.438-35.704,10.317-52.084c6.881-16.374,16.377-30.733,28.497-43.074
c12.118-12.335,26.316-22.054,42.586-29.154c16.269-7.095,33.79-10.647,52.576-10.647c20.087,0,39.145,4.314,57.161,12.938
c18.012,8.636,33.686,20.804,47.008,36.527l-55.687,37.02c-6.771-6.771-14.252-11.963-22.444-15.563
c-8.183-3.605-16.866-5.404-26.038-5.404c-9.617,0-18.508,1.91-26.698,5.729c-8.191,3.825-15.291,8.901-21.29,15.237
c-6.008,6.333-10.708,13.703-14.086,22.11c-3.394,8.406-5.075,17.306-5.075,26.69c0,9.397,1.682,18.349,5.075,26.864
c3.379,8.518,8.127,15.943,14.246,22.276c6.11,6.336,13.267,11.415,21.457,15.232c8.19,3.825,17.082,5.729,26.698,5.729
c10.262,0,20.031-2.29,29.321-6.871c9.274-4.594,17.082-11.029,23.415-19.333h-44.871v-61.256h111.704v143.479H231.721z"/>
<path fill="#F05133" d="M319.513,1150.067V934.196h63.215v215.871H319.513z"/>
<path fill="#F05133" d="M589.756,990.212h-55.684v159.855h-61.589V990.212h-55.685l-5.243-5.243v-50.772h183.442v50.772
L589.756,990.212z"/>
<path fill="#F05133" d="M615.299,1150.067v-254.2h70.433v191.311h133.646v62.89H615.299z"/>
<path fill="#F05133" d="M836.413,1150.067V934.196h63.222v215.871H836.413z"/>
<path fill="#F05133" d="M1023.121,1156.945c-14.197,0-28.229-1.752-42.09-5.243c-13.873-3.485-27.139-8.293-39.808-14.412
c-0.214,0-0.542-0.104-0.979-0.327c-0.439-0.215-0.981-0.434-1.644-0.65c-1.09-0.656-1.91-1.365-2.451-2.133
c-0.551-0.762-0.82-1.362-0.82-1.799c0-0.217,1.201-2.566,3.6-7.045c2.405-4.473,5.243-9.549,8.519-15.234
c3.058-5.021,5.902-9.877,8.515-14.576c2.622-4.692,4.807-8.459,6.559-11.301c2.399,1.096,4.197,1.916,5.401,2.455
c1.195,0.551,2.344,1.148,3.442,1.805c9.61,4.804,19.21,8.515,28.826,11.137c9.607,2.621,19.655,3.928,30.133,3.928
c1.529,0,3.006,0,4.423,0c1.418,0,2.892-0.103,4.421-0.325c3.283,0,6.225-0.437,8.846-1.307c2.619-1.095,4.859-2.624,6.717-4.593
c1.854-1.963,2.789-4.909,2.789-8.84c0-2.839-1.102-5.077-3.275-6.721c-2.191-1.634-4.479-2.993-6.884-4.089
c-1.532-0.655-2.949-1.2-4.256-1.638c-3.72-1.525-7.481-2.674-11.307-3.441c-3.814-0.768-7.695-1.582-11.623-2.455
c-5.243-1.089-10.376-2.237-15.402-3.441c-5.018-1.195-9.936-2.455-14.739-3.77c-5.027-1.521-9.714-3.217-14.087-5.074
c-4.364-1.851-8.516-3.983-12.446-6.391c-8.079-5.021-14.523-11.623-19.327-19.813s-7.202-19.052-7.202-32.597
c0-9.607,2.07-18.887,6.221-27.845c4.146-8.729,9.441-15.888,15.889-21.454c6.438-5.57,13.592-9.991,21.456-13.269
c7.865-3.275,16.056-5.51,24.57-6.714c8.519-1.198,17.036-1.805,25.546-1.805c13.976,0,27.895,1.752,41.773,5.243
c13.864,3.498,27.455,9.395,40.777,17.687c-5.029,8.519-9.722,16.656-14.086,24.406c-4.368,7.757-9.069,15.892-14.087,24.403
c-11.14-5.674-21.567-10.094-31.281-13.267c-9.719-3.163-20.142-4.748-31.281-4.748c-2.19,0-4.643,0.056-7.376,0.164
c-2.727,0.114-5.234,0.606-7.53,1.474c-2.294,0.879-4.253,2.188-5.896,3.931c-1.641,1.752-2.452,4.26-2.452,7.534
c0,1.963,0.542,3.825,1.632,5.571c0.87,1.746,2.788,3.223,5.738,4.42c2.946,1.204,6.922,2.458,11.951,3.771
c4.804,1.31,10.103,2.568,15.885,3.764c5.785,1.204,11.737,2.678,17.856,4.421c6.11,1.528,12.332,3.336,18.677,5.406
c6.324,2.08,12.276,4.699,17.845,7.862c5.571,3.17,10.59,6.878,15.068,11.137c4.479,4.26,8.031,9.339,10.653,15.232
c1.96,4.37,3.321,9.068,4.095,14.089c0.756,5.021,1.14,9.937,1.14,14.74c0,14.412-2.894,26.205-8.679,35.373
c-5.791,9.174-13.319,16.494-22.603,21.951c-9.282,5.457-19.654,9.222-31.12,11.301
C1045.884,1155.908,1034.475,1156.945,1023.121,1156.945z"/>
<path fill="#F05133" d="M1308.772,990.212h-55.693v159.855h-61.581V990.212h-55.693l-5.234-5.243v-50.772h183.437v50.772
L1308.772,990.212z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.3 KiB

View file

@ -0,0 +1,187 @@
<?php
namespace GitList;
use GitList\Provider\GitServiceProvider;
use GitList\Provider\RepositoryUtilServiceProvider;
use GitList\Provider\RoutingUtilServiceProvider;
use GitList\Provider\ViewUtilServiceProvider;
use Silex\Application as SilexApplication;
use Silex\Provider\TwigServiceProvider;
use Silex\Provider\UrlGeneratorServiceProvider;
use Symfony\Component\Filesystem\Filesystem;
/**
* GitList application.
*/
class Application extends SilexApplication
{
protected $path;
/**
* Constructor initialize services.
*
* @param Config $config
* @param string $root Base path of the application files (views, cache)
*/
public function __construct(Config $config, $root = null)
{
parent::__construct();
$app = $this;
$this->path = realpath($root);
$this['debug'] = $config->get('app', 'debug');
$this['theme'] = $config->get('app', 'theme') ? $config->get('app', 'theme') : 'default';
$this['date.format'] = $config->get('date', 'format') ? $config->get('date', 'format') : 'd/m/Y H:i:s';
$this['filetypes'] = $config->getSection('filetypes');
$this['binary_filetypes'] = $config->getSection('binary_filetypes');
$this['cache.archives'] = $this->getCachePath() . 'archives';
$this['avatar.url'] = $config->get('avatar', 'url');
$this['avatar.query'] = $config->get('avatar', 'query');
// Register services
$this->register(new TwigServiceProvider(), array(
'twig.path' => array($this->getThemePath($this['theme']), $this->getThemePath('default')),
'twig.options' => $config->get('app', 'cache') ?
array('cache' => $this->getCachePath() . 'views') : array(),
));
$repositories = $config->get('git', 'repositories');
$this['git.projects'] = $config->get('git', 'project_list') ?
$this->parseProjectList($config->get('git', 'project_list')) :
false;
$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 RoutingUtilServiceProvider());
$this->register(new UrlGeneratorServiceProvider());
$this['twig'] = $this->share($this->extend('twig', function ($twig, $app) use ($config) {
$twig->addFilter(new \Twig_SimpleFilter('htmlentities', 'htmlentities'));
$twig->addFilter(new \Twig_SimpleFilter('md5', 'md5'));
$twig->addFilter(new \Twig_SimpleFilter('format_date', array($app, 'formatDate')));
$twig->addFilter(new \Twig_SimpleFilter('format_size', array($app, 'formatSize')));
$twig->addFunction(new \Twig_SimpleFunction('avatar', array($app, 'getAvatar')));
$twig->addGlobal('theme', $app['theme']);
$twig->addGlobal('title', $config->get('app', 'title') ? $config->get('app', 'title') : 'GitList');
$twig->addGlobal('show_http_remote', $config->get('clone_button', 'show_http_remote'));
$twig->addGlobal('use_https', $config->get('clone_button', 'use_https'));
$twig->addGlobal('http_url_subdir', $config->get('clone_button', 'http_url_subdir'));
$twig->addGlobal('http_user', $config->get('clone_button', 'http_user_dynamic') ? $_SERVER['PHP_AUTH_USER'] : $config->get('clone_button', 'http_user'));
$twig->addGlobal('http_host', $config->get('clone_button', 'http_host'));
$twig->addGlobal('show_ssh_remote', $config->get('clone_button', 'show_ssh_remote'));
$twig->addGlobal('ssh_user', $config->get('clone_button', 'ssh_user_dynamic') ? $_SERVER['PHP_AUTH_USER'] : $config->get('clone_button', 'ssh_user'));
$twig->addGlobal('ssh_url_subdir', $config->get('clone_button', 'ssh_url_subdir'));
$twig->addGlobal('ssh_host', $config->get('clone_button', 'ssh_host'));
$twig->addGlobal('ssh_port', $config->get('clone_button', 'ssh_port'));
return $twig;
}));
$this['escaper.argument'] = $this->share(function() {
return new Escaper\ArgumentEscaper();
});
// Handle errors
$this->error(function (\Exception $e, $code) use ($app) {
if ($app['debug']) {
return;
}
return $app['twig']->render('error.twig', array(
'message' => $e->getMessage(),
));
});
$this->finish(function () use ($app, $config) {
if (!$config->get('app', 'cache')) {
$fs = new Filesystem();
$fs->remove($app['cache.archives']);
}
});
}
public function formatDate($date)
{
return $date->format($this['date.format']);
}
public function formatSize($size)
{
$mod = 1000;
$units = array('B', 'kB', 'MB', 'GB');
for ($i = 0; $size > $mod; $i++) {
$size /= $mod;
}
return round($size, 2) . $units[$i];
}
public function getAvatar($email, $size)
{
$url = $this['avatar.url'] ? $this['avatar.url'] : '//gravatar.com/avatar/';
$query = array("s=$size");
if (is_string($this['avatar.query'])) {
$query[] = $this['avatar.query'];
} elseif (is_array($this['avatar.query'])) {
$query = array_merge($query, $this['avatar.query']);
}
$id = md5(strtolower($email));
return $url . $id . '?' . implode('&', $query);
}
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 getThemePath($theme)
{
return $this->path
. DIRECTORY_SEPARATOR
. 'themes'
. DIRECTORY_SEPARATOR
. $theme
. DIRECTORY_SEPARATOR
. 'twig'
. DIRECTORY_SEPARATOR;
}
public function parseProjectList($project_list)
{
$projects = array();
$file = fopen($project_list, 'r');
while ($file && !feof($file)) {
$projects[] = trim(fgets($file));
}
fclose($file);
return $projects;
}
}

View file

@ -0,0 +1,77 @@
<?php
namespace GitList;
class Config
{
protected $data;
public function __construct($data = array())
{
$this->data = $data;
}
public static function fromFile($file)
{
if (!file_exists($file)) {
die(sprintf('Please, create the %1$s file.', $file));
}
$data = parse_ini_file($file, true);
$config = new static($data);
$config->validateOptions();
return $config;
}
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');
}
}
}

View file

@ -0,0 +1,95 @@
<?php
namespace GitList\Controller;
use Silex\ControllerProviderInterface;
use Silex\Application;
use Symfony\Component\HttpFoundation\Response;
class BlobController implements ControllerProviderInterface
{
public function connect(Application $app)
{
$route = $app['controllers_factory'];
$route->get(MODULE_NAME.'/{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', '.+')
->convert('commitishPath', 'escaper.argument:escape')
->bind('blob');
$route->get(MODULE_NAME.'/{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())
->convert('commitishPath', 'escaper.argument:escape')
->bind('blob_raw');
$route->get(MODULE_NAME.'/{repo}/logpatch/{commitishPath}', function ($repo, $commitishPath) use ($app) {
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
list($branch, $file) = $app['util.routing']
->parseCommitishPathParam($commitishPath, $repo);
$filePatchesLog = $repository->getCommitsLogPatch($file);
$breadcrumbs = $app['util.view']->getBreadcrumbs($file);
return $app['twig']->render('logpatch.twig', array(
'branch' => $branch,
'repo' => $repo,
'breadcrumbs' => $breadcrumbs,
'commits' => $filePatchesLog,
));
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('commitishPath', '.+')
->convert('commitishPath', 'escaper.argument:escape')
->bind('logpatch');
return $route;
}
}

View file

@ -0,0 +1,132 @@
<?php
namespace GitList\Controller;
use Silex\ControllerProviderInterface;
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
class CommitController implements ControllerProviderInterface
{
public function connect(Application $app)
{
$route = $app['controllers_factory'];
$route->get(MODULE_NAME.'/{repo}/commits/search', function (Request $request, $repo) use ($app) {
$subRequest = Request::create(
'/' . $repo . '/commits/master/search',
'POST',
array('query' => $request->get('query'))
);
return $app->handle($subRequest, \Symfony\Component\HttpKernel\HttpKernelInterface::SUB_REQUEST);
})->assert('repo', $app['util.routing']->getRepositoryRegex());
$route->get(MODULE_NAME.'/{repo}/commits/{commitishPath}', function (Request $request, $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($request->get('page'), $repository->getTotalCommits($type));
$commits = $repository->getPaginatedCommits($type, $pager['current']);
$categorized = array();
foreach ($commits as $commit) {
$date = $commit->getCommiterDate();
$date = $date->format('Y-m-d');
$categorized[$date][] = $commit;
}
$template = $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)
->convert('commitishPath', 'escaper.argument:escape')
->bind('commits');
$route->post(MODULE_NAME.'/{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($query, $branch);
$categorized = array();
foreach ($commits as $commit) {
$date = $commit->getCommiterDate();
$date = $date->format('Y-m-d');
$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())
->convert('branch', 'escaper.argument:escape')
->bind('searchcommits');
$route->get(MODULE_NAME.'/{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(MODULE_NAME.'/{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())
->convert('commitishPath', 'escaper.argument:escape')
->bind('blame');
return $route;
}
}

View file

@ -0,0 +1,77 @@
<?php
namespace GitList\Controller;
use Silex\ControllerProviderInterface;
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class MainController implements ControllerProviderInterface
{
public function connect(Application $app)
{
$route = $app['controllers_factory'];
$route->get(MODULE_NAME.'/', function () use ($app) {
$repositories = $app['git']->getRepositories($app['git.repos']);
return $app['twig']->render('index.twig', array(
'repositories' => $repositories,
));
})->bind('homepage');
$route->get(MODULE_NAME.'/refresh', function (Request $request) use ($app) {
// Go back to calling page
return $app->redirect($request->headers->get('Referer'));
})->bind('refresh');
$route->get(MODULE_NAME.'/{repo}/stats/{branch}', function ($repo, $branch) use ($app) {
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
if ($branch === null) {
$branch = $repository->getHead();
}
$stats = $repository->getBranchStatistics($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)
->convert('branch', 'escaper.argument:escape')
->bind('stats');
$route->get(MODULE_NAME.'/{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)
->convert('branch', 'escaper.argument:escape')
->bind('rss');
return $route;
}
}

View file

@ -0,0 +1,129 @@
<?php
namespace GitList\Controller;
use GitList\Git\Repository;
use Gitter\Model\Commit\Commit;
use Silex\ControllerProviderInterface;
use Silex\Application;
class NetworkController implements ControllerProviderInterface
{
public function connect(Application $app)
{
$route = $app['controllers_factory'];
$route->get(
MODULE_NAME.'/{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(),
'image' => $app->getAvatar($commit->getAuthor()->getEmail(), 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)
->convert('commitishPath', 'escaper.argument:escape')
->assert('page', '\d+')
->value('page', '0')
->bind('networkData');
$route->get(
MODULE_NAME.'/{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)
->convert('commitishPath', 'escaper.argument:escape')
->bind('network');
return $route;
}
}

View file

@ -0,0 +1,128 @@
<?php
namespace GitList\Controller;
use Silex\ControllerProviderInterface;
use Silex\Application;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Request;
class TreeController implements ControllerProviderInterface
{
public function connect(Application $app)
{
$route = $app['controllers_factory'];
$route->get(MODULE_NAME.'/{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, $tree ? "$tree" : ''),
));
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('commitishPath', $app['util.routing']->getCommitishPathRegex())
->convert('commitishPath', 'escaper.argument:escape')
->bind('tree');
$route->post(MODULE_NAME.'/{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(),
'query' => $query,
));
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', $app['util.routing']->getBranchRegex())
->convert('branch', 'escaper.argument:escape')
->bind('search');
$route->get(MODULE_NAME.'/{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);
}
/**
* Generating name for downloading, lowercasing and removing all non
* ascii and special characters.
*/
$filename = strtolower($repo . '_' . $branch);
$filename = preg_replace('#[^a-z0-9]+#', '_', $filename);
$filename = $filename . '.' . $format;
$response = new BinaryFileResponse($file);
$response->setContentDisposition('attachment', $filename);
return $response;
})->assert('format', '(zip|tar)')
->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', $app['util.routing']->getBranchRegex())
->convert('branch', 'escaper.argument:escape')
->bind('archive');
$route->get(MODULE_NAME.'/{repo}/{branch}/', function ($repo, $branch) use ($app, $treeController) {
return $treeController($repo, $branch);
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', $app['util.routing']->getBranchRegex())
->convert('branch', 'escaper.argument:escape')
->bind('branch');
$route->get(MODULE_NAME.'/{repo}/', function ($repo) use ($app, $treeController) {
return $treeController($repo);
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->bind('repository');
return $route;
}
}

View file

@ -0,0 +1,72 @@
<?php
namespace GitList\Controller;
use Silex\ControllerProviderInterface;
use Silex\Application;
class TreeGraphController implements ControllerProviderInterface
{
public function connect(Application $app)
{
$route = $app['controllers_factory'];
$route->get(
MODULE_NAME.'/{repo}/treegraph/{commitishPath}',
function ($repo, $commitishPath) use ($app) {
/** @var \GitList\Git\Repository $repository */
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
$command = 'log --graph --date-order --all -C -M -n 100 --date=iso ' .
'--pretty=format:"B[%d] C[%H] D[%ad] A[%an] E[%ae] H[%h] S[%s]"';
$rawRows = $repository->getClient()->run($repository, $command);
$rawRows = explode("\n", $rawRows);
$graphItems = array();
foreach ($rawRows as $row) {
if (preg_match("/^(.+?)(\s(B\[(.*?)\])? C\[(.+?)\] D\[(.+?)\] A\[(.+?)\] E\[(.+?)\] H\[(.+?)\] S\[(.+?)\])?$/", $row, $output)) {
if (!isset($output[4])) {
$graphItems[] = array(
'relation' => $output[1],
);
continue;
}
$graphItems[] = array(
'relation' => $output[1],
'branch' => $output[4],
'rev' => $output[5],
'date' => $output[6],
'author' => $output[7],
'author_email' => $output[8],
'short_rev' => $output[9],
'subject' => preg_replace('/(^|\s)(#[[:xdigit:]]+)(\s|$)/', '$1<a href="$2">$2</a>$3', $output[10]),
);
}
}
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(
'treegraph.twig',
array(
'repo' => $repo,
'branch' => $branch,
'commitishPath' => $commitishPath,
'graphItems' => $graphItems,
)
);
}
)->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('commitishPath', $app['util.routing']->getCommitishPathRegex())
->value('commitishPath', null)
->convert('commitishPath', 'escaper.argument:escape')
->bind('treegraph');
return $route;
}
}

View file

@ -0,0 +1,15 @@
<?php
namespace GitList\Escaper;
class ArgumentEscaper
{
public function escape($argument)
{
if ($argument === null) {
return null;
}
return escapeshellcmd($argument);
}
}

View file

@ -0,0 +1,7 @@
<?php
namespace GitList\Exception;
class BlankDataException extends \RuntimeException
{
}

View file

@ -0,0 +1,7 @@
<?php
namespace GitList\Exception;
class EmptyRepositoryException extends \RuntimeException
{
}

View file

@ -0,0 +1,232 @@
<?php
namespace GitList\Git;
use Gitter\Client as BaseClient;
class Client extends BaseClient
{
protected $defaultBranch;
protected $hidden;
protected $projects;
public function __construct($options = null)
{
parent::__construct($options['path']);
$this->setDefaultBranch($options['default_branch']);
$this->setHidden($options['hidden']);
$this->setProjects($options['projects']);
}
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 sorted
* by repository name
*/
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);
}
/**
* Use "+" to preserve keys, only a problem with numeric repos.
*/
$allRepositories = $allRepositories + $repositories;
}
$allRepositories = array_unique($allRepositories, SORT_REGULAR);
uksort($allRepositories, function ($k1, $k2) {
return strtolower($k2) < strtolower($k1);
});
return $allRepositories;
}
/**
* Return name of default branch as a string.
*/
public function getDefaultBranch()
{
return $this->defaultBranch;
}
/**
* 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);
}
/**
* Set default branch as a string.
*
* @param string $branch name of branch to use when repo's HEAD is detached
*
* @return object
*/
protected function setDefaultBranch($branch)
{
$this->defaultBranch = $branch;
return $this;
}
/**
* 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
*
* @return object
*/
protected function setHidden($hidden)
{
$this->hidden = $hidden;
return $this;
}
/**
* Get project list.
*
* @return array List of repositories to show
*/
protected function getProjects()
{
return $this->projects;
}
/**
* Set the shown repository list.
*
* @param array $projects List of repositories to show
*/
protected function setProjects($projects)
{
$this->projects = $projects;
return $this;
}
private function recurseDirectory($path, $appendPath = '')
{
$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) {
$hidden = function ($path, $hide) {
$return = false;
array_walk($hide, function ($value, $key) use ($path, &$return) {
if (($path === $value) || (1 === preg_match($value, $path))) {
$return = true;
}
});
return $return;
};
if ($hidden($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;
}
$repoName = $appendPath . $file->getFilename();
if (is_array($this->getProjects()) && !in_array($repoName, $this->getProjects())) {
continue;
}
$repositories[$repoName] = array(
'name' => $repoName,
'path' => $file->getPathname(),
'description' => $description,
);
continue;
}
$repositories = array_merge($repositories, $this->recurseDirectory($file->getPathname(), $appendPath . $file->getFilename() . '/'));
}
}
return $repositories;
}
}

View file

@ -0,0 +1,457 @@
<?php
namespace GitList\Git;
use Gitter\Model\Commit\Commit;
use Gitter\Model\Commit\Diff;
use Gitter\PrettyFormat;
use Gitter\Repository as BaseRepository;
use Symfony\Component\Filesystem\Filesystem;
class Repository extends BaseRepository
{
/**
* Return true if the repo contains this commit.
*
* @param string $commitHash Hash of commit whose existence we want to check
*
* @return bool Whether or not the commit exists in this repo
*/
public function hasCommit($commitHash)
{
$logs = $this->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 Patches that where apllied to the selected file.
*
* @param string $file File path for which we will retrieve a list of patch logs
*
* @return array Collection of Commits data
*/
public function getCommitsLogPatch($file)
{
$record_delimiter = chr(hexdec('0x1e'));
$file_patches = $this->getClient()->run(
$this,
'log -p --pretty=format:"' . $record_delimiter . '<item><hash>%H</hash>'
. '<short_hash>%h</short_hash><tree>%T</tree><parents>%P</parents>'
. '<author>%aN</author><author_email>%aE</author_email>'
. '<date>%at</date><commiter>%cN</commiter><commiter_email>%cE</commiter_email>'
. '<commiter_date>%ct</commiter_date>'
. '<message><![CDATA[%s]]></message>'
. '<body><![CDATA[%b]]></body>'
. "</item>\" -- $file"
);
$patch_collection = array();
foreach (preg_split('/(' . $record_delimiter . '\<item\>)/', $file_patches, null, PREG_SPLIT_NO_EMPTY) as $patches) {
$patches = '<item>' . $patches;
$xmlEnd = strpos($patches, '</item>') + 7;
$commitInfo = substr($patches, 0, $xmlEnd);
$commitData = substr($patches, $xmlEnd);
$logs = explode("\n", $commitData);
// Read commit metadata
$format = new PrettyFormat();
$data = $format->parse($commitInfo);
$commit = new Commit();
$commit->importData($data[0]);
$commit->setDiffs($this->readDiffLogs($logs));
$patch_collection[] = $commit;
}
return $patch_collection;
}
/**
* 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:"<item><hash>%H</hash>'
. '<short_hash>%h</short_hash><tree>%T</tree><parents>%P</parents>'
. '<author>%aN</author><author_email>%aE</author_email>'
. '<date>%at</date><commiter>%cN</commiter><commiter_email>%cE</commiter_email>'
. '<commiter_date>%ct</commiter_date>'
. '<message><![CDATA[%s]]></message>'
. '<body><![CDATA[%b]]></body>'
. "</item>\" $commitHash"
);
$xmlEnd = strpos($logs, '</item>') + 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'] .= $match[3][0] . PHP_EOL;
$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]+)(?:,[0-9]+)? \+([0-9]+)/', $log, $matches);
$lineNumOld = $matches[1] - 1;
$lineNumNew = $matches[2] - 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.
*
* @param string $file
* @param int $page
*
* @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:\"<item><hash>%H</hash>"
. '<short_hash>%h</short_hash><tree>%T</tree><parents>%P</parents>'
. '<author>%aN</author><author_email>%aE</author_email>'
. '<date>%at</date><commiter>%cN</commiter>'
. '<commiter_email>%cE</commiter_email>'
. '<commiter_date>%ct</commiter_date>'
. '<message><![CDATA[%s]]></message></item>"';
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, $branch)
{
$query = escapeshellarg($query);
$query = strtr($query, array('[' => '\\[', ']' => '\\]'));
$command =
"log --grep={$query} -i --pretty=format:\"<item><hash>%H</hash>"
. '<short_hash>%h</short_hash><tree>%T</tree><parents>%P</parents>'
. '<author>%aN</author><author_email>%aE</author_email>'
. '<date>%at</date><commiter>%cN</commiter>'
. '<commiter_email>%cE</commiter_email>'
. '<commiter_date>%ct</commiter_date>'
. '<message><![CDATA[%s]]></message></item>"'
. " $branch";
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)
{
if (empty($query)) {
return null;
}
$query = preg_replace('/(--?[A-Za-z0-9\-]+)/', '', $query);
$query = escapeshellarg($query);
try {
$results = $this->getClient()->run($this, "grep -i --line-number -- {$query} $branch");
} catch (\RuntimeException $e) {
return false;
}
$results = explode("\n", $results);
$searchResults = array();
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 getBranchStatistics($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];
}
}
$logs = $this->getClient()->run($this, 'ls-tree -l -r --name-only ' . $branch);
$files = explode("\n", $logs);
foreach ($files as $file) {
if (($pos = strrpos($file, '.')) !== false) {
$extension = substr($file, $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
*
* @return bool
*
* 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;
}
}

View file

@ -0,0 +1,27 @@
<?php
namespace GitList\Provider;
use GitList\Git\Client;
use Silex\Application;
use Silex\ServiceProviderInterface;
class GitServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['git'] = function () use ($app) {
$options['path'] = $app['git.client'];
$options['hidden'] = $app['git.hidden'];
$options['projects'] = $app['git.projects'];
$options['ini.file'] = $app['ini.file'];
$options['default_branch'] = $app['git.default_branch'];
return new Client($options);
};
}
public function boot(Application $app)
{
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace GitList\Provider;
use GitList\Util\Repository;
use Silex\Application;
use Silex\ServiceProviderInterface;
class RepositoryUtilServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['util.repository'] = function () use ($app) {
return new Repository($app);
};
}
public function boot(Application $app)
{
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace GitList\Provider;
use GitList\Util\Routing;
use Silex\Application;
use Silex\ServiceProviderInterface;
class RoutingUtilServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['util.routing'] = function () use ($app) {
return new Routing($app);
};
}
public function boot(Application $app)
{
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace GitList\Provider;
use GitList\Util\View;
use Silex\Application;
use Silex\ServiceProviderInterface;
class ViewUtilServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['util.view'] = function () {
return new View();
};
}
public function boot(Application $app)
{
}
}

View file

@ -0,0 +1,235 @@
<?php
namespace GitList\Util;
use Silex\Application;
class Repository
{
protected $app;
protected $defaultFileTypes = array(
'php' => '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' => 'application/x-jsp',
'asp' => 'htmlembedded',
'aspx' => 'htmlembedded',
'html' => 'htmlmixed',
'tpl' => 'htmlmixed',
'js' => 'javascript',
'json' => 'javascript',
'less' => 'less',
'lua' => 'lua',
'md' => 'markdown',
'markdown' => 'markdown',
'sql' => 'mysql',
'ml' => 'ocaml',
'mli' => 'ocaml',
'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',
'vb' => '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 (!empty($this->app['filetypes'])) {
if (isset($this->app['filetypes'][$fileType])) {
return $this->app['filetypes'][$fileType];
}
}
if (isset($this->defaultFileTypes[$fileType])) {
return $this->defaultFileTypes[$fileType];
}
return 'text';
}
/**
* Returns whether the file is binary.
*
* @param string $file
*
* @return bool
*/
public function isBinary($file)
{
if (($pos = strrpos($file, '.')) !== false) {
$fileType = substr($file, $pos + 1);
} else {
return false;
}
if (!empty($this->app['binary_filetypes']) && array_key_exists($fileType, $this->app['binary_filetypes'])) {
return $this->app['binary_filetypes'][$fileType];
}
if (in_array($fileType, self::$binaryTypes)) {
return true;
}
return false;
}
public function getReadme($repository, $branch = null, $path = '')
{
if ($branch === null) {
$branch = $repository->getHead();
}
if ($path != '') {
$path = "$path/";
}
$files = $repository->getTree($path != '' ? "$branch:\"$path\"" : $branch)->output();
foreach ($files as $file) {
if (preg_match('/^readme*/i', $file['name'])) {
return array(
'filename' => $file['name'],
'content' => $repository->getBlob("$branch:\"$path{$file['name']}\"")->output(),
);
}
}
// No contextual readme, try to catch the main one if we are in deeper context
if ($path != '') {
return $this->getReadme($repository, $branch, '');
}
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);
}
}

View file

@ -0,0 +1,164 @@
<?php
namespace GitList\Util;
use GitList\Exception\EmptyRepositoryException;
use Silex\Application;
class Routing
{
protected $app;
public function __construct(Application $app)
{
$this->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.
*
* @param string $commitishPath
* @param string $repo
* @return array
*/
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 (preg_match('/[^a-zA-Z0-9]/i', $hash) === 0) {
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) {
$commitish = $matchedBranch;
} else {
// We may have partial commit hash as our commitish.
$hash = $slashPosition === false ? $commitishPath : substr($commitishPath, 0, $slashPosition);
if ($repository->hasCommit($hash)) {
$commit = $repository->getCommit($hash);
$commitish = $commit->getHash();
} else {
throw new EmptyRepositoryException('This repository is currently empty. There are no commits.');
}
}
}
$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 ~^:?*\[]+(?<!\.lock|[/.])';
}
return $branchRegex;
}
public function getCommitishPathRegex()
{
static $commitishPathRegex = null;
if ($commitishPathRegex === null) {
$commitishPathRegex = '.+';
}
return $commitishPathRegex;
}
public function getRepositoryRegex()
{
static $regex = null;
if ($regex === null) {
$quotedPaths = array_map(
function ($repo) {
return preg_quote($repo['name'], '#');
},
$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, '\\', '/'), '/');
}
throw new \InvalidArgumentException(
sprintf("Path '%s' does not match configured repository directory", $repoPath)
);
}
}

View file

@ -0,0 +1,49 @@
<?php
namespace GitList\Util;
class View
{
/**
* Builds a breadcrumb array based on a path spec.
*
* @param string $spec Path spec
*
* @return array Array with parts of the breadcrumb
*/
public function getBreadcrumbs($spec)
{
if (!$spec) {
return array();
}
$paths = explode('/', $spec);
foreach ($paths as $i => $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 = (int) ($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,
);
}
}

View file

@ -0,0 +1,25 @@
{% extends 'layout_page.twig' %}
{% set page = 'commits' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: [{dir: 'Blame', path:''}]} %}
<div class="source-view">
<div class="source-header">
<div class="meta">{{ file }}</div>
</div>
<table class="blame-view">
{% for blame in blames %}
<tr>
<td class="commit"><a href="{{ path('commit', {repo: repo, commit: blame.commit}) }}">{{ blame.commitShort }}</a></td>
<td><pre>{{ blame.line }}</pre></td>
</tr>
{% endfor %}
</table>
</div>
<hr />
{% endblock %}

View file

@ -0,0 +1,21 @@
<div class="btn-group pull-left space-right" id="branchList">
<button class="btn dropdown-toggle" data-toggle="dropdown">browsing: <strong>{{ branch }}</strong> <span class="caret"></span></button>
<div class="dropdown-menu">
<div class="search">
<input class="search" placeholder="Filter branch/tags" autofocus>
</div>
<ul class="unstyled list">
<li class="dropdown-header">Branches</li>
{% for item in branches %}
<li><a href="{{ path('branch', {repo: repo, branch: item}) }}"><span class="item">{{ item }}</span></a></li>
{% endfor %}
{% if tags %}
<li class="dropdown-header">Tags</li>
{% for item in tags %}
<li><a href="{{ path('branch', {repo: repo, branch: item}) }}"><span class="item">{{ item }}</span></a></li>
{% endfor %}
{% endif %}
</ul>
</div>
</div>

View file

@ -0,0 +1,9 @@
<ul class="breadcrumb">
<li><a href="{{ path('tree', {repo: repo, commitishPath: branch}) }}">{{ repo }}</a></li>
{% for breadcrumb in breadcrumbs %}
<span class="divider">/</span>
<li{% if loop.last %} class="active"{% endif %}>{% if not loop.last %}<a href="{{ path('tree', {repo: repo, commitishPath: branch ~ '/' ~ breadcrumb.path}) }}">{{ breadcrumb.dir }}</a>{% endif %}{% if loop.last %}{{ breadcrumb.dir }}{% endif %}</li>
{% endfor %}
{% block extra %}{% endblock %}
</ul>

View file

@ -0,0 +1,82 @@
{% extends 'layout_page.twig' %}
{% set page = 'commits' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: [{dir: "Commit #{commit.hash}", path:''}]} %}
<div class="commit-view">
<div class="commit-header">
<span class="pull-right"><a class="btn btn-small" href="{{ path('branch', {repo: repo, branch: commit.hash}) }}" title="Browse code at this point in history"><i class="icon-list-alt"></i> Browse code</a></span>
<h4>{{ commit.message }}</h4>
</div>
<div class="commit-body">
{% if commit.body is not empty %}
<p>{{ commit.body | nl2br }}</p>
{% endif %}
<img src="{{ avatar(commit.author.email, 32) }}" class="pull-left space-right" />
<span>
<a href="mailto:{{ commit.author.email }}">{{ commit.author.name }}</a> authored on {{ commit.date | format_date }}
{% if commit.author.email != commit.commiter.email %}
&bull; <a href="mailto:{{ commit.commiter.email }}">{{ commit.commiter.name }}</a> committed on {{ commit.commiterDate | format_date }}
{% endif %}
<br />Showing {{ commit.changedFiles }} changed files
</span>
</div>
</div>
<ul class="commit-list">
{% for diff in commit.diffs %}
<li><i class="icon-file"></i> <a href="#diff-{{ loop.index }}">{{ diff.file }}</a> <span class="meta pull-right">{{ diff.index }}</span></li>
{% endfor %}
</ul>
{% for diff in commit.diffs %}
<div class="source-view">
<div class="source-header">
<div class="meta"><a id="diff-{{ loop.index }}">{{ diff.file }}</div>
<div class="btn-group pull-right">
<a href="{{ path('commits', {repo: repo, commitishPath: commit.hash ~ '/' ~ diff.file}) }}" class="btn btn-small"><i class="icon-list-alt"></i> History</a>
<a href="{{ path('blob', {repo: repo, commitishPath: commit.hash ~'/' ~ diff.file}) }}" class="btn btn-small"><i class="icon-file"></i> View file @ {{ commit.shortHash }}</a>
</div>
</div>
<div class="source-diff">
<table>
{% for line in diff.getLines %}
<tr>
<td class="lineNo">
{% if line.getType != 'chunk' %}
<a name="L{{ loop.index }}R{{ line.getNumOld }}"></a>
<a href="#L{{ loop.index }}R{{ line.getNumOld }}">
{% endif %}
{{ line.getNumOld }}
{% if line.getType != 'chunk' %}
</a>
{% endif %}
</td>
<td class="lineNo">
{% if line.getType != 'chunk' %}
<a name="L{{ loop.index }}L{{ line.getNumNew }}"></a>
<a href="#L{{ loop.index }}L{{ line.getNumNew }}">
{% endif %}
{{ line.getNumNew }}
{% if line.getType != 'chunk' %}
</a>
{% endif %}
</td>
<td style="width: 100%">
<pre{% if line.getType %} class="{{ line.getType }}"{% endif %}>{{ line.getLine }}</pre>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endfor %}
<hr />
{% endblock %}

View file

@ -0,0 +1,13 @@
{% extends 'layout_page.twig' %}
{% set page = 'commits' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: [{dir: 'Commit history', path:''}]} %}
{% include 'commits_list.twig' %}
<hr />
{% endblock %}

View file

@ -0,0 +1,45 @@
{% if commits %}
{% for date, commit in commits %}
<table class="table table-striped table-bordered">
<thead>
<tr>
<th colspan="3">{{ date | date("F j, Y") }}</th>
</tr>
</thead>
<tbody>
{% for item in commit %}
<tr>
<td width="5%"><img src="{{ avatar( item.author.email, 40 ) }}" /></td>
<td width="95%">
<span class="pull-right"><a class="btn btn-small" href="{{ path('commit', {repo: repo, commit: item.hash}) }}"><i class="icon-list-alt"></i> View {{ item.shortHash }}</a></span>
<h4>{{ item.message }}</h4>
<span>
<a href="mailto:{{ item.author.email }}">{{ item.author.name }}</a> authored on {{ item.date | format_date }}
{% if item.author.email != item.commiter.email %}
&bull; <a href="mailto:{{ item.commiter.email }}">{{ item.commiter.name }}</a> committed on {{ item.commiterDate | format_date }}
{% endif %}
</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endfor %}
{% else %}
<p>No results found.</p>
{% endif %}
{% if page != 'searchcommits' %}
<ul class="pager">
{% if pager.current != 0 %}
<li class="previous">
<a href="?page={{ pager.previous }}">&larr; Newer</a>
</li>
{% endif %}
{% if pager.current != pager.last %}
<li class="next">
<a href="?page={{ pager.next }}">Older &rarr;</a>
</li>
{% endif %}
</ul>
{% endif %}

View file

@ -0,0 +1,17 @@
{% extends 'layout.twig' %}
{% block title %}GitList{% endblock %}
{% block body %}
{% include 'navigation.twig' %}
<div class="container">
<div class="alert alert-error">
<strong>Oops!</strong> {{ message }}
</div>
<hr />
{% include 'footer.twig' %}
</div>
{% endblock %}

View file

@ -0,0 +1,33 @@
{% extends 'layout_page.twig' %}
{% set page = 'files' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: breadcrumbs} %}
<div class="source-view">
<div class="source-header">
<div class="meta"></div>
<div class="btn-group pull-right">
<a href="{{ path('blob_raw', {repo: repo, commitishPath: branch ~ '/' ~ file}) }}" class="btn btn-small"><i class="icon-file"></i> Raw</a>
<a href="{{ path('blame', {repo: repo, commitishPath: branch ~ '/' ~ file}) }}" class="btn btn-small"><i class="icon-bullhorn"></i> Blame</a>
<a href="{{ path('logpatch', {repo: repo, commitishPath: branch ~ '/' ~ file}) }}" class="btn btn-small"><i class="icon-calendar"></i> Patch Log</a>
<a href="{{ path('commits', {repo: repo, commitishPath: branch ~ '/' ~ file}) }}" class="btn btn-small"><i class="icon-list-alt"></i> History</a>
</div>
</div>
{% if fileType == 'image' %}
<center><img src="{{ path('blob_raw', {repo: repo, commitishPath: branch ~ '/' ~ file}) }}" alt="{{ file }}" class="image-blob" /></center>
{% elseif fileType == 'markdown' %}
<div class="md-view"><div id="md-content">{{ blob }}</div></div>
{% else %}
<pre id="sourcecode" language="{{ fileType }}">{{ blob|htmlentities|raw }}</pre>
{% endif %}
</div>
<hr />
{% endblock %}

View file

@ -0,0 +1,3 @@
<footer>
<p>Powered by <a href="https://github.com/klaussilveira/gitlist">GitList 1.0.2</a></p>
</footer>

View file

@ -0,0 +1,34 @@
{% extends 'layout.twig' %}
{% block title %}GitList{% endblock %}
{% block body %}
{% include 'navigation.twig' %}
<div class="container" id="repositories">
<div class="search">
<input class="search" placeholder="search" autofocus>
</div>
<div class="list">
{% for repository in repositories %}
<div class="repository">
<div class="repository-header">
<i class="icon-folder-open icon-spaced"></i> <a href="{{ path('repository', {repo: repository.name}) }}"><span class="name">{{ repository.name }}</span></a>
<a href="{{ path('rss', {repo: repository.name, branch: 'master'}) }}"><i class="rss pull-right"></i></a>
</div>
<div class="repository-body">
{% if repository.description %}
<p>{{ repository.description }}</p>
{% else %}
<p>There is no repository description file. Please, create one to remove this message.</p>
{% endif %}
</div>
</div>
{% endfor %}
</div>
<hr />
{% include 'footer.twig' %}
</div>
{% endblock %}

View file

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>{{ title }}{% if title %} - {% endif %}{% block title %}Welcome!{% endblock %}</title>
<link rel="stylesheet" type="text/css" href="{{ app.request.basepath }}/themes/{{ theme }}/css/style.css">
<link rel="stylesheet" type="text/css" href="{{ app.request.basepath }}/themes/{{ theme }}/css/gitgraph.css">
<link rel="shortcut icon" type="image/png" href="{{ app.request.basepath }}/themes/{{ theme }}/img/favicon.png" />
<!--[if lt IE 9]>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/html5.js"></script>
<![endif]-->
</head>
<body>
{% block body %}{% endblock %}
{% block javascripts %}
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/jquery.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/raphael.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/bootstrap.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/codemirror.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/showdown.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/table.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/list.min.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/main.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/networkGraph.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/gitgraph.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/draw.js"></script>
{% endblock %}
</body>
</html>

View file

@ -0,0 +1,31 @@
{% extends 'layout.twig' %}
{% block body %}
{% include 'navigation.twig' %}
<div class="container">
<div class="row">
<div class="span12">
{% if page in ['commits', 'searchcommits'] %}
<form class="form-search pull-right" action="{{ app.request.basepath }}/{{repo}}/commits/{{branch}}/search" method="POST">
<input type="text" name="query" class="input-medium search-query" placeholder="Search commits..." value="{{ query | default("") }}">
</form>
{% else %}
<form class="form-search pull-right" action="{{ app.request.basepath }}/{{repo}}/tree/{{branch}}/search" method="POST">
<input type="text" name="query" class="input-medium search-query" placeholder="Search tree..." value="{{ query | default("") }}">
</form>
{% endif %}
{% if branches is defined %}
{% include 'branch_menu.twig' %}
{% endif %}
{% include 'menu.twig' %}
</div>
</div>
{% block content %}{% endblock %}
{% include 'footer.twig' %}
</div>
{% endblock %}

View file

@ -0,0 +1,83 @@
{% extends 'layout_page.twig' %}
{% set page = 'commits' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: breadcrumbs} %}
{% for commit in commits %}
<div class="commit-view">
<div class="commit-header">
<span class="pull-right"><a class="btn btn-small" href="{{ path('branch', {repo: repo, branch: commit.hash}) }}" title="Browse code at this point in history"><i class="icon-list-alt"></i> Browse code</a></span>
<h4>{{ commit.message }}</h4>
</div>
<div class="commit-body">
{% if commit.body is not empty %}
<p>{{ commit.body | nl2br }}</p>
{% endif %}
<img src="{{ avatar(commit.author.email, 32) }}" class="pull-left space-right" />
<span>
<a href="mailto:{{ commit.author.email }}">{{ commit.author.name }}</a> authored on {{ commit.date | format_date }}
{% if commit.author.email != commit.commiter.email %}
&bull; <a href="mailto:{{ commit.commiter.email }}">{{ commit.commiter.name }}</a> committed on {{ commit.commiterDate | format_date }}
{% endif %}
<br />Showing {{ commit.changedFiles }} changed files
</span>
</div>
</div>
{% for diff in commit.diffs %}
<div class="source-view">
<div class="source-header">
<div class="meta"><a id="diff-{{ loop.index }}">{{ diff.file }}</div>
<div class="btn-group pull-right">
<a href="{{ path('commits', {repo: repo, commitishPath: commit.hash ~ '/' ~ diff.file}) }}" class="btn btn-small"><i class="icon-list-alt"></i> History</a>
<a href="{{ path('blob', {repo: repo, commitishPath: commit.hash ~'/' ~ diff.file}) }}" class="btn btn-small"><i class="icon-file"></i> View file @ {{ commit.shortHash }}</a>
</div>
</div>
<div class="source-diff">
<table>
{% for line in diff.getLines %}
<tr>
<td class="lineNo">
{% if line.getType != 'chunk' %}
<a name="L{{ loop.index }}R{{ line.getNumOld }}"></a>
<a href="#L{{ loop.index }}R{{ line.getNumOld }}">
{% endif %}
{{ line.getNumOld }}
{% if line.getType != 'chunk' %}
</a>
{% endif %}
</td>
<td class="lineNo">
{% if line.getType != 'chunk' %}
<a name="L{{ loop.index }}L{{ line.getNumNew }}"></a>
<a href="#L{{ loop.index }}L{{ line.getNumNew }}">
{% endif %}
{{ line.getNumNew }}
{% if line.getType != 'chunk' %}
</a>
{% endif %}
</td>
<td style="width: 100%">
<pre{% if line.getType %} class="{{ line.getType }}"{% endif %}>{{ line.getLine }}</pre>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endfor %}
{% endfor %}
<hr />
{% endblock %}

View file

@ -0,0 +1,7 @@
<ul class="nav nav-tabs">
<li{% if page == 'files' %} class="active"{% endif %}><a href="{{ path('branch', {repo: repo, branch: branch}) }}">Files</a></li>
<li{% if page in ['commits', 'searchcommits'] %} class="active"{% endif %}><a href="{{ path('commits', {repo: repo, commitishPath: branch}) }}">Commits</a></li>
<li{% if page == 'stats' %} class="active"{% endif %}><a href="{{ path('stats', {repo: repo, branch: branch}) }}">Stats</a></li>
<li{% if page == 'network' %} class="active"{% endif %}><a href="{{ path('network', {repo: repo, commitishPath: branch}) }}">Network</a></li>
<li{% if page == 'treegraph' %} class="active"{% endif %}><a href="{{ path('treegraph', {repo: repo, branch: branch}) }}">Graph</a></li>
</ul>

View file

@ -0,0 +1,20 @@
<div class="navbar navbar-scroll-top">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="{{ path('homepage') }}">{{ title }}</a>
<div class="nav-collapse">
<ul class="nav pull-right">
<li><a href="http://gitlist.org/">About</a></li>
<li><a href="{{ path('homepage') }}refresh">Refresh</a></li>
<li><a href="https://github.com/klaussilveira/gitlist/issues/new">Report bug</a></li>
<li><a href="https://github.com/klaussilveira/gitlist/wiki">Help</a></li>
</ul>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,23 @@
{% extends 'layout_page.twig' %}
{% set page = 'network' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: [{dir: 'Network', path:''}]} %}
<div class="network-view">
<div class="network-header">
<div class="meta">Network Graph of {{ repo }} / {{ commitishPath }}</div>
</div>
<div class="network-graph" data-source="{{ path('networkData', {repo: repo, commitishPath: commitishPath}) }}">
{#<div class="network-graph" data-source="/dummynetwork.json">#}
</div>
</div>
<hr />
{% endblock %}

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>Latest commits in {{ repo }}:{{ branch }}</title>
<description>RSS provided by GitList</description>
<link>{{ url('homepage') }}</link>
{% for commit in commits %}
<item>
<title>{{ commit.message }}</title>
<description>{{ commit.author.name }} authored {{ commit.shortHash }} in {{ commit.date | format_date }}</description>
<link>{{ url('commit', {repo: repo, commit: commit.hash}) }}</link>
<pubDate>{{ commit.date | date('r') }}</pubDate>
<author>{{ commit.author.email }} ({{ commit.author.name }})</author>
</item>
{% endfor %}
</channel>
</rss>

View file

@ -0,0 +1,42 @@
{% extends 'layout_page.twig' %}
{% set page = 'files' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% embed 'breadcrumb.twig' with {breadcrumbs: breadcrumbs} %}
{% block extra %}
<div class="pull-right">
<div class="btn-group download-buttons">
<a href="{{ path('archive', {repo: repo, branch: branch, format: 'zip'}) }}" class="btn btn-mini" title="Download '{{ branch }}' as a ZIP archive">ZIP</a>
<a href="{{ path('archive', {repo: repo, branch: branch, format: 'tar'}) }}" class="btn btn-mini" title="Download '{{ branch }}' as a TAR archive">TAR</a>
</div>
<a href="{{ path('rss', {repo: repo, branch: branch}) }}" class="rss-icon"><i class="rss"></i></a>
</div>
{% endblock %}
{% endembed %}
{% if results %}
<table class="tree">
<thead>
<tr>
<th width="20%">name</th>
<th width="80%">match</th>
</tr>
</thead>
<tbody>
{% for result in results %}
<tr>
<td><i class="icon-file icon-spaced"></i> <a href="{{ path('blob', {repo: repo, branch: branch, file: result.file, commitishPath: branch ~ '/' ~ result.file}) }}#L{{ result.line }}">{{ result.file }}</a></td>
<td>{{ result.match }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>No results found.</p>
{% endif %}
<hr />
{% endblock %}

View file

@ -0,0 +1,13 @@
{% extends 'layout_page.twig' %}
{% set page = 'searchcommits' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: [{dir: 'Commits search results for: ' ~ query, path:''}]} %}
{% include 'commits_list.twig' %}
<hr />
{% endblock %}

View file

@ -0,0 +1,48 @@
{% extends 'layout_page.twig' %}
{% set page = 'stats' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: [{dir: 'Statistics', path:''}]} %}
<table class="table table-striped table-bordered">
<thead>
<tr>
<th width="30%">File extensions ({{ stats.extensions|length }})</th>
<th width="40%">Authors ({{ authors|length }})</th>
<th width="30%">Other</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<ul>
{% for ext, amount in stats.extensions %}
<li><strong>{{ ext }}</strong>: {{ amount }} files</li>
{% endfor %}
</ul>
</td>
<td>
<ul>
{% for author in authors %}
<li><strong><a href="mailto:{{ author.email }}">{{ author.name }}</a></strong>: {{ author.commits }} commits</li>
{% endfor %}
</ul>
</td>
<td>
<p>
<strong>Total files:</strong> {{ stats.files }}
</p>
<p>
<strong>Total bytes:</strong> {{ stats.size }} bytes ({{ stats.size | format_size }})
</p>
</td>
</tr>
</tbody>
</table>
<hr />
{% endblock %}

View file

@ -0,0 +1,95 @@
{% extends 'layout_page.twig' %}
{% set page = 'files' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% embed 'breadcrumb.twig' with {breadcrumbs: breadcrumbs} %}
{% block extra %}
<div class="pull-right">
<div class="btn-group download-buttons">
{% if show_http_remote or show_ssh_remote %}
<a href="#" class="btn btn-mini" title="Show remotes to clone this repository." id="clone-button-show">Clone</a>
{% endif %}
<a href="{{ path('archive', {repo: repo, branch: branch, format: 'zip'}) }}" class="btn btn-mini" title="Download '{{ branch }}' as a ZIP archive">ZIP</a>
<a href="{{ path('archive', {repo: repo, branch: branch, format: 'tar'}) }}" class="btn btn-mini" title="Download '{{ branch }}' as a TAR archive">TAR</a>
</div>
<a href="{{ path('rss', {repo: repo, branch: branch}) }}" class="rss-icon"><i class="rss"></i></a>
</div>
{% if show_http_remote or show_ssh_remote %}
<div id="clone-popup">
<div id="clone-popup-inner-wrapper">
<a class="close" href="#" id="clone-button-hide">&times;</a>
<div class="btn-group">
{% if show_ssh_remote %}
<button class="btn{{ show_ssh_remote and show_http_remote ? ' active' }}" id="clone-button-ssh">SSH</button>
{% endif %}
{% if show_http_remote %}
<button class="btn" id="clone-button-http">HTTP{{ use_https ? 'S' }}</button>
{% endif %}
</div><br />
{% if show_ssh_remote %}
<input type="text" class="form-control{{ show_ssh_remote ? ' visible' }}" id="clone-input-ssh" value="git clone {{ ssh_port ? 'ssh://' }}{{ ssh_user | url_encode }}{{ ssh_user ? '@' }}{{ ssh_host ? ssh_host : app.request.host }}:{{ ssh_port ? ssh_port ~ '/' : '' }}{{ ssh_url_subdir }}{{ repo }}">
{% endif %}
{% if show_http_remote %}
<input type="text" class="form-control{{ show_ssh_remote is empty and show_http_remote ? ' visible' }}" id="clone-input-http" value="git clone http{{ use_https ? 's' }}://{{ http_user | url_encode }}{{ http_user ? '@' }}{{ http_host ? http_host : app.request.host }}/{{ http_url_subdir }}{{ repo }}">
{% endif %}
</div>
</div>
{% endif %}
{% endblock %}
{% endembed %}
{% if files is not empty %}
<table class="tree">
<thead>
<tr>
<th width="80%">name</th>
<th width="10%">mode</th>
<th width="10%">size</th>
</tr>
</thead>
<tbody>
{% if parent is not null %}
<tr>
<td><i class="icon-spaced"></i>
{% if not parent %}
<a href="{{ path('branch', {repo: repo, branch: branch}) }}">..</a>
{% else %}
<a href="{{ path('tree', {repo: repo, commitishPath: branch ~ '/' ~ parent}) }}">..</a>
{% endif %}
</td>
<td></td>
<td></td>
</tr>
{% endif %}
{% for file in files %}
<tr>
<td><i class="{{ file.type == "folder" or file.type == "symlink" ? "icon-folder-open" : "icon-file" }} icon-spaced"></i> <a href="
{%- if file.type == "folder" or file.type == "symlink" -%}
{{ path('tree', {repo: repo, commitishPath: branch ~ '/' ~ path ~ (file.type == "symlink" ? file.path : file.name)}) }}
{%- else -%}
{{ path('blob', {repo: repo, commitishPath: branch ~ '/' ~ path ~ (file.type == "symlink" ? file.path : file.name)}) }}
{%- endif -%}
">{{ file.name }}</a></td>
<td>{{ file.mode }}</td>
<td>{% if file.size %}{{ file.size | format_size }}{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>This repository is empty.</p>
{% endif %}
{% if readme is defined and readme is not empty %}
<div class="readme-view">
<div class="md-header">
<div class="meta">{{ readme.filename }}</div>
</div>
<div id="md-content">{{ readme.content }}</div>
</div>
{% endif %}
<hr />
{% endblock %}

View file

@ -0,0 +1,48 @@
{% extends 'layout_page.twig' %}
{% set page = 'treegraph' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: [{dir: 'Graph', path:''}]} %}
<div class="network-view">
<div class="network-header">
<div class="meta">Graph of {{ repo }} </div>
</div>
<div id="git-graph-container">
<div id="rel-container">
<canvas id="graph-canvas" width="100px">
<ul id="graph-raw-list">
{% for item in graphItems %}
<li><span class="node-relation">{{ item.relation }}</span></li>
{% endfor %}
</ul>
</canvas>
</div>
<div style="float:left;" id="rev-container">
<ul id="rev-list">
{% for item in graphItems %}
<li>
{% if item.rev is defined %}
<a id="{{ item.short_rev }}" class="btn btn-small" href="{{ path('commit', {repo: repo, commit: item.rev}) }}"> {{ item.short_rev }} </a>
<strong> {{ item.branch }} </strong>
<em>{{ item.subject }}</em> by
<span class="author">{{ item.author }} &lt;{{ item.author_email }}&gt;</span>
<span class="time">{{ item.date }}</span>;
{% else %}
<span/>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
<div style="clear:both"><!-- --></div>
</div>
</div>
<hr/>
{% endblock %}

View file

@ -0,0 +1,25 @@
{% extends 'layout_page.twig' %}
{% set page = 'commits' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: [{dir: 'Blame', path:''}]} %}
<div class="source-view">
<div class="source-header">
<div class="meta">{{ file }}</div>
</div>
<table class="blame-view">
{% for blame in blames %}
<tr>
<td class="commit"><a href="{{ path('commit', {repo: repo, commit: blame.commit}) }}">{{ blame.commitShort }}</a></td>
<td><pre>{{ blame.line }}</pre></td>
</tr>
{% endfor %}
</table>
</div>
<hr />
{% endblock %}

View file

@ -0,0 +1,21 @@
<div class="btn-group pull-left space-right" id="branchList">
<button class="btn dropdown-toggle" data-toggle="dropdown">browsing: <strong>{{ branch }}</strong> <span class="caret"></span></button>
<div class="dropdown-menu">
<div class="search">
<input class="search" placeholder="Filter branch/tags" autofocus>
</div>
<ul class="unstyled list">
<li class="dropdown-header">Branches</li>
{% for item in branches %}
<li><a href="{{ path('branch', {repo: repo, branch: item}) }}"><span class="item">{{ item }}</span></a></li>
{% endfor %}
{% if tags %}
<li class="dropdown-header">Tags</li>
{% for item in tags %}
<li><a href="{{ path('branch', {repo: repo, branch: item}) }}"><span class="item">{{ item }}</span></a></li>
{% endfor %}
{% endif %}
</ul>
</div>
</div>

View file

@ -0,0 +1,9 @@
<ul class="breadcrumb">
<li><a href="{{ path('tree', {repo: repo, commitishPath: branch}) }}">{{ repo }}</a></li>
{% for breadcrumb in breadcrumbs %}
<span class="divider">/</span>
<li{% if loop.last %} class="active"{% endif %}>{% if not loop.last %}<a href="{{ path('tree', {repo: repo, commitishPath: branch ~ '/' ~ breadcrumb.path}) }}">{{ breadcrumb.dir }}</a>{% endif %}{% if loop.last %}{{ breadcrumb.dir }}{% endif %}</li>
{% endfor %}
{% block extra %}{% endblock %}
</ul>

View file

@ -0,0 +1,82 @@
{% extends 'layout_page.twig' %}
{% set page = 'commits' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: [{dir: "Commit #{commit.hash}", path:''}]} %}
<div class="commit-view">
<div class="commit-header">
<span class="pull-right"><a class="btn btn-small" href="{{ path('branch', {repo: repo, branch: commit.hash}) }}" title="Browse code at this point in history"><i class="icon-list-alt"></i> Browse code</a></span>
<h4>{{ commit.message }}</h4>
</div>
<div class="commit-body">
{% if commit.body is not empty %}
<p>{{ commit.body | nl2br }}</p>
{% endif %}
<img src="{{ avatar(commit.author.email, 32) }}" class="pull-left space-right" />
<span>
<a href="mailto:{{ commit.author.email }}">{{ commit.author.name }}</a> authored on {{ commit.date | format_date }}
{% if commit.author.email != commit.commiter.email %}
&bull; <a href="mailto:{{ commit.commiter.email }}">{{ commit.commiter.name }}</a> committed on {{ commit.commiterDate | format_date }}
{% endif %}
<br />Showing {{ commit.changedFiles }} changed files
</span>
</div>
</div>
<ul class="commit-list">
{% for diff in commit.diffs %}
<li><i class="icon-file"></i> <a href="#diff-{{ loop.index }}">{{ diff.file }}</a> <span class="meta pull-right">{{ diff.index }}</span></li>
{% endfor %}
</ul>
{% for diff in commit.diffs %}
<div class="source-view">
<div class="source-header">
<div class="meta"><a id="diff-{{ loop.index }}">{{ diff.file }}</div>
<div class="btn-group pull-right">
<a href="{{ path('commits', {repo: repo, commitishPath: commit.hash ~ '/' ~ diff.file}) }}" class="btn btn-small"><i class="icon-list-alt"></i> History</a>
<a href="{{ path('blob', {repo: repo, commitishPath: commit.hash ~'/' ~ diff.file}) }}" class="btn btn-small"><i class="icon-file"></i> View file @ {{ commit.shortHash }}</a>
</div>
</div>
<div class="source-diff">
<table>
{% for line in diff.getLines %}
<tr>
<td class="lineNo">
{% if line.getType != 'chunk' %}
<a name="L{{ loop.index }}R{{ line.getNumOld }}"></a>
<a href="#L{{ loop.index }}R{{ line.getNumOld }}">
{% endif %}
{{ line.getNumOld }}
{% if line.getType != 'chunk' %}
</a>
{% endif %}
</td>
<td class="lineNo">
{% if line.getType != 'chunk' %}
<a name="L{{ loop.index }}L{{ line.getNumNew }}"></a>
<a href="#L{{ loop.index }}L{{ line.getNumNew }}">
{% endif %}
{{ line.getNumNew }}
{% if line.getType != 'chunk' %}
</a>
{% endif %}
</td>
<td style="width: 100%">
<pre{% if line.getType %} class="{{ line.getType }}"{% endif %}>{{ line.getLine }}</pre>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endfor %}
<hr />
{% endblock %}

View file

@ -0,0 +1,13 @@
{% extends 'layout_page.twig' %}
{% set page = 'commits' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: [{dir: 'Commit history', path:''}]} %}
{% include 'commits_list.twig' %}
<hr />
{% endblock %}

View file

@ -0,0 +1,45 @@
{% if commits %}
{% for date, commit in commits %}
<table class="table table-striped table-bordered">
<thead>
<tr>
<th colspan="3">{{ date | date("F j, Y") }}</th>
</tr>
</thead>
<tbody>
{% for item in commit %}
<tr>
<td width="5%"><img src="{{ avatar( item.author.email, 40 ) }}" /></td>
<td width="95%">
<span class="pull-right"><a class="btn btn-small" href="{{ path('commit', {repo: repo, commit: item.hash}) }}"><i class="icon-list-alt"></i> View {{ item.shortHash }}</a></span>
<h4>{{ item.message }}</h4>
<span>
<a href="mailto:{{ item.author.email }}">{{ item.author.name }}</a> authored on {{ item.date | format_date }}
{% if item.author.email != item.commiter.email %}
&bull; <a href="mailto:{{ item.commiter.email }}">{{ item.commiter.name }}</a> committed on {{ item.commiterDate | format_date }}
{% endif %}
</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endfor %}
{% else %}
<p>No results found.</p>
{% endif %}
{% if page != 'searchcommits' %}
<ul class="pager">
{% if pager.current != 0 %}
<li class="previous">
<a href="?page={{ pager.previous }}">&larr; Newer</a>
</li>
{% endif %}
{% if pager.current != pager.last %}
<li class="next">
<a href="?page={{ pager.next }}">Older &rarr;</a>
</li>
{% endif %}
</ul>
{% endif %}

View file

@ -0,0 +1,17 @@
{% extends 'layout.twig' %}
{% block title %}GitList{% endblock %}
{% block body %}
{% include 'navigation.twig' %}
<div class="container">
<div class="alert alert-error">
<strong>Oops!</strong> {{ message }}
</div>
<hr />
{% include 'footer.twig' %}
</div>
{% endblock %}

View file

@ -0,0 +1,33 @@
{% extends 'layout_page.twig' %}
{% set page = 'files' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: breadcrumbs} %}
<div class="source-view">
<div class="source-header">
<div class="meta"></div>
<div class="btn-group pull-right">
<a href="{{ path('blob_raw', {repo: repo, commitishPath: branch ~ '/' ~ file}) }}" class="btn btn-small"><i class="icon-file"></i> Raw</a>
<a href="{{ path('blame', {repo: repo, commitishPath: branch ~ '/' ~ file}) }}" class="btn btn-small"><i class="icon-bullhorn"></i> Blame</a>
<a href="{{ path('logpatch', {repo: repo, commitishPath: branch ~ '/' ~ file}) }}" class="btn btn-small"><i class="icon-calendar"></i> Patch Log</a>
<a href="{{ path('commits', {repo: repo, commitishPath: branch ~ '/' ~ file}) }}" class="btn btn-small"><i class="icon-list-alt"></i> History</a>
</div>
</div>
{% if fileType == 'image' %}
<center><img src="{{ path('blob_raw', {repo: repo, commitishPath: branch ~ '/' ~ file}) }}" alt="{{ file }}" class="image-blob" /></center>
{% elseif fileType == 'markdown' %}
<div class="md-view"><div id="md-content">{{ blob }}</div></div>
{% else %}
<pre id="sourcecode" language="{{ fileType }}">{{ blob|htmlentities|raw }}</pre>
{% endif %}
</div>
<hr />
{% endblock %}

View file

@ -0,0 +1,3 @@
<footer>
<p>Powered by <a href="https://github.com/klaussilveira/gitlist">GitList 1.0.2</a></p>
</footer>

View file

@ -0,0 +1,34 @@
{% extends 'layout.twig' %}
{% block title %}GitList{% endblock %}
{% block body %}
{% include 'navigation.twig' %}
<div class="container" id="repositories">
<div class="search">
<input class="search" placeholder="search" autofocus>
</div>
<div class="list">
{% for repository in repositories %}
<div class="repository">
<div class="repository-header">
<i class="icon-folder-open icon-spaced"></i> <a href="{{ path('repository', {repo: repository.name}) }}"><span class="name">{{ repository.name }}</span></a>
<a href="{{ path('rss', {repo: repository.name, branch: 'master'}) }}"><i class="rss pull-right"></i></a>
</div>
<div class="repository-body">
{% if repository.description %}
<p>{{ repository.description }}</p>
{% else %}
<p>There is no repository description file. Please, create one to remove this message.</p>
{% endif %}
</div>
</div>
{% endfor %}
</div>
<hr />
{% include 'footer.twig' %}
</div>
{% endblock %}

View file

@ -0,0 +1,21 @@
<link rel="stylesheet" type="text/css" href="{{ app.request.basepath }}/themes/{{ theme }}/css/style.css">
<link rel="stylesheet" type="text/css" href="{{ app.request.basepath }}/themes/{{ theme }}/css/gitgraph.css">
<link rel="shortcut icon" type="image/png" href="{{ app.request.basepath }}/themes/{{ theme }}/img/favicon.png"
<!--[if lt IE 9]>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/html5.js"></script>
<![endif]-->
{% block body %}{% endblock %}
{% block javascripts %}
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/jquery.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/raphael.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/bootstrap.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/codemirror.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/showdown.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/table.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/list.min.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/main.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/networkGraph.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/gitgraph.js"></script>
<script type="application/javascript" src="{{ app.request.basepath }}/themes/{{ theme }}/js/draw.js"></script>
{% endblock %}

View file

@ -0,0 +1,31 @@
{% extends 'layout.twig' %}
{% block body %}
{% include 'navigation.twig' %}
<div class="container">
<div class="row">
<div class="span12">
{% if page in ['commits', 'searchcommits'] %}
<form class="form-search pull-right" action="{{ app.request.basepath }}/{{repo}}/commits/{{branch}}/search" method="POST">
<input type="text" name="query" class="input-medium search-query" placeholder="Search commits..." value="{{ query | default("") }}">
</form>
{% else %}
<form class="form-search pull-right" action="{{ app.request.basepath }}/{{repo}}/tree/{{branch}}/search" method="POST">
<input type="text" name="query" class="input-medium search-query" placeholder="Search tree..." value="{{ query | default("") }}">
</form>
{% endif %}
{% if branches is defined %}
{% include 'branch_menu.twig' %}
{% endif %}
{% include 'menu.twig' %}
</div>
</div>
{% block content %}{% endblock %}
{% include 'footer.twig' %}
</div>
{% endblock %}

View file

@ -0,0 +1,83 @@
{% extends 'layout_page.twig' %}
{% set page = 'commits' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: breadcrumbs} %}
{% for commit in commits %}
<div class="commit-view">
<div class="commit-header">
<span class="pull-right"><a class="btn btn-small" href="{{ path('branch', {repo: repo, branch: commit.hash}) }}" title="Browse code at this point in history"><i class="icon-list-alt"></i> Browse code</a></span>
<h4>{{ commit.message }}</h4>
</div>
<div class="commit-body">
{% if commit.body is not empty %}
<p>{{ commit.body | nl2br }}</p>
{% endif %}
<img src="{{ avatar(commit.author.email, 32) }}" class="pull-left space-right" />
<span>
<a href="mailto:{{ commit.author.email }}">{{ commit.author.name }}</a> authored on {{ commit.date | format_date }}
{% if commit.author.email != commit.commiter.email %}
&bull; <a href="mailto:{{ commit.commiter.email }}">{{ commit.commiter.name }}</a> committed on {{ commit.commiterDate | format_date }}
{% endif %}
<br />Showing {{ commit.changedFiles }} changed files
</span>
</div>
</div>
{% for diff in commit.diffs %}
<div class="source-view">
<div class="source-header">
<div class="meta"><a id="diff-{{ loop.index }}">{{ diff.file }}</div>
<div class="btn-group pull-right">
<a href="{{ path('commits', {repo: repo, commitishPath: commit.hash ~ '/' ~ diff.file}) }}" class="btn btn-small"><i class="icon-list-alt"></i> History</a>
<a href="{{ path('blob', {repo: repo, commitishPath: commit.hash ~'/' ~ diff.file}) }}" class="btn btn-small"><i class="icon-file"></i> View file @ {{ commit.shortHash }}</a>
</div>
</div>
<div class="source-diff">
<table>
{% for line in diff.getLines %}
<tr>
<td class="lineNo">
{% if line.getType != 'chunk' %}
<a name="L{{ loop.index }}R{{ line.getNumOld }}"></a>
<a href="#L{{ loop.index }}R{{ line.getNumOld }}">
{% endif %}
{{ line.getNumOld }}
{% if line.getType != 'chunk' %}
</a>
{% endif %}
</td>
<td class="lineNo">
{% if line.getType != 'chunk' %}
<a name="L{{ loop.index }}L{{ line.getNumNew }}"></a>
<a href="#L{{ loop.index }}L{{ line.getNumNew }}">
{% endif %}
{{ line.getNumNew }}
{% if line.getType != 'chunk' %}
</a>
{% endif %}
</td>
<td style="width: 100%">
<pre{% if line.getType %} class="{{ line.getType }}"{% endif %}>{{ line.getLine }}</pre>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endfor %}
{% endfor %}
<hr />
{% endblock %}

View file

@ -0,0 +1,7 @@
<ul class="nav nav-tabs">
<li{% if page == 'files' %} class="active"{% endif %}><a href="{{ path('branch', {repo: repo, branch: branch}) }}">Files</a></li>
<li{% if page in ['commits', 'searchcommits'] %} class="active"{% endif %}><a href="{{ path('commits', {repo: repo, commitishPath: branch}) }}">Commits</a></li>
<li{% if page == 'stats' %} class="active"{% endif %}><a href="{{ path('stats', {repo: repo, branch: branch}) }}">Stats</a></li>
<li{% if page == 'network' %} class="active"{% endif %}><a href="{{ path('network', {repo: repo, commitishPath: branch}) }}">Network</a></li>
<li{% if page == 'treegraph' %} class="active"{% endif %}><a href="{{ path('treegraph', {repo: repo, branch: branch}) }}">Graph</a></li>
</ul>

View file

@ -0,0 +1,20 @@
<div class="navbar navbar-scroll-top">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="{{ path('homepage') }}">{{ title }}</a>
<div class="nav-collapse">
<ul class="nav pull-right">
<li><a href="http://gitlist.org/">About</a></li>
<li><a href="{{ path('homepage') }}refresh">Refresh</a></li>
<li><a href="https://github.com/klaussilveira/gitlist/issues/new">Report bug</a></li>
<li><a href="https://github.com/klaussilveira/gitlist/wiki">Help</a></li>
</ul>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,23 @@
{% extends 'layout_page.twig' %}
{% set page = 'network' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: [{dir: 'Network', path:''}]} %}
<div class="network-view">
<div class="network-header">
<div class="meta">Network Graph of {{ repo }} / {{ commitishPath }}</div>
</div>
<div class="network-graph" data-source="{{ path('networkData', {repo: repo, commitishPath: commitishPath}) }}">
{#<div class="network-graph" data-source="/dummynetwork.json">#}
</div>
</div>
<hr />
{% endblock %}

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>Latest commits in {{ repo }}:{{ branch }}</title>
<description>RSS provided by GitList</description>
<link>{{ url('homepage') }}</link>
{% for commit in commits %}
<item>
<title>{{ commit.message }}</title>
<description>{{ commit.author.name }} authored {{ commit.shortHash }} in {{ commit.date | format_date }}</description>
<link>{{ url('commit', {repo: repo, commit: commit.hash}) }}</link>
<pubDate>{{ commit.date | date('r') }}</pubDate>
<author>{{ commit.author.email }} ({{ commit.author.name }})</author>
</item>
{% endfor %}
</channel>
</rss>

View file

@ -0,0 +1,42 @@
{% extends 'layout_page.twig' %}
{% set page = 'files' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% embed 'breadcrumb.twig' with {breadcrumbs: breadcrumbs} %}
{% block extra %}
<div class="pull-right">
<div class="btn-group download-buttons">
<a href="{{ path('archive', {repo: repo, branch: branch, format: 'zip'}) }}" class="btn btn-mini" title="Download '{{ branch }}' as a ZIP archive">ZIP</a>
<a href="{{ path('archive', {repo: repo, branch: branch, format: 'tar'}) }}" class="btn btn-mini" title="Download '{{ branch }}' as a TAR archive">TAR</a>
</div>
<a href="{{ path('rss', {repo: repo, branch: branch}) }}" class="rss-icon"><i class="rss"></i></a>
</div>
{% endblock %}
{% endembed %}
{% if results %}
<table class="tree">
<thead>
<tr>
<th width="20%">name</th>
<th width="80%">match</th>
</tr>
</thead>
<tbody>
{% for result in results %}
<tr>
<td><i class="icon-file icon-spaced"></i> <a href="{{ path('blob', {repo: repo, branch: branch, file: result.file, commitishPath: branch ~ '/' ~ result.file}) }}#L{{ result.line }}">{{ result.file }}</a></td>
<td>{{ result.match }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>No results found.</p>
{% endif %}
<hr />
{% endblock %}

View file

@ -0,0 +1,13 @@
{% extends 'layout_page.twig' %}
{% set page = 'searchcommits' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: [{dir: 'Commits search results for: ' ~ query, path:''}]} %}
{% include 'commits_list.twig' %}
<hr />
{% endblock %}

View file

@ -0,0 +1,48 @@
{% extends 'layout_page.twig' %}
{% set page = 'stats' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: [{dir: 'Statistics', path:''}]} %}
<table class="table table-striped table-bordered">
<thead>
<tr>
<th width="30%">File extensions ({{ stats.extensions|length }})</th>
<th width="40%">Authors ({{ authors|length }})</th>
<th width="30%">Other</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<ul>
{% for ext, amount in stats.extensions %}
<li><strong>{{ ext }}</strong>: {{ amount }} files</li>
{% endfor %}
</ul>
</td>
<td>
<ul>
{% for author in authors %}
<li><strong><a href="mailto:{{ author.email }}">{{ author.name }}</a></strong>: {{ author.commits }} commits</li>
{% endfor %}
</ul>
</td>
<td>
<p>
<strong>Total files:</strong> {{ stats.files }}
</p>
<p>
<strong>Total bytes:</strong> {{ stats.size }} bytes ({{ stats.size | format_size }})
</p>
</td>
</tr>
</tbody>
</table>
<hr />
{% endblock %}

View file

@ -0,0 +1,95 @@
{% extends 'layout_page.twig' %}
{% set page = 'files' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% embed 'breadcrumb.twig' with {breadcrumbs: breadcrumbs} %}
{% block extra %}
<div class="pull-right">
<div class="btn-group download-buttons">
{% if show_http_remote or show_ssh_remote %}
<a href="#" class="btn btn-mini" title="Show remotes to clone this repository." id="clone-button-show">Clone</a>
{% endif %}
<a href="{{ path('archive', {repo: repo, branch: branch, format: 'zip'}) }}" class="btn btn-mini" title="Download '{{ branch }}' as a ZIP archive">ZIP</a>
<a href="{{ path('archive', {repo: repo, branch: branch, format: 'tar'}) }}" class="btn btn-mini" title="Download '{{ branch }}' as a TAR archive">TAR</a>
</div>
<a href="{{ path('rss', {repo: repo, branch: branch}) }}" class="rss-icon"><i class="rss"></i></a>
</div>
{% if show_http_remote or show_ssh_remote %}
<div id="clone-popup">
<div id="clone-popup-inner-wrapper">
<a class="close" href="#" id="clone-button-hide">&times;</a>
<div class="btn-group">
{% if show_ssh_remote %}
<button class="btn{{ show_ssh_remote and show_http_remote ? ' active' }}" id="clone-button-ssh">SSH</button>
{% endif %}
{% if show_http_remote %}
<button class="btn" id="clone-button-http">HTTP{{ use_https ? 'S' }}</button>
{% endif %}
</div><br />
{% if show_ssh_remote %}
<input type="text" class="form-control{{ show_ssh_remote ? ' visible' }}" id="clone-input-ssh" value="git clone {{ ssh_port ? 'ssh://' }}{{ ssh_user | url_encode }}{{ ssh_user ? '@' }}{{ ssh_host ? ssh_host : app.request.host }}:{{ ssh_port ? ssh_port ~ '/' : '' }}{{ ssh_url_subdir }}{{ repo }}">
{% endif %}
{% if show_http_remote %}
<input type="text" class="form-control{{ show_ssh_remote is empty and show_http_remote ? ' visible' }}" id="clone-input-http" value="git clone http{{ use_https ? 's' }}://{{ http_user | url_encode }}{{ http_user ? '@' }}{{ http_host ? http_host : app.request.host }}/{{ http_url_subdir }}{{ repo }}">
{% endif %}
</div>
</div>
{% endif %}
{% endblock %}
{% endembed %}
{% if files is not empty %}
<table class="tree">
<thead>
<tr>
<th width="80%">name</th>
<th width="10%">mode</th>
<th width="10%">size</th>
</tr>
</thead>
<tbody>
{% if parent is not null %}
<tr>
<td><i class="icon-spaced"></i>
{% if not parent %}
<a href="{{ path('branch', {repo: repo, branch: branch}) }}">..</a>
{% else %}
<a href="{{ path('tree', {repo: repo, commitishPath: branch ~ '/' ~ parent}) }}">..</a>
{% endif %}
</td>
<td></td>
<td></td>
</tr>
{% endif %}
{% for file in files %}
<tr>
<td><i class="{{ file.type == "folder" or file.type == "symlink" ? "icon-folder-open" : "icon-file" }} icon-spaced"></i> <a href="
{%- if file.type == "folder" or file.type == "symlink" -%}
{{ path('tree', {repo: repo, commitishPath: branch ~ '/' ~ path ~ (file.type == "symlink" ? file.path : file.name)}) }}
{%- else -%}
{{ path('blob', {repo: repo, commitishPath: branch ~ '/' ~ path ~ (file.type == "symlink" ? file.path : file.name)}) }}
{%- endif -%}
">{{ file.name }}</a></td>
<td>{{ file.mode }}</td>
<td>{% if file.size %}{{ file.size | format_size }}{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>This repository is empty.</p>
{% endif %}
{% if readme is defined and readme is not empty %}
<div class="readme-view">
<div class="md-header">
<div class="meta">{{ readme.filename }}</div>
</div>
<div id="md-content">{{ readme.content }}</div>
</div>
{% endif %}
<hr />
{% endblock %}

View file

@ -0,0 +1,48 @@
{% extends 'layout_page.twig' %}
{% set page = 'treegraph' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: [{dir: 'Graph', path:''}]} %}
<div class="network-view">
<div class="network-header">
<div class="meta">Graph of {{ repo }} </div>
</div>
<div id="git-graph-container">
<div id="rel-container">
<canvas id="graph-canvas" width="100px">
<ul id="graph-raw-list">
{% for item in graphItems %}
<li><span class="node-relation">{{ item.relation }}</span></li>
{% endfor %}
</ul>
</canvas>
</div>
<div style="float:left;" id="rev-container">
<ul id="rev-list">
{% for item in graphItems %}
<li>
{% if item.rev is defined %}
<a id="{{ item.short_rev }}" class="btn btn-small" href="{{ path('commit', {repo: repo, commit: item.rev}) }}"> {{ item.short_rev }} </a>
<strong> {{ item.branch }} </strong>
<em>{{ item.subject }}</em> by
<span class="author">{{ item.author }} &lt;{{ item.author_email }}&gt;</span>
<span class="time">{{ item.date }}</span>;
{% else %}
<span/>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
<div style="clear:both"><!-- --></div>
</div>
</div>
<hr/>
{% endblock %}

View file

@ -0,0 +1,66 @@
<?php
namespace MVC\Object;
class Ldap
{
public static function testLdap(){
echo '<h3>requête de test de LDAP</h3>';
echo 'Connexion ...';
$ds = ldap_connect(LDAP_URL,LDAP_PORT); // doit être un serveur LDAP valide !
echo 'Le résultat de connexion est ' . $ds . '<br />';
if ($ds) {
echo 'Liaison ...';
$r = ldap_bind_ext($ds, LDAP_USER, LDAP_PASSWORD);
//$r = ldap_bind($ds); // connexion anonyme, typique
// pour un accès en lecture seule.
echo 'Le résultat de connexion depuis ' . $_SERVER['SERVER_ADDR'] . ' est ' . $r . '<br />';
echo 'Recherchons (uid=m*) ...';
// Recherche par nom de famille
$sr=ldap_search($ds, "ou=people, dc=univ-fcomte, dc=fr", "uid=m*");
echo 'Le résultat de la recherche est ' . $sr . '<br />';
echo 'Le nombre d\'entrées retournées est ' . ldap_count_entries($ds,$sr)
. '<br />';
echo 'Lecture des entrées ...<br />';
$info = ldap_get_entries($ds, $sr);
echo 'Données pour ' . $info["count"] . ' entrées:<br />';
echo "<ul>";
for ($i=0; $i<$info["count"]; $i++) {
echo "<li>" . $info[$i]['mail'][0] ;
echo "<ul>";
foreach($info[$i] as $key => $value){
if(is_int($key)) continue;
echo "<li>" . $key . ' est : ';
echo "<ul>";
if(isset($value["count"])) {
for ($j = 0; $j < $value["count"]; $j++) {
echo "<li>" . $value[$j] . "</li>";
}
}else{
echo "<li>" . $value . "</li>";
}
echo "</ul>";
echo "</li>";
}
echo "</ul>";
echo "</li>";
}
echo "</ul>";
echo "</li>";
echo 'Fermeture de la connexion';
ldap_close($ds);
} else {
echo '<h4>Impossible de se connecter au serveur LDAP.</h4>';
}
}
}

View file

@ -0,0 +1,25 @@
<?php
namespace MVC\Command;
class Action
{
public static function help()
{
print "explaination of the command\n\n";
}
public static function add()
{
print "adding action...\n\n";
print "Quel est le nom de l'action a ajouter? ";
$action = trim(fgets(STDIN));
$shell_controlleur = shell_exec('cp ' . CONSOLE_PATH . '/skel/action.php.skel ' . ACTION_PATH . '/' . ucfirst($action) . 'Action.php');
$controlleur = file_get_contents(CONTROLLERS_PATH . '/' . ucfirst($action) . 'Action.php');
$controlleur = preg_replace('%%ACTION%%', ucfirst($action), $controlleur);
file_put_contents(CONTROLLERS_PATH . '/' . ucfirst($action) . 'Action.php', $controlleur);
print $shell_controlleur;
}
}

View file

@ -0,0 +1,25 @@
<?php
namespace MVC\Command;
class Conduit
{
public static function help()
{
print "explaination of the command\n\n";
}
public static function add()
{
print "adding conduit...\n\n";
print "Quel est le nom du conduit symfony a ajouter? ";
$conduit = trim(fgets(STDIN));
$shell_controlleur = shell_exec('cp ' . CONSOLE_PATH . '/skel/conduit.php.skel ' . ACTION_PATH . '/' . ucfirst($conduit) . 'Conduit.php');
$controlleur = file_get_contents(CONTROLLERS_PATH . '/' . ucfirst($conduit) . 'Conduit.php');
$controlleur = preg_replace('%%CONDUIT%%', ucfirst($conduit), $controlleur);
file_put_contents(CONTROLLERS_PATH . '/' . ucfirst($conduit) . 'Conduit.php', $controlleur);
print $shell_controlleur;
}
}

View file

@ -117,17 +117,17 @@ class Module
print $git_chown;
$git_controlleur = shell_exec('cp '.CONSOLE_PATH.'/skel/module_symfony.php '.CONTROLLERS_PATH.'/'.$name.'.php');
$controlleur = file_get_contents(CONTROLLERS_PATH.'/'.$name.'.php');
$controlleur = preg_replace('%MODULE%', $name, $controlleur);
$controlleur = preg_replace('%%MODULE%%', $name, $controlleur);
file_put_contents(CONTROLLERS_PATH.'/'.$name.'.php', $controlleur);
print $git_controlleur;
$git_modele = shell_exec('cp '.CONSOLE_PATH.'/skel/module.model '.MODELS_PATH.'/'.$name.'.model');
$modele = file_get_contents(MODELS_PATH.'/'.$name.'.model');
$modele = preg_replace('%MODULE%', $name, $modele);
$modele = preg_replace('%%MODULE%%', $name, $modele);
file_put_contents(MODELS_PATH.'/'.$name.'.model', $modele);
print $git_modele;
$git_view = shell_exec('cp '.CONSOLE_PATH.'/skel/module.blade.php '.VIEW_PATH.'/view/'.$name.'.blade.php');
$vue = file_get_contents(VIEW_PATH.'/view/'.$name.'.blade.php');
$vue = preg_replace('%MODULE%', 'symfony', $vue);
$vue = preg_replace('%%MODULE%%', 'symfony', $vue);
file_put_contents(VIEW_PATH.'/view/'.$name.'.blade.php', $vue);
print $git_view;
@ -178,17 +178,17 @@ class Module
$git_controlleur = shell_exec('cp '.CONSOLE_PATH.'/skel/module.php '.CONTROLLERS_PATH.'/wordpress.php');
$controlleur = file_get_contents(CONTROLLERS_PATH.'/wordpress.php');
$controlleur = preg_replace('%MODULE%', 'wordpress', $controlleur);
$controlleur = preg_replace('%%MODULE%%', 'wordpress', $controlleur);
file_put_contents(CONTROLLERS_PATH.'/wordpress.php', $controlleur);
print $git_controlleur;
$git_modele = shell_exec('cp '.CONSOLE_PATH.'/skel/module.model '.MODELS_PATH.'/wordpress.model');
$modele = file_get_contents(MODELS_PATH.'/wordpress.model');
$modele = preg_replace('%MODULE%', 'wordpress', $modele);
$modele = preg_replace('%%MODULE%%', 'wordpress', $modele);
file_put_contents(MODELS_PATH.'/wordpress.model', $modele);
print $git_modele;
$git_view = shell_exec('cp '.CONSOLE_PATH.'/skel/module.blade.php '.VIEW_PATH.'/view/wordpress.blade.php');
$vue = file_get_contents(VIEW_PATH.'/view/wordpress.blade.php');
$vue = preg_replace('%MODULE%', 'wordpress', $vue);
$vue = preg_replace('%%MODULE%%', 'wordpress', $vue);
file_put_contents(VIEW_PATH.'/view/wordpress.blade.php', $vue);
print $git_view;
@ -231,17 +231,17 @@ class Module
print $git_ln_2;
$git_controlleur = shell_exec('cp '.CONSOLE_PATH.'/skel/module.php '.CONTROLLERS_PATH.'/prestashop.php');
$controlleur = file_get_contents(CONTROLLERS_PATH.'/prestashop.php');
$controlleur = preg_replace('%MODULE%', 'prestashop', $controlleur);
$controlleur = preg_replace('%%MODULE%%', 'prestashop', $controlleur);
file_put_contents(CONTROLLERS_PATH.'/prestashop.php', $controlleur);
print $git_controlleur;
$git_modele = shell_exec('cp '.CONSOLE_PATH.'/skel/module.model '.MODELS_PATH.'/prestashop.model');
$controlleur = file_get_contents(MODELS_PATH.'/prestashop.model');
$controlleur = preg_replace('%MODULE%', 'prestashop', $controlleur);
$controlleur = preg_replace('%%MODULE%%', 'prestashop', $controlleur);
file_put_contents(MODELS_PATH.'/prestashop.model', $controlleur);
print $git_modele;
$git_view = shell_exec('cp '.CONSOLE_PATH.'/skel/module.blade.php '.VIEW_PATH.'/view/prestashop.blade.php');
$controlleur = file_get_contents(VIEW_PATH.'/view/prestashop.blade.php');
$controlleur = preg_replace('%MODULE%', 'prestashop', $controlleur);
$controlleur = preg_replace('%%MODULE%%', 'prestashop', $controlleur);
file_put_contents(VIEW_PATH.'/view/prestashop.blade.php', $controlleur);
print $git_view;
@ -292,17 +292,17 @@ class Module
print $git_chown;
$git_controlleur = shell_exec('cp '.CONSOLE_PATH.'/skel/module.php '.CONTROLLERS_PATH.'/phplist.php');
$controlleur = file_get_contents(CONTROLLERS_PATH.'/phplist.php');
$controlleur = preg_replace('%MODULE%', 'phplist', $controlleur);
$controlleur = preg_replace('%%MODULE%%', 'phplist', $controlleur);
file_put_contents(CONTROLLERS_PATH.'/phplist.php', $controlleur);
print $git_controlleur;
$git_modele = shell_exec('cp '.CONSOLE_PATH.'/skel/module.model '.MODELS_PATH.'/phplist.model');
$controlleur = file_get_contents(MODELS_PATH.'/phplist.model');
$controlleur = preg_replace('%MODULE%', 'phplist', $controlleur);
$controlleur = preg_replace('%%MODULE%%', 'phplist', $controlleur);
file_put_contents(MODELS_PATH.'/phplist.model', $controlleur);
print $git_modele;
$git_view = shell_exec('cp '.CONSOLE_PATH.'/skel/module.blade.php '.VIEW_PATH.'/view/phplist.blade.php');
$controlleur = file_get_contents(VIEW_PATH.'/view/phplist.blade.php');
$controlleur = preg_replace('%MODULE%', 'phplist', $controlleur);
$controlleur = preg_replace('%%MODULE%%', 'phplist', $controlleur);
file_put_contents(VIEW_PATH.'/view/phplist.blade.php', $controlleur);
print $git_view;
@ -382,17 +382,17 @@ class Module
print $git_chown;
$git_controlleur = shell_exec('cp '.CONSOLE_PATH.'/skel/module.php '.CONTROLLERS_PATH.'/wanewsletter.php');
$controlleur = file_get_contents(CONTROLLERS_PATH.'/wanewsletter.php');
$controlleur = preg_replace('%MODULE%', 'wanewsletter', $controlleur);
$controlleur = preg_replace('%%MODULE%%', 'wanewsletter', $controlleur);
file_put_contents(CONTROLLERS_PATH.'/wanewsletter.php', $controlleur);
print $git_controlleur;
$git_modele = shell_exec('cp '.CONSOLE_PATH.'/skel/module.model '.MODELS_PATH.'/wanewsletter.model');
$controlleur = file_get_contents(MODELS_PATH.'/wanewsletter.model');
$controlleur = preg_replace('%MODULE%', 'wanewsletter', $controlleur);
$controlleur = preg_replace('%%MODULE%%', 'wanewsletter', $controlleur);
file_put_contents(MODELS_PATH.'/wanewsletter.model', $controlleur);
print $git_modele;
$git_view = shell_exec('cp '.CONSOLE_PATH.'/skel/module.blade.php '.VIEW_PATH.'/view/wanewsletter.blade.php');
$controlleur = file_get_contents(VIEW_PATH.'/view/wanewsletter.blade.php');
$controlleur = preg_replace('%MODULE%', 'wanewsletter', $controlleur);
$controlleur = preg_replace('%%MODULE%%', 'wanewsletter', $controlleur);
file_put_contents(VIEW_PATH.'/view/wanewsletter.blade.php', $controlleur);
print $git_view;
@ -470,17 +470,17 @@ class Module
print $git_chown;
$git_controlleur = shell_exec('cp '.CONSOLE_PATH.'/skel/module.php '.CONTROLLERS_PATH.'/phpmynewsletter.php');
$controlleur = file_get_contents(CONTROLLERS_PATH.'/phpmynewsletter.php');
$controlleur = preg_replace('%MODULE%', 'phpmynewsletter', $controlleur);
$controlleur = preg_replace('%%MODULE%%', 'phpmynewsletter', $controlleur);
file_put_contents(CONTROLLERS_PATH.'/phpmynewsletter.php', $controlleur);
print $git_controlleur;
$git_modele = shell_exec('cp '.CONSOLE_PATH.'/skel/module.model '.MODELS_PATH.'/phpmynewsletter.model');
$controlleur = file_get_contents(MODELS_PATH.'/phpmynewsletter.model');
$controlleur = preg_replace('%MODULE%', 'phpmynewsletter', $controlleur);
$controlleur = preg_replace('%%MODULE%%', 'phpmynewsletter', $controlleur);
file_put_contents(MODELS_PATH.'/phpmynewsletter.model', $controlleur);
print $git_modele;
$git_view = shell_exec('cp '.CONSOLE_PATH.'/skel/module.blade.php '.VIEW_PATH.'/view/phpmynewsletter.blade.php');
$controlleur = file_get_contents(VIEW_PATH.'/view/phpmynewsletter.blade.php');
$controlleur = preg_replace('%MODULE%', 'phpmynewsletter', $controlleur);
$controlleur = preg_replace('%%MODULE%%', 'phpmynewsletter', $controlleur);
file_put_contents(VIEW_PATH.'/view/phpmynewsletter.blade.php', $controlleur);
print $git_view;

View file

@ -9,51 +9,60 @@ class Page
print "explaination of the command\n\n";
}
/**
* TODO: ajouter en fonction du type de template (blade ou twig)
*/
public static function add()
{
print "adding page...\n\n";
print "Quel est le nom de la page a ajouter? ";
$page = trim(fgets(STDIN));
/*print "Es-ce un template blade?(Y,N) Par defaut:Y ";
print "Es-ce un template blade?(Y,N) Par defaut:Y ";
$template = trim(fgets(STDIN));
if($template == ''){
$template = 'Y';
}else if($template !== 'Y'){
$template = 'N';
}*/
$vue = "";
if ($template == '' || $template == 'Y') {
$template = 'blade';
print "Es-ce une SPA vue.js? (Y,N) Par defaut:N ";
$vue = trim(fgets(STDIN));
if($vue == ''){
$vue = 'N';
}else if($vue !== 'Y'){
$vue = 'N';
print "Es-ce une SPA vue.js? (Y,N) Par defaut:N ";
$vue = trim(fgets(STDIN));
if ($vue == '') {
$vue = 'N';
} else if ($vue !== 'Y') {
$vue = 'N';
}
} else if ($template !== 'Y') {
$template = 'twig';
}
$shell_controlleur = shell_exec('cp '.CONSOLE_PATH.'/skel/page.php '.CONTROLLERS_PATH.'/'.$page.'.php');
$controlleur = file_get_contents(CONTROLLERS_PATH.'/'.$page.'.php');
$controlleur = preg_replace('%PAGE%', $page, $controlleur);
file_put_contents(CONTROLLERS_PATH.'/'.$page.'.php', $controlleur);
$shell_controlleur = shell_exec('cp ' . CONSOLE_PATH . '/skel/page.php ' . CONTROLLERS_PATH . '/' . $page . '.php');
$controlleur = file_get_contents(CONTROLLERS_PATH . '/' . $page . '.php');
$controlleur = preg_replace('%%PAGE%%', $page, $controlleur);
file_put_contents(CONTROLLERS_PATH . '/' . $page . '.php', $controlleur);
print $shell_controlleur;
$shell_modele = shell_exec('cp '.CONSOLE_PATH.'/skel/page.model '.MODELS_PATH.'/'.$page.'.model');
$modele = file_get_contents(MODELS_PATH.'/'.$page.'.model');
$modele = preg_replace('%PAGE%', $page, $modele);
file_put_contents(MODELS_PATH.'/'.$page.'.model', $modele);
$shell_modele = shell_exec('cp ' . CONSOLE_PATH . '/skel/page.model ' . MODELS_PATH . '/' . $page . '.model');
$modele = file_get_contents(MODELS_PATH . '/' . $page . '.model');
$modele = preg_replace('%%PAGE%%', $page, $modele);
$modele = preg_replace('%%ENGINE%%', $template, $modele);
file_put_contents(MODELS_PATH . '/' . $page . '.model', $modele);
print $shell_modele;
if($vue == 'N'){
$shell_view = shell_exec('cp '.CONSOLE_PATH.'/skel/page.blade.php '.VIEW_PATH.'/view/'.$page.'.blade.php');
if ($template == 'blade'){
if ($vue == 'N') {
$shell_view = shell_exec('cp ' . CONSOLE_PATH . '/skel/page.blade.php ' . VIEW_PATH . '/view/' . $page . '.blade.php');
} else {
$shell_view = shell_exec('cp ' . CONSOLE_PATH . '/skel/page-vuejs.blade.php ' . VIEW_PATH . '/view/' . $page . '.blade.php');
}
$view = file_get_contents(VIEW_PATH . '/view/' . $page . '.blade.php');
$view = preg_replace('%%PAGE%%', $page, $view);
file_put_contents(VIEW_PATH.'/view/'.$page.'.blade.php', $view);
}else{
$shell_view = shell_exec('cp '.CONSOLE_PATH.'/skel/page-vuejs.blade.php '.VIEW_PATH.'/view/'.$page.'.blade.php');
$shell_view = shell_exec('cp ' . CONSOLE_PATH . '/skel/page.html.twig ' . VIEW_PATH . '/view/' . $page . '.html.twig');
$view = file_get_contents(VIEW_PATH . '/view/' . $page . '.html.twig');
$view = preg_replace('%%PAGE%%', $page, $view);
file_put_contents(VIEW_PATH.'/view/'.$page.'.html.twig', $view);
}
$view = file_get_contents(VIEW_PATH.'/view/'.$page.'.blade.php');
$view = preg_replace('%PAGE%', $page, $view);
file_put_contents(VIEW_PATH.'/view/'.$page.'.blade.php', $view);
print $shell_view;
}
/**

View file

@ -0,0 +1,12 @@
<?php
class %%ACTION%%Action extends MVC\Classe\Implement\Action
{
public function render()
{
return $this->render('', array());
}
}

View file

@ -0,0 +1,25 @@
<?php
use MVC\Classe\Implement\Conduit;
class %%CONDUIT%%Conduit extends Conduit
{
// Route('/ajax/get-service/{$id}')
public function getService()
{
\MVC\Object\Session::checkACL_heberges();
if ($this->id != 'undefined') {
$bdd = new \MVC\Classe\Bdd();
$sql = "SELECT * FROM table WHERE id = '{$this->id}';";
$req = $bdd->faireSQLRequete($sql);
$data = $bdd->exploiterResultat($req);
} else {
$data = false;
}
return $this->render('', array());
}
}

View file

@ -1 +1 @@
{{$app->load('MODULE')}}
{{$app->load('%%MODULE%%')}}

View file

@ -1,5 +1,6 @@
name : MODULE
name : %%MODULE%%
page_title : module_title
description : module_description
params : module_params
ariane : {%%MODULE%%}
arianelink : {%%MODULE%%}

View file

@ -1,3 +1,3 @@
<?php
$app = new MVC\Classe\Modular($name, 'MODULE', $url_params);
$app = new MVC\Classe\Modular($name, '%%MODULE%%', $url_params);
$templateData = array('app' => $app);

View file

@ -3,5 +3,5 @@
use MVC\Classe\Session;
Session::start();
$app = new MVC\Classe\Modular($name, 'MODULE', $url_params);
$app = new MVC\Classe\Modular($name, '%%MODULE%%', $url_params);
$templateData = array('app' => $app);

View file

@ -6,7 +6,7 @@
@endsection
@section('content')
<h1>%PAGE% Controlleur</h1>
<h1>%%PAGE%% Controlleur</h1>
<br/><br/><br/>
@if (isset($id))
{{$id}}

View file

@ -0,0 +1,20 @@
{% extends "base.html" %}
{% block top-css %}
{{ parent() }}
{% endblock %}
{% block top-javascript %}
{{ parent() }}
{% endblock %}
{% block bottom-javascript %}
{{ parent() }}
{% endblock %}
{% block content %}
<h1>%%PAGE%%</h1>
<p class="important">
Welcome to my awesome homepage.
</p>
{% endblock %}

View file

@ -1,6 +1,7 @@
name : PAGE
name : %%PAGE%%
page_title : module_title
description : module_description
engine : blade
params : module_params
engine : %%ENGINE%%
ariane : {acceuil, %%PAGE%%}
arianelink : {index, %%PAGE%%}

View file

@ -19,7 +19,7 @@
# Options +SymLinksIfOwnerMatch
# (4)
#RewriteBase /directory/public/
#RewriteBase /fiches3pro/public/
#RewriteBase /
# (5)
@ -27,9 +27,8 @@
# (6)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php [L]
RewriteRule ^$ /index.php [L]
#RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
</IfModule>

Some files were not shown because too many files have changed in this diff Show more