Commit 35b710ea authored by Christopher Gervais's avatar Christopher Gervais
Browse files

Complete platform git implementation.

parent 4db24641
Loading
Loading
Loading
Loading
+67 −16
Original line number Diff line number Diff line
@@ -21,51 +21,102 @@ class Provision_PlatformGit extends Provision_ShellCommand {
  // The Git reference that we'll clone or checkout.
  protected $reference = FALSE;

  // A list of references fetched from a Git repository.
  protected $references = [];

  public function validateProvisionVerify() {
    if ($this->pathExists($this->repository_path)) {
      return $this->error(dt('Platform Git repository path already exists. Aborting.'));
      return $this->notice(dt('Platform Git repository path already exists. Aborting.'));
    }
    else {
      $this->notice(dt("Platform Git repository path does not exist."));
      return $this->gitClone();
      $this->notice(dt('Platform Git repository path does not exist. Proceeding.'));
      return $this->deployPlatform();
    }
  }

  /**
   * Implements the provision-git-clone command.
   */
  protected function deployPlatform() {
    $this->notice(dt('Deploying platform.'));
    return $this->gitClone() && $this->gitCheckout();
  }

  protected function gitClone() {
    $this->notice(dt('Cloning `:url` to `:path`', [
      ':url' => $this->repository_url,
      ':path' => $this->repository_path,
    ]));

    $command = 'git clone --recursive --depth=1';
    if ($this->referenceIsBranch()) {
    return $this->runCommand($this->buildGitCloneCommand());
  }

  protected function gitCheckout() {
    if ($this->referenceIsACommit()) {
      $this->notice(dt('Fetching full Git history and checking out commit `:ref`', [
        ':ref' => $this->reference,
      ]));

      return $this->runCommand($this->buildGitCheckoutCommand());
    }
  }

  protected function buildGitCloneCommand() {
    $command = 'git clone --recursive --depth 1 --no-progress --quiet';
    if ($this->referenceIsABranch() || $this->referenceIsATag()) {
      $command .= ' --branch ' . escapeshellarg(trim($this->reference));
    }
    $command .= ' ' . escapeshellarg(trim($this->repository_url));
    $command .= ' ' . escapeshellarg(trim($this->repository_path));
    return $command;
  }

    return $this->runCommand($command);
  protected function buildGitCheckoutCommand() {
    $command = 'cd ' . escapeshellarg(trim($this->repository_path));
    $command .= ' && git fetch --unshallow && ';
    $command .= 'git checkout ' . escapeshellarg(trim($this->reference));
    return $command;
  }

  protected function runCommand($command) {

    $this->notice("Running `$command`");
    if (drush_shell_exec($command)) {
      $this->success(dt('Clone successful.'));
      $this->success(dt('Command succeeded.'));
      $this->success(implode("\n", drush_shell_exec_output()));
      return TRUE;
    }
    else {
      return $this->error(dt("Git clone failed! \nThe specific errors are below:\n!errors", array('!errors' => implode("\n", drush_shell_exec_output()))));
      $this->error(dt('Command failed. The specific errors follow:'));
      $this->error(implode("\n", drush_shell_exec_output()));
      return FALSE;
    }
  }

  protected function referenceIsBranch() {
    // TODO: implement this check so that we can determine whether to clone a
    // branch, or the full repo, the checkout.
    return TRUE;
  protected function referenceIsABranch() {
    return $this->reference && in_array($this->reference, $this->lsRemote('heads'));
  }

  protected function referenceIsATag() {
    return $this->reference && in_array($this->reference, $this->lsRemote('tags'));
  }

  protected function referenceIsACommit() {
    return $this->reference && !$this->referenceIsABranch() && !$this->referenceIsATag();
  }

  protected function lsRemote($type = FALSE) {
    if (empty($this->references)) {
      $this->notice(dt('Scanning remote git repository tags and branches.'));
      $debug = drush_get_context('DRUSH_DEBUG');
      drush_set_context('DRUSH_DEBUG', FALSE);
      drush_shell_exec('git ls-remote ' . escapeshellarg(trim($this->repository_url)));
      drush_set_context('DRUSH_DEBUG', $debug);
      $lines = drush_shell_exec_output();
      foreach ($lines as $line) {
        $ref = explode('/', $line);
        if (isset($ref[1]) && isset($ref[2])) {
          $this->references[$ref[1]][] = $ref[2];
        }
      }
    }
    return $type ? $this->references[$type] : $this->references;
  }

  public function postProvisionDelete() {
+1 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ class Provision_ShellCommand {
    $context_property_name = $this->context_prefix . $property;
    $context_property = d()->$context_property_name;
    if (is_null($context_property)) {
      return $this->error(dt('Required context property missing: ') . $context_property_name);
      return $this->notice(dt('Skipping unset context property: ') . $context_property_name);
    }
    $this->$property = $context_property;
  }
+2 −2
Original line number Diff line number Diff line
@@ -9,8 +9,8 @@
 */
function hosting_platform_git_hosting_feature() {
  $features['platform_git'] = array(
    'title' => t('Platform Git'),
    'description' => t('Build platforms from Git.'),
    'title' => t('Git Deploy'),
    'description' => t('Deploy platforms using Git.'),
    'status' => HOSTING_FEATURE_DISABLED,
    'module' => 'hosting_platform_git',
    'group' => 'experimental',
+6 −3
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@ function hosting_platform_git_field_default_field_instances() {
    'bundle' => 'platform',
    'default_value' => NULL,
    'deleted' => 0,
    'description' => '',
    'description' => 'If Drupal resides in a sub-directory of your Git repository, specify it here. This path should be relative to the root of the git repository.',
    'display' => array(
      'default' => array(
        'label' => 'above',
@@ -55,7 +55,7 @@ function hosting_platform_git_field_default_field_instances() {
    'bundle' => 'platform',
    'default_value' => NULL,
    'deleted' => 0,
    'description' => '',
    'description' => 'A branch, tag or commit hash to checkout once the repository is cloned. Note that specifying a commit hash can take significantly longer, as the entire Git history must be fetched.',
    'display' => array(
      'default' => array(
        'label' => 'above',
@@ -135,7 +135,7 @@ function hosting_platform_git_field_default_field_instances() {
    'bundle' => 'platform',
    'default_value' => NULL,
    'deleted' => 0,
    'description' => '',
    'description' => 'The URL of the Git repository that will be cloned to deploy this platform. Note that this repository must be accessible by the `aegir` system user.',
    'display' => array(
      'default' => array(
        'label' => 'above',
@@ -172,8 +172,11 @@ function hosting_platform_git_field_default_field_instances() {

  // Translatables
  // Included for use with string extractors like potx.
  t('If Drupal resides in a sub-directory of your Git repository, specify it here. This path should be relative to the root of the git repository.');
  t('Docroot');
  t('A branch, tag or commit hash to checkout once the repository is cloned. Note that specifying a commit hash can take significantly longer, as the entire Git history must be fetched.');
  t('Git reference');
  t('The URL of the Git repository that will be cloned to deploy this platform. Note that this repository must be accessible by the `aegir` system user.');
  t('Git repository URL');
  t('Git repository path');

+3 −1
Original line number Diff line number Diff line
name = Aegir Platform Git
description = Build Aegir platforms from Git.
core = 7.x
package = Aegir Git
package = Aegir Deployment
dependencies[] = features
dependencies[] = aegir_objects
dependencies[] = features
dependencies[] = hosting_platform
dependencies[] = hosting_platform_strategy
dependencies[] = text
features[features_api][] = api:2
features[field_base][] = field_git_docroot
Loading