Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 25 additions & 16 deletions src/Documentation/Git/Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@

namespace Synapse\Documentation\Git;

use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RuntimeException;
use UnexpectedValueException;

/**
* Represents a git repository for documentation
Expand Down Expand Up @@ -103,30 +106,36 @@ public function getMarkdownFiles(): array
$searchPath .= DS . str_replace('/', DS, $this->root);
}

if (!is_dir($searchPath)) {
if (!is_dir($searchPath) || !is_readable($searchPath)) {
return [];
}

$command = sprintf(
'find %s -type f -name "*.md" 2>/dev/null',
escapeshellarg($searchPath),
);

$output = [];
exec($command, $output);

$files = [];
$pathPrefix = $this->path . DS;
$pathPrefixLen = strlen($pathPrefix);

foreach ($output as $file) {
// Convert absolute path to relative path from repo root
if (str_starts_with($file, $pathPrefix)) {
$relativePath = substr($file, $pathPrefixLen);
// Normalize directory separators
$relativePath = str_replace(DS, '/', $relativePath);
$files[] = $relativePath;
try {
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
$searchPath,
RecursiveDirectoryIterator::SKIP_DOTS,
),
);

foreach ($iterator as $file) {
if ($file->isFile() && $file->getExtension() === 'md') {
$absolutePath = $file->getPathname();
if (str_starts_with($absolutePath, $pathPrefix)) {
$relativePath = substr($absolutePath, $pathPrefixLen);
$relativePath = str_replace(DS, '/', $relativePath);
$files[] = $relativePath;
}
}
}
} catch (UnexpectedValueException $unexpectedValueException) {
// Permission denied or unreadable subdirectory encountered
// Return files collected so far to allow partial indexing
return $files;
}

return $files;
Expand Down
31 changes: 31 additions & 0 deletions tests/TestCase/Documentation/Git/RepositoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -537,4 +537,35 @@ public function testMultiplePullsTracked(): void
$repository->pull();
$this->assertEquals(3, $this->gitAdapter->getPullCount($repoPath));
}

/**
* Test getMarkdownFiles normalizes path separators to forward slashes
*
* Verifies that the RecursiveDirectoryIterator implementation returns
* paths with forward slashes regardless of the operating system.
*/
public function testGetMarkdownFilesNormalizesPathSeparators(): void
{
$repoPath = $this->testDir . 'test-repo';
mkdir($repoPath . DS . '.git', 0755, true);
mkdir($repoPath . DS . 'docs' . DS . 'guides' . DS . 'advanced', 0755, true);

file_put_contents($repoPath . DS . 'docs' . DS . 'guides' . DS . 'advanced' . DS . 'tips.md', '# Tips');

$repository = new Repository(
url: 'https://github.com/test/repo.git',
branch: 'main',
path: $repoPath,
gitAdapter: $this->gitAdapter,
);

$files = $repository->getMarkdownFiles();

// All paths should use forward slashes, never backslashes
foreach ($files as $file) {
$this->assertStringNotContainsString('\\', $file, 'Path should not contain backslashes: ' . $file);
}

$this->assertContains('docs/guides/advanced/tips.md', $files);
}
}
Loading