Skip to content

Fixed issue #19481: After composer installation sample data can't be installed from command line #27481

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 5, 2020
134 changes: 107 additions & 27 deletions app/code/Magento/SampleData/Console/Command/SampleDataDeployCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,63 +7,83 @@
namespace Magento\SampleData\Console\Command;

use Composer\Console\Application;
use Composer\Console\ApplicationFactory;
use Exception;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Console\Cli;
use Magento\Framework\Exception\FileSystemException;
use Magento\Framework\Exception\InvalidArgumentException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Filesystem;
use Magento\Framework\Serialize\Serializer\Json;
use Magento\SampleData\Model\Dependency;
use Magento\Setup\Model\PackagesAuth;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\ArrayInputFactory;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Command for deployment of Sample Data
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class SampleDataDeployCommand extends Command
{
const OPTION_NO_UPDATE = 'no-update';

/**
* @var \Magento\Framework\Filesystem
* @var Filesystem
*/
private $filesystem;

/**
* @var \Magento\SampleData\Model\Dependency
* @var Dependency
*/
private $sampleDataDependency;

/**
* @var \Symfony\Component\Console\Input\ArrayInputFactory
* @var ArrayInputFactory
* @deprecated 100.1.0
*/
private $arrayInputFactory;

/**
* @var \Composer\Console\ApplicationFactory
* @var ApplicationFactory
*/
private $applicationFactory;

/**
* @param \Magento\Framework\Filesystem $filesystem
* @param \Magento\SampleData\Model\Dependency $sampleDataDependency
* @param \Symfony\Component\Console\Input\ArrayInputFactory $arrayInputFactory
* @param \Composer\Console\ApplicationFactory $applicationFactory
* @var Json
*/
private $serializer;

/**
* @param Filesystem $filesystem
* @param Dependency $sampleDataDependency
* @param ArrayInputFactory $arrayInputFactory
* @param ApplicationFactory $applicationFactory
* @param Json $serializer
*/
public function __construct(
\Magento\Framework\Filesystem $filesystem,
\Magento\SampleData\Model\Dependency $sampleDataDependency,
\Symfony\Component\Console\Input\ArrayInputFactory $arrayInputFactory,
\Composer\Console\ApplicationFactory $applicationFactory
Filesystem $filesystem,
Dependency $sampleDataDependency,
ArrayInputFactory $arrayInputFactory,
ApplicationFactory $applicationFactory,
Json $serializer
) {
$this->filesystem = $filesystem;
$this->sampleDataDependency = $sampleDataDependency;
$this->arrayInputFactory = $arrayInputFactory;
$this->applicationFactory = $applicationFactory;
$this->serializer = $serializer;
parent::__construct();
}

/**
* {@inheritdoc}
* @inheritdoc
*/
protected function configure()
{
Expand All @@ -79,15 +99,42 @@ protected function configure()
}

/**
* {@inheritdoc}
* @inheritdoc
*
* @param InputInterface $input
* @param OutputInterface $output
* @return int
* @throws FileSystemException
* @throws LocalizedException
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$rootJson = json_decode($this->filesystem->getDirectoryRead(DirectoryList::ROOT)->readFile("composer.json"));
if (!isset($rootJson->version)) {
// @codingStandardsIgnoreLine
$output->writeln('<info>' . 'Git installations must deploy sample data from GitHub; see https://devdocs.magento.com/guides/v2.3/install-gde/install/sample-data-after-clone.html for more information.' . '</info>');
return;
$rootJson = $this->serializer->unserialize(
$this->filesystem->getDirectoryRead(
DirectoryList::ROOT
)->readFile("composer.json")
);
if (!isset($rootJson['version'])) {
$magentoProductPackage = array_filter(
$rootJson['require'],
function ($package) {
return false !== strpos($package, 'magento/product-');
},
ARRAY_FILTER_USE_KEY
);
$version = reset($magentoProductPackage);
$output->writeln(
'<info>' .
// @codingStandardsIgnoreLine
'We don\'t recommend to remove the "version" field from your composer.json; see https://getcomposer.org/doc/02-libraries.md#library-versioning for more information.' .
'</info>'
);
$restoreVersion = new ArrayInput([
'command' => 'config',
'setting-key' => 'version',
'setting-value' => [$version],
'--quiet' => 1
]);
}
$this->updateMemoryLimit();
$this->createAuthFile();
Expand All @@ -109,16 +156,28 @@ protected function execute(InputInterface $input, OutputInterface $output)
/** @var Application $application */
$application = $this->applicationFactory->create();
$application->setAutoExit(false);
if (!empty($restoreVersion)) {
$result = $application->run($restoreVersion, clone $output);
if ($result === 0) {
$output->writeln('<info>The field "version" has been restored.</info>');
}
}
$result = $application->run($commandInput, $output);
if ($result !== 0) {
$output->writeln(
'<info>' . 'There is an error during sample data deployment. Composer file will be reverted.'
. '</info>'
);
$application->resetComposer();

return Cli::RETURN_FAILURE;
}

return Cli::RETURN_SUCCESS;
} else {
$output->writeln('<info>' . 'There is no sample data for current set of modules.' . '</info>');

return Cli::RETURN_FAILURE;
}
}

Expand All @@ -128,7 +187,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
* We create auth.json with correct permissions instead of relying on Composer.
*
* @return void
* @throws \Exception
* @throws LocalizedException
*/
private function createAuthFile()
{
Expand All @@ -137,30 +196,51 @@ private function createAuthFile()
if (!$directory->isExist(PackagesAuth::PATH_TO_AUTH_FILE)) {
try {
$directory->writeFile(PackagesAuth::PATH_TO_AUTH_FILE, '{}');
} catch (\Exception $e) {
$message = 'Error in writing Auth file '
. $directory->getAbsolutePath(PackagesAuth::PATH_TO_AUTH_FILE)
. '. Please check permissions for writing.';
throw new \Exception($message);
} catch (Exception $e) {
throw new LocalizedException(__(
'Error in writing Auth file %1. Please check permissions for writing.',
$directory->getAbsolutePath(PackagesAuth::PATH_TO_AUTH_FILE)
));
}
}
}

/**
* Updates PHP memory limit
*
* @throws InvalidArgumentException
* @return void
*/
private function updateMemoryLimit()
{
if (function_exists('ini_set')) {
@ini_set('display_errors', 1);
Copy link
Contributor Author

@andrewbess andrewbess Mar 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @lbajsarowicz
I changed @ini_set to ini_alter (that's the alias of ini_set) and added throwing an exception when ini_set returns an error.
Please check it.
Thank you in advance.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use // phpcs:ignore Magento2.Functions.DiscouragedFunction for the legacy code. ini_alter should be added to the discouraged list as well https://github.com/magento/magento-coding-standard/blob/develop/Magento2/Sniffs/Functions/DiscouragedFunctionSniff.php

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @lenaorobei
Thank you for your remark.
I have reverted ini_alter to ini_set (without @).
Also, today I am going to add all alias to discouraged functions

// phpcs:ignore Magento2.Functions.DiscouragedFunction
$result = ini_set('display_errors', 1);
if ($result === false) {
$error = error_get_last();
throw new InvalidArgumentException(__(
'Failed to set ini option display_errors to value 1. %1',
$error['message']
));
}
$memoryLimit = trim(ini_get('memory_limit'));
if ($memoryLimit != -1 && $this->getMemoryInBytes($memoryLimit) < 756 * 1024 * 1024) {
@ini_set('memory_limit', '756M');
// phpcs:ignore Magento2.Functions.DiscouragedFunction
$result = ini_set('memory_limit', '756M');
if ($result === false) {
$error = error_get_last();
throw new InvalidArgumentException(__(
'Failed to set ini option memory_limit to 756M. %1',
$error['message']
));
}
}
}
}

/**
* Retrieves the memory size in bytes
*
* @param string $value
* @return int
*/
Expand Down
Loading