Skip to main content
Glama

CTX: Context as Code (CaC) tool

by context-hub
MIT License
235
  • Apple
  • Linux
ReleaseManager.php5.48 kB
<?php declare(strict_types=1); namespace Butschster\ContextGenerator\Lib\GithubClient; use Butschster\ContextGenerator\Lib\GithubClient\Model\GithubRepository; use Butschster\ContextGenerator\Lib\GithubClient\Model\Release; use Butschster\ContextGenerator\Lib\HttpClient\Exception\HttpException; use Butschster\ContextGenerator\Lib\HttpClient\HttpClientInterface; use Psr\Log\LoggerInterface; /** * Manages GitHub releases for a repository. */ final readonly class ReleaseManager { public function __construct( private HttpClientInterface $httpClient, private GithubRepository $repository, private ?string $token = null, private BinaryNameBuilder $binaryNameBuilder = new BinaryNameBuilder(), private ?LoggerInterface $logger = null, ) {} /** * Get the latest release from GitHub. * * @throws \RuntimeException If the request fails */ public function getLatestRelease(): Release { $url = \sprintf( 'https://api.github.com/repos/%s/releases/latest', $this->repository->repository, ); $response = $this->httpClient->get( $url, $this->getHeaders(), ); if (!$response->isSuccess()) { throw new \RuntimeException( "Failed to fetch latest release. Server returned status code {$response->getStatusCode()}", ); } try { $data = $response->getJson(); return Release::fromApiResponse($data); } catch (HttpException $e) { throw new \RuntimeException("Failed to parse GitHub response: {$e->getMessage()}", 0, $e); } } /** * Attempts to download the appropriate binary for the current platform. * First tries the platform-specific binary, then falls back to the generic binary. */ public function downloadBinary(string $version, string $binaryName, string $type, string $destinationPath): bool { // First try platform-specific binary try { $fileName = $this->binaryNameBuilder->buildPlatformSpecificName($binaryName, $version, $type); $this->logger?->info("Attempting to download platform-specific binary: {$fileName}"); $assetUrl = $this->getAssetUrlOrFail($fileName); $this->downloadAsset($assetUrl, $destinationPath); $this->logger?->info("Successfully downloaded platform-specific binary: {$fileName}"); return true; } catch (\Throwable $e) { $this->logger?->warning("Failed to download platform-specific binary: {$e->getMessage()}"); // Fall back to generic binary try { $fileName = $this->binaryNameBuilder->buildGenericName($binaryName, $type); $this->logger?->info("Falling back to generic binary: {$fileName}"); $assetUrl = $this->getAssetUrlOrFail($fileName); $this->downloadAsset($assetUrl, $destinationPath); $this->logger?->info("Successfully downloaded generic binary: {$fileName}"); return true; } catch (\Throwable $e2) { $this->logger?->error("Failed to download generic binary: {$e2->getMessage()}"); throw new \RuntimeException("Failed to download binary: {$e2->getMessage()}", 0, $e2); } } } /** * Download a release asset to a local file. */ private function downloadAsset(string $assetUrl, string $destinationPath): void { $response = $this->httpClient->getWithRedirects( $assetUrl, $this->getHeaders(), ); if (!$response->isSuccess()) { throw new \RuntimeException( "Failed to download asset. Server returned status code {$response->getStatusCode()}", ); } // Write the file if (!\file_put_contents($destinationPath, $response->getBody())) { throw new \RuntimeException("Failed to write file: {$destinationPath}"); } // Make the file executable if it's not a Windows system if (\PHP_OS_FAMILY !== 'Windows') { if (!\chmod($destinationPath, 0755)) { throw new \RuntimeException("Failed to set executable permissions on the file: {$destinationPath}"); } } } /** * Gets the asset URL for a specific filename or throws an exception if not found. * * @param string $fileName Name of the file * @return string The asset URL * @throws \RuntimeException If the asset is not found */ private function getAssetUrlOrFail(string $fileName): string { $release = $this->getLatestRelease(); $assetUrl = $release->getAssetUrl($fileName); if ($assetUrl === null) { throw new \RuntimeException("Could not find asset '{$fileName}' in release {$release->getVersion()}"); } return $assetUrl; } /** * Generate standard headers for GitHub API requests. * * @return array<string, string> Headers */ private function getHeaders(): array { $headers = [ 'Accept' => 'application/vnd.github.v3+json', 'User-Agent' => 'ContextGenerator', ]; if ($this->token) { $headers['Authorization'] = 'token ' . $this->token; } return $headers; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/context-hub/generator'

If you have feedback or need assistance with the MCP directory API, please join our Discord server