t("Drupal sites"));
}
/**
* 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");
}
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;
}
}
return FALSE;
}
/**
* Implentation of hook_provision_backup()
*/
function provision_drupal_provision_backup($url, $data) {
// Adds the site directory into the backup file
provision_log("backup", "Adding sites directory to $data[backup_file].gz");
$result = provision_shell_exec("cd %s; tar -rf %s * ", "sites/$url", $data['backup_file']);
if (!$result) {
$log = join('\n', _drush_shell_exec_output_set());
provision_log("error", t("Could not back up sites directory for drupal, error: @log", array('@log' => $log)));
provision_set_error(PROVISION_FRAMEWORK_ERROR);
}
}
/**
* The default template to use while generating config files.
*
* @return
* The default template for the config file
*/
function _provision_drupal_default_template() {
return file_get_contents(dirname(__FILE__) .'/provision_drupal_settings.tpl.php');
}
/**
* 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.
*/
function _provision_drupal_create_settings_file($url, &$data) {
provision_log('notice', t("Generate settings.php file"));
if (provision_path("exists", "sites/$url/settings.php")) {
provision_path("chmod", "sites/$url/settings.php", 0640,
t('Changed permissions of settings.php to @confirm'),
t('Could not change permissions of settings.php to @confirm'));
}
$data['extra_config'] = "# Extra configuration from modules:\n";
foreach (module_implements('provision_drupal_config') as $module) {
$data['extra_config'] .= "# -- $module settings --\n";
$data['extra_config'] .= module_invoke($module, 'provision_drupal_config', $url, $data) . "\n";
}
$fp = fopen("sites/$url/settings.php", "w");
$text = variable_get('provision_drupal_settings_template', _provision_drupal_default_template());
fwrite($fp, " 0755,
"sites/$url/files" => 02770,
"sites/$url/files/tmp" => 02770,
"sites/$url/files/images" => 02770,
"sites/$url/files/pictures" => 02770,
"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",
);
foreach ($paths as $path => $perm) {
if (!is_dir($path)) {
provision_path("mkdir", $path, TRUE,
t("Created @path
"),
t("Could not create @path
"),
PROVISION_PERM_ERROR | PROVISION_INSTALL_ERROR );
}
if (in_array($path, $grps)) {
provision_path("chown", $path, PROVISION_SCRIPT_USER,
t("Changed ownership of @path
"),
t("Could not change ownership @path
"),
PROVISION_PERM_ERROR | PROVISION_INSTALL_ERROR );
provision_path("chgrp", $path, PROVISION_WEB_GROUP,
t("Changed group ownership of @path
"),
t("Could not change group ownership @path
"));
}
provision_path("chmod", $path, $perm,
t("Changed permissions of @path
to @confirm"),
t("Could not change permissions @path
to @confirm"),
PROVISION_PERM_ERROR | PROVISION_INSTALL_ERROR );
}
}
/**
* Switch the active database to the newly created database
*
* This function tricks Drupal into thinking that it's running on an uninstalled site,
* so that it can cleanly install the database schema. It also handles switching back to the
* main provisioning site.
*/
function _provision_drupal_switch_active_site($url = NULL) {
static $backups;
if ($url) {
/* Pretend to be the site being installed */
// Fake the necessary HTTP headers that Drupal needs:
$_SERVER['HTTP_HOST'] = $url;
$_SERVER['PHP_SELF'] = '/index.php';
$_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] = $_SERVER['PHP_SELF']; // Coder generates a warning. But this is correct.
$_SERVER['REMOTE_ADDR'] = NULL;
$_SERVER['REQUEST_METHOD'] = NULL;
/**
* This code is sourced from bootstrap.inc. I am trying to avoid patching core, but it might
* be smarter to make a small patch to allow core to re-initialize itself more easily
*/
// Export the following settings.php variables to the global namespace
global $base_url, $base_path, $base_root;
global $cookie_domain, $conf, $profile, $profile, $db_prefix;
// This is just for backup, to be able to restore to the old DRUSH system.
$backups = compact("active_db", "base_url", "base_path", "db_prefix", "cookie_domain", "conf", "profile");
include_once $_SERVER['DOCUMENT_ROOT'] .'sites/'. $url .'/settings.php';
// Create base URL
$base_root = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
$base_url = $base_root .= '://'. preg_replace('/[^a-z0-9-:._]/i', '', $_SERVER['HTTP_HOST']);
if ($dir = trim(dirname($_SERVER['SCRIPT_NAME']), '\,/')) {
$base_path = "/$dir";
$base_url .= $base_path;
$base_path .= '/';
}
else {
$base_path = '/';
}
provision_set_active_db($db_url);
}
else {
/**
* Restore everything to the way it was before we switched sites.
*/
// Fake the necessary HTTP headers that Drupal needs:
$drupal_base_url = parse_url(DRUSH_URI);
$_SERVER['HTTP_HOST'] = $drupal_base_url['host'];
$_SERVER['PHP_SELF'] = $drupal_base_url['path'] .'/index.php';
$_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] = $_SERVER['PHP_SELF']; // Coder generates a warning, but this is correct.
$_SERVER['REMOTE_ADDR'] = NULL;
$_SERVER['REQUEST_METHOD'] = NULL;
global $base_url, $base_path, $base_root;
// Export the following settings.php variables to the global namespace
global $db_prefix, $cookie_domain, $conf, $profile;
// This is just for backup, to be able to restore to the old DRUSH system.
extract($backups, EXTR_OVERWRITE);
provision_set_active_db();
}
}
function provision_drupal_provision_post_restore($url, $data) {
_provision_drupal_create_settings_file($url, $data);
}
function provision_drupal_provision_restore($url, $data) {
$old = PROVISION_SITES_PATH ."/$url.restore";
$new = PROVISION_SITES_PATH ."/$url";
provision_path("switch_paths", $old, $new ,
t('Swapping out the @path and @confirm directories was successful.'),
t('Swapping the @path and @confirm directories has failed.'),
PROVISION_PERM_ERROR);
// make sure it has the latest site data available
provision_save_site_data($url, $data);
}
// Luckily this is reversable =)
function provision_drupal_provision_restore_rollback($url, $data) {
provision_drupal_provision_restore($url, $data);
}
function provision_drupal_provision_pre_install($url, &$data) {
// This is the actual drupal provisioning requirements.
_provision_drupal_create_directories($url, $data['profile']);
// Requires at least the database settings to complete.
_provision_drupal_create_settings_file($url, $data);
}
function provision_drupal_provision_install($url, &$data) {
$cmd = sprintf("php %s/install.php %s %s %s %s", dirname(__FILE__), escapeshellarg($url), escapeshellarg($data['profile']), escapeshellarg($data['language']), escapeshellarg($data['client_email']));
if (provision_exec($cmd, $data)) {
$data['installed'] = TRUE;
// Create symlinks for site aliases (if any)
_provision_drupal_maintain_aliases($url, $data);
}
}
function provision_drupal_provision_post_install($url, &$data) {
if ($url) {
provision_path("chmod", "./sites/$url/settings.php", 0440, t("Secured settings.php with safe permissions"));
_provision_drupal_rebuild_caches($url, $data);
}
}
/**
* implementation of provision_verify
*/
function provision_drupal_provision_verify($url, &$data) {
if (!$url) {
provision_path("writable", "sites", TRUE, t("Drupal sites directory is writable by the provisioning script"),
t("Drupal sites directory is not writable by the provisioning script"), PROVISION_PERM_ERROR);
$data['modules'] = _provision_drupal_get_cvs_versions(module_rebuild_cache());
// Find theme engines
$data['engines'] = drupal_system_listing('\.engine$', 'themes/engines');
$data['profiles'] = _provision_find_profiles();
$data['themes'] = system_theme_data();
$data['platform'] = array('short_name' => 'drupal', 'version' => VERSION);
provision_log('notice', t("This platform is running @short_name @version",
array('@short_name' => 'drupal', '@version' => VERSION)));
$sites = provision_drupal_find_sites();
$data['sites'] = array_keys($sites); // return list of hosted sites. used to determine whether or not to import.
}
else {
// This is the actual drupal provisioning requirements.
_provision_drupal_create_directories($url, $data['profile']);
_provision_drupal_maintain_aliases($url, $data);
// Requires at least the database settings to complete.
_provision_drupal_create_settings_file($url, $data);
}
}
/**
* Implementation of hook_provision_post_verify
*/
function provision_drupal_provision_post_verify($url, &$data) {
if ($url) {
_provision_drupal_rebuild_caches($url, $data);
}
}
/**
* Runs an external script to reload all the various drupal caches
*/
function _provision_drupal_rebuild_caches($url, &$data) {
if ($url) {
$cmd = sprintf("php %s/provision_drupal_clear.php %s", dirname(__FILE__), escapeshellarg($url));
provision_exec($cmd, $data);
}
}
/**
* Find available profiles on this platform.
*/
function _provision_find_profiles() {
include_once('includes/install.inc');
if (!$dir = opendir("./profiles")) {
provision_log('error', t("Cannot find profiles directory"));
return FALSE;
}
while (FALSE !== ($name = readdir($dir))) {
$languages = array();
$file = "./profiles/$name/$name.profile";
if ($name == '..' || $name == '.' || !file_exists($file)) {
continue;
}
$profile = new stdClass();
$profile->name = $name;
$profile->filename = $file;
require_once($profile->filename);
$func = $profile->name . "_profile_details";
if (function_exists($func)) {
$profile->info = $func();
}
$languages['en'] = 1;
// Find languages available
$files = array_keys(file_scan_directory('./profiles/' . $name . '/translations', '\.po$', array('.', '..', 'CVS'), 0, FALSE, 'filepath'));
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
}
}
}
$profile->info['languages'] = array_keys($languages);
$return[$name] = $profile;
provision_log('notice', t('found install profile %name', array('%name' => $name)));
}
return $return;
}
/**
* Remove any directories for the site in sites
* This can't be rolled back. so won't even try.
*/
function provision_drupal_provision_delete($url, $data) {
if ($old_data = provision_load_site_data($url)) {
if (sizeof($old_aliases = $old_data['aliases'])) {
_provision_drupal_delete_aliases($old_aliases);
}
}
return _provision_recursive_delete("sites/$url");
}
function provision_drupal_find_sites() {
if ($dir = opendir("./sites")) {
while (FALSE !== ($subdir = readdir($dir))) {
$file = "./sites/$subdir/settings.php";
if (file_exists("$file") && ($subdir != 'default') && !is_link("./sites/$subdir")) {
$sites[$subdir] = $file;
}
}
closedir($dir);
} else {
provision_log("error", t("Cannot find sites directory"));
$sites = FALSE;
}
return $sites;
}
function _provision_drupal_get_cvs_versions($files) {
foreach ($files as $modulename => $file) {
$project = array();
$project['filename'] = $file->filename;
$project['name'] = $file->name;
$file->info['description'] = str_replace("\n", "", $file->info['description']);
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;
$files[$name] = $file;
}
return $files;
}
function provision_drupal_provision_import($url, &$data) {
$cmd = sprintf("php %s/provision_drupal_import.php %s", dirname(__FILE__), escapeshellarg($url));
if (provision_exec($cmd, $data)) {
$data['installed'] = TRUE;
provision_log("notice", "Returning information for $url");
}
else {
$data['installed'] = FALSE;
}
return TRUE;
}
/**
* 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;
}
/**
* Create and remove symlinks for each of the possible domain aliases of an existing site
*/
function _provision_drupal_maintain_aliases($url, $data) {
if ($url) {
$old_aliases = array();
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,
t("Created symlink for alias @alias", array("@alias" => $alias)),
t("Could not create symlink for alias @alias", array("@alias" => $alias)));
}
// Delete existing aliases that are no longer present
_provision_drupal_delete_aliases(array_keys($old_aliases));
}
}
}
/**
* Delete a list of aliases
*/
function _provision_drupal_delete_aliases($aliases) {
foreach ($aliases as $alias) {
provision_path("unlink", PROVISION_DOCROOT_PATH . "/sites/" . $alias, TRUE,
t("Removed symlink for alias @alias", array("@alias" => $alias)),
t("Could not remove symlink for alias @alias", array("@alias" => $alias)));
}
}