diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f70dc88..0000000 --- a/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: php -php: - - 5.4 - - 5.5 - - 5.6 - - hhvm - - nightly diff --git a/README.md b/README.md index f15efed..6243442 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Working on Magento client sites typically requires a fresh copy of the productio Download the phar. ``` -wget https://github.com/meanbee/magedbm/releases/download/v.1.3.0/magedbm.phar +wget https://s3-eu-west-1.amazonaws.com/magedbm-releases/magedbm.phar ``` Make sure it's executable diff --git a/src/Meanbee/Magedbm/Application.php b/src/Meanbee/Magedbm/Application.php index 69f29fa..9d0bdce 100644 --- a/src/Meanbee/Magedbm/Application.php +++ b/src/Meanbee/Magedbm/Application.php @@ -7,14 +7,16 @@ use Meanbee\Magedbm\Command\ListCommand; use Meanbee\Magedbm\Command\PutCommand; -class Application extends \Symfony\Component\Console\Application { +class Application extends \Symfony\Component\Console\Application +{ const APP_NAME = "Magedbm"; const APP_VERSION = "1.0.0"; protected $autoloader; - public function __construct($autoloader = null) { + public function __construct($autoloader = null) + { parent::__construct(self::APP_NAME, self::APP_VERSION); if ($autoloader !== null) { @@ -28,11 +30,13 @@ public function __construct($autoloader = null) { $this->add(new PutCommand()); } - public function getAutoloader() { + public function getAutoloader() + { return $this->autoloader; } - public function setAutoloader($autoloader) { + public function setAutoloader($autoloader) + { $this->autoloader = $autoloader; return $this; diff --git a/src/Meanbee/Magedbm/Command/BaseCommand.php b/src/Meanbee/Magedbm/Command/BaseCommand.php index c48d35a..04d53b4 100644 --- a/src/Meanbee/Magedbm/Command/BaseCommand.php +++ b/src/Meanbee/Magedbm/Command/BaseCommand.php @@ -9,14 +9,15 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -class BaseCommand extends Command { +class BaseCommand extends Command +{ - const AWS_DIR_PATH = '/.aws'; - const AWS_CREDENTIALS_PATH = '/.aws/credentials'; - const AWS_CONFIG_PATH = '/.aws/config'; - const APP_DIR_PATH = '/.magedbm'; - const APP_CONFIG_PATH = '/.magedbm/config'; - const TMP_PATH = '/tmp/magedbm'; + const AWS_DIR_PATH = '/.aws'; + const AWS_CREDENTIALS_PATH = '/.aws/credentials'; + const AWS_CONFIG_PATH = '/.aws/config'; + const APP_DIR_PATH = '/.magedbm'; + const APP_CONFIG_PATH = '/.magedbm/config'; + const TMP_PATH = '/tmp/magedbm'; /** @var InputInterface $input */ protected $input; @@ -38,7 +39,8 @@ class BaseCommand extends Command { * * @return $this */ - public function setInput(InputInterface $input) { + public function setInput(InputInterface $input) + { $this->input = $input; return $this; @@ -49,7 +51,8 @@ public function setInput(InputInterface $input) { * * @return InputInterface */ - public function getInput() { + public function getInput() + { return $this->input; } @@ -60,7 +63,8 @@ public function getInput() { * * @return $this */ - public function setOutput(OutputInterface $output) { + public function setOutput(OutputInterface $output) + { $this->output = $output; return $this; @@ -71,7 +75,8 @@ public function setOutput(OutputInterface $output) { * * @return OutputInterface */ - public function getOutput() { + public function getOutput() + { return $this->output; } @@ -114,7 +119,7 @@ public function getS3Client($region = null) try { // Upload to S3. $this->s3Client = S3Client::factory(array( - 'region' => $region + 'region' => $region )); } catch (CredentialsException $e) { $this->getOutput()->writeln('AWS credentials failed'); @@ -137,7 +142,7 @@ public function getConfig(InputInterface $input) $config = $iniReader->readFile($this->getAppConfigPath()); $this->config = $config['default']; - foreach($input->getOptions() as $option => $value) { + foreach ($input->getOptions() as $option => $value) { if ($value) { $this->config[$option] = $value; } @@ -152,10 +157,11 @@ public function getConfig(InputInterface $input) } /** - * @param InputInterface $input + * @param InputInterface $input * @param OutputInterface $output */ - protected function initialize(InputInterface $input, OutputInterface $output) { + protected function initialize(InputInterface $input, OutputInterface $output) + { parent::initialize($input, $output); $this->setInput($input); @@ -201,7 +207,8 @@ protected function getAwsConfigPath() /** * Check for AWS Credentials */ - protected function validateConfiguration() { + protected function validateConfiguration() + { if ($this instanceof ConfigureCommand) { return true; } diff --git a/src/Meanbee/Magedbm/Command/ConfigureCommand.php b/src/Meanbee/Magedbm/Command/ConfigureCommand.php index 73e6081..db526c8 100644 --- a/src/Meanbee/Magedbm/Command/ConfigureCommand.php +++ b/src/Meanbee/Magedbm/Command/ConfigureCommand.php @@ -54,7 +54,7 @@ protected function configure() /** * Execute the command. * - * @param InputInterface $input + * @param InputInterface $input * @param OutputInterface $output * * @throws \Exception @@ -73,7 +73,7 @@ protected function execute(InputInterface $input, OutputInterface $output) mkdir($this->getAwsDirPath()); } - if(!is_writeable($this->getAwsDirPath())) { + if (!is_writeable($this->getAwsDirPath())) { $this->getOutput()->writeln('Unable to write AWS credentials. Please manually add to ~/.aws/credentials'); exit; } @@ -90,7 +90,7 @@ protected function execute(InputInterface $input, OutputInterface $output) if ($input->getOption('key') && $input->getOption('secret')) { $credentials = array( 'default' => array( - 'aws_access_key_id' => $input->getOption('key'), + 'aws_access_key_id' => $input->getOption('key'), 'aws_secret_access_key' => $input->getOption('secret') ) ); @@ -136,8 +136,9 @@ protected function execute(InputInterface $input, OutputInterface $output) public function isConfigured() { if (file_exists($this->getAwsCredentialsPath()) && file_exists($this->getAwsConfigPath()) && - file_exists($this->getAppConfigPath())) { - return true; + file_exists($this->getAppConfigPath()) + ) { + return true; } return false; diff --git a/src/Meanbee/Magedbm/Command/DeleteCommand.php b/src/Meanbee/Magedbm/Command/DeleteCommand.php index 25fcd00..1ba1ea9 100644 --- a/src/Meanbee/Magedbm/Command/DeleteCommand.php +++ b/src/Meanbee/Magedbm/Command/DeleteCommand.php @@ -46,7 +46,7 @@ protected function configure() /** * Execute the command. * - * @param InputInterface $input + * @param InputInterface $input * @param OutputInterface $output * * @throws \Exception diff --git a/src/Meanbee/Magedbm/Command/GetCommand.php b/src/Meanbee/Magedbm/Command/GetCommand.php index 0653031..1ef0157 100644 --- a/src/Meanbee/Magedbm/Command/GetCommand.php +++ b/src/Meanbee/Magedbm/Command/GetCommand.php @@ -63,7 +63,7 @@ protected function configure() /** * Execute the command. * - * @param InputInterface $input + * @param InputInterface $input * @param OutputInterface $output * * @throws \Exception @@ -78,7 +78,8 @@ protected function execute(InputInterface $input, OutputInterface $output) $output, 'Are you sure you wish to overwrite local database [y/n]?', false - )) { + ) + ) { return; } } @@ -151,7 +152,7 @@ protected function downloadBackup($file, $s3, $config, $input) try { $s3->getObject(array( 'Bucket' => $config['bucket'], - 'Key' => $input->getArgument('name') . '/' . $file, + 'Key' => $input->getArgument('name') . '/' . $file, 'SaveAs' => $this->getFilePath($file) )); } catch (NoSuchKeyException $e) { @@ -183,8 +184,8 @@ protected function backupImport($file, $input) } $params = array( - 'filename' => $this->getFilePath($file), - '--compression' => 'gzip', + 'filename' => $this->getFilePath($file), + '--compression' => 'gzip', ); if ($input->getOption('drop-tables')) { diff --git a/src/Meanbee/Magedbm/Command/ListCommand.php b/src/Meanbee/Magedbm/Command/ListCommand.php index d71b1e1..9d03e45 100644 --- a/src/Meanbee/Magedbm/Command/ListCommand.php +++ b/src/Meanbee/Magedbm/Command/ListCommand.php @@ -42,7 +42,7 @@ protected function configure() /** * Execute the command. * - * @param InputInterface $input + * @param InputInterface $input * @param OutputInterface $output * * @throws \Exception @@ -61,7 +61,7 @@ protected function execute(InputInterface $input, OutputInterface $output) foreach ($results as $item) { $itemKeyChunks = explode('/', $item['Key']); - $this->getOutput()->writeln(sprintf('%s %dMB', array_pop($itemKeyChunks) , $item['Size'] / 1024 / 1024)); + $this->getOutput()->writeln(sprintf('%s %dMB', array_pop($itemKeyChunks), $item['Size'] / 1024 / 1024)); } if (!$results->count()) { diff --git a/src/Meanbee/Magedbm/Command/PutCommand.php b/src/Meanbee/Magedbm/Command/PutCommand.php index 811fa61..e5f697e 100644 --- a/src/Meanbee/Magedbm/Command/PutCommand.php +++ b/src/Meanbee/Magedbm/Command/PutCommand.php @@ -67,7 +67,7 @@ protected function configure() /** * Execute the command. * - * @param InputInterface $input + * @param InputInterface $input * @param OutputInterface $output * * @throws \Exception @@ -82,13 +82,18 @@ protected function execute(InputInterface $input, OutputInterface $output) try { $result = $s3->putObject(array( - 'Bucket' => $config['bucket'], - 'Key' => $input->getArgument('name') . '/' . $this->getFileName($input), + 'Bucket' => $config['bucket'], + 'Key' => $input->getArgument('name') . '/' . $this->getFileName($input), 'SourceFile' => $this->getFilePath($input), )); - $this->getOutput()->writeln(sprintf('%s database uploaded to %s.', - $input->getArgument('name'), $result->get('ObjectURL'))); + $this->getOutput()->writeln( + sprintf( + '%s database uploaded to %s.', + $input->getArgument('name'), + $result->get('ObjectURL') + ) + ); } catch (InstanceProfileCredentialsException $e) { $this->cleanUp(); @@ -113,7 +118,8 @@ protected function execute(InputInterface $input, OutputInterface $output) * @param $s3 * @param $config */ - protected function maintainDatabaseHistory($input, $output, $s3, $config) { + protected function maintainDatabaseHistory($input, $output, $s3, $config) + { try { $results = $s3->getIterator( 'ListObjects', @@ -136,7 +142,7 @@ protected function maintainDatabaseHistory($input, $output, $s3, $config) { } /** - * @param InputInterface $input + * @param InputInterface $input * @param OutputInterface $output */ protected function initialize(InputInterface $input, OutputInterface $output) @@ -195,7 +201,7 @@ protected function cleanUp() * Create database backup in tmp directory. * Use magerun db:dump if available. Otherwise use php alternative if exec not available. * - * @param InputInterface $input + * @param InputInterface $input * @param OutputInterface $output * * @throws \Exception @@ -209,56 +215,115 @@ private function createBackup(InputInterface $input, OutputInterface $output) /** @var \N98\Magento\Command\Database\DumpCommand $dumpCommand */ $dumpCommand = $magerun->find("db:dump"); + $stripOptions = $input->getOption('strip') ? : '@development'; $dumpInput = new ArrayInput(array( - 'filename' => $filePath, - '--strip' => '@development', - '--compression' => 'gzip', + 'filename' => $filePath, + '--strip' => $stripOptions, + '--compression' => 'gzip', )); if ($dumpCommand->run($dumpInput, $output)) { throw new \Exception("magerun db:dump failed to create backup.."); } } catch (\InvalidArgumentException $e) { + $this->createBackupWithoutExec($input, $output); + + $output->writeln('Finished'); + } + } + + /** + * PHP alternative to dump database without exec + * + * @param InputInterface $input + * @param OutputInterface $output + * @throws \Exception + */ + private function createBackupWithoutExec(InputInterface $input, OutputInterface $output) + { + $magerun = $this->getMagerun(); + $filePath = $this->getFilePath($input); + + $stripOptions = $input->getOption('strip') ? : '@development'; + + // Exec must be unavailable so use PHP alternative (match output) + $dbHelper = new DatabaseHelper(); + $dbHelper->setHelperSet($magerun->getHelperSet()); + $dbHelper->detectDbSettings(new NullOutput()); + $magerunConfig = $magerun->getConfig(); + $stripTables = $dbHelper->resolveTables( + explode(' ', $stripOptions), + $dbHelper->getTableDefinitions($magerunConfig['commands']['N98\Magento\Command\Database\DumpCommand']) + ); + + $output->writeln( + array( + '', + $magerun->getHelperSet()->get('formatter')->formatBlock( + 'Dump MySQL Database (without exec)', + 'bg=blue;fg=white', + true + ), + '' + ) + ); + + $dbSettings = $dbHelper->getDbSettings(); + $username = (string)$dbSettings['username']; + $password = (string)$dbSettings['password']; + $dbName = (string)$dbSettings['dbname']; - // Exec must be unavailable so use PHP alternative (match output) - $dbHelper = new DatabaseHelper(); - $dbHelper->setHelperSet($magerun->getHelperSet()); - $dbHelper->detectDbSettings(new NullOutput()); - $magerunConfig = $magerun->getConfig(); - $stripTables = $dbHelper->resolveTables(explode(' ', '@development'), - $dbHelper->getTableDefinitions($magerunConfig['commands']['N98\Magento\Command\Database\DumpCommand']) + try { + $output->writeln( + 'No-data export for: ' . implode(' ', $stripTables) . '' ); - $output->writeln(array('', - $magerun->getHelperSet()->get('formatter')->formatBlock('Dump MySQL Database (without exec)', - 'bg=blue;fg=white', true), '', - )); + $output->writeln( + 'Start dumping database ' . $dbSettings['dbname'] . ' to file ' + . $filePath . '' + ); - $dbSettings = $dbHelper->getDbSettings(); - $username = (string) $dbSettings['username']; - $password = (string) $dbSettings['password']; - $dbName = (string) $dbSettings['dbname']; + // Dump Structure for tables that we are not to receive data from + $dumpStructure = new Mysqldump( + sprintf('%s;dbname=%s', $dbHelper->dsn(), $dbName), + $username, + $password, + array( + 'include-tables' => $stripTables, + 'no-data' => true, + ) + ); - try { - $dump = new Mysqldump(sprintf('%s;dbname=%s', $dbHelper->dsn(), $dbName), $username, $password, array( - 'compress' => Mysqldump::GZIP, - 'exclude-tables' => $stripTables - )); + $dumpStructure->start($filePath . '.structure'); - $output->writeln('No-data export for: ' . implode(' ', $stripTables) - . '' - ); + $dump = new Mysqldump(sprintf('%s;dbname=%s', $dbHelper->dsn(), $dbName), $username, $password, array( + 'exclude-tables' => $stripTables + )); - $output->writeln('Start dumping database ' . $dbSettings['dbname'] - . ' to file ' . $filePath . '' - ); + $dump->start($filePath . '.data'); - $dump->start($filePath); - } catch (\Exception $e) { - throw new \Exception("Unable to export database."); + // Now merge two files + $fhData = fopen($filePath . '.data', 'a+'); + $fhStructure = fopen($filePath . '.structure', 'r'); + if ($fhData && $fhStructure) { + while (!feof($fhStructure)) { + fwrite($fhData, fgets($fhStructure, 4096)); + } } - $output->writeln('Finished'); + fclose($fhStructure); + + // Gzip + rewind($fhData); + $zfh = gzopen($filePath, 'wb'); + while (!feof($fhData)) { + gzwrite($zfh, fgets($fhData, 4096)); + } + gzclose($zfh); + fclose($fhData); + + } catch (\Exception $e) { + throw new \Exception("Unable to export database."); } } }