provision_drupal.drush.inc 11.4 KB
Newer Older
1
<?php
2
// $Id$
3 4 5 6 7 8 9 10
/**
 * @file
 * Drupal specific functions for the provisioning framework.
 *
 * This module is responsible for the creation and maintenance of the drupal settings.php file, the sites directory structure
 * and all the install api code. 
 */

11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
/**
 * Initialize the platform / site
 *
 * This function is executed by provision_invoke, and is responsible
 * for populating the $data context array
 */
function provision_drupal_provision_init(&$data, $url = NULL) {
  if ($url) {
    define('PROVISION_ACTIVE_URL', $url);
    $data = provision_get_site_data($url); // load the existing site's context into the system.
  }
  define('PROVISION_CONTEXT_SITE', ($url) ? TRUE : FALSE);
  define('PROVISION_CONTEXT_PLATFORM', !PROVISION_CONTEXT_SITE);
}

/**
 * Finalize the platform / site
 *
 * This will run only if there were no errors in any of the previous hooks,
 * and will allow us to cache the successful settings to the site.php/ drushrc.php
 * files for future runs.
 */
function provision_drupal_provision_finalize(&$data, $url = NULL) {
  if (PROVISION_CONTEXT_SITE) {
Adrian Rossouw's avatar
Adrian Rossouw committed
35 36 37
    if ($data['installed']) {
      provision_save_site_data($data, $url);
    }
38 39 40 41 42 43 44 45 46 47 48 49 50
  }
  else {
    _provision_generate_config();
  }
}

/**
 * Some commands need to have a url to operate on.
 *  This prints out a message to that effect.
 */
function _provision_drupal_url_required() {
  if (PROVISION_CONTEXT_PLATFORM) {
    provision_set_error(PROVISION_FRAMEWORK_ERROR);
51
    provision_log('error', dt('You need to specify the URL argument for this command'));
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
  }
}

/**
 * Validate a site exists, ie: has a settings.php file
 *
 * This will return an error for sites that haven't been created yet
 */
function _provision_drupal_valid_site() {
  if (PROVISION_CONTEXT_SITE) {
    if (!_provision_drupal_site_exists(PROVISION_ACTIVE_URL)) {
      provision_set_error(PROVISION_SITE_NOT_FOUND);
      provision_log("error", "Site could not be found.");
    }
  }
67 68
}

69 70 71 72 73 74 75 76 77 78 79 80
/**
 * Test to see if the site settings.php exists
 *
 * @param url
 *   The url of the site to check
 * @return
 *   If the file exists, return TRUE, else return FALSE.
 */
function _provision_drupal_site_exists($url) {
  return file_exists("sites/$url/settings.php");
}

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99

/**
 * Validate a site has been installed, by checking it's site.php file. 
 *
 * This will return an error for sites that haven't been installed yet
 */
function _provision_drupal_valid_installed_site() {
  if (PROVISION_CONTEXT_SITE) {
    if (!_provision_drupal_site_installed(PROVISION_ACTIVE_URL)) {
      provision_set_error(PROVISION_SITE_NOT_FOUND);
      provision_log("error", "Site has not been installed yet.");
    }
  }
}

function _provision_drupal_valid_not_installed_site() {
  if (PROVISION_CONTEXT_SITE) {
    if (_provision_drupal_site_installed(PROVISION_ACTIVE_URL)) {
      provision_set_error(PROVISION_SITE_INSTALLED);
100
      provision_log('error', dt('This site has already been installed.'));
Adrian Rossouw's avatar
Adrian Rossouw committed
101 102 103
    }
  }
}
104 105

/**
106
 * Test to see if the site has a site.php and has it set to 'installed'
107
 */
108 109 110 111 112
function _provision_drupal_site_installed($url) {
  if (_provision_drupal_site_exists($url)) {
    if ($data = provision_load_site_data($url)) {
      return isset($data['installed']) ? $data['installed'] : FALSE;
    }
113
  }
114
  return FALSE;
115 116
}

117 118 119 120 121 122 123
/**
 * The default template to use while generating config files.
 *
 * @return
 *   The default template for the config file
 */
function _provision_drupal_default_template() {
124
  return file_get_contents(dirname(__FILE__) .'/provision_drupal_settings.tpl.php');
125 126 127 128 129 130 131 132 133 134 135
}

/**
 * Generate a settings file for the site.
 *
 * @param url
 *   The url of the site being invoked.
 * @param data
 *   A reference to the associated array containing the data for the site. This needs to be a reference, 
 *   because the modules might provide additional information about the site.
 */
136
function _provision_drupal_create_settings_file(&$data, $url = NULL) {
137
  provision_log('notice', dt("Generate settings.php file"));
138
  if (provision_path("exists", "sites/$url/settings.php")) {
139
    provision_path("chmod", "sites/$url/settings.php", 0640,
140 141
      dt('Changed permissions of settings.php to @confirm'),
      dt('Could not change permissions of settings.php to @confirm'));
142 143
  }

144 145 146 147 148 149 150
  $data['extra_config'] = "# Extra configuration from modules:\n";
  foreach (drush_command_implements('provision_drupal_config') as $module) {
    $data['extra_config'] .= "# -- $module settings --\n";
    $data['extra_config'] .= module_invoke($module, 'provision_drupal_config', $url, $data) . "\n";
  }


151
  $fp = fopen("sites/$url/settings.php", "w");
152
  $text =  _provision_drupal_default_template();
153
  fwrite($fp, "<?php\n". provision_render_config($text, $data));
154
  fclose($fp);
155

156
  # Change the permissions of the file
157
  provision_path("chmod", "sites/$url/settings.php", 0440,
158 159
    dt('Changed permissions of settings.php to @confirm'),
    dt('Could not change permissions of settings.php to @confirm'));
160
  provision_path("chgrp", "sites/$url/settings.php", PROVISION_WEB_GROUP,
161 162
    dt('Change group ownership of settings.php to @confirm'),
    dt('Could not change group ownership of settings.php to @confirm'));
163 164 165 166 167 168 169
}

/**
 * Create the directories needed to host a drupal site
 * 
 * Also maintains permissions on existing directories.
 */
170
function _provision_drupal_create_directories($url, $profile = NULL) {  
171
  $paths = array(
172
    "sites/$url"                 => 0755,
173
    "sites/$url/files"           => 02770,
174 175 176
    "sites/$url/files/tmp"       => 02770,
    "sites/$url/files/images"    => 02770,
    "sites/$url/files/pictures"  => 02770,
177 178 179 180 181 182 183 184
    "sites/$url/themes"          => 0755,
    "sites/$url/modules"         => 0755,  
  );
  $grps = array(
    "sites/$url/files",
    "sites/$url/files/tmp",
    "sites/$url/files/images",
    "sites/$url/files/pictures",
185 186 187 188
  );

  foreach ($paths as $path => $perm) {
    if (!is_dir($path)) {
189
      provision_path("mkdir", $path, TRUE, 
190 191
        dt("Created <code>@path</code>"),
        dt("Could not create <code>@path</code>"),
192
        PROVISION_PERM_ERROR | PROVISION_INSTALL_ERROR );
193
    }
194 195

    provision_path("chmod", $path, $perm, 
196 197
      dt("Changed permissions of <code>@path</code> to @confirm"),
      dt("Could not change permissions <code>@path</code> to @confirm"),
198 199 200 201
      PROVISION_PERM_ERROR | PROVISION_INSTALL_ERROR );
  }
  foreach ($grps as $path) {
      provision_path("chown", $path, PROVISION_SCRIPT_USER, 
202 203
      dt("Changed ownership of <code>@path</code>"),
      dt("Could not change ownership <code>@path</code>"),
204
      PROVISION_PERM_ERROR | PROVISION_INSTALL_ERROR );
205
    provision_path("chgrp", $path, PROVISION_WEB_GROUP,
206 207
      dt("Changed group ownership of <code>@path</code>"),
      dt("Could not change group ownership <code>@path</code>"));
208 209 210
  }
}

211 212 213
/**
 * Runs an external script to reload all the various drupal caches
 */
214
function _provision_drupal_rebuild_caches(&$data, $url = NULL) {
215 216 217 218 219
  if (PLATFORM_CONTEXT_SITE) {
    ini_set('error_reporting', E_ALL);
    ini_set('display_errors', TRUE);
    provision_internal_init($url);
    provision_platform_include(dirname(__FILE__), 'clear');
220
  }
Adrian Rossouw's avatar
Adrian Rossouw committed
221 222
}

223

224 225 226 227 228 229
/**
 * Find available profiles on this platform.
 */
function _provision_find_profiles() {
  include_once('includes/install.inc');

230
  if (!$dir = opendir("./profiles")) {
231
    provision_log('error', dt("Cannot find profiles directory"));
232 233 234
    return FALSE;
  }
  while (FALSE !== ($name = readdir($dir))) {
235
    $languages = array();
236 237 238 239 240 241 242 243
    $file = "./profiles/$name/$name.profile";
    if ($name == '..' || $name == '.' || !file_exists($file)) {
      continue;
    }
    $profile = new stdClass();
    $profile->name = $name;
    $profile->filename = $file;

244 245 246 247 248
    require_once($profile->filename);
    $func = $profile->name . "_profile_details";
    if (function_exists($func)) {
      $profile->info =  $func();
    }
249

250
    $languages['en'] = 1;
251
    // Find languages available
252
    $files = array_keys(drush_scan_directory('./profiles/' . $name . '/translations', '\.po$', array('.', '..', 'CVS'), 0, FALSE, 'filepath'));
253 254 255 256 257
    if (is_array($files)) {
      foreach ($files as $file) {
        if (preg_match('!(/|\.)([^\./]+)\.po$!', $file, $langcode)) {
          $languages[$langcode[2]] = 1; // use the language name as an index to weed out duplicates
        }
258 259
      }
    }
Adrian Rossouw's avatar
Adrian Rossouw committed
260
    $profile->info['languages'] = array_keys($languages);
anarcat's avatar
anarcat committed
261
    $return[$name] = $profile;
262
    provision_log('notice', dt('found install profile %name', array('%name' => $name)));
263
  }
264

265 266 267 268
  return $return;

}

269
function provision_drupal_find_sites() {
270 271 272
  if ($dir = opendir("./sites")) {
    while (FALSE !== ($subdir = readdir($dir))) {
      $file = "./sites/$subdir/settings.php";
273
      if (file_exists("$file") && ($subdir != 'default') && !is_link("./sites/$subdir")) {
274 275 276
        $sites[$subdir] = $file;
      }
    }
277
    closedir($dir);
278
  } else {
279
    provision_log("error", dt("Cannot find sites directory"));
280
    $sites = FALSE;
281 282
  }
  return $sites;
283 284
}

Adrian Rossouw's avatar
Adrian Rossouw committed
285 286
function _provision_drupal_get_cvs_versions($files) {
  foreach ($files as $modulename => $file) {
287 288 289
      $project = array();
      $project['filename'] = $file->filename;
      $project['name'] = $file->name;
290
      $file->info['description'] = str_replace("\n", "", $file->info['description']);
291 292 293 294 295
      if (empty($project['project'])) {
        $project['project'] = cvs_deploy_get_project_name($project);
      }
      _cvs_deploy_version_alter($file->info['version'], $project);
      $name = ($project['project']) ? $project['project'] : $modulename;
Adrian Rossouw's avatar
Adrian Rossouw committed
296
      $files[$name] = $file; 
297
  }
298

Adrian Rossouw's avatar
Adrian Rossouw committed
299
  return $files;
300
}
301 302


303 304 305

function _provision_drupal_import_site(&$data, $url = NULL) {
  $cmd = sprintf("php %s/drupal_import.php %s", dirname(__FILE__), escapeshellarg($url));
306
  if (provision_exec($cmd, $data)) {
307
    $data['installed'] = TRUE;
308
  }
309 310 311
  else {
    $data['installed'] = FALSE;
  }
312
}
313

314 315 316 317 318 319 320 321 322 323 324
/**
 * Retrieve drupal variable from database
 *
 * This is different to the normal variable_get in that it doesn't
 * do any caching whatsoever.
 */
function _provision_drupal_variable_get($name, $default) {
 $value =  db_result(db_query("SELECT value FROM {variable} WHERE name='%s'", $name));
 return ($value) ? unserialize($value) : $default;
}

325 326 327
/**
 * Create and remove symlinks for each of the possible domain aliases of an existing site
 */
328
function _provision_drupal_maintain_aliases($data, $url) {
329
  if (PROVISION_CONTEXT_SITE) {
330
    $old_aliases = array();
331 332 333 334 335 336 337 338 339 340 341 342 343 344
    if ($old_data = provision_load_site_data($url)) {
      if (is_array($old_data['aliases'])) {
         // Flip the array to make it easier to remove duplicates
        $old_aliases = array_flip($old_data['aliases']);
      }
    }
   
    if (is_array($data['aliases'])) {
      foreach($data['aliases'] as $alias) {
        if (isset($old_aliases[$alias])) {
          // We have already created an alias for this site.
          unset($old_aliases[$alias]);
        }
        provision_path("symlink", $url, PROVISION_DOCROOT_PATH . "/sites/" . $alias, 
345 346
          dt("Created symlink for alias @alias", array("@alias" => $alias)), 
          dt("Could not create symlink for alias @alias", array("@alias" => $alias)));
347
      }
348 349
      // Delete existing aliases that are no longer present
      _provision_drupal_delete_aliases(array_keys($old_aliases));
350 351 352 353 354 355 356 357 358 359
    }
  }
}

/**
 * Delete a list of aliases
 */
function _provision_drupal_delete_aliases($aliases) {
  foreach ($aliases as $alias) {
    provision_path("unlink", PROVISION_DOCROOT_PATH . "/sites/" . $alias, TRUE,
360 361
          dt("Removed symlink for alias @alias", array("@alias" => $alias)), 
          dt("Could not remove symlink for alias @alias", array("@alias" => $alias)));
362 363
  }
}
364 365