diff --git a/src/Command/Archive/ArchiveExportCommand.php b/src/Command/Archive/ArchiveExportCommand.php index 82ea8ca10..e3eed864e 100644 --- a/src/Command/Archive/ArchiveExportCommand.php +++ b/src/Command/Archive/ArchiveExportCommand.php @@ -3,6 +3,7 @@ use Platformsh\Cli\Command\CommandBase; use Platformsh\Cli\Model\RemoteContainer\App; +use Platformsh\Client\Model\Deployment\Service; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\BufferedOutput; @@ -159,6 +160,12 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->stdErr->writeln(''); + $this->stdErr->writeln('Warning'); + $this->stdErr->writeln('Your site may be changing data during archiving, resulting in inconsistencies.'); + $this->stdErr->writeln('This tool is not suitable for making consistent backups (instead, see ' . $this->config()->get('application.executable') . ' snapshot:create).'); + + $this->stdErr->writeln(''); + if (!$questionHelper->confirm('Are you sure you want to continue?')) { return 1; } @@ -221,19 +228,8 @@ protected function execute(InputInterface $input, OutputInterface $output) return 1; } if ($type === 'mysql' || $type === 'pgsql') { - // Get a list of schemas from the service configuration. - $service = $deployment->getService($serviceName); - $schemas = !empty($service->configuration['schemas']) - ? $service->configuration['schemas'] - : []; - - // Filter the list by the schemas accessible from the endpoint. - if (isset($service->configuration['endpoints'][$relationshipName]['privileges'])) { - $schemas = array_intersect( - $schemas, - array_keys($service->configuration['endpoints'][$relationshipName]['privileges']) - ); - } + // Get a list of schemas for this relationship. + $schemas = $this->getSchemas($deployment->getService($serviceName), $relationshipName); mkdir($archiveDir . '/services/' . $serviceName, 0755, true); @@ -286,7 +282,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $filename = $appName . '--' . $relationshipName . '.bson'; // @todo dump directly to a file without the buffer $buffer = new BufferedOutput(); - $exitCode = $this->runOtherCommand('db:dump', $args, $buffer); + $exitCode = $this->runOtherCommand('service:mongo:dump', $args, $buffer); if ($exitCode !== 0) { return $exitCode; @@ -304,6 +300,8 @@ protected function execute(InputInterface $input, OutputInterface $output) if ($hasMounts && !$excludeMounts) { /** @var \Platformsh\Cli\Service\Mount $mountService */ $mountService = $this->getService('mount'); + /** @var \Platformsh\Cli\Service\Rsync $rsync */ + $rsync = $this->getService('rsync'); foreach ($apps as $app) { $sourcePaths = []; $mounts = $mountService->normalizeMounts($app->getMounts()); @@ -319,10 +317,9 @@ protected function execute(InputInterface $input, OutputInterface $output) } $this->stdErr->writeln(''); $this->stdErr->writeln('Copying from mount ' . $path . ''); - $source = ltrim($path, '/'); $destination = $archiveDir . '/mounts/' . trim($path, '/'); mkdir($destination, 0755, true); - $this->rsync($app->getSshUrl(), $source, $destination); + $rsync->syncDown($app->getSshUrl(), ltrim($path, '/'), $destination); $metadata['mounts'][$path] = [ 'app' => $app->getName(), 'path' => 'mounts/' . trim($path, '/'), @@ -359,44 +356,6 @@ protected function execute(InputInterface $input, OutputInterface $output) return 0; } - /** - * Rsync from a remote path to a local one. - * - * @param string $sshUrl - * @param string $sshPath - * @param string $localPath - * @param array $options - */ - private function rsync($sshUrl, $sshPath, $localPath, array $options = []) - { - /** @var \Platformsh\Cli\Service\Shell $shell */ - $shell = $this->getService('shell'); - - $params = ['rsync', '--archive', '--compress', '--human-readable']; - - if ($this->stdErr->isVeryVerbose()) { - $params[] = '-vv'; - } elseif ($this->stdErr->isVerbose()) { - $params[] = '-v'; - } - - $params[] = sprintf('%s:%s/', $sshUrl, $sshPath); - $params[] = $localPath; - - if (!empty($options['delete'])) { - $params[] = '--delete'; - } - foreach (['exclude', 'include'] as $option) { - if (!empty($options[$option])) { - foreach ($options[$option] as $value) { - $params[] = '--' . $option . '=' . $value; - } - } - } - - $shell->execute($params, null, true, false, [], null); - } - /** * @param \Platformsh\Cli\Model\RemoteContainer\App $app * @param string $serviceName @@ -416,4 +375,31 @@ private function getRelationshipNameForService(App $app, $serviceName) return false; } + + /** + * Get a list of schemas configured for the service. + * + * @param \Platformsh\Client\Model\Deployment\Service $service + * @param string $relationshipName + * + * @return array + */ + private function getSchemas(Service $service, $relationshipName) + { + if (empty($service->configuration['schemas'])) { + return []; + } + + $schemas = $service->configuration['schemas']; + + // Filter the list by the schemas accessible from the endpoint. + if (isset($service->configuration['endpoints'][$relationshipName]['privileges'])) { + $schemas = array_intersect( + $schemas, + array_keys($service->configuration['endpoints'][$relationshipName]['privileges']) + ); + } + + return $schemas; + } } diff --git a/src/Command/Archive/ArchiveImportCommand.php b/src/Command/Archive/ArchiveImportCommand.php index 62b1a6777..06c4895ae 100644 --- a/src/Command/Archive/ArchiveImportCommand.php +++ b/src/Command/Archive/ArchiveImportCommand.php @@ -3,6 +3,8 @@ use Platformsh\Cli\Command\CommandBase; use Platformsh\Cli\Model\RemoteContainer\App; +use Platformsh\Client\Model\Environment; +use Platformsh\Client\Model\Project; use Platformsh\Client\Model\ProjectLevelVariable; use Platformsh\Client\Model\Variable; use Symfony\Component\Console\Input\InputArgument; @@ -56,9 +58,6 @@ protected function execute(InputInterface $input, OutputInterface $output) /** @var \Platformsh\Cli\Service\Filesystem $fs */ $fs = $this->getService('fs'); - /** @var \Platformsh\Cli\Service\Shell $shell */ - $shell = $this->getService('shell'); - $environment = $this->getSelectedEnvironment(); $this->stdErr->writeln(sprintf( @@ -130,25 +129,20 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->stdErr->writeln(' Error: no variable value found.'); continue; } - unset($var['project'], $var['environment'], $var['created_at'], $var['updated_at'], $var['id'], $var['attributes']); if ($current = $environment->getVariable($name)) { $this->stdErr->writeln(' The variable already exists.'); - if ($current->is_sensitive === $var['is_sensitive'] - && $current->value === $var['value'] - && $current->is_json === $var['is_json'] - && $current->is_enabled === $var['is_enabled'] - && $current->is_inheritable === $var['is_inheritable']) { + if ($this->variablesAreEqual($current->getProperties(), $var)) { $this->stdErr->writeln(' No change required.'); continue; } - if (!$questionHelper->confirm(' Do you want to update it?')) { - return 1; + if ($questionHelper->confirm(' Do you want to update it?')) { + $result = $current->update($var); + } else { + continue; } - - $result = $current->update($var); } else { - $result = Variable::create($var, $environment->getLink('#manage-variables'), $this->api()->getHttpClient()); + $result = $this->createEnvironmentVariableFromProperties($var, $environment); } $this->stdErr->writeln(' Done'); @@ -173,14 +167,9 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->stdErr->writeln(' Error: no variable value found.'); continue; } - unset($var['project'], $var['created_at'], $var['updated_at'], $var['id'], $var['attributes']); if ($current = $project->getVariable($name)) { $this->stdErr->writeln(' The variable already exists.'); - if ($current->is_sensitive === $var['is_sensitive'] - && $current->value === $var['value'] - && $current->visible_build === $var['visible_build'] - && $current->visible_runtime === $var['visible_runtime'] - && $current->is_json === $var['is_json']) { + if ($this->variablesAreEqual($current->getProperties(), $var)) { $this->stdErr->writeln(' No change required.'); continue; } @@ -191,7 +180,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $result = $current->update($var); } else { - $result = ProjectLevelVariable::create($var, $project->getLink('#manage-variables'), $this->api()->getHttpClient()); + $result = $this->createProjectVariableFromProperties($var, $project); } $this->stdErr->writeln(' Done'); $activities = array_merge($activities, $result->getActivities()); @@ -224,12 +213,18 @@ protected function execute(InputInterface $input, OutputInterface $output) } if (!empty($metadata['mounts'])) { + /** @var \Platformsh\Cli\Service\Rsync $rsync */ + $rsync = $this->getService('rsync'); + $rsyncOptions = [ + 'verbose' => $output->isVeryVerbose(), + 'quiet' => !$output->isVerbose(), + ]; $deployment = $environment->getCurrentDeployment(); foreach ($metadata['mounts'] as $path => $info) { $this->stdErr->writeln(''); $this->stdErr->writeln('Importing files to mount ' . $path . ''); $app = new App($deployment->getWebApp($info['app']), $environment); - $this->rsyncUp($app->getSshUrl(), $path, $archiveDir . '/' . $info['path']); + $rsync->syncUp($app->getSshUrl(), $archiveDir . '/' . $info['path'], $path, $rsyncOptions); } } @@ -243,41 +238,61 @@ protected function execute(InputInterface $input, OutputInterface $output) } /** - * Rsync from a local path to a remote one. + * @param array $properties + * @param \Platformsh\Client\Model\Environment $environment * - * @param string $sshUrl - * @param string $sshPath - * @param string $localPath - * @param array $options + * @return \Platformsh\Client\Model\Result */ - private function rsyncUp($sshUrl, $sshPath, $localPath, array $options = []) + private function createEnvironmentVariableFromProperties(array $properties, Environment $environment) { - /** @var \Platformsh\Cli\Service\Shell $shell */ - $shell = $this->getService('shell'); + $var = $properties; + unset($var['project'], $var['environment'], $var['created_at'], $var['updated_at'], $var['id'], $var['attributes']); - $params = ['rsync', '--archive', '--compress', '--human-readable']; + return Variable::create($var, $environment->getLink('#manage-variables'), $this->api()->getHttpClient()); + } - if ($this->stdErr->isVeryVerbose()) { - $params[] = '-vv'; - } elseif ($this->stdErr->isVerbose()) { - $params[] = '-v'; - } + /** + * @param array $properties + * @param \Platformsh\Client\Model\Project $project + * + * @return \Platformsh\Client\Model\Result + */ + private function createProjectVariableFromProperties(array $properties, Project $project) + { + $var = $properties; + unset($var['project'], $var['environment'], $var['created_at'], $var['updated_at'], $var['id'], $var['attributes']); - $params[] = rtrim($localPath, '/') . '/'; - $params[] = sprintf('%s:%s', $sshUrl, $sshPath); + return ProjectLevelVariable::create($var, $project->getLink('#manage-variables'), $this->api()->getHttpClient()); + } - if (!empty($options['delete'])) { - $params[] = '--delete'; - } - foreach (['exclude', 'include'] as $option) { - if (!empty($options[$option])) { - foreach ($options[$option] as $value) { - $params[] = '--' . $option . '=' . $value; - } + + /** + * Checks if two variables are equal. + * + * @param array $var1Properties + * @param array $var2Properties + * + * @return bool + */ + private function variablesAreEqual(array $var1Properties, $var2Properties) + { + $keys = [ + 'value', + 'is_json', + 'is_enabled', + 'is_sensitive', + 'is_inheritable', + 'visible_build', + 'visible_runtime', + ]; + foreach ($keys as $key) { + if (array_key_exists($key, $var1Properties) + && (!array_key_exists($key, $var2Properties) || $var1Properties[$key] !== $var2Properties[$key])) { + return false; } } - $shell->execute($params, null, true, false, [], null); + return true; } /**