function _drush_cm_merge_local_and_remote_configurations

7.x config.drush.inc _drush_cm_merge_local_and_remote_configurations(&$merge_info)
1 call to _drush_cm_merge_local_and_remote_configurations()

File

commands/core/config.drush.inc, line 1009
Provides Configuration Management commands.

Code

function _drush_cm_merge_local_and_remote_configurations(&$merge_info) {
  $configuration_path = _drush_cm_get_configuration_path($merge_info);

  $result = drush_shell_cd_and_exec($configuration_path, 'git add -A .');
  if (!$result) {
    return drush_set_error('DRUSH_CONFIG_MERGE_FAILURE', dt("`git add -A` failed."));
  }
  // Note that this commit will be `merge --squash`-ed away.  We'll put in
  // a descriptive message to help users understand where it came from, if
  // they end up with dirty branches after an aborted run.
  $result = drush_shell_cd_and_exec($configuration_path, 'git commit -m %s', 'Drush config-merge exported configuration from ' . $merge_info['dev-site'] . ' ' . $merge_info['message']);
  if (!$result) {
    return drush_set_error('DRUSH_CONFIG_MERGE_FAILURE', dt("`git commit` failed."));
  }

  // git checkout live-config && git rebase dev-config.
  // This will put us back on the live-config branch,
  // merge in the changes from the temporary dev branch,
  // and rebase the live-config branch to include all of
  // the commits from the dev config branch.
  $result = drush_shell_cd_and_exec($configuration_path, 'git checkout %s && git rebase %s', $merge_info['live-config'], $merge_info['dev-config']);

  // We don't need the dev-config branch any more, so we'll get rid of
  // it right away, so there is less to clean up / hang around should
  // we happen to abort before everything is done.
  if ($merge_info['autodelete-dev-config']) {
    drush_shell_cd_and_exec($configuration_path, 'git branch -D %s 2>/dev/null', $merge_info['dev-config']);
  }

  // If there are MERGE CONFLICTS: prompt the user and run 3-way diff tool.
  $result = drush_shell_cd_and_exec($configuration_path, 'git status --porcelain .', $configuration_path);
  if (!$result) {
    return drush_set_error('DRUSH_CONFIG_MERGE_FAILURE', dt("`git status` failed."));
  }
  // Check to see if any line in the output starts with 'UU'.
  // This means "both sides updated" -- i.e. a conflict.
  $conflicting_configuration_changes = drush_shell_exec_output();
  $conflicting_files = array_reduce($conflicting_configuration_changes, function($reduce, $item) use ($configuration_path) {
    if (substr($item, 0, 2) == "UU") {
      $reduce[] = str_replace($configuration_path . '/', '', substr($item, 3));
    }
    return $reduce;
  }, array());
  // Report on any conflicts found.
  if (!empty($conflicting_files)) {
    drush_print("\nCONFLICTS:\n");
    drush_print(implode("\n", $conflicting_files));
    drush_print("\n");
  }

  // Stop right here if the user specified --merge-only.
  if (drush_get_option('fetch-only', FALSE)) {
    drush_log(dt("Specified --fetch-only, so stopping here after the merge.  Use `git checkout !b` to return to your original branch.", array('!b' => $merge_info['original-branch'])), 'ok');
    return TRUE;
  }

  // If there are any conflicts, run the merge tool.
  if (!empty($conflicting_files)) {
    if (!$merge_info['tool'] && ($merge_info['tool'] != '')) {
      // If --tool=0, then we will never run the merge tool
      return drush_set_error('DRUSH_CONFLICTS_NOT_MERGED', dt("There were conflicts that needed merging, but mergetool disabled via --tool option.  Rolling back; run again with --fetch-only to stop prior to merge."));
    }
    $choice = 'mergetool';
    while ($choice == 'mergetool') {
      if (empty($merge_info['tool'])) {
        $result = drush_shell_cd_and_exec($configuration_path, 'git mergetool .');
      }
      else {
        $result = drush_shell_cd_and_exec($configuration_path, 'git mergetool --tool=%s .', $merge_info['tool']);
      }
      // There is no good way to tell what the result of 'git mergetool'
      // was.
      //
      // The documentation says that $result will be FALSE if the user
      // quits without saving; however, in my experience, git mergetool
      // hangs, and never returns if kdiff3 or meld exits without saving.
      //
      // We will not allow the user to continue if 'git mergetool' exits with
      // an error.  If there was no error, we will ask the user how to continue,
      // since save and exit does not necessarily mean that the user was
      // satisfied with the result of the merge.
      $done = array();
      if ($result) {
        if ($merge_info['commit']) {
          $done = array('done' => dt("All conflicts resolved!  Commit changes, re-import configuration and exit."));
        }
        else {
          $done = array('done' => dt("All conflicts resolved!  Re-import configuration and exit with unstaged changes."));
        }
      }
      $selections = $done + array(
        'abandon' => dt("Abandon merge; erase all work, and go back to original state."),
        'mergetool' => dt("Run mergetool again."),
      );
      $choice = drush_choice($selections, dt("Done with merge.  What would you like to do next?"));
      // If the user cancels, we must call drush_user_abort() for things to work right.
      if ($choice === FALSE) {
        return drush_user_abort();
      }
      // If there is an action function, then call it.
      $fn = '_drush_config_merge_action_' . $choice;
      if (function_exists($fn)) {
        $choice = $fn($merge_info);
      }
      // If the action function returns TRUE or FALSE, then
      // return with that result without taking further action.
      if (is_bool($choice)) {
        return $choice;
      }
    }
    // Commit the results of the merge to the working branch.  This
    // commit will be squash-merged with the others below; if the
    // --no-commit option was selected, the results of the squash-merge
    // will remain unstaged.
    $result = drush_shell_cd_and_exec($configuration_path, 'git add -A .');
    if (!$result) {
      return drush_set_error('DRUSH_CONFIG_MERGE_FAILURE', dt("`git add -A` failed."));
    }
    $result = drush_shell_cd_and_exec($configuration_path, 'git commit -m %s', 'Drush config-merge merge commit for ' . $merge_info['live-site'] . ' configuration with ' . $merge_info['dev-site'] . ' configuration.');
    if (!$result) {
      return drush_set_error('DRUSH_CONFIG_MERGE_FAILURE', dt("`git commit` failed."));
    }
  }
}