From 5d10b5b755c386807faebd4de7c61b156136cab5 Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Fri, 24 Sep 2021 11:56:15 +0200 Subject: [PATCH 1/7] Ignore errors when importing, but show trimmed stderr to the user. --- bin/craft-copy-import-db.php | 13 +++++++++---- src/Actions/DbUpAction.php | 24 +++++++++++++++++++++++- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/bin/craft-copy-import-db.php b/bin/craft-copy-import-db.php index aa10e3c..073f883 100755 --- a/bin/craft-copy-import-db.php +++ b/bin/craft-copy-import-db.php @@ -48,7 +48,7 @@ } -$cmd = 'mysql -u {DB_USER} -p{DB_PASSWORD} -h {DB_SERVER} {DB_DATABASE} < {file} && echo 1'; +$cmd = 'mysql --force -u {DB_USER} -p{DB_PASSWORD} -h {DB_SERVER} {DB_DATABASE} < {file} && echo 1'; $tokens = [ '{file}' => $file, '{DB_USER}' => getenv('DB_USER'), @@ -61,11 +61,16 @@ $process = \Symfony\Component\Process\Process::fromShellCommandline($cmd); $process->run(); +if ($stderr = $process->getErrorOutput()) { + echo "ERROR:" . PHP_EOL; + echo substr($stderr, 0, 200); + exit(1); +} + if ($process->isSuccessful()) { echo 'OK'; exit(0); } -echo "ERROR: "; -echo $process->getErrorOutput(); -exit(1); +echo 'Unknown error'; +exit(0); diff --git a/src/Actions/DbUpAction.php b/src/Actions/DbUpAction.php index 2e1fd21..da1cf5a 100644 --- a/src/Actions/DbUpAction.php +++ b/src/Actions/DbUpAction.php @@ -55,6 +55,18 @@ public function run(?string $stage = null) return ExitCode::UNSPECIFIED_ERROR; } + if ($plugin->ssh->exec('ls vendor/bin/craft-copy-import-db.php | wc -l')) { + if (trim($plugin->ssh->getOutput()) != '1') { + $this->errorBlock( + [ + 'Unable to import database. Deploy code first using this command:', + 'php craft copy/code/up', + ] + ); + return ExitCode::UNSPECIFIED_ERROR; + } + } + $bar = $this->createProgressBar($steps); // Step 1: Create dump of the current database @@ -69,6 +81,8 @@ public function run(?string $stage = null) $bar->advance(); } + + if ($this->force) { // Import on remote (does not require craft or copy on remote) $bar->setMessage($messages[] = 'Importing dump on fortrabbit App'); @@ -80,6 +94,10 @@ public function run(?string $stage = null) $plugin->ssh->exec( "php vendor/bin/craft-copy-import-db.php {$transferFile} --force" ); + if (stristr($plugin->ssh->getOutput(), 'error')) { + $this->errorBlock($plugin->ssh->getOutput()); + } + $bar->advance(); $bar->setMessage('Database imported'); } catch (RemoteException $e) { @@ -91,7 +109,11 @@ public function run(?string $stage = null) ); return ExitCode::UNSPECIFIED_ERROR; } - } else { + } + + + + else { // Step 3: Backup the remote database before importing the uploaded dump $bar->setMessage( $messages[] = "Creating a database dump on fortrabbit App ({$backupFile})" From bb12aa190234ed5a6a1259964c4f2a92b0108178 Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Fri, 24 Sep 2021 12:07:06 +0200 Subject: [PATCH 2/7] Adjust ignoreTables for mysqldump --- src/EventHandlers/IgnoredBackupTablesHandler.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/EventHandlers/IgnoredBackupTablesHandler.php b/src/EventHandlers/IgnoredBackupTablesHandler.php index fb72e59..d313c47 100644 --- a/src/EventHandlers/IgnoredBackupTablesHandler.php +++ b/src/EventHandlers/IgnoredBackupTablesHandler.php @@ -18,9 +18,15 @@ class IgnoredBackupTablesHandler */ public function __invoke(BackupEvent $event): void { - // Since we sync assets, we keep assettransformindex if (property_exists($event, 'ignoreTables')) { - $event->ignoreTables = array_diff($event->ignoreTables, [Table::ASSETTRANSFORMINDEX]); + + // Include assettransformindex (do backup) + $ignoreTables = array_diff($event->ignoreTables, [Table::ASSETTRANSFORMINDEX]); + + // Exclude resourcepaths (don't backup) + $ignoreTables[] = Table::RESOURCEPATHS; + + $event->ignoreTables = $ignoreTables; } } } From 62b321f51997a0ffd85a38cd8e53fd10a9d547a4 Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Fri, 24 Sep 2021 12:12:48 +0200 Subject: [PATCH 3/7] 1.0.6 Changelog + style fixes --- CHANGELOG.md | 4 ++++ src/Actions/DbUpAction.php | 10 ++-------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8c68bb..85b637c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 1.0.6 - 2021-09-24 +- Exclude `resourcepaths` table from db backup +- Ignore mysql import errors 🤞🏻 + ## 1.0.5 - 2021-05-12 - Update craft-auto-migrate to use `project-config/apply` - Code style cleanup diff --git a/src/Actions/DbUpAction.php b/src/Actions/DbUpAction.php index da1cf5a..a2cb8af 100644 --- a/src/Actions/DbUpAction.php +++ b/src/Actions/DbUpAction.php @@ -56,7 +56,7 @@ public function run(?string $stage = null) } if ($plugin->ssh->exec('ls vendor/bin/craft-copy-import-db.php | wc -l')) { - if (trim($plugin->ssh->getOutput()) != '1') { + if (trim($plugin->ssh->getOutput()) !== '1') { $this->errorBlock( [ 'Unable to import database. Deploy code first using this command:', @@ -81,8 +81,6 @@ public function run(?string $stage = null) $bar->advance(); } - - if ($this->force) { // Import on remote (does not require craft or copy on remote) $bar->setMessage($messages[] = 'Importing dump on fortrabbit App'); @@ -109,11 +107,7 @@ public function run(?string $stage = null) ); return ExitCode::UNSPECIFIED_ERROR; } - } - - - - else { + } else { // Step 3: Backup the remote database before importing the uploaded dump $bar->setMessage( $messages[] = "Creating a database dump on fortrabbit App ({$backupFile})" From ce1e533a02b637e5168c439767f70b730e4d3261 Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Fri, 24 Sep 2021 12:40:43 +0200 Subject: [PATCH 4/7] Show actual sql error --- bin/craft-copy-import-db.php | 6 +++--- src/Actions/DbUpAction.php | 10 +--------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/bin/craft-copy-import-db.php b/bin/craft-copy-import-db.php index 073f883..27c8818 100755 --- a/bin/craft-copy-import-db.php +++ b/bin/craft-copy-import-db.php @@ -62,7 +62,7 @@ $process->run(); if ($stderr = $process->getErrorOutput()) { - echo "ERROR:" . PHP_EOL; + echo 'ERROR (sql):' . PHP_EOL; echo substr($stderr, 0, 200); exit(1); } @@ -72,5 +72,5 @@ exit(0); } -echo 'Unknown error'; -exit(0); +echo 'ERROR (unknown)'; +exit(1); diff --git a/src/Actions/DbUpAction.php b/src/Actions/DbUpAction.php index a2cb8af..a79c6b1 100644 --- a/src/Actions/DbUpAction.php +++ b/src/Actions/DbUpAction.php @@ -92,19 +92,11 @@ public function run(?string $stage = null) $plugin->ssh->exec( "php vendor/bin/craft-copy-import-db.php {$transferFile} --force" ); - if (stristr($plugin->ssh->getOutput(), 'error')) { - $this->errorBlock($plugin->ssh->getOutput()); - } $bar->advance(); $bar->setMessage('Database imported'); } catch (RemoteException $e) { - $this->errorBlock( - [ - 'Unable to import database. Deploy code first using this command:', - 'php craft copy/code/up', - ] - ); + $this->errorBlock([$e->getMessage()]); return ExitCode::UNSPECIFIED_ERROR; } } else { From 8d5ff8fb34c1c9908e89aaa993ebe35b7be4ace8 Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Fri, 24 Sep 2021 13:35:58 +0200 Subject: [PATCH 5/7] Use --defaults-extra-file instead of -p --- bin/craft-copy-import-db.php | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/bin/craft-copy-import-db.php b/bin/craft-copy-import-db.php index 27c8818..f87965a 100755 --- a/bin/craft-copy-import-db.php +++ b/bin/craft-copy-import-db.php @@ -47,17 +47,28 @@ exit(1); } +$credentialsFile = "/tmp/mysql-extra.cnf"; +$credentialsFileContent = [ + "[client]", + "user=" . getenv('DB_USER'), + "password=" . getenv('DB_PASSWORD'), + "host=" . getenv('DB_SERVER') +]; + +if (false === file_put_contents($credentialsFile, join(PHP_EOL, $credentialsFileContent))) { + echo "ERROR: unable to write $credentialsFile"; + exit(1); +} -$cmd = 'mysql --force -u {DB_USER} -p{DB_PASSWORD} -h {DB_SERVER} {DB_DATABASE} < {file} && echo 1'; $tokens = [ - '{file}' => $file, - '{DB_USER}' => getenv('DB_USER'), - '{DB_PASSWORD}' => getenv('DB_PASSWORD'), - '{DB_SERVER}' => getenv('DB_SERVER'), + '{FILE}' => $file, + '{EXTRA_FILE}' => $credentialsFile, '{DB_DATABASE}' => getenv('DB_DATABASE'), ]; +$cmd = 'mysql --defaults-extra-file={EXTRA_FILE} --force {DB_DATABASE} < {FILE} && echo 1'; $cmd = str_replace(array_keys($tokens), array_values($tokens), $cmd); + $process = \Symfony\Component\Process\Process::fromShellCommandline($cmd); $process->run(); From 859d881ce71e291fe9c5accdfd341384001cdf3e Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Fri, 24 Sep 2021 15:46:23 +0200 Subject: [PATCH 6/7] Code style --- bin/craft-copy-import-db.php | 8 +++-- src/Actions/DbUpAction.php | 56 +++++++++++++++++------------- src/Exceptions/RemoteException.php | 17 +++++++++ src/Services/Ssh.php | 4 ++- 4 files changed, 56 insertions(+), 29 deletions(-) diff --git a/bin/craft-copy-import-db.php b/bin/craft-copy-import-db.php index f87965a..3099a88 100755 --- a/bin/craft-copy-import-db.php +++ b/bin/craft-copy-import-db.php @@ -72,9 +72,11 @@ $process = \Symfony\Component\Process\Process::fromShellCommandline($cmd); $process->run(); +unlink($credentialsFile); + if ($stderr = $process->getErrorOutput()) { - echo 'ERROR (sql):' . PHP_EOL; - echo substr($stderr, 0, 200); + fwrite(STDERR, 'ERROR (sql):' . PHP_EOL); + fwrite(STDERR, substr($stderr, 0, 200)); exit(1); } @@ -83,5 +85,5 @@ exit(0); } -echo 'ERROR (unknown)'; +fwrite(STDERR, 'ERROR (unknown)'); exit(1); diff --git a/src/Actions/DbUpAction.php b/src/Actions/DbUpAction.php index a79c6b1..6fd4dd8 100644 --- a/src/Actions/DbUpAction.php +++ b/src/Actions/DbUpAction.php @@ -57,13 +57,7 @@ public function run(?string $stage = null) if ($plugin->ssh->exec('ls vendor/bin/craft-copy-import-db.php | wc -l')) { if (trim($plugin->ssh->getOutput()) !== '1') { - $this->errorBlock( - [ - 'Unable to import database. Deploy code first using this command:', - 'php craft copy/code/up', - ] - ); - return ExitCode::UNSPECIFIED_ERROR; + return $this->printAndExit(new PluginNotInstalledException()); } } @@ -92,12 +86,10 @@ public function run(?string $stage = null) $plugin->ssh->exec( "php vendor/bin/craft-copy-import-db.php {$transferFile} --force" ); - $bar->advance(); $bar->setMessage('Database imported'); } catch (RemoteException $e) { - $this->errorBlock([$e->getMessage()]); - return ExitCode::UNSPECIFIED_ERROR; + return $this->printAndExit($e); } } else { // Step 3: Backup the remote database before importing the uploaded dump @@ -108,21 +100,8 @@ public function run(?string $stage = null) try { $plugin->ssh->exec("php craft copy/db/to-file {$backupFile} --interactive=0"); $bar->advance(); - } catch (CraftNotInstalledException $e) { - $this->errorBlock( - [ - 'Unable to import database. Deploy code first using this command:', - 'php craft copy/code/up', - ] - ); - return ExitCode::UNSPECIFIED_ERROR; - } catch (PluginNotInstalledException $e) { - $this->errorBlock( - [ - 'The plugin seems not to be installed on fortrabbit. Deploy code first using this command:', - 'php craft copy/code/up', - ] - ); + } catch (RemoteException $e) { + return $this->printAndExit($e); } // Step 4: Import on remote @@ -147,4 +126,31 @@ public function run(?string $stage = null) return ExitCode::OK; } + + protected function printAndExit(RemoteException $exception): int + { + if ($exception instanceof CraftNotInstalledException) { + $this->errorBlock( + [ + 'Unable to import database. Deploy code first using this command:', + 'php craft copy/code/up', + ] + ); + return ExitCode::UNSPECIFIED_ERROR; + } + + if ($exception instanceof PluginNotInstalledException) { + $this->errorBlock( + [ + 'The plugin seems not to be installed on fortrabbit. Deploy code first using this command:', + 'php craft copy/code/up', + ] + ); + return ExitCode::UNSPECIFIED_ERROR; + } + + $this->errorBlock([$exception->getMessage()]); + + return ExitCode::UNSPECIFIED_ERROR; + } } diff --git a/src/Exceptions/RemoteException.php b/src/Exceptions/RemoteException.php index 0419a7e..fb42f6b 100644 --- a/src/Exceptions/RemoteException.php +++ b/src/Exceptions/RemoteException.php @@ -4,8 +4,25 @@ namespace fortrabbit\Copy\Exceptions; +use Throwable; use yii\base\Exception; class RemoteException extends Exception { + public function __construct($message = '', $code = 0, ?Throwable $previous = null) + { + parent::__construct($this->cleanMessage($message), $code, $previous); + } + + protected function cleanMessage(string $message): string + { + // remove double new lines + $message = preg_replace("/[\r\n]+/", "\n", $message); + + // strip after ∙ƒ + if ($endPos = strpos($message, '∙ƒ')) { + $message = substr($message, 0, $endPos); + } + return trim($message); + } } diff --git a/src/Services/Ssh.php b/src/Services/Ssh.php index 7bb9d98..623ab5e 100644 --- a/src/Services/Ssh.php +++ b/src/Services/Ssh.php @@ -126,7 +126,9 @@ public function exec(string $cmd) } if (trim($process->getErrorOutput()) === 'Could not open input file') { - throw new CraftNotInstalledException(trim($process->getErrorOutput())); + throw new CraftNotInstalledException( + trim($process->getErrorOutput()) + ); } if (stristr($process->getErrorOutput(), 'Unknown command')) { From f4867763c6960c7b3372bc0044f30eda7ddf1261 Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Fri, 24 Sep 2021 16:07:15 +0200 Subject: [PATCH 7/7] 1.0.6 --- CHANGELOG.md | 1 + src/Exceptions/CraftNotInstalledException.php | 4 ++++ src/Services/Ssh.php | 21 ++++++++++--------- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85b637c..2f27d67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 1.0.6 - 2021-09-24 - Exclude `resourcepaths` table from db backup - Ignore mysql import errors 🤞🏻 +- Better error output ## 1.0.5 - 2021-05-12 - Update craft-auto-migrate to use `project-config/apply` diff --git a/src/Exceptions/CraftNotInstalledException.php b/src/Exceptions/CraftNotInstalledException.php index fb7dd4f..d61b00d 100644 --- a/src/Exceptions/CraftNotInstalledException.php +++ b/src/Exceptions/CraftNotInstalledException.php @@ -6,4 +6,8 @@ class CraftNotInstalledException extends RemoteException { + /** + * @var string + */ + public $message = 'Craft is not installed on the fortrabbit App.'; } diff --git a/src/Services/Ssh.php b/src/Services/Ssh.php index 623ab5e..ec30a3c 100644 --- a/src/Services/Ssh.php +++ b/src/Services/Ssh.php @@ -125,16 +125,17 @@ public function exec(string $cmd) return true; } - if (trim($process->getErrorOutput()) === 'Could not open input file') { - throw new CraftNotInstalledException( - trim($process->getErrorOutput()) - ); - } + $out = $process->getOutput(); + $err = $process->getOutput(); - if (stristr($process->getErrorOutput(), 'Unknown command')) { - throw new PluginNotInstalledException( - 'The Craft Copy plugin is not installed on remote.' - ); + if (stristr($out, 'Could not open input file')) { + throw new CraftNotInstalledException(); + } + if (stristr($err, 'Could not open input file')) { + throw new CraftNotInstalledException(); + } + if (stristr($err, 'Unknown command')) { + throw new PluginNotInstalledException(); } throw new RemoteException( @@ -142,7 +143,7 @@ public function exec(string $cmd) 'SSH Remote error: ' . $process->getExitCode(), 'Command: ' . $process->getCommandLine(), 'Output:', - $process->getErrorOutput(), + $err, ]) ); }