Skip to content

Commit

Permalink
cleanup installed.json after deleting files
Browse files Browse the repository at this point in the history
  • Loading branch information
BrianHenryIE committed Apr 25, 2024
1 parent f72148e commit f53236b
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 0 deletions.
51 changes: 51 additions & 0 deletions src/Cleanup.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
namespace BrianHenryIE\Strauss;

use BrianHenryIE\Strauss\Composer\Extra\StraussConfig;
use Composer\Json\JsonFile;
use FilesystemIterator;
use League\Flysystem\Filesystem;
use League\Flysystem\Local\LocalFilesystemAdapter;
Expand Down Expand Up @@ -123,6 +124,8 @@ function (string $path): string {
}
}
}

$this->cleanupInstalledJson();
}

// TODO: Use Symfony or Flysystem functions.
Expand All @@ -132,6 +135,54 @@ protected function dirIsEmpty(string $dir): bool
return iterator_count($di) === 0;
}

/**
* Composer creates a file `vendor/composer/installed.json` which is uses when running `composer dump-autoload`.
* When `delete-vendor-packages` or `delete-vendor-files` is true, files and directories which have been deleted
* must also be removed from `installed.json` or Composer will throw an error.
*
* TODO: {@see self::cleanupFilesAutoloader()} might be redundant if we run this function and then run `composer dump-autoload`.
*/
public function cleanupInstalledJson(): void
{
$installedJsonFile = new JsonFile($this->workingDir . '/vendor/composer/installed.json');
if (!$installedJsonFile->exists()) {
return;
}
$installedJsonArray = $installedJsonFile->read();

foreach ($installedJsonArray['packages'] as $key => $package) {
$packageDir = $this->workingDir . $this->vendorDirectory . ltrim($package['install-path'], '.');
$autoload_key = $package['autoload'];
foreach ($autoload_key as $type => $autoload) {
switch ($type) {
case 'psr-4':
foreach ($autoload_key[$type] as $namespace => $dirs) {
if (is_array($dirs)) {
$autoload_key[$type][$namespace] = array_filter($dirs, function ($dir) use ($packageDir) {
$dir = $packageDir . $dir;
return is_readable($dir);
});
} else {
$dir = $packageDir . $dirs;
if (! is_readable($dir)) {
unset($autoload_key[$type][$namespace]);
}
}
}
break;
default: // files, classmap
$autoload_key[$type] = array_filter($autoload, function ($file) use ($packageDir) {
$filename = $packageDir . $file;
return file_exists($packageDir . $file);
});
break;
}
}
$installedJsonArray['packages'][$key]['autoload'] = array_filter($autoload_key);
}
$installedJsonFile->write($installedJsonArray);
}

/**
* After files are deleted, remove them from the Composer files autoloaders.
*
Expand Down
66 changes: 66 additions & 0 deletions tests/Issues/StraussIssue87Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php
/**
* Strauss does not remove namespaced classes from the composer classmap files when optimize-autoloader is enabled
*
* @see https://github.com/BrianHenryIE/strauss/issues/87
*/

namespace BrianHenryIE\Strauss\Tests\Issues;

use BrianHenryIE\Strauss\Console\Commands\Compose;
use BrianHenryIE\Strauss\Tests\Integration\Util\IntegrationTestCase;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
* @package BrianHenryIE\Strauss\Tests\Issues
* @coversNothing
*/
class StraussIssue87Test extends IntegrationTestCase
{
public function test_autoload_classmap()
{

$composerJsonString = <<<'EOD'
{
"require": {
"psr/container": "^1.1"
},
"extra": {
"strauss": {
"target_directory": "vendor-prefixed",
"classmap_prefix": "Class_Prefix_",
"constant_prefix": "Constant_",
"namespace_prefix": "New\\Namespace",
"delete_vendor_files": true,
"packages": [
"psr/container"
]
}
}
}
EOD;

chdir($this->testsWorkingDir);

file_put_contents($this->testsWorkingDir . '/composer.json', $composerJsonString);

exec('composer install');
exec('composer dump-autoload --optimize');

$autoload_classmap_php_string = file_get_contents($this->testsWorkingDir . '/vendor/composer/autoload_classmap.php');
self::assertStringContainsString("'Psr\\\\Container\\\\ContainerExceptionInterface' => \$vendorDir . '/psr/container/src/ContainerExceptionInterface.php',", $autoload_classmap_php_string);

$inputInterfaceMock = $this->createMock(InputInterface::class);
$outputInterfaceMock = $this->createMock(OutputInterface::class);

$strauss = new Compose();

$result = $strauss->run($inputInterfaceMock, $outputInterfaceMock);

exec('composer dump-autoload');

$autoload_classmap_php_string = file_get_contents($this->testsWorkingDir . '/vendor/composer/autoload_classmap.php');
self::assertStringNotContainsString("'Psr\\\\Container\\\\ContainerExceptionInterface' => \$vendorDir . '/psr/container/src/ContainerExceptionInterface.php',", $autoload_classmap_php_string);
}
}
55 changes: 55 additions & 0 deletions tests/Issues/StraussIssue93Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php
/**
* Cleanup vendor/composer/installed.json after delete-vendor-directories
*
* @see https://github.com/BrianHenryIE/strauss/issues/93#issuecomment-2043919370
*/

namespace BrianHenryIE\Strauss\Tests\Issues;

use BrianHenryIE\Strauss\Console\Commands\Compose;
use BrianHenryIE\Strauss\Tests\Integration\Util\IntegrationTestCase;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
* @package BrianHenryIE\Strauss\Tests\Issues
* @coversNothing
*/
class StraussIssue93Test extends IntegrationTestCase
{
public function test_removes_entries_from_installed_json()
{
$composerJsonString = <<<'EOD'
{
"name": "strauss/issue93",
"require": {
"symfony/polyfill-php80": "v1.29.0"
},
"extra": {
"strauss": {
"namespace_prefix": "Strauss\\Issue93\\",
"delete_vendor_files": true
}
}
}
EOD;

chdir($this->testsWorkingDir);

file_put_contents($this->testsWorkingDir . '/composer.json', $composerJsonString);

exec('composer install');

$inputInterfaceMock = $this->createMock(InputInterface::class);
$outputInterfaceMock = $this->createMock(OutputInterface::class);

$strauss = new Compose();

$strauss->run($inputInterfaceMock, $outputInterfaceMock);

exec('composer dump-autoload', $output, $result_code);

self::assertEquals(0, $result_code);
}
}

0 comments on commit f53236b

Please sign in to comment.