@param Node        $node
@param Application $application
@param Deployment  $deployment
@param array       $options

@throws InvalidConfigurationException
@throws TaskExecutionException
338653
public function execute(Node $node, Application $application, Deployment $deployment, array $options = [])
    {
        $options = array_replace_recursive($this->options, $options);

        $credentials = $this->getCredentials($node, $deployment, $options, $application);
        $dumpFile = $this->getDumpFile($options, $credentials);
        $mysqlArguments = $this->getMysqlArguments($credentials);
        $mysqlAuthArguments = $this->getMysqlArguments($credentials, false);

        $commands = [];
        $commands[] = 'echo "CREATE DATABASE IF NOT EXISTS '.$credentials['database'].
            ' DEFAULT CHARACTER SET = \'utf8\''.
            ' DEFAULT COLLATE \'utf8_general_ci\'"'.
            ' | mysql '.$mysqlAuthArguments;
        $commands[] = 'gzip -d < '.escapeshellarg($dumpFile).' | mysql '.$mysqlArguments;
        if (!empty($options['truncateTables']) && is_array($options['truncateTables'])) {
            $commands[] = $this->getTruncateCommand($mysqlArguments, $options);
        }

        $this->shell->executeOrSimulate($commands, $node, $deployment, false, false);
    }
872304
public function execute(Node $node, Application $application, Deployment $deployment, array $options = [])
    {
        $targetPath = $deployment->getApplicationReleasePath($application);
        $this->shell->executeOrSimulate(
            'cd '.$targetPath.' && FLOW_CONTEXT='.$options['context'].' ./flow typo3.flow:cache:flush',
            $node,
            $deployment
        );
    }
199801
public function rollback(Node $node, Application $application, Deployment $deployment, array $options = [])
    {
        if (!isset($options['rollbackCommand'])) {
            return;
        }

        $replacePaths = [
            '{deploymentPath}' => $application->getDeploymentPath(),
            '{sharedPath}' => $application->getSharedPath(),
            '{releasePath}' => $deployment->getApplicationReleasePath($application),
            '{currentPath}' => $application->getReleasesPath() . '/current',
            '{previousPath}' => $application->getReleasesPath() . '/previous'
        ];

        $command = $options['rollbackCommand'];
        $command = str_replace(array_keys($replacePaths), $replacePaths, $command);

        $this->shell->execute($command, $node, $deployment, true);
    }
1102334
public function simulate(Node $node, Application $application, Deployment $deployment, array $options = [])
    {
        $options = $this->configureOptions($options);
        $this->shell->executeOrSimulate($options['varnishadm'] . ' -S ' . $options['secretFile'] . ' -T 127.0.0.1:6082 status', $node, $deployment);
    }
900253
public function execute(Node $node, Application $application, Deployment $deployment, array $options = [])
    {
        $options = $this->configureOptions($options);

        if (empty($options['symlinks'])) {
            return;
        }

        $baseDirectory = $options['genericSymlinksBaseDir'] ?: $deployment->getApplicationReleasePath($application);

        $commands = [
            'cd ' . $baseDirectory,
        ];

        foreach ($options['symlinks'] as $linkPath => $sourcePath) {
            $commands[] = sprintf('ln -s %s %s', $sourcePath, $linkPath);
        }

        $this->shell->executeOrSimulate($commands, $node, $deployment);
    }
1337852
protected function getCredentialsFromTypo3Cms(
        Node $node,
        Deployment $deployment,
        array $options,
        Application $application
    )
    {
        $commands = $this->buildCommands($deployment, $application, $options);
        if (empty($commands) === false) {
            // Overwrite first command
            $commands[0] = 'cd ' . escapeshellarg($options['deploymentPath']);
        } else {
            throw new TaskExecutionException('Could not receive database credentials', 1409252547);
        }

        $returnedOutput = $this->shell->execute($commands, $node, $deployment, false, false);
        $returnedOutput = json_decode($returnedOutput, true);

        if (empty($returnedOutput)) {
            throw new TaskExecutionException('Could not receive database credentials', 1409252546);
        }

        // Compatibility with TYPO3 v8
        if (!empty($returnedOutput['Connections'])) {
            $returnedOutput = $returnedOutput['Connections']['Default'];
        }

        $credentials = [];
        foreach ($returnedOutput as $key => $value) {
            switch ($key) {
                case 'username':
                    $credentials['user'] = $value;
                    break;
                case 'dbname':
                    $credentials['database'] = $value;
                    break;
                default:
                    $credentials[$key] = $value;
                    break;
            }
        }

        return $credentials;
    }
1334005
public function execute(Node $node, Application $application, Deployment $deployment, array $options = [])
    {
        $options = $this->configureOptions($options);

        $dumpCommand = new Process([
            'mysqldump',
            '-h',
            $options['sourceHost'],
            '-u',
            $options['sourceUser'],
            '-p' . $options['sourcePassword'],
            $options['sourceDatabase']
        ]);

        $mysqlCommand = new Process([
            'mysql',
            '-h',
            $options['targetHost'],
            '-u',
            $options['targetUser'],
            '-p' . $options['targetPassword'],
            $options['targetDatabase']

        ]);

        $sshCommand = ['ssh'];
        $username = isset($options['username']) ? $options['username'] . '@' : '';
        $hostname = $node->getHostname();
        $sshCommand[] = $username . $hostname;
        if ($node->hasOption('port')) {
            $sshCommand[] = '-P';
            $sshCommand[] = $node->getOption('port');
        }
        $sshCommand[] = $mysqlCommand->getCommandLine();
        $sshCommand = new Process($sshCommand);

        $command = $dumpCommand->getCommandLine()
            . ' | '
            . $sshCommand->getCommandLine();

        $localhost = new Node('localhost');
        $localhost->onLocalhost();

        $this->shell->executeOrSimulate($command, $localhost, $deployment);
    }
930697
public function execute(Node $node, Application $application, Deployment $deployment, array $options = [])
    {
        $configurationFileExtension = isset($options['configurationFileExtension']) ? $options['configurationFileExtension'] : 'yaml';
        $targetReleasePath = $deployment->getApplicationReleasePath($application);
        $configurationPath = $deployment->getDeploymentConfigurationPath();
        if (!is_dir($configurationPath)) {
            return;
        }
        $commands = [];
        $configurationFiles = Files::readDirectoryRecursively($configurationPath, $configurationFileExtension);
        foreach ($configurationFiles as $configuration) {
            $targetConfigurationPath = dirname(str_replace($configurationPath, '', $configuration));
            $escapedSourcePath = escapeshellarg($configuration);
            $escapedTargetPath = escapeshellarg(Files::concatenatePaths([$targetReleasePath, 'Configuration', $targetConfigurationPath]) . '/');
            if ($node->isLocalhost()) {
                $commands[] = 'mkdir -p ' . $escapedTargetPath;
                $commands[] = 'cp ' . $escapedSourcePath . ' ' . $escapedTargetPath;
            } else {
                $username = isset($options['username']) ? $options['username'] . '@' : '';
                $hostname = $node->getHostname();

                $sshPort = isset($options['port']) ? '-p ' . escapeshellarg($options['port']) . ' ' : '';
                $scpPort = isset($options['port']) ? '-P ' . escapeshellarg($options['port']) . ' ' : '';
                $sshOptions = '';
                $expect = '';
                if ($node->hasOption('password')) {
                    $sshOptions .= '-o PubkeyAuthentication=no ';
                    $passwordSshLoginScriptPathAndFilename = Files::concatenatePaths([dirname(dirname(dirname(dirname(__DIR__)))), 'Resources', 'Private/Scripts/PasswordSshLogin.expect']);
                    if (Phar::running() !== '') {
                        $passwordSshLoginScriptContents = file_get_contents($passwordSshLoginScriptPathAndFilename);
                        $passwordSshLoginScriptPathAndFilename = Files::concatenatePaths([$deployment->getTemporaryPath(), 'PasswordSshLogin.expect']);
                        file_put_contents($passwordSshLoginScriptPathAndFilename, $passwordSshLoginScriptContents);
                    }
                    $expect = sprintf('expect %s %s', escapeshellarg($passwordSshLoginScriptPathAndFilename), escapeshellarg($node->getOption('password')));
                }
                $createDirectoryCommand = '"mkdir -p ' . $escapedTargetPath . '"';
                $commands[] = ltrim("{$expect} ssh {$sshOptions}{$sshPort}{$username}{$hostname} {$createDirectoryCommand}");
                $commands[] = ltrim("{$expect} scp {$sshOptions}{$scpPort}{$escapedSourcePath} {$username}{$hostname}:\"{$escapedTargetPath}\"");
            }
        }

        $localhost = new Node('localhost');
        $localhost->onLocalhost();

        $this->shell->executeOrSimulate($commands, $localhost, $deployment);
    }
365939
public function execute(Node $node, Application $application, Deployment $deployment, array $options = [])
    {
        try {
            $options = $this->configureOptions($options);
        } catch (ExceptionInterface $e) {
            return;
        }

        if (empty($options['directories'])) {
            return;
        }

        $baseDirectory = $options['baseDirectory'] ?: $deployment->getApplicationReleasePath($application);

        $commands = array_map(function ($directory) {
            return sprintf('mkdir -p %s', $directory);
        }, $options['directories']);

        array_unshift($commands, sprintf('cd %s', $baseDirectory));

        $this->shell->executeOrSimulate($commands, $node, $deployment);
    }
1109077
public function execute(Node $node, Application $application, Deployment $deployment, array $options = [])
    {
        try {
            $commands = $this->buildCommands(
                $deployment,
                $application,
                $options
            );
            $this->shell->executeOrSimulate($commands, $node, $deployment);
        } catch (CommandProviderException $e) {
            $deployment->getLogger()->log('Task was skipped! Reason: ' . $e->getMessage(), LOG_WARNING);
        }
    }
1294422
public function execute(Node $node, Application $application, Deployment $deployment, array $options = [])
    {
        if (empty($options['sourceNode']) || !is_array($options['sourceNode'])) {
            throw new InvalidConfigurationException('SourceNode is missing', 1409263510);
        }
        $sourceNode = $this->nodeFactory->getNodeByArray($options['sourceNode']);

        $options = array_replace_recursive($this->options, $options);

        $source = $this->getArgument($sourceNode, $application, $options['sourcePath'], $options['sourceFile']);
        $target = $this->getArgument($node, $application, $options['targetPath'], $options['targetFile']);
        $command = 'scp -o BatchMode=\'yes\' '.$source.' '.$target;

        $this->shell->executeOrSimulate($command, $node, $deployment);
    }
499281
public function registerTasks(Workflow $workflow, Deployment $deployment)
    {
        parent::registerTasks($workflow, $deployment);

        $this->checkIfMandatoryOptionsExist();
        $this->buildConfiguration();
        $this->defineTasks($workflow, $deployment);

        if ($this->getOption('enableTests') !== false) {
            $workflow
                ->addTask([
                    UnitTestTask::class,
                    FunctionalTestTask::class
                ], 'test', $this);
        }

        $workflow->addTask([
                'TYPO3\\Surf\\DefinedTask\\CreateZipDistributionTask',
                'TYPO3\\Surf\\DefinedTask\\CreateTarGzDistributionTask',
                'TYPO3\\Surf\\DefinedTask\\CreateTarBz2DistributionTask',
            ], 'cleanup', $this);

        if ($this->hasOption('enableSourceforgeUpload') && $this->getOption('enableSourceforgeUpload') === true) {
            $workflow->addTask(SourceforgeUploadTask::class, 'cleanup', $this);
        }
        if ($this->hasOption('releaseHost')) {
            $workflow->addTask(PrepareReleaseTask::class, 'initialize', $this);
            $workflow->addTask(ReleaseTask::class, 'cleanup', $this);
        }
        if ($this->hasOption('releaseHost') && $this->hasOption('enableSourceforgeUpload') && $this->getOption('enableSourceforgeUpload') === true) {
            $workflow->addTask(AddDownloadTask::class, 'cleanup', $this);
        }
        if ($this->hasOption('createTags') && $this->getOption('createTags') === true) {
            $workflow->addTask(TagTask::class, 'cleanup', $this);
            if ($this->hasOption('TYPO3\\Surf\\DefinedTask\\Git\\PushTagsTask') && $this->getOption('TYPO3\\Surf\\DefinedTask\\Git\\PushTagsTask') === true) {
                $workflow->afterTask(TagTask::class, 'TYPO3\\Surf\\DefinedTask\\Git\\PushTagsTask', $this);
            }
        }

        $workflow->removeTask(MigrateTask::class);
    }
94473
protected function defineTasks(Workflow $workflow, Deployment $deployment)
    {
        $excludePatterns = [
            '.git*',
            'Data/*',
            'Web/_Resources/*',
            'Build/Reports',
            './Cache',
            'Configuration/PackageStates.php'
        ];

        $baseArchiveConfiguration = [
            'sourceDirectory' => $deployment->getApplicationReleasePath($this),
            'baseDirectory' => $this->configuration['versionAndProjectName'],
            'exclude' => $excludePatterns
        ];

        $workflow->defineTask('TYPO3\\Surf\\DefinedTask\\CreateZipDistributionTask', CreateArchiveTask::class, array_merge($baseArchiveConfiguration, [
            'targetFile' => $this->configuration['zipFile']
        ]));

        $workflow->defineTask('TYPO3\\Surf\\DefinedTask\\CreateTarGzDistributionTask', CreateArchiveTask::class, array_merge($baseArchiveConfiguration, [
            'targetFile' => $this->configuration['tarGzFile'],
        ]));

        $workflow->defineTask('TYPO3\\Surf\\DefinedTask\\CreateTarBz2DistributionTask', CreateArchiveTask::class, array_merge($baseArchiveConfiguration, [
            'targetFile' => $this->configuration['tarBz2File'],
        ]));

        if ($this->hasOption('enableSourceforgeUpload') && $this->getOption('enableSourceforgeUpload') === true) {
            $workflow->defineTask(SourceforgeUploadTask::class, SourceforgeUploadTask::class, [
                'sourceforgeProjectName' => $this->getOption('sourceforgeProjectName'),
                'sourceforgePackageName' => $this->getOption('sourceforgePackageName'),
                'sourceforgeUserName' => $this->getOption('sourceforgeUserName'),
                'version' => $this->getOption('version'),
                'files' => [
                    $this->configuration['zipFile'],
                    $this->configuration['tarGzFile'],
                    $this->configuration['tarBz2File'],
                ]
            ]);
        }

        if ($this->hasOption('releaseHost')) {
            $workflow->defineTask(PrepareReleaseTask::class, PrepareReleaseTask::class, [
                'releaseHost' =>  $this->getOption('releaseHost'),
                'releaseHostSitePath' => $this->getOption('releaseHostSitePath'),
                'releaseHostLogin' =>  $this->hasOption('releaseHostLogin') ? $this->getOption('releaseHostLogin') : null,
                'productName' => $this->getOption('projectName'),
                'version' => $this->getOption('version'),
            ]);
            $workflow->defineTask(ReleaseTask::class, ReleaseTask::class, [
                'releaseHost' =>  $this->getOption('releaseHost'),
                'releaseHostSitePath' => $this->getOption('releaseHostSitePath'),
                'releaseHostLogin' =>  $this->hasOption('releaseHostLogin') ? $this->getOption('releaseHostLogin') : null,
                'productName' => $this->getOption('projectName'),
                'version' => $this->getOption('version'),
                'changeLogUri' =>  $this->hasOption('changeLogUri') ? $this->getOption('changeLogUri') : null,
            ]);
        }

        if ($this->hasOption('releaseHost') && $this->hasOption('enableSourceforgeUpload') && $this->getOption('enableSourceforgeUpload') === true) {
            $workflow->defineTask(AddDownloadTask::class, AddDownloadTask::class, [
                'releaseHost' =>  $this->getOption('releaseHost'),
                'releaseHostSitePath' => $this->getOption('releaseHostSitePath'),
                'releaseHostLogin' =>  $this->hasOption('releaseHostLogin') ? $this->getOption('releaseHostLogin') : null,
                'productName' => $this->getOption('projectName'),
                'version' => $this->getOption('version'),
                'label' => $this->getOption('releaseDownloadLabel'),
                'downloadUriPattern' => $this->getOption('releaseDownloadUriPattern'),
                'files' => [
                    $this->configuration['zipFile'],
                    $this->configuration['tarGzFile'],
                    $this->configuration['tarBz2File'],
                ]
            ]);
        }

        $workflow->defineTask(TagTask::class, TagTask::class, [
            'tagName' => $this->configuration['versionAndProjectName'],
            'description' => 'Tag distribution with tag ' . $this->configuration['versionAndProjectName'],
            'recurseIntoSubmodules' => $this->getOption('tagRecurseIntoSubmodules')
        ]);

        $workflow->defineTask('TYPO3\\Surf\\DefinedTask\\Git\\PushTagsTask', PushTask::class, [
            'remote' => 'origin',
            'refspec' => $this->configuration['versionAndProjectName'] . ':refs/tags/' . $this->configuration['versionAndProjectName'],
            'recurseIntoSubmodules' => $this->getOption('tagRecurseIntoSubmodules')
        ]);
    }
758810
private synchronized void doNodeLeft(final String nodeID) {
    log.info(String.format("%s - %s left the cluster", this, nodeID));
    context.run(new Runnable() {
      @Override
      public void run() {
        // Redeploy any failed deployments.
        synchronized (deployments) {
          Collection<String> sdeploymentsInfo = deployments.get(group);
          for (final String sdeploymentInfo : sdeploymentsInfo) {
            final JsonObject deploymentInfo = new JsonObject(sdeploymentInfo);
            // If the deployment node is equal to the node that left the cluster then
            // remove the deployment from the deployments list and attempt to redeploy it.
            if (deploymentInfo.getString("node").equals(nodeID)) {
              // If the deployment is an HA deployment then attempt to redeploy it on this node.
              if (deployments.remove(group, sdeploymentInfo) && deploymentInfo.getBoolean("ha", false)) {
                doRedeploy(deploymentInfo);
              }
            }
          }
        }
      }
    });
  }
262030
@TaskAction
  public void deployAllAction() throws AppEngineException {
    List<Path> deployables = new ArrayList<>();

    // Look for app.yaml
    Path appYaml = stageDirectory.toPath().resolve("app.yaml");
    if (!Files.isRegularFile(appYaml)) {
      throw new GradleException("Failed to deploy all: app.yaml not found.");
    }
    addDeployable(deployables, appYaml);

    // Look for configuration yamls
    String[] validYamls = {"cron.yaml", "dispatch.yaml", "dos.yaml", "index.yaml", "queue.yaml"};
    for (String yamlName : validYamls) {
      Path yaml = deployExtension.getAppEngineDirectory().toPath().resolve(yamlName);
      if (Files.isRegularFile(yaml)) {
        addDeployable(deployables, yaml);
      }
    }

    // Deploy
    Deployment deploy = gcloud.newDeployment(CloudSdkOperations.getDefaultHandler(getLogger()));

    DeployConfiguration deployConfig = deployExtension.toDeployConfiguration(deployables);
    deploy.deploy(deployConfig);
  }
1248917
public function execute(Node $node, Application $application, Deployment $deployment, array $options = [])
    {
        $localPackagePath = $deployment->getWorkspacePath($application);
        $releasePath = $deployment->getApplicationReleasePath($application);

        $remotePath = Files::concatenatePaths([$application->getDeploymentPath(), 'cache/transfer']);
        // make sure there is a remote .cache folder
        $command = 'mkdir -p ' . $remotePath;
        $this->shell->executeOrSimulate($command, $node, $deployment);

        $username = $node->hasOption('username') ? $node->getOption('username') . '@' : '';
        $hostname = $node->getHostname();
        $noPubkeyAuthentication = $node->hasOption('password') ? ' -o PubkeyAuthentication=no' : '';
        $port = $node->hasOption('port') ? ' -p ' . escapeshellarg($node->getOption('port')) : '';
        $key = $node->hasOption('privateKeyFile') ? ' -i ' . escapeshellarg($node->getOption('privateKeyFile')) : '';
        $quietFlag = (isset($options['verbose']) && $options['verbose']) ? '' : '-q';
        $rshFlag = ($node->isLocalhost() ? '' : '--rsh="ssh' . $noPubkeyAuthentication . $port . $key . '" ');

        $rsyncExcludes = isset($options['rsyncExcludes']) ? $options['rsyncExcludes'] : ['.git'];
        $excludeFlags = $this->getExcludeFlags($rsyncExcludes);

        $rsyncFlags = (isset($options['rsyncFlags']) ? $options['rsyncFlags'] : '--recursive --times --perms --links --delete --delete-excluded') . $excludeFlags;

        $destinationArgument = ($node->isLocalhost() ? $remotePath : "{$username}{$hostname}:{$remotePath}");

        $command = "rsync {$quietFlag} --compress {$rshFlag} {$rsyncFlags} " . escapeshellarg($localPackagePath . '/.') . ' ' . escapeshellarg($destinationArgument);

        if ($node->hasOption('password')) {
            $passwordSshLoginScriptPathAndFilename = Files::concatenatePaths([dirname(dirname(dirname(__DIR__))), 'Resources', 'Private/Scripts/PasswordSshLogin.expect']);
            if (Phar::running() !== '') {
                $passwordSshLoginScriptContents = file_get_contents($passwordSshLoginScriptPathAndFilename);
                $passwordSshLoginScriptPathAndFilename = Files::concatenatePaths([$deployment->getTemporaryPath(), 'PasswordSshLogin.expect']);
                file_put_contents($passwordSshLoginScriptPathAndFilename, $passwordSshLoginScriptContents);
            }
            $command = sprintf('expect %s %s %s', escapeshellarg($passwordSshLoginScriptPathAndFilename), escapeshellarg($node->getOption('password')), $command);
        }

        $localhost = new Node('localhost');
        $localhost->onLocalhost();
        $this->shell->executeOrSimulate($command, $localhost, $deployment);

        if (isset($passwordSshLoginScriptPathAndFilename) && Phar::running() !== '') {
            unlink($passwordSshLoginScriptPathAndFilename);
        }

        $command = strtr("cp -RPp $remotePath/. $releasePath", "\t\n", '  ');
        // TODO Copy revision file (if it exists) for application to deployment path with release identifier

        $this->shell->executeOrSimulate($command, $node, $deployment);
    }
649002
public function run(Deployment $deployment)
    {
        parent::run($deployment);

        $applications = $deployment->getApplications();
        if (count($applications) === 0) {
            throw InvalidConfigurationException::createNoApplicationConfigured();
        }

        $nodes = $deployment->getNodes();
        if (count($nodes) === 0) {
            throw InvalidConfigurationException::createNoNodesConfigured();
        }

        $this->configureRollbackTasks($deployment);

        foreach ($this->stages as $stage) {
            $deployment->getLogger()->notice('Stage ' . $stage);
            foreach ($nodes as $node) {
                $deployment->getLogger()->debug('Node ' . $node->getName());
                foreach ($applications as $application) {
                    if (! $application->hasNode($node)) {
                        continue;
                    }

                    $deployment->getLogger()->debug('Application ' . $application->getName());

                    try {
                        $this->executeStage($stage, $node, $application, $deployment);
                    } catch (Exception $exception) {
                        return;
                    }
                }
            }
        }
        if ($deployment->getStatus() === Deployment::STATUS_UNKNOWN) {
            $deployment->setStatus(Deployment::STATUS_SUCCESS);
        }
    }