summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Weipert <git@mail.dweipert.de>2025-07-22 11:16:40 +0200
committerDaniel Weipert <git@mail.dweipert.de>2025-07-22 11:16:40 +0200
commitd51eee7ed707568f58d305abb750349cb2f27bcc (patch)
treed9b32a2e8466c5c9e04d769889fb9e9ed3496447
parent4fd85782abf9005a0d27d7890023a21d9dad6ef3 (diff)
add blob route and log parse cache
-rw-r--r--index.php93
1 files changed, 82 insertions, 11 deletions
diff --git a/index.php b/index.php
index 9f8b568..d45341a 100644
--- a/index.php
+++ b/index.php
@@ -1,5 +1,10 @@
<?php
+/**
+ * find projects at $path
+ *
+ * @return array<string>
+ */
function find_projects(string $path, array $projects = []): array {
$directories = glob($path . "/{.[!.],}*", GLOB_ONLYDIR | GLOB_BRACE);
if (($idx = array_search("$path/.git", $directories)) !== false) {
@@ -14,10 +19,23 @@ function find_projects(string $path, array $projects = []): array {
return $projects;
}
-function parse_log(string $path): array|null {
+
+global $cache_parse_log;
+$cache_parse_log = [];
+
+/**
+ * parse git log at $path
+ */
+function parse_log(string $path): array {
+ global $cache_parse_log;
+
+ if (isset($cache_parse_log[$path])) {
+ return $cache_parse_log[$path];
+ }
+
$proxy = md5(strval(microtime(true)));
$process = proc_open(
- "git -C {$path} log " . "--pretty=format:'{%n {$proxy}commit{$proxy}: {$proxy}%H{$proxy},%n {$proxy}author{$proxy}: {$proxy}%aN <%aE>{$proxy},%n {$proxy}date{$proxy}: {$proxy}%ad{$proxy},%n {$proxy}message{$proxy}: {$proxy}%s{$proxy}%n},'",
+ "git -C \"{$path}\" log " . "--pretty=format:'{%n {$proxy}commit{$proxy}: {$proxy}%H{$proxy},%n {$proxy}author{$proxy}: {$proxy}%aN <%aE>{$proxy},%n {$proxy}date{$proxy}: {$proxy}%ad{$proxy},%n {$proxy}message{$proxy}: {$proxy}%s{$proxy}%n},'",
[
["pipe", "r"],
["pipe", "w"],
@@ -32,12 +50,15 @@ function parse_log(string $path): array|null {
$json = json_decode($string, true);
- return $json;
+ return $cache_parse_log[$path] = $json ?? [];
}
+/**
+ * parse git status at $path
+ */
function parse_status(string $path): array {
$process = proc_open(
- "git -C {$path} status --porcelain=v2 --branch",
+ "git -C \"{$path}\" status --porcelain=v2 --branch",
[
["pipe", "r"],
["pipe", "w"],
@@ -117,11 +138,14 @@ function parse_status(string $path): array {
return $status;
}
+/**
+ * get git file tree at $path for $revision under $tree_base_path
+ */
function get_file_tree(string $path, string $revision, string $tree_base_path): array
{
$proxy = md5(strval(microtime(true)));
$process = proc_open(
- "git -C {$path} ls-tree {$revision} {$tree_base_path}" . " --format='{%n {$proxy}mode{$proxy}: {$proxy}%(objectmode){$proxy},%n {$proxy}type{$proxy}: {$proxy}%(objecttype){$proxy},%n {$proxy}name{$proxy}: {$proxy}%(objectname){$proxy},%n {$proxy}size{$proxy}: {$proxy}%(objectsize){$proxy},%n {$proxy}path{$proxy}: {$proxy}%(path){$proxy}%n},'",
+ "git -C \"{$path}\" ls-tree {$revision} {$tree_base_path}" . " --format='{%n {$proxy}mode{$proxy}: {$proxy}%(objectmode){$proxy},%n {$proxy}type{$proxy}: {$proxy}%(objecttype){$proxy},%n {$proxy}name{$proxy}: {$proxy}%(objectname){$proxy},%n {$proxy}size{$proxy}: {$proxy}%(objectsize){$proxy},%n {$proxy}path{$proxy}: {$proxy}%(path){$proxy}%n},'",
[
["pipe", "r"],
["pipe", "w"],
@@ -131,7 +155,7 @@ function get_file_tree(string $path, string $revision, string $tree_base_path):
);
$output = stream_get_contents($pipes[1]);
- $string = str_replace(['"', $proxy], ['\\"', '"'], $output);
+ $string = str_replace(['\\', '"', $proxy], ['\\\\', '\\"', '"'], $output);
$string = "[" . rtrim(trim($string), ",") . "]";
$tree = json_decode($string, true);
@@ -140,6 +164,9 @@ function get_file_tree(string $path, string $revision, string $tree_base_path):
}
+/**
+ * Template root
+ */
function template_root(string $content, array $meta = []): string
{
$meta = array_replace_recursive([
@@ -149,9 +176,19 @@ function template_root(string $content, array $meta = []): string
ob_start();
?>
+ <!doctype html>
<html>
<head>
<title><?php echo $meta["title"]; ?></title>
+ <style>
+ .blob-code-block {
+ pre {
+ border: 1px solid;
+ display: inline-block;
+ padding: 1rem;
+ }
+ }
+ </style>
</head>
<body><?php echo $content; ?></body>
</html>
@@ -167,6 +204,7 @@ $url = parse_url("http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
ob_start();
+// Route: /
if ($url["path"] == "/") {
$projects = find_projects($projects_path);
@@ -238,10 +276,10 @@ if ($url["path"] == "/") {
}
-// /$project/tree/$file_path
+// Route: /$project/tree/$file_path
elseif (preg_match("#(.*)/tree/?(.*)#", $url["path"], $matches)) {
- $project = ltrim($matches[1], "/");
- $file_path = rtrim($matches[2], "/");
+ $project = urldecode(ltrim($matches[1], "/"));
+ $file_path = urldecode(rtrim($matches[2], "/"));
// get tree
$tree = get_file_tree("$projects_path/$project", "HEAD", "./{$file_path}/");
@@ -260,6 +298,7 @@ elseif (preg_match("#(.*)/tree/?(.*)#", $url["path"], $matches)) {
<table>
<thead>
<tr>
+ <td>Mode</td>
<td>File</td>
</tr>
</thead>
@@ -267,11 +306,18 @@ elseif (preg_match("#(.*)/tree/?(.*)#", $url["path"], $matches)) {
<?php
foreach ($tree as $file) {
- $relative_path = str_replace("$file_path/", "", $file["path"]);
+ $current_file_path = $file_path . "/";
+ $basename = basename($file["path"]);
?><tr><?php
- ?><td><a href="<?php echo "$url[path]/$relative_path"; ?>"><?php echo $relative_path; ?></a><td><?php
+ ?><td><?php echo $file["mode"]; ?></td><?php
+
+ if ($file["type"] == "blob"):
+ ?><td><a href="<?php echo "/$project/blob/$current_file_path$basename"; ?>"><?php echo $basename; ?></a><td><?php
+ else:
+ ?><td><a href="<?php echo "/$project/tree/$current_file_path$basename"; ?>"><?php echo $basename; ?></a><td><?php
+ endif;
?></tr><?php
}
@@ -282,6 +328,31 @@ elseif (preg_match("#(.*)/tree/?(.*)#", $url["path"], $matches)) {
<?php
}
+// Route: /$project/blob/$file_path
+elseif (preg_match("#(.*)/blob/?(.*)#", $url["path"], $matches)) {
+ $project = urldecode(ltrim($matches[1], "/"));
+ $file_path = urldecode(rtrim($matches[2], "/"));
+
+ // show breadcrumbs
+ $breadcrumbs = explode("/", $file_path);
+ echo "<a href='/$project/tree'>root</a>";
+ $crumb_parts = "";
+ foreach ($breadcrumbs as $idx => $crumb) {
+ $crumb_parts .= "/$crumb";
+ if ($idx != count($breadcrumbs) - 1) {
+ echo "/<a href='/$project/tree$crumb_parts'>$crumb</a>";
+ } else {
+ echo "/$crumb";
+ }
+ }
+
+ ?>
+ <div class="blob-code-block">
+ <pre><code><?php echo file_get_contents("$projects_path/$project/$file_path"); ?></code></pre>
+ </div>
+ <?php
+}
+
else {
$path = $projects_path . $url["path"];
var_dump(parse_log($path));