Magento 2 bug: «bin/magento module:enable» fails with the «The file "/composer.json" doesn't exist» message when a Composer package contains multiple Magento modules

Where is it fail?

Magento\Framework\Filesystem\File\Read::assertValid()

https://github.com/magento/magento2/blob/2.2.0-RC1.5/lib/internal/Magento/Framework/Filesystem/File/Read.php#L66-L79

Magento\Framework\Module\PackageInfo::load()

https://github.com/magento/magento2/blob/2.2.0-RC1.5/lib/internal/Magento/Framework/Module/PackageInfo.php#L73-L114

How to fix?

I have added a workaround to the 2.9.9 version of the mage2pro/core package:

https://github.com/mage2pro/core/commit/cd3fc519

To fix the issue just upgrade your extensions.

The defect method is \Magento\Framework\Module\Dir\Reader::getFiles():

By the way, in my 2 years Magento 2 experience, the filesystem handling is one of the less quality (one of the most buggy) Magento 2 parts.

Particularly, Magento 2 uses this method to find out all the composer.json files of all the installed modules.
In this case, the $filename input argument has the composer.json value.
If a Composer package contains multiple Magento 2 modules in subfolders (as mage2pro/core), then the following code line works for such modules incorrectly and returns an empty string:

The next code line ignores the incorrect result of the previous line and concatenates in with the /composer.json string:

So the $file is /composer.json.
The following lines is an ugly attempt to detect the existence of the $file:

It is incorrect, because /composer.json is really interpreted here as the root Magento 2 composer.json file, and the detection result is true, but actually it should be false.

How to fix it manually without my official patch (I do not recommend this method!)

Locate the following code block (it is explained above):

Replace it with the folllowing one:

if ($moduleSubDir) {
	$file = $moduleSubDir . '/' . $filename;
	$directoryRead = $this->readFactory->create($moduleSubDir);
	$path = $directoryRead->getRelativePath($file);
	if ($directoryRead->isExist($path)) {
		$result[] = $file;
	}            	
}

Today I have fixed a similar issue in the mage2pro/core package with Magento Marketplace:

https://github.com/mage2pro/core/issues/67