Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/treetrek.git

Clarifies code

Author Dave Jarvis <email>
Date 2026-02-17 23:29:48 GMT-0800
Commit 3eec789b0aff9afe0ede5690ca848d21d577a7aa
Parent 21d5ae0
RepositoryList.php
<?php
-class RepositoryList {
- private const GIT_EXT = '.git';
- private const ORDER_FILE = '/order.txt';
- private const GLOB_PATTERN = '/*';
- private const HIDDEN_PREFIX = '.';
- private const EXCLUDE_CHAR = '-';
- private const SORT_MAX = PHP_INT_MAX;
-
- private const KEY_SAFE_NAME = 'safe_name';
- private const KEY_EXCLUDE = 'exclude';
- private const KEY_ORDER = 'order';
- private const KEY_PATH = 'path';
- private const KEY_NAME = 'name';
+require_once __DIR__ . '/RepositoryList.php';
+require_once __DIR__ . '/git/Git.php';
+require_once __DIR__ . '/pages/CommitsPage.php';
+require_once __DIR__ . '/pages/DiffPage.php';
+require_once __DIR__ . '/pages/HomePage.php';
+require_once __DIR__ . '/pages/FilePage.php';
+require_once __DIR__ . '/pages/RawPage.php';
+require_once __DIR__ . '/pages/TagsPage.php';
+require_once __DIR__ . '/pages/ClonePage.php';
+require_once __DIR__ . '/pages/ComparePage.php';
- private string $reposPath;
+class Router {
+ private const ACTION_TREE = 'tree';
+ private const ACTION_BLOB = 'blob';
+ private const ACTION_RAW = 'raw';
+ private const ACTION_COMMITS = 'commits';
+ private const ACTION_COMMIT = 'commit';
+ private const ACTION_COMPARE = 'compare';
+ private const ACTION_TAGS = 'tags';
- public function __construct( string $path ) {
- $this->reposPath = $path;
- }
+ private const GET_REPOSITORY = 'repo';
+ private const GET_ACTION = 'action';
+ private const GET_HASH = 'hash';
+ private const GET_NAME = 'name';
- public function eachRepository( callable $callback ): void {
- $repos = $this->sortRepositories( $this->loadRepositories() );
+ private const REFERENCE_HEAD = 'HEAD';
+ private const ROUTE_REPO = 'repo';
+ private const EXTENSION_GIT = '.git';
- foreach( $repos as $repo ) {
- $callback( $repo );
- }
- }
+ private array $repos = [];
+ private Git $git;
- private function loadRepositories(): array {
- $repos = [];
- $path = $this->reposPath . self::GLOB_PATTERN;
- $dirs = glob( $path, GLOB_ONLYDIR );
+ private string $repoName = '';
+ private array $repoData = [];
+ private string $action = '';
+ private string $commitHash = '';
+ private string $filePath = '';
+ private string $baseHash = '';
- if( $dirs !== false ) {
- $repos = $this->processDirectories( $dirs );
- }
+ public function __construct( string $reposPath ) {
+ $this->git = new Git( $reposPath );
+ $list = new RepositoryList( $reposPath );
- return $repos;
+ $list->eachRepository( function( $repo ) {
+ $this->repos[$repo['safe_name']] = $repo;
+ });
}
-
- private function processDirectories( array $dirs ): array {
- $repos = [];
- foreach( $dirs as $dir ) {
- $data = $this->createRepositoryData( $dir );
+ public function route(): Page {
+ $this->normalizeQueryString();
+ $uriParts = $this->parseUriParts();
+ $repoName = !empty( $uriParts ) ? array_shift( $uriParts ) : '';
+ $page = new HomePage( $this->repos, $this->git );
- if( $data !== [] ) {
- $repos[$data[self::KEY_NAME]] = $data;
+ if( $repoName !== '' ) {
+ if( str_ends_with( $repoName, self::EXTENSION_GIT ) ) {
+ $page = $this->handleCloneRoute( $repoName, $uriParts );
+ } elseif( isset( $this->repos[$repoName] ) ) {
+ $page = $this->resolveActionRoute( $repoName, $uriParts );
}
}
- return $repos;
+ return $page;
}
- private function createRepositoryData( string $dir ): array {
- $data = [];
- $base = basename( $dir );
+ private function handleCloneRoute(
+ string $repoName,
+ array $uriParts
+ ): Page {
+ $realName = substr( $repoName, 0, -4 );
+ $path = '';
- if( $base[0] !== self::HIDDEN_PREFIX ) {
- $name = $this->extractName( $base );
- $data = [
- self::KEY_NAME => $name,
- self::KEY_SAFE_NAME => $name,
- self::KEY_PATH => $dir,
- ];
+ if( isset( $this->repos[$realName]['path'] ) ) {
+ $path = $this->repos[$realName]['path'];
+ } elseif( isset( $this->repos[$repoName]['path'] ) ) {
+ $path = $this->repos[$repoName]['path'];
}
-
- return $data;
- }
-
- private function extractName( string $base ): string {
- $name = $base;
- if( str_ends_with( $base, self::GIT_EXT ) ) {
- $len = strlen( self::GIT_EXT );
- $name = substr( $base, 0, -$len );
+ if( $path === '' ) {
+ http_response_code( 404 );
+ exit( "Repository not found" );
}
-
- return $name;
- }
-
- private function sortRepositories( array $repos ): array {
- $file = __DIR__ . self::ORDER_FILE;
- if( file_exists( $file ) ) {
- $repos = $this->applyCustomOrder( $repos, $file );
- } else {
- ksort( $repos, SORT_NATURAL | SORT_FLAG_CASE );
- }
+ $this->git->setRepository( $path );
- return $repos;
+ return new ClonePage( $this->git, implode( '/', $uriParts ) );
}
- private function applyCustomOrder( array $repos, string $file ): array {
- $lines = file( $file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
+ private function resolveActionRoute(
+ string $repoName,
+ array $uriParts
+ ): Page {
+ $this->repoData = $this->repos[$repoName];
+ $this->repoName = $repoName;
- if( $lines !== false ) {
- $config = $this->parseOrderFile( $lines );
- $repos = $this->filterExcluded( $repos, $config[self::KEY_EXCLUDE] );
- $repos = $this->sortWithConfig( $repos, $config[self::KEY_ORDER] );
- }
+ $this->git->setRepository( $this->repoData['path'] );
- return $repos;
- }
+ $act = array_shift( $uriParts );
+ $this->action = $act ?: self::ACTION_TREE;
- private function parseOrderFile( array $lines ): array {
- $order = [];
- $exclude = [];
+ $this->commitHash = self::REFERENCE_HEAD;
+ $this->filePath = '';
+ $this->baseHash = '';
- foreach( $lines as $line ) {
- $trim = trim( $line );
+ $hasHash = [
+ self::ACTION_TREE, self::ACTION_BLOB, self::ACTION_RAW,
+ self::ACTION_COMMITS
+ ];
- if( $trim !== '' ) {
- if( str_starts_with( $trim, self::EXCLUDE_CHAR ) ) {
- $exclude = $this->addExclusion( $exclude, $trim );
- } else {
- $order[$trim] = count( $order );
- }
- }
+ if( in_array( $this->action, $hasHash ) ) {
+ $hash = array_shift( $uriParts );
+ $this->commitHash = $hash ?: self::REFERENCE_HEAD;
+ $this->filePath = implode( '/', $uriParts );
+ } elseif( $this->action === self::ACTION_COMMIT ) {
+ $this->commitHash = array_shift( $uriParts );
+ } elseif( $this->action === self::ACTION_COMPARE ) {
+ $this->commitHash = array_shift( $uriParts );
+ $this->baseHash = array_shift( $uriParts );
}
- return [ self::KEY_ORDER => $order, self::KEY_EXCLUDE => $exclude ];
- }
+ $this->populateGet();
- private function addExclusion( array $exclude, string $line ): array {
- $name = substr( $line, 1 );
- $exclude[$name] = true;
+ return $this->createPage();
+ }
- return $exclude;
+ private function createPage(): Page {
+ return match( $this->action ) {
+ self::ACTION_TREE,
+ self::ACTION_BLOB => new FilePage(
+ $this->repos, $this->repoData, $this->git, $this->commitHash,
+ $this->filePath
+ ),
+ self::ACTION_RAW => new RawPage(
+ $this->git, $this->commitHash
+ ),
+ self::ACTION_COMMITS => new CommitsPage(
+ $this->repos, $this->repoData, $this->git, $this->commitHash
+ ),
+ self::ACTION_COMMIT => new DiffPage(
+ $this->repos, $this->repoData, $this->git, $this->commitHash
+ ),
+ self::ACTION_TAGS => new TagsPage(
+ $this->repos, $this->repoData, $this->git
+ ),
+ self::ACTION_COMPARE => new ComparePage(
+ $this->repos, $this->repoData, $this->git, $this->commitHash,
+ $this->baseHash
+ ),
+ default => new FilePage(
+ $this->repos, $this->repoData, $this->git, self::REFERENCE_HEAD, ''
+ )
+ };
}
- private function filterExcluded( array $repos, array $exclude ): array {
- foreach( $repos as $key => $repo ) {
- if( isset( $exclude[$repo[self::KEY_SAFE_NAME]] ) ) {
- unset( $repos[$key] );
- }
+ private function normalizeQueryString(): void {
+ if( empty( $_GET ) && !empty( $_SERVER['QUERY_STRING'] ) ) {
+ parse_str( $_SERVER['QUERY_STRING'], $_GET );
}
-
- return $repos;
}
- private function sortWithConfig( array $repos, array $order ): array {
- uasort( $repos, function( array $repoA, array $repoB ) use( $order ): int {
- return $this->compareRepositories( $repoA, $repoB, $order );
- } );
+ private function parseUriParts(): array {
+ $requestUri = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );
+ $scriptName = dirname( $_SERVER['SCRIPT_NAME'] );
- return $repos;
- }
+ if( $scriptName !== '/' && strpos( $requestUri, $scriptName ) === 0 ) {
+ $requestUri = substr( $requestUri, strlen( $scriptName ) );
+ }
- private function compareRepositories(
- array $repoA,
- array $repoB,
- array $order
- ): int {
- $safeA = $repoA[self::KEY_SAFE_NAME];
- $safeB = $repoB[self::KEY_SAFE_NAME];
- $posA = $order[$safeA] ?? self::SORT_MAX;
- $posB = $order[$safeB] ?? self::SORT_MAX;
+ $requestUri = trim( $requestUri, '/' );
+ $uriParts = explode( '/', $requestUri );
- $result = $posA === $posB
- ? strcasecmp( $safeA, $safeB )
- : $posA <=> $posB;
+ if( !empty( $uriParts ) && $uriParts[0] === self::ROUTE_REPO ) {
+ array_shift( $uriParts );
+ }
- return $result;
+ return $uriParts;
+ }
+
+ private function populateGet(): void {
+ $_GET[self::GET_REPOSITORY] = $this->repoName;
+ $_GET[self::GET_ACTION] = $this->action;
+ $_GET[self::GET_HASH] = $this->commitHash;
+ $_GET[self::GET_NAME] = $this->filePath;
}
}
Delta 142 lines added, 123 lines removed, 19-line increase