mirror of
https://github.com/wallabag/wallabag.git
synced 2024-11-26 02:51:04 +00:00
Improve install command & add test
Also add fixtures for Config InstallCommand now check if database, schema are here and ask the user what to do (keep or trash & re-create)
This commit is contained in:
parent
0bd2cb1ecd
commit
0bf99bb144
4 changed files with 333 additions and 83 deletions
|
@ -4,134 +4,194 @@ namespace Wallabag\CoreBundle\Command;
|
|||
|
||||
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Output\NullOutput;
|
||||
use Wallabag\CoreBundle\Entity\User;
|
||||
use Wallabag\CoreBundle\Entity\Config;
|
||||
|
||||
class InstallCommand extends ContainerAwareCommand
|
||||
{
|
||||
/**
|
||||
* @var InputInterface
|
||||
*/
|
||||
protected $defaultInput;
|
||||
|
||||
/**
|
||||
* @var OutputInterface
|
||||
*/
|
||||
protected $defaultOutput;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('wallabag:install')
|
||||
->setDescription('Wallabag installer.')
|
||||
->addOption(
|
||||
'reset',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'Reset current database'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$output->writeln('<info>Installing Wallabag.</info>');
|
||||
$this->defaultInput = $input;
|
||||
$this->defaultOutput = $output;
|
||||
|
||||
$output->writeln('<info>Installing Wallabag...</info>');
|
||||
$output->writeln('');
|
||||
|
||||
$this
|
||||
->checkStep($output)
|
||||
->setupStep($input, $output)
|
||||
->checkRequirements()
|
||||
->setupDatabase()
|
||||
->setupAdmin()
|
||||
->setupAsset()
|
||||
;
|
||||
|
||||
$output->writeln('<info>Wallabag has been successfully installed.</info>');
|
||||
$output->writeln('<comment>Just execute `php app/console server:run` for using wallabag: http://localhost:8000</comment>');
|
||||
}
|
||||
|
||||
protected function checkStep(OutputInterface $output)
|
||||
protected function checkRequirements()
|
||||
{
|
||||
$output->writeln('<info>Checking system requirements.</info>');
|
||||
$this->defaultOutput->writeln('<info><comment>Step 1 of 4.</comment> Checking system requirements.</info>');
|
||||
|
||||
$fulfilled = true;
|
||||
|
||||
// @TODO: find a better way to check requirements
|
||||
$output->writeln('<comment>Check PCRE</comment>');
|
||||
$label = '<comment>PCRE</comment>';
|
||||
if (extension_loaded('pcre')) {
|
||||
$output->writeln(' <info>OK</info>');
|
||||
$status = '<info>OK!</info>';
|
||||
$help = '';
|
||||
} else {
|
||||
$fulfilled = false;
|
||||
$output->writeln(' <error>ERROR</error>');
|
||||
$output->writeln('<comment>You should enabled PCRE extension</comment>');
|
||||
$status = '<error>ERROR!</error>';
|
||||
$help = 'You should enabled PCRE extension';
|
||||
}
|
||||
$rows[] = array($label, $status, $help);
|
||||
|
||||
$output->writeln('<comment>Check DOM</comment>');
|
||||
$label = '<comment>DOM</comment>';
|
||||
if (extension_loaded('DOM')) {
|
||||
$output->writeln(' <info>OK</info>');
|
||||
$status = '<info>OK!</info>';
|
||||
$help = '';
|
||||
} else {
|
||||
$fulfilled = false;
|
||||
$output->writeln(' <error>ERROR</error>');
|
||||
$output->writeln('<comment>You should enabled DOM extension</comment>');
|
||||
$status = '<error>ERROR!</error>';
|
||||
$help = 'You should enabled DOM extension';
|
||||
}
|
||||
$rows[] = array($label, $status, $help);
|
||||
|
||||
$this->getHelper('table')
|
||||
->setHeaders(array('Checked', 'Status', 'Recommendation'))
|
||||
->setRows($rows)
|
||||
->render($this->defaultOutput);
|
||||
|
||||
if (!$fulfilled) {
|
||||
throw new RuntimeException('Some system requirements are not fulfilled. Please check output messages and fix them.');
|
||||
}
|
||||
|
||||
$output->writeln('');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function setupStep(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$output->writeln('<info>Setting up database.</info>');
|
||||
|
||||
$this->setupDatabase($input, $output);
|
||||
|
||||
// if ($this->getHelperSet()->get('dialog')->askConfirmation($output, '<question>Load fixtures (Y/N)?</question>', false)) {
|
||||
// $this->setupFixtures($input, $output);
|
||||
// }
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<info>Administration setup.</info>');
|
||||
|
||||
$this->setupAdmin($output);
|
||||
|
||||
$output->writeln('');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function setupDatabase(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($this->getHelperSet()->get('dialog')->askConfirmation($output, '<question>Drop current database (Y/N)?</question>', true)) {
|
||||
$connection = $this->getContainer()->get('doctrine')->getConnection();
|
||||
$params = $connection->getParams();
|
||||
|
||||
$name = isset($params['path']) ? $params['path'] : (isset($params['dbname']) ? $params['dbname'] : false);
|
||||
unset($params['dbname']);
|
||||
|
||||
if (!isset($params['path'])) {
|
||||
$name = $connection->getDatabasePlatform()->quoteSingleIdentifier($name);
|
||||
}
|
||||
|
||||
$connection->getSchemaManager()->dropDatabase($name);
|
||||
throw new \RuntimeException('Some system requirements are not fulfilled. Please check output messages and fix them.');
|
||||
} else {
|
||||
throw new \Exception("Install setup stopped, database need to be dropped. Please backup your current one and re-launch the install command.");
|
||||
$this->defaultOutput->writeln('<info>Success! Your system can run Wallabag properly.</info>');
|
||||
}
|
||||
|
||||
$this->defaultOutput->writeln('');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function setupDatabase()
|
||||
{
|
||||
$this->defaultOutput->writeln('<info><comment>Step 2 of 4.</comment> Setting up database.</info>');
|
||||
|
||||
// user want to reset everything? Don't care about what is already here
|
||||
if (true === $this->defaultInput->getOption('reset')) {
|
||||
$this->defaultOutput->writeln('Droping database, creating database and schema');
|
||||
|
||||
$this
|
||||
->runCommand('doctrine:database:create', $input, $output)
|
||||
->runCommand('doctrine:schema:create', $input, $output)
|
||||
->runCommand('cache:clear', $input, $output)
|
||||
->runCommand('assets:install', $input, $output)
|
||||
->runCommand('assetic:dump', $input, $output)
|
||||
->runCommand('doctrine:database:drop', array('--force' => true))
|
||||
->runCommand('doctrine:database:create')
|
||||
->runCommand('doctrine:schema:create')
|
||||
;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (!$this->isDatabasePresent()) {
|
||||
$this->defaultOutput->writeln('Creating database and schema, clearing the cache');
|
||||
|
||||
$this
|
||||
->runCommand('doctrine:database:create')
|
||||
->runCommand('doctrine:schema:create')
|
||||
->runCommand('cache:clear')
|
||||
;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$dialog = $this->getHelper('dialog');
|
||||
|
||||
if ($dialog->askConfirmation($this->defaultOutput, '<question>It appears that your database already exists. Would you like to reset it? (y/N)</question> ', false)) {
|
||||
$this->defaultOutput->writeln('Droping database, creating database and schema');
|
||||
|
||||
$this
|
||||
->runCommand('doctrine:database:drop', array('--force' => true))
|
||||
->runCommand('doctrine:database:create')
|
||||
->runCommand('doctrine:schema:create')
|
||||
;
|
||||
} elseif ($this->isSchemaPresent()) {
|
||||
if ($dialog->askConfirmation($this->defaultOutput, '<question>Seems like your database contains schema. Do you want to reset it? (y/N)</question> ', false)) {
|
||||
$this->defaultOutput->writeln('Droping schema and creating schema');
|
||||
|
||||
$this
|
||||
->runCommand('doctrine:schema:drop', array('--force' => true))
|
||||
->runCommand('doctrine:schema:create')
|
||||
;
|
||||
}
|
||||
} else {
|
||||
$this->defaultOutput->writeln('Creating schema');
|
||||
|
||||
$this
|
||||
->runCommand('doctrine:schema:create')
|
||||
;
|
||||
}
|
||||
|
||||
protected function setupFixtures(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->defaultOutput->writeln('Clearing the cache');
|
||||
$this->runCommand('cache:clear');
|
||||
|
||||
/*
|
||||
if ($this->getHelperSet()->get('dialog')->askConfirmation($this->defaultOutput, '<question>Load fixtures (Y/N)?</question>', false)) {
|
||||
$doctrineConfig = $this->getContainer()->get('doctrine.orm.entity_manager')->getConnection()->getConfiguration();
|
||||
$logger = $doctrineConfig->getSQLLogger();
|
||||
// speed up fixture load
|
||||
$doctrineConfig->setSQLLogger(null);
|
||||
$this->runCommand('doctrine:fixtures:load', $input, $output);
|
||||
$this->runCommand('doctrine:fixtures:load');
|
||||
$doctrineConfig->setSQLLogger($logger);
|
||||
}
|
||||
*/
|
||||
|
||||
protected function setupAdmin(OutputInterface $output)
|
||||
$this->defaultOutput->writeln('');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function setupAdmin()
|
||||
{
|
||||
$this->defaultOutput->writeln('<info><comment>Step 3 of 4.</comment> Administration setup.</info>');
|
||||
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
|
||||
if (false === $dialog->askConfirmation($this->defaultOutput, '<question>Would you like to create a new user ? (y/N)</question>', true)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$em = $this->getContainer()->get('doctrine.orm.entity_manager');
|
||||
|
||||
$user = new User();
|
||||
$user->setUsername($dialog->ask($output, '<question>Username</question> <comment>(default: wallabag)</comment> :', 'wallabag'));
|
||||
$user->setPassword($dialog->ask($output, '<question>Password</question> <comment>(default: wallabag)</comment> :', 'wallabag'));
|
||||
$user->setEmail($dialog->ask($output, '<question>Email:</question>', ''));
|
||||
$user->setUsername($dialog->ask($this->defaultOutput, '<question>Username</question> <comment>(default: wallabag)</comment> :', 'wallabag'));
|
||||
$user->setPassword($dialog->ask($this->defaultOutput, '<question>Password</question> <comment>(default: wallabag)</comment> :', 'wallabag'));
|
||||
$user->setEmail($dialog->ask($this->defaultOutput, '<question>Email:</question>', ''));
|
||||
|
||||
$em->persist($user);
|
||||
|
||||
|
@ -141,16 +201,100 @@ class InstallCommand extends ContainerAwareCommand
|
|||
$config->setLanguage($this->getContainer()->getParameter('language'));
|
||||
|
||||
$em->persist($config);
|
||||
}
|
||||
|
||||
protected function runCommand($command, InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this
|
||||
->getApplication()
|
||||
->find($command)
|
||||
->run($input, $output)
|
||||
;
|
||||
$em->flush();
|
||||
|
||||
$this->defaultOutput->writeln('');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function setupAsset()
|
||||
{
|
||||
$this->defaultOutput->writeln('<info><comment>Step 4 of 4.</comment> Installing assets.</info>');
|
||||
|
||||
$this
|
||||
->runCommand('assets:install')
|
||||
->runCommand('assetic:dump')
|
||||
;
|
||||
|
||||
$this->defaultOutput->writeln('');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a command
|
||||
*
|
||||
* @param string $command
|
||||
* @param array $parameters Parameters to this command (usually 'force' => true)
|
||||
*/
|
||||
protected function runCommand($command, $parameters = array())
|
||||
{
|
||||
$parameters = array_merge(
|
||||
array('command' => $command),
|
||||
$parameters,
|
||||
array(
|
||||
'--no-debug' => true,
|
||||
'--env' => $this->defaultInput->getOption('env') ?: 'dev',
|
||||
)
|
||||
);
|
||||
|
||||
if ($this->defaultInput->getOption('no-interaction')) {
|
||||
$parameters = array_merge($parameters, array('--no-interaction' => true));
|
||||
}
|
||||
|
||||
$this->getApplication()->setAutoExit(false);
|
||||
$exitCode = $this->getApplication()->run(new ArrayInput($parameters), new NullOutput());
|
||||
|
||||
if (0 !== $exitCode) {
|
||||
$this->getApplication()->setAutoExit(true);
|
||||
|
||||
$errorMessage = sprintf('The command "%s" terminated with an error code: %u.', $command, $exitCode);
|
||||
$this->defaultOutput->writeln("<error>$errorMessage</error>");
|
||||
$exception = new \Exception($errorMessage, $exitCode);
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
// PDO does not always close the connection after Doctrine commands.
|
||||
// See https://github.com/symfony/symfony/issues/11750.
|
||||
$this->getContainer()->get('doctrine')->getManager()->getConnection()->close();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the database already exists
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function isDatabasePresent()
|
||||
{
|
||||
$databaseName = $this->getContainer()->getParameter('database_name');
|
||||
|
||||
try {
|
||||
$schemaManager = $this->getContainer()->get('doctrine')->getManager()->getConnection()->getSchemaManager();
|
||||
} catch (\Exception $exception) {
|
||||
if (false !== strpos($exception->getMessage(), sprintf("Unknown database '%s'", $databaseName))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
return in_array($databaseName, $schemaManager->listDatabases());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the schema is already created
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function isSchemaPresent()
|
||||
{
|
||||
$schemaManager = $this->getContainer()->get('doctrine')->getManager()->getConnection()->getSchemaManager();
|
||||
|
||||
return $schemaManager->tablesExist(array('entry'));
|
||||
}
|
||||
}
|
||||
|
|
45
src/Wallabag/CoreBundle/DataFixtures/ORM/LoadConfigData.php
Normal file
45
src/Wallabag/CoreBundle/DataFixtures/ORM/LoadConfigData.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\DataFixtures\ORM;
|
||||
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Wallabag\CoreBundle\Entity\Config;
|
||||
|
||||
class LoadConfigData extends AbstractFixture implements OrderedFixtureInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function load(ObjectManager $manager)
|
||||
{
|
||||
$adminConfig = new Config($this->getReference('admin-user'));
|
||||
$adminConfig->setTheme('baggy');
|
||||
$adminConfig->setItemsPerPage(30);
|
||||
$adminConfig->setLanguage('en_US');
|
||||
|
||||
$manager->persist($adminConfig);
|
||||
|
||||
$this->addReference('admin-config', $adminConfig);
|
||||
|
||||
$bobConfig = new Config($this->getReference('bob-user'));
|
||||
$bobConfig->setTheme('default');
|
||||
$bobConfig->setItemsPerPage(10);
|
||||
$bobConfig->setLanguage('fr_FR');
|
||||
|
||||
$manager->persist($bobConfig);
|
||||
|
||||
$this->addReference('bob-config', $bobConfig);
|
||||
|
||||
$manager->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getOrder()
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
}
|
|
@ -49,6 +49,6 @@ class LoadEntryData extends AbstractFixture implements OrderedFixtureInterface
|
|||
*/
|
||||
public function getOrder()
|
||||
{
|
||||
return 20;
|
||||
return 30;
|
||||
}
|
||||
}
|
||||
|
|
61
src/Wallabag/CoreBundle/Tests/Command/InstallCommandTest.php
Normal file
61
src/Wallabag/CoreBundle/Tests/Command/InstallCommandTest.php
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Tests\Command;
|
||||
|
||||
use Wallabag\CoreBundle\Tests\WallabagTestCase;
|
||||
use Wallabag\CoreBundle\Command\InstallCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Output\NullOutput;
|
||||
|
||||
class InstallCommandTest extends WallabagTestCase
|
||||
{
|
||||
public function tearDown()
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
$application = new Application(static::$kernel);
|
||||
$application->setAutoExit(false);
|
||||
|
||||
$code = $application->run(new ArrayInput(array(
|
||||
'command' => 'doctrine:fixtures:load',
|
||||
'--no-interaction' => true,
|
||||
'--env' => 'test',
|
||||
)), new NullOutput());
|
||||
}
|
||||
|
||||
public function testRunInstallCommand()
|
||||
{
|
||||
$this->container = static::$kernel->getContainer();
|
||||
|
||||
$application = new Application(static::$kernel);
|
||||
$application->add(new InstallCommand());
|
||||
|
||||
$command = $application->find('wallabag:install');
|
||||
|
||||
// We mock the DialogHelper
|
||||
$dialog = $this->getMockBuilder('Symfony\Component\Console\Helper\DialogHelper')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$dialog->expects($this->any())
|
||||
->method('ask')
|
||||
->will($this->returnValue('test'));
|
||||
$dialog->expects($this->any())
|
||||
->method('askConfirmation')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
// We override the standard helper with our mock
|
||||
$command->getHelperSet()->set($dialog, 'dialog');
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute(array(
|
||||
'command' => $command->getName()
|
||||
));
|
||||
|
||||
$this->assertContains('Step 1 of 4. Checking system requirements.', $tester->getDisplay());
|
||||
$this->assertContains('Step 2 of 4. Setting up database.', $tester->getDisplay());
|
||||
$this->assertContains('Step 3 of 4. Administration setup.', $tester->getDisplay());
|
||||
$this->assertContains('Step 4 of 4. Installing assets.', $tester->getDisplay());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue