diff --git a/git/src/GitList/Application.php b/git/src/GitList/Application.php
index 0c658e65..18cc6815 100755
--- a/git/src/GitList/Application.php
+++ b/git/src/GitList/Application.php
@@ -9,6 +9,7 @@ use GitList\Provider\GitServiceProvider;
use GitList\Provider\RepositoryUtilServiceProvider;
use GitList\Provider\ViewUtilServiceProvider;
use GitList\Provider\RoutingUtilServiceProvider;
+use Symfony\Component\Filesystem\Filesystem;
/**
* GitList application.
@@ -30,14 +31,15 @@ class Application extends SilexApplication
$this->path = realpath($root);
$this['debug'] = $config->get('app', 'debug');
+ $this['date.format'] = $config->get('date', 'format') ? $config->get('date', 'format') : 'd/m/Y H:i:s';
+ $this['theme'] = $config->get('app', 'theme') ? $config->get('app', 'theme') : 'default';
$this['filetypes'] = $config->getSection('filetypes');
+ $this['binary_filetypes'] = $config->getSection('binary_filetypes');
$this['cache.archives'] = $this->getCachePath() . 'archives';
- $this['path_prefix'] = $config->get('app', 'path_prefix');
- $this['clone_url'] = $config->get('app', 'clone_url');
// Register services
$this->register(new TwigServiceProvider(), array(
- 'twig.path' => $this->getViewPath(),
+ 'twig.path' => array($this->getThemePath($this['theme']), $this->getThemePath('default')),
'twig.options' => $config->get('app', 'cache') ?
array('cache' => $this->getCachePath() . 'views') : array(),
));
@@ -60,12 +62,17 @@ class Application extends SilexApplication
$this->register(new RoutingUtilServiceProvider());
$this['twig'] = $this->share($this->extend('twig', function ($twig, $app) {
- $twig->addFilter('htmlentities', new \Twig_Filter_Function('htmlentities'));
- $twig->addFilter('md5', new \Twig_Filter_Function('md5'));
+ $twig->addFilter(new \Twig_SimpleFilter('htmlentities', 'htmlentities'));
+ $twig->addFilter(new \Twig_SimpleFilter('md5', 'md5'));
+ $twig->addFilter(new \Twig_SimpleFilter('format_date', array($app, 'formatDate')));
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']) {
@@ -76,26 +83,49 @@ class Application extends SilexApplication
'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 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;
+ return $this->path
+ . DIRECTORY_SEPARATOR
+ . 'cache'
+ . DIRECTORY_SEPARATOR;
}
- public function getViewPath()
+ public function getThemePath($theme)
{
- return $this->path . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR;
+ return $this->path
+ . DIRECTORY_SEPARATOR
+ . 'themes'
+ . DIRECTORY_SEPARATOR
+ . $theme
+ . DIRECTORY_SEPARATOR
+ . 'twig'
+ . DIRECTORY_SEPARATOR;
}
}
diff --git a/git/src/GitList/Controller/BlobController.php b/git/src/GitList/Controller/BlobController.php
index fc5ec907..86cef8bd 100755
--- a/git/src/GitList/Controller/BlobController.php
+++ b/git/src/GitList/Controller/BlobController.php
@@ -43,6 +43,7 @@ class BlobController implements ControllerProviderInterface
));
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('commitishPath', '.+')
+ ->convert('commitishPath', 'escaper.argument:escape')
->bind('blob');
$route->get('{repo}/raw/{commitishPath}', function ($repo, $commitishPath) use ($app) {
@@ -66,6 +67,7 @@ class BlobController implements ControllerProviderInterface
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');
return $route;
diff --git a/git/src/GitList/Controller/CommitController.php b/git/src/GitList/Controller/CommitController.php
index 86dc4093..292e94c7 100755
--- a/git/src/GitList/Controller/CommitController.php
+++ b/git/src/GitList/Controller/CommitController.php
@@ -12,6 +12,15 @@ class CommitController implements ControllerProviderInterface
{
$route = $app['controllers_factory'];
+ $route->get('{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('{repo}/commits/{commitishPath}', function ($repo, $commitishPath) use ($app) {
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
@@ -31,10 +40,12 @@ class CommitController implements ControllerProviderInterface
foreach ($commits as $commit) {
$date = $commit->getDate();
- $date = $date->format('m/d/Y');
+ $date = $date->format('Y-m-d');
$categorized[$date][] = $commit;
}
+ krsort($categorized);
+
$template = $app['request']->isXmlHttpRequest() ? 'commits_list.twig' : 'commits.twig';
return $app['twig']->render($template, array(
@@ -50,6 +61,7 @@ class CommitController implements ControllerProviderInterface
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('commitishPath', $app['util.routing']->getCommitishPathRegex())
->value('commitishPath', null)
+ ->convert('commitishPath', 'escaper.argument:escape')
->bind('commits');
$route->post('{repo}/commits/{branch}/search', function (Request $request, $repo, $branch = '') use ($app) {
@@ -61,10 +73,12 @@ class CommitController implements ControllerProviderInterface
foreach ($commits as $commit) {
$date = $commit->getDate();
- $date = $date->format('m/d/Y');
+ $date = $date->format('Y-m-d');
$categorized[$date][] = $commit;
}
+ krsort($categorized);
+
return $app['twig']->render('searchcommits.twig', array(
'repo' => $repo,
'branch' => $branch,
@@ -76,6 +90,7 @@ class CommitController implements ControllerProviderInterface
));
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', $app['util.routing']->getBranchRegex())
+ ->convert('branch', 'escaper.argument:escape')
->bind('searchcommits');
$route->get('{repo}/commit/{commit}', function ($repo, $commit) use ($app) {
@@ -112,6 +127,7 @@ class CommitController implements ControllerProviderInterface
));
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('commitishPath', $app['util.routing']->getCommitishPathRegex())
+ ->convert('commitishPath', 'escaper.argument:escape')
->bind('blame');
return $route;
diff --git a/git/src/GitList/Controller/MainController.php b/git/src/GitList/Controller/MainController.php
index 3c8919cf..92de6aef 100755
--- a/git/src/GitList/Controller/MainController.php
+++ b/git/src/GitList/Controller/MainController.php
@@ -48,6 +48,7 @@ class MainController implements ControllerProviderInterface
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', $app['util.routing']->getBranchRegex())
->value('branch', null)
+ ->convert('branch', 'escaper.argument:escape')
->bind('stats');
$route->get('{repo}/{branch}/rss/', function($repo, $branch) use ($app) {
@@ -69,6 +70,7 @@ class MainController implements ControllerProviderInterface
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', $app['util.routing']->getBranchRegex())
->value('branch', null)
+ ->convert('branch', 'escaper.argument:escape')
->bind('rss');
return $route;
diff --git a/git/src/GitList/Controller/NetworkController.php b/git/src/GitList/Controller/NetworkController.php
index 2814e9c5..1c6a9208 100755
--- a/git/src/GitList/Controller/NetworkController.php
+++ b/git/src/GitList/Controller/NetworkController.php
@@ -55,7 +55,7 @@ class NetworkController implements ControllerProviderInterface
}
$nextPageUrl = null;
-
+
if ($pager['last'] !== $pager['current']) {
$nextPageUrl = $app['url_generator']->generate(
'networkData',
@@ -66,10 +66,10 @@ class NetworkController implements ControllerProviderInterface
)
);
}
-
+
// when no commits are given, return an empty response - issue #369
if( count($commits) === 0 ) {
- return $app->json( array(
+ return $app->json( array(
'repo' => $repo,
'commitishPath' => $commitishPath,
'nextPage' => null,
@@ -91,6 +91,7 @@ class NetworkController implements ControllerProviderInterface
)->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');
@@ -119,6 +120,7 @@ class NetworkController implements ControllerProviderInterface
)->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('commitishPath', $app['util.routing']->getCommitishPathRegex())
->value('commitishPath', null)
+ ->convert('commitishPath', 'escaper.argument:escape')
->bind('network');
return $route;
diff --git a/git/src/GitList/Controller/TreeController.php b/git/src/GitList/Controller/TreeController.php
index 384b5378..b3d88b43 100755
--- a/git/src/GitList/Controller/TreeController.php
+++ b/git/src/GitList/Controller/TreeController.php
@@ -4,8 +4,8 @@ namespace GitList\Controller;
use Silex\Application;
use Silex\ControllerProviderInterface;
-use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\BinaryFileResponse;
class TreeController implements ControllerProviderInterface
{
@@ -45,6 +45,7 @@ class TreeController implements ControllerProviderInterface
));
})->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('commitishPath', $app['util.routing']->getCommitishPathRegex())
+ ->convert('commitishPath', 'escaper.argument:escape')
->bind('tree');
$route->post('{repo}/tree/{branch}/search', function (Request $request, $repo, $branch = '', $tree = '') use ($app) {
@@ -65,14 +66,13 @@ class TreeController implements ControllerProviderInterface
'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');
-
- # Intentionally before next statement, because order appears
- # to be important, and the other statement got precedence previously.
$route->get('{repo}/{format}ball/{branch}', function($repo, $format, $branch) use ($app) {
$repository = $app['git']->getRepositoryFromName($app['git.repos'], $repo);
@@ -93,17 +93,11 @@ class TreeController implements ControllerProviderInterface
$repository->createArchive($tree, $file, $format);
}
- return new StreamedResponse(function () use ($file) {
- readfile($file);
- }, 200, array(
- 'Content-type' => ('zip' === $format) ? 'application/zip' : 'application/x-tar',
- 'Content-Description' => 'File Transfer',
- 'Content-Disposition' => 'attachment; filename="'.$repo.'-'.substr($tree, 0, 6).'.'.$format.'"',
- 'Content-Transfer-Encoding' => 'binary',
- ));
+ return new BinaryFileResponse($file);
})->assert('format', '(zip|tar)')
->assert('repo', $app['util.routing']->getRepositoryRegex())
->assert('branch', $app['util.routing']->getBranchRegex())
+ ->convert('branch', 'escaper.argument:escape')
->bind('archive');
@@ -111,6 +105,7 @@ class TreeController implements ControllerProviderInterface
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('{repo}/', function($repo) use ($app, $treeController) {
diff --git a/git/src/GitList/Escaper/ArgumentEscaper.php b/git/src/GitList/Escaper/ArgumentEscaper.php
new file mode 100755
index 00000000..6717dd8a
--- /dev/null
+++ b/git/src/GitList/Escaper/ArgumentEscaper.php
@@ -0,0 +1,15 @@
+%H"
- . "%h%T%P"
+ . "%h%T%P"
. "%an%ae"
. "%at%cn"
. "%ce"
@@ -241,9 +241,10 @@ class Repository extends BaseRepository
public function searchCommitLog($query)
{
$query = escapeshellarg($query);
+ $query = strtr($query, array('[' => '\\[', ']' => '\\]'));
$command =
"log --grep={$query} --pretty=format:\"- %H"
- . "%h%T%P"
+ . "%h%T%P"
. "%an%ae"
. "%at%cn"
. "%ce"
@@ -369,7 +370,7 @@ class Repository extends BaseRepository
{
$fs = new Filesystem;
$fs->mkdir(dirname($output));
- $this->getClient()->run($this, "archive --format=$format --output=$output $tree");
+ $this->getClient()->run($this, "archive --format=$format --output='$output' $tree");
}
/**
diff --git a/git/src/GitList/Util/Repository.php b/git/src/GitList/Util/Repository.php
index 5f6c80c0..1295276b 100755
--- a/git/src/GitList/Util/Repository.php
+++ b/git/src/GitList/Util/Repository.php
@@ -40,6 +40,8 @@ class Repository
'md' => 'markdown',
'markdown' => 'markdown',
'sql' => 'mysql',
+ 'ml' => 'ocaml',
+ 'mli' => 'ocaml',
'pl' => 'perl',
'pm' => 'perl',
'pas' => 'pascal',
@@ -60,6 +62,7 @@ class Repository
'st' => 'smalltalk',
'tex' => 'stex',
'vbs' => 'vbscript',
+ 'vb' => 'vbscript',
'v' => 'verilog',
'xml' => 'xml',
'xsd' => 'xml',
diff --git a/git/src/GitList/Util/Routing.php b/git/src/GitList/Util/Routing.php
index 65ea13fe..677f2aac 100755
--- a/git/src/GitList/Util/Routing.php
+++ b/git/src/GitList/Util/Routing.php
@@ -58,11 +58,18 @@ class Routing
}
}
- if ($matchedBranch === null) {
- throw new EmptyRepositoryException('This repository is currently empty. There are no commits.');
+ 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.');
+ }
}
-
- $commitish = $matchedBranch;
}
$commitishLength = strlen($commitish);
@@ -101,15 +108,15 @@ class Routing
static $regex = null;
if ($regex === null) {
- $app = $this->app;
- $self = $this;
+ $isWindows = $this->isWindows();
$quotedPaths = array_map(
- function ($repo) use ($app, $self) {
- $repoName = $repo['name'];
- //Windows
- if ($self->isWindows()){
- $repoName = str_replace('\\', '',$repoName);
+ function ($repo) use ($isWindows) {
+ $repoName = preg_quote($repo['name']);
+
+ if ($isWindows) {
+ $repoName = str_replace('\\', '\\\\', $repoName);
}
+
return $repoName;
},
$this->app['git']->getRepositories($this->app['git.repos'])