Skip to content
Snippets Groups Projects
Commit bd2ce8e4 authored by Wim Leers's avatar Wim Leers Committed by Adam G-H
Browse files

Issue #3321933 by omkar.podey, Wim Leers, tedbow, yash.rode, phenaproxima:...

Issue #3321933 by omkar.podey, Wim Leers, tedbow, yash.rode, phenaproxima: Remove dependency on symfony/finder
parent 431d5344
No related branches found
No related tags found
No related merge requests found
......@@ -16,8 +16,7 @@
"php-tuf/composer-stager": "^1.2",
"composer/composer": "^2.2.12 || ^2.3.5",
"composer-runtime-api": "^2.1",
"symfony/config": "^4.4 || ^6.1",
"symfony/finder": "^4.4 || ^6.1"
"symfony/config": "^4.4 || ^6.1"
},
"scripts": {
"phpcbf": "scripts/phpcbf.sh",
......
......@@ -8,7 +8,6 @@ use Drupal\Core\File\FileSystemInterface;
use Drupal\package_manager\Event\CollectIgnoredPathsEvent;
use Drupal\package_manager\PathLocator;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Finder\Finder;
/**
* Excludes .git directories from stage operations.
......@@ -50,16 +49,6 @@ final class GitExcluder implements EventSubscriberInterface {
* The event object.
*/
public function excludeGitDirectories(CollectIgnoredPathsEvent $event): void {
// Find all .git directories in the project. We cannot do this with
// FileSystemInterface::scanDirectory() because it unconditionally excludes
// anything starting with a dot.
$finder = Finder::create()
->in($this->pathLocator->getProjectRoot())
->directories()
->name('.git')
->ignoreVCS(FALSE)
->ignoreDotFiles(FALSE);
$paths_to_exclude = [];
$installed_paths = [];
......@@ -70,13 +59,14 @@ final class GitExcluder implements EventSubscriberInterface {
$installed_paths[] = $this->fileSystem->realpath($package_data['install_path']);
}
}
foreach ($finder as $git_directory) {
$paths = $this->scanForDirectoriesByName('.git');
foreach ($paths as $git_directory) {
// Don't exclude any `.git` directory that is directly under an installed
// package's path, since it means Composer probably installed that package
// from source and therefore needs the `.git` directory in order to update
// the package.
if (!in_array(dirname((string) $git_directory), $installed_paths, TRUE)) {
$paths_to_exclude[] = $git_directory->getPathname();
if (!in_array($git_directory, $installed_paths, TRUE)) {
$paths_to_exclude[] = $git_directory;
}
}
$this->excludeInProjectRoot($event, $paths_to_exclude);
......
......@@ -7,7 +7,6 @@ namespace Drupal\package_manager\PathExcluder;
use Drupal\package_manager\Event\CollectIgnoredPathsEvent;
use Drupal\package_manager\PathLocator;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Finder\Finder;
/**
* Excludes node_modules files from stage directories.
......@@ -38,16 +37,7 @@ class NodeModulesExcluder implements EventSubscriberInterface {
* The event object.
*/
public function excludeNodeModulesFiles(CollectIgnoredPathsEvent $event): void {
$finder = Finder::create()
->in($this->pathLocator->getProjectRoot())
->directories()
->name('node_modules')
->ignoreVCS(FALSE)
->ignoreDotFiles(FALSE);
$paths = [];
foreach ($finder as $directory) {
$paths[] = $directory->getPathname();
}
$paths = $this->scanForDirectoriesByName('node_modules');
$this->excludeInProjectRoot($event, $paths);
}
......
......@@ -69,4 +69,24 @@ trait PathExclusionsTrait {
}
}
/**
* Finds all directories in the project root matching the given name.
*
* @param string $directory_name
* The directory name to scan for.
*
* @return string[]
* All discovered absolute paths matching the given directory name.
*/
protected function scanForDirectoriesByName(string $directory_name): array {
$flags = \FilesystemIterator::UNIX_PATHS;
$flags |= \FilesystemIterator::CURRENT_AS_SELF;
$directories_tree = new \RecursiveDirectoryIterator($this->pathLocator->getProjectRoot(), $flags);
$filtered_directories = new \RecursiveIteratorIterator($directories_tree, \RecursiveIteratorIterator::SELF_FIRST);
$matched_directories = new \CallbackFilterIterator($filtered_directories,
fn (\RecursiveDirectoryIterator $current) => $current->isDir() && $current->getFilename() === $directory_name
);
return array_keys(iterator_to_array($matched_directories));
}
}
......@@ -4,11 +4,11 @@ declare(strict_types = 1);
namespace Drupal\package_manager\Validator;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\package_manager\Event\PreApplyEvent;
use Drupal\package_manager\PathLocator;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Finder\Finder;
/**
* Validates the stage does not have duplicate info.yml not present in active.
......@@ -86,47 +86,35 @@ class DuplicateInfoFileValidator implements EventSubscriberInterface {
* Array of count of info.yml files in the directory keyed by file name.
*/
protected function findInfoFiles(string $dir): array {
$info_files_finder = Finder::create()
->in($dir)
->ignoreUnreadableDirs()
->name('*.info.yml');
$info_files = [];
/** @var \Symfony\Component\Finder\SplFileInfo $info_file */
foreach (iterator_to_array($info_files_finder) as $info_file) {
if ($this->skipInfoFile($info_file->getPath())) {
continue;
// Use the official extension discovery mechanism, but tweak it, because by
// default it resolves duplicates.
// @see \Drupal\Core\Extension\ExtensionDiscovery::process()
$duplicate_aware_extension_discovery = new class($dir, FALSE, []) extends ExtensionDiscovery {
/**
* {@inheritdoc}
*/
protected function process(array $all_files) {
// Unlike parent implementation: no processing, to retain duplicates.
return $all_files;
}
$file_name = $info_file->getFilename();
};
// Scan all 4 extension types, explicitly ignoring tests.
$extension_info_files = array_merge(
array_keys($duplicate_aware_extension_discovery->scan('module', FALSE)),
array_keys($duplicate_aware_extension_discovery->scan('theme', FALSE)),
array_keys($duplicate_aware_extension_discovery->scan('profile', FALSE)),
array_keys($duplicate_aware_extension_discovery->scan('theme_engine', FALSE)),
);
$info_files = [];
foreach ($extension_info_files as $info_file) {
$file_name = basename($info_file);
$info_files[$file_name] = ($info_files[$file_name] ?? 0) + 1;
}
return $info_files;
}
/**
* Determines if an info.yml file should be skipped.
*
* @param string $info_file_path
* The path of the info.yml file.
*
* @return bool
* TRUE if the info.yml file should be skipped, FALSE otherwise.
*/
private function skipInfoFile(string $info_file_path): bool {
$directories_to_skip = [
DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'fixtures',
DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'modules',
DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'themes',
DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'profiles',
];
foreach ($directories_to_skip as $directory_to_skip) {
// Skipping info.yml files in tests/fixtures, tests/modules, tests/themes,
// tests/profiles because Drupal will not scan these directories when
// doing extension discovery.
if (str_contains($info_file_path, $directory_to_skip)) {
return TRUE;
}
}
return FALSE;
}
}
......@@ -124,15 +124,15 @@ class DuplicateInfoFileValidatorTest extends PackageManagerKernelTestBase {
],
'Multiple duplicate info.yml files in stage' => [
[
'/module1.info.yml',
'/module2.info.yml',
'/modules/module1/module1.info.yml',
'/modules/module2/module2.info.yml',
],
[
'/module1.info.yml',
'/modules/module1.info.yml',
'/module2.info.yml',
'/modules/module2.info.yml',
'/module2/module2.info.yml',
'/modules/module1/module1.info.yml',
'/modules/module2/module2.info.yml',
'/modules/foo/module1.info.yml',
'/modules/bar/module2.info.yml',
'/modules/baz/module2.info.yml',
],
[
ValidationResult::createError([
......@@ -146,11 +146,11 @@ class DuplicateInfoFileValidatorTest extends PackageManagerKernelTestBase {
'Multiple duplicate info.yml files in stage not present in active' => [
[],
[
'/module1.info.yml',
'/modules/module1.info.yml',
'/module2.info.yml',
'/modules/module2.info.yml',
'/module2/module2.info.yml',
'/modules/module1/module1.info.yml',
'/modules/module2/module2.info.yml',
'/modules/foo/module1.info.yml',
'/modules/bar/module2.info.yml',
'/modules/baz/module2.info.yml',
],
[
ValidationResult::createError([
......@@ -163,14 +163,14 @@ class DuplicateInfoFileValidatorTest extends PackageManagerKernelTestBase {
],
'Multiple duplicate info.yml files in stage with one info.yml file not present in active' => [
[
'/module1.info.yml',
'/modules/module1/module1.info.yml',
],
[
'/module1.info.yml',
'/modules/module1.info.yml',
'/module2.info.yml',
'/modules/module2.info.yml',
'/module2/module2.info.yml',
'/modules/module1/module1.info.yml',
'/modules/module2/module2.info.yml',
'/modules/foo/module1.info.yml',
'/modules/bar/module2.info.yml',
'/modules/baz/module2.info.yml',
],
[
ValidationResult::createError([
......@@ -236,7 +236,7 @@ class DuplicateInfoFileValidatorTest extends PackageManagerKernelTestBase {
if (!file_exists($file_dir)) {
$fs->mkdir($root_directory . $file_dir);
}
file_put_contents($root_directory . $file_path, ' ');
file_put_contents($root_directory . $file_path, "name: SOME MODULE\ntype: module\n");
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment