Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/treetrek.git
<?php
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';

class Router {
  private $repos = [];
  private $git;

  public function __construct( string $reposPath ) {
    $this->git = new Git( $reposPath );
    $list = new RepositoryList( $reposPath );

    $list->eachRepository( function( $repo ) {
      $this->repos[] = $repo;
    } );
  }

  public function route(): Page {
    $reqRepo = $_GET['repo'] ?? '';
    $action = $_GET['action'] ?? 'file';
    $hash = $this->sanitize( $_GET['hash'] ?? '' );
    $subPath = '';
    $uri = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );
    $scriptName = $_SERVER['SCRIPT_NAME'];

    if( strpos( $uri, $scriptName ) === 0 ) {
      $uri = substr( $uri, strlen( $scriptName ) );
    }

    if( preg_match( '#^/([^/]+)\.git(?:/(.*))?$#', $uri, $matches ) ) {
      $reqRepo = urldecode( $matches[1] );
      $subPath = isset( $matches[2] ) ? ltrim( $matches[2], '/' ) : '';
      $action = 'clone';
    }

    $currRepo = null;
    $decoded = urldecode( $reqRepo );

    foreach( $this->repos as $repo ) {
      if( $repo['safe_name'] === $reqRepo || $repo['name'] === $decoded ) {
        $currRepo = $repo;

        break;
      }

      $prefix = $repo['safe_name'] . '/';

      if( strpos( $reqRepo, $prefix ) === 0 ) {
        $currRepo = $repo;
        $subPath = substr( $reqRepo, strlen( $prefix ) );
        $action = 'clone';

        break;
      }
    }

    if( $currRepo ) {
      $this->git->setRepository( $currRepo['path'] );
    }

    $routes = [
      'home'    => fn() => new HomePage( $this->repos, $this->git ),
      'file'    => fn() => new FilePage( $this->repos, $currRepo, $this->git, $hash ),
      'raw'     => fn() => new RawPage( $this->git, $hash ),
      'commit'  => fn() => new DiffPage( $this->repos, $currRepo, $this->git, $hash ),
      'commits' => fn() => new CommitsPage( $this->repos, $currRepo, $this->git, $hash ),
      'tags'    => fn() => new TagsPage( $this->repos, $currRepo, $this->git ),
      'clone'   => fn() => new ClonePage( $this->git, $subPath ),
    ];

    $action = !$currRepo ? 'home' : $action;

    return ($routes[$action] ?? $routes['file'])();
  }

  private function sanitize( $path ) {
    $path = str_replace( [ '..', '\\', "\0" ], [ '', '/', '' ], $path );

    return preg_replace( '/[^a-zA-Z0-9_\-\.\/]/', '', $path );
  }
}