diff --git a/src/Provision/Context.php b/src/Provision/Context.php
index 5bfd8afd..25e6ace5 100644
--- a/src/Provision/Context.php
+++ b/src/Provision/Context.php
@@ -996,28 +996,19 @@ public function shell_exec($command, $dir = NULL, $return = 'stdout') {
$this->getProperty('root')
;
- if ($this->getProvision()->getOutput()->isVerbose()) {
- $this->getProvision()->io()->commandBlock($command, $effective_wd);
- $this->getProvision()->io()->customLite("Writing output to $tmp_output_file", ProvisionStyle::ICON_FILE, 'comment');
-
- // If verbose, Use tee so we see it and it saves to file.
- // Thanks to https://askubuntu.com/a/731237
- // Uses "2>&1 |" so it works with older bash shells.
- $command = "$command 2>&1 | tee -a $tmp_output_file; exit \${PIPESTATUS[0]}
-";
- }
- else {
- // If not verbose, just save it to file.
- $command .= "> $tmp_output_file 2>&1";
- }
-
// Output and Errors to file.
- $process = $this->process_exec($command, $effective_wd);
+ $process = $this->process_exec($command, $effective_wd, $tmp_output_file);
$exit_code = $process->getExitCode();
+
// print 'EXIT CODE! ' . $exit_code; die;
$exit = $process->getExitCode();
$stdout = file_get_contents($tmp_output_file);
-
+
+ $this->getProvision()->getLogger()->debug('Shell exec command: ' . print_r($command, 1));
+ $this->getProvision()->getLogger()->debug('Shell exec dir: ' . print_r($effective_wd, 1));
+ $this->getProvision()->getLogger()->debug('Shell exec exit code: ' . print_r($exit, 1));
+ $this->getProvision()->getLogger()->debug('Shell exec output: ' . print_r($stdout, 1));
+
if ($exit != ResultData::EXITCODE_OK) {
throw new \Exception($stdout);
}
@@ -1030,14 +1021,39 @@ public function shell_exec($command, $dir = NULL, $return = 'stdout') {
* @param null $dir
* @param string $return
*/
- public function process_exec($command, $dir = NULL) {
+ public function process_exec($command, $dir = NULL, $output_file = NULL) {
+
+ if(!$this->isLocalHost()){
+ $ssh_command = 'ssh -o PasswordAuthentication=no ' . $this->getProperty('script_user') . '@' . $this->getProperty('remote_host');
+ if($dir){
+ $command = 'cd ' . $dir . ' && ' . $command;
+ }
+ $command = $ssh_command . ' "' . $command . '"';
+ }
+ if($output_file){
+ if ($this->getProvision()->getOutput()->isVerbose()) {
+ $this->getProvision()->io()->commandBlock($command, $dir);
+ $this->getProvision()->io()->customLite("Writing output to $output_file", ProvisionStyle::ICON_FILE, 'comment');
+
+ // If verbose, Use tee so we see it and it saves to file.
+ // Thanks to https://askubuntu.com/a/731237
+ // Uses "2>&1 |" so it works with older bash shells.
+ $command = "$command 2>&1 | tee -a $output_file";
+ }
+ else {
+ // If not verbose, just save it to file.
+ $command .= " > $output_file 2>&1";
+ }
+ }
+
$process = new Process($command);
$process->setTimeout(null);
$process->setTty(true);
$env = $_SERVER;
+ $this->getProvision()->getLogger()->debug('Command: ' . print_r($command, 1));
$this->getProvision()->getLogger()->debug('Environment: ' . print_r($env, 1));
$env['PROVISION_CONTEXT'] = $this->name;
@@ -1091,4 +1107,135 @@ function getServiceCommandClasses() {
return $classes;
}
+
+ public function isLocalHost(){
+ if($this->hasProperty('remote_host')){
+ $host = $this->getProperty('remote_host');
+
+ $host = strtolower($host);
+ // In order for this to work right, you must use 'localhost' or '127.0.0.1'
+ // or the machine returned by 'uname -n' for your 'remote-host' entry in
+ // your site alias. Note that sometimes 'uname -n' does not return the
+ // correct value. To fix it, put the correct hostname in /etc/hostname
+ // and then run 'hostname -F /etc/hostname'.
+ return ($host == 'localhost') ||
+ ($host == '127.0.0.1') ||
+ (gethostbyname($host) == '127.0.0.1') ||
+ (gethostbyname($host) == '127.0.1.1') || // common setting on
+ // ubuntu and friends
+ ($host == strtolower(php_uname('n'))) ||
+ ($host == static::provisionFqdn());
+ }
+
+ return true;
+ }
+
+ public static function provisionFqdn($host = NULL) {
+ if (is_null($host)) {
+ $host = php_uname('n');
+ }
+ return strtolower(gethostbyaddr(gethostbyname($host)));
+ }
+
+ public function sync($path = NULL, $additional_options = array()) {
+ if(!$this->isLocalHost()){
+ if (is_null($path)) {
+ $path = $this->getWorkingDir();
+ }
+ if ($this->fs->exists($path)) {
+ $default_options = array(
+ 'relative' => TRUE,
+ 'keep-dirlinks' => TRUE,
+ 'omit-dir-times' => TRUE,
+ );
+ $options = array_merge($default_options,$additional_options);
+ $parameters[] = $this->rsyncOptions($options);
+ $parameters[] = $path;
+ $parameters[] = $this->getProperty('script_user') . '@' . $this->getProperty('remote_host') . ':/';
+
+ $exec = "rsync -e 'ssh -o PasswordAuthentication=no' " . implode(' ', array_filter($parameters)) . ' 2>&1';
+
+ $process = new \Symfony\Component\Process\Process($exec);
+ $process->run();
+
+ $this->getProvision()->getLogger()->debug('Sync command: ' . print_r($exec, 1));
+ $this->getProvision()->getLogger()->debug('Sync command output: ' . print_r($process->getOutput(), 1));
+ $this->getProvision()->getLogger()->debug('Sync command exitcode: ' . print_r($process->getExitCode(), 1));
+
+ return $process->getExitCode() == ResultData::EXITCODE_OK;
+ }
+ else { // File does not exist, remove it.
+ return $this->shell_exec('rm -rf ' . escapeshellarg($path));
+ }
+ }
+ return 0;
+ }
+ public function fetch($path, $additional_options = array()) {
+ if(!$this->isLocalHost()){
+ if (is_null($path)) {
+ return;
+ }
+ if ($this->fs->exists($path)) {
+ $default_options = array(
+ 'omit-dir-times' => TRUE,
+ );
+ $options = array_merge($default_options,$additional_options);
+ $parameters[] = $this->rsyncOptions($options);
+ $parameters[] = $this->getProperty('script_user') . '@' . $this->getProperty('remote_host') . ':' . $path ;
+ $parameters[] = $path;
+
+ $exec = "rsync -e 'ssh -o PasswordAuthentication=no' " . implode(' ', array_filter($parameters)) . ' 2>&1';
+
+ $process = new \Symfony\Component\Process\Process($exec);
+ $process->run();
+
+ $this->getProvision()->getLogger()->debug('Sync command: ' . print_r($exec, 1));
+ $this->getProvision()->getLogger()->debug('Sync command output: ' . print_r($process->getOutput(), 1));
+ $this->getProvision()->getLogger()->debug('Sync command exitcode: ' . print_r($process->getExitCode(), 1));
+
+ return $process->getExitCode() == ResultData::EXITCODE_OK;
+ }
+ else { // File does not exist, remove it.
+ return $this->shell_exec('rm -rf ' . escapeshellarg($path));
+ }
+ }
+ }
+
+ public function rsyncOptions($options)
+ {
+ $verbose = $paths = $op = '';
+ $options += [
+ 'mode' => 'akz'
+ ];
+ // Process --include-paths and --exclude-paths options the same way
+ foreach (['include', 'exclude'] as $include_exclude) {
+ // Get the option --include-paths or --exclude-paths and explode to an array of paths
+ // that we will translate into an --include or --exclude option to pass to rsync
+ $inc_ex_path = explode(PATH_SEPARATOR, @$options[$include_exclude . '-paths']);
+ foreach ($inc_ex_path as $one_path_to_inc_ex) {
+ if (!empty($one_path_to_inc_ex)) {
+ $paths .= ' --' . $include_exclude . '="' . $one_path_to_inc_ex . '"';
+ }
+ }
+ }
+
+ $mode = '-'. $options['mode'];
+ if ($this->getProvision()->getOutput()->isVerbose()) {
+ $mode .= 'v';
+ $verbose = ' --stats --progress';
+ }
+ $options_to_exclude = array('mode','ssh-options');
+ foreach ($options as $test_option => $value) {
+ if ((isset($test_option)) && !in_array($test_option, $options_to_exclude) && (isset($value) && !is_array($value))) {
+ if (($value === TRUE) || (!isset($value))) {
+ $op .= " --$test_option";
+ }
+ else {
+ $op .= " --$test_option=" . escapeshellarg($value);
+ }
+ }
+ }
+
+ return implode(' ', array_filter([$mode, $verbose, $op, $paths]));
+ }
}
diff --git a/src/Provision/Context/SiteContext.php b/src/Provision/Context/SiteContext.php
index c421f1e4..cead2d45 100644
--- a/src/Provision/Context/SiteContext.php
+++ b/src/Provision/Context/SiteContext.php
@@ -216,7 +216,7 @@ public function verify()
// @TODO: This is only true for Drupal version 7.50 and up. See Provision/Config/Drupal/Settings.php
// We are treading more and more into the Drupal-only world, so I'm leaving this hard coded to TRUE until we develop something else.
$database_settings = << \$_SERVER['db_type'],
@@ -260,6 +260,14 @@ public function verify()
//
// provision_drupal_push_site(drush_get_option('override_slave_authority', FALSE));
//
+ $steps['site.sync'] = Provision::newStep()
+ ->start("Running site sync ...")
+ ->execute(function (){
+ if($this->sync()){
+ return 0;
+ }
+ return 1;
+ });
return $steps;
}
@@ -315,4 +323,7 @@ public static function randomBytes($count) {
public static function randomBytesBase64($count = 32) {
return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode(static::randomBytes($count)));
}
+ public function sync($path = NULL, $additional_options = array()) {
+ return $this->getSubscription('http')->service->provider->sync($this->getWorkingDir(), $additional_options);
+ }
}
diff --git a/src/Provision/Provision.php b/src/Provision/Provision.php
index 38d9df36..d19ee7e3 100644
--- a/src/Provision/Provision.php
+++ b/src/Provision/Provision.php
@@ -69,22 +69,22 @@ class Provision implements ConfigAwareInterface, ContainerAwareInterface, Logger
/**
* @var \Robo\Runner
*/
- private $runner;
+ protected $runner;
/**
* @var ProvisionTasks
*/
- private $tasks;
+ protected $tasks;
/**
* @var string[]
*/
- private $commands = [];
+ protected $commands = [];
/**
* @var \Aegir\Provision\Application
*/
- private $application;
+ protected $application;
/**
* @var \Aegir\Provision\Context[]
@@ -99,7 +99,7 @@ class Provision implements ConfigAwareInterface, ContainerAwareInterface, Logger
/**
* @var array[]
*/
- private $context_files = [];
+ protected $context_files = [];
/**
* @var ConsoleOutput
@@ -168,7 +168,7 @@ public function __construct(
/**
* Lookup all context yml files and load into Context classes.
*/
- private function loadAllContexts()
+ protected function loadAllContexts()
{
try {
$folder = $this->getConfig()->get('contexts_path');
diff --git a/src/Provision/Service.php b/src/Provision/Service.php
index dd0db6d2..3d3ef3d7 100644
--- a/src/Provision/Service.php
+++ b/src/Provision/Service.php
@@ -229,6 +229,10 @@ protected function writeConfigurations(Context $context = NULL)
$success = FALSE;
}
}
+ if($context->type != 'server'){
+ $context = $context->getSubscription('http')->service->provider;
+ }
+ $success = $success && $context->sync();
return $success;
}