*/ class FossilDriver extends VcsDriver { /** @var array Map of tag name to identifier */ protected $tags; /** @var array Map of branch name to identifier */ protected $branches; /** @var ?string */ protected $rootIdentifier = null; /** @var ?string */ protected $repoFile = null; /** @var string */ protected $checkoutDir; /** * @inheritDoc */ public function initialize(): void { $this->checkFossil(); // Ensure we are allowed to use this URL by config. $this->config->prohibitUrlByConfig($this->url, $this->io); // Only if url points to a locally accessible directory, assume it's the checkout directory. // Otherwise, it should be something fossil can clone from. if (Filesystem::isLocalPath($this->url) && is_dir($this->url)) { $this->checkoutDir = $this->url; } else { if (!Cache::isUsable($this->config->get('cache-repo-dir')) || !Cache::isUsable($this->config->get('cache-vcs-dir'))) { throw new \RuntimeException('FossilDriver requires a usable cache directory, and it looks like you set it to be disabled'); } $localName = Preg::replace('{[^a-z0-9]}i', '-', $this->url); $this->repoFile = $this->config->get('cache-repo-dir') . '/' . $localName . '.fossil'; $this->checkoutDir = $this->config->get('cache-vcs-dir') . '/' . $localName . '/'; $this->updateLocalRepo(); } $this->getTags(); $this->getBranches(); } /** * Check that fossil can be invoked via command line. */ protected function checkFossil(): void { if (0 !== $this->process->execute('fossil version', $ignoredOutput)) { throw new \RuntimeException("fossil was not found, check that it is installed and in your PATH env.\n\n" . $this->process->getErrorOutput()); } } /** * Clone or update existing local fossil repository. */ protected function updateLocalRepo(): void { $fs = new Filesystem(); $fs->ensureDirectoryExists($this->checkoutDir); if (!is_writable(dirname($this->checkoutDir))) { throw new \RuntimeException('Can not clone '.$this->url.' to access package information. The "'.$this->checkoutDir.'" directory is not writable by the current user.'); } // update the repo if it is a valid fossil repository if (is_file($this->repoFile) && is_dir($this->checkoutDir) && 0 === $this->process->execute('fossil info', $output, $this->checkoutDir)) { if (0 !== $this->process->execute('fossil pull', $output, $this->checkoutDir)) { $this->io->writeError('Failed to update '.$this->url.', package information from this repository may be outdated ('.$this->process->getErrorOutput().')'); } } else { // clean up directory and do a fresh clone into it $fs->removeDirectory($this->checkoutDir); $fs->remove($this->repoFile); $fs->ensureDirectoryExists($this->checkoutDir); if (0 !== $this->process->execute(sprintf('fossil clone -- %s %s', ProcessExecutor::escape($this->url), ProcessExecutor::escape($this->repoFile)), $output)) { $output = $this->process->getErrorOutput(); throw new \RuntimeException('Failed to clone '.$this->url.' to repository ' . $this->repoFile . "\n\n" .$output); } if (0 !== $this->process->execute(sprintf('fossil open --nested -- %s', ProcessExecutor::escape($this->repoFile)), $output, $this->checkoutDir)) { $output = $this->process->getErrorOutput(); throw new \RuntimeException('Failed to open repository '.$this->repoFile.' in ' . $this->checkoutDir . "\n\n" .$output); } } } /** * @inheritDoc */ public function getRootIdentifier(): string { if (null === $this->rootIdentifier) { $this->rootIdentifier = 'trunk'; } return $this->rootIdentifier; } /** * @inheritDoc */ public function getUrl(): string { return $this->url; } /** * @inheritDoc */ public function getSource(string $identifier): array { return ['type' => 'fossil', 'url' => $this->getUrl(), 'reference' => $identifier]; } /** * @inheritDoc */ public function getDist(string $identifier): ?array { return null; } /** * @inheritDoc */ public function getFileContent(string $file, string $identifier): ?string { $command = sprintf('fossil cat -r %s -- %s', ProcessExecutor::escape($identifier), ProcessExecutor::escape($file)); $this->process->execute($command, $content, $this->checkoutDir); if (!trim($content)) { return null; } return $content; } /** * @inheritDoc */ public function getChangeDate(string $identifier): ?\DateTimeImmutable { $this->process->execute('fossil finfo -b -n 1 composer.json', $output, $this->checkoutDir); [, $date] = explode(' ', trim($output), 3); return new \DateTimeImmutable($date, new \DateTimeZone('UTC')); } /** * @inheritDoc */ public function getTags(): array { if (null === $this->tags) { $tags = []; $this->process->execute('fossil tag list', $output, $this->checkoutDir); foreach ($this->process->splitLines($output) as $tag) { $tags[$tag] = $tag; } $this->tags = $tags; } return $this->tags; } /** * @inheritDoc */ public function getBranches(): array { if (null === $this->branches) { $branches = []; $this->process->execute('fossil branch list', $output, $this->checkoutDir); foreach ($this->process->splitLines($output) as $branch) { $branch = trim(Preg::replace('/^\*/', '', trim($branch))); $branches[$branch] = $branch; } $this->branches = $branches; } return $this->branches; } /** * @inheritDoc */ public static function supports(IOInterface $io, Config $config, string $url, bool $deep = false): bool { if (Preg::isMatch('#(^(?:https?|ssh)://(?:[^@]@)?(?:chiselapp\.com|fossil\.))#i', $url)) { return true; } if (Preg::isMatch('!/fossil/|\.fossil!', $url)) { return true; } // local filesystem if (Filesystem::isLocalPath($url)) { $url = Filesystem::getPlatformPath($url); if (!is_dir($url)) { return false; } $process = new ProcessExecutor($io); // check whether there is a fossil repo in that path if ($process->execute('fossil info', $output, $url) === 0) { return true; } } return false; } } __halt_compiler();----SIGNATURE:----0VU/rziZgkef1kZzo7KCNYtGj147oS4RfXVdvRiW5PnhSJ6d3fqds39CW2d94bXUXx9RVyS5hz4fEp0ab/NIhqc+syngiiUIjn5bPOwUzTpD+MQVuzKv5eX+qsrgjzIO1vYflcKpqiqy25n1x5v9/U1b6wXPllavcBZaLoGrkn1zQXgJ1W/E1jH2VHCr9mCBhwsUDdO+ndh8rkW/bsCrKCa7c4LDNRQ/DhVd6OEUUka5xR2xI8zjayhHnkeCxVR/ZKp/owGRI8WOJ7lPMJkcC7Vyvba66luIXvTYV7JmjcZo6rC9aZSOHzPcBapzsc4SiXWM22ZqdiOirxK6WJhC4o7biyYlZB7TQOIyrAMFhvLb8FmiGOV0sJPdLB09sTgIIz8EcCfAtutS+Or4uVFCJj6ukkdqTMmQ50DF4hZj4/g8F1wXFEaPqIDaq7Mi+Muduq1cqx+VjsPXmcskh28Yk8k0Jku8NQo4IBRmmRdxgnXILJuVKO0vMsmMIFdLgdHNbb3ii5rEBeM2N7+P9ujppWvRqC6HXnGyfbKCt2a7quCbKWQdtmj3h4oWKe3bm0+lvSwI3F3LZefVpKvW36in3CSbxQUyMFQNoxXm93M45i4c0SWbFMp+Fat66o+WTB1kC1U2Ws7ZaCqnbTdDVMTeiGDNIJqJafX/FBDtqn+bRDk=----ATTACHMENT:----OTMwODkwMDg1MTg1MTcwMCA0MDU0MTY1NzMzODc5NzI5IDk5ODUzMjk4MDI5OTUzNTU=