Commit 1c437d30 authored by Adrian Rossouw's avatar Adrian Rossouw
Browse files

drumm's file branch code commit. checking it out and improving on it

parent 14a892bc
......@@ -6,7 +6,7 @@ function drush_db_pre_provision_backup($url = NULL) {
}
function drush_db_pre_provision_backup_rollback($url = NULL) {
provision_path("unlink", drush_get_option('sites_path') . "/$url/database.sql", TRUE, dt("Deleted mysql dump from sites directory"),
provision_service('file')->path("unlink", drush_get_option('sites_path') . "/$url/database.sql", TRUE, dt("Deleted mysql dump from sites directory"),
dt("Could not delete mysql dump from sites directory"));
}
......
......@@ -185,12 +185,12 @@ class provisionService_db extends provisionService {
$creds = $this->fetch_site_credentials();
$exists = provision_path("exists", $dump_file, TRUE,
$exists = provision_service('file')->path("exists", $dump_file, TRUE,
dt('Found database dump at @path.'),
dt('No database dump was found at @path.'),
'PROVISION_DB_DUMP_NOT_FOUND');
if ($exists) {
$readable = provision_path("readable", $dump_file, TRUE, dt('Database dump at @path is readable'),
$readable = provision_service('file')->path("readable", $dump_file, TRUE, dt('Database dump at @path is readable'),
dt('The database dump at @path could not be read.'),
'PROVISION_DB_DUMP_NOT_READABLE');
if ($readable) {
......
......@@ -17,7 +17,7 @@ function drush_db_provision_deploy_rollback($url = NULL) {
// Rollback doesn't apply here yet. Unless we trigger a deploy of the first dump
// made. Which could go on infinitely if something is really long.
function drush_db_post_provision_deploy($url) {
provision_path('unlink', drush_get_option('sites_path') .'/'. $url .'/database.sql', TRUE,
provision_service('file')->path('unlink', drush_get_option('sites_path') .'/'. $url .'/database.sql', TRUE,
dt("Removed dump file @path after restoring from it"),
dt("Could not remove dump file @path"), 'DRUSH_PERM_ERROR');
}
......@@ -30,7 +30,7 @@ function drush_db_pre_provision_restore_rollback($url = NULL) {
// Rollback doesn't apply here yet. Unless we trigger a restore of the first dump
// made. Which could go on infinitely if something is really long.
function drush_db_post_provision_restore($url = NULL) {
provision_path('unlink', drush_get_option('sites_path') . '/' . $url .'/database.sql', TRUE,
provision_service('file')->path('unlink', drush_get_option('sites_path') . '/' . $url .'/database.sql', TRUE,
dt("Removed dump file @path after restoring from it"),
dt("Could not remove dump file @path"), 'DRUSH_PERM_ERROR');
......
<?php
// $Id$
/**
* @file Filesystem access module.
*
* Handle writing and syncing configuation files across multiple servers.
* Provides an interface to common path handling operations, through the path
* helper method, which will take care of verification and any error logging
* required.
*/
include_once(dirname(__FILE__) . '/../provision.service.inc');
function file_drush_init() {
$command = drush_get_command();
$command = explode(" ", $command['command']);
if (preg_match("/^provision-/", $command[0])) {
provision_service('file', new provisionService_file());
}
}
function file_drush_exit() {
// todo sync out to other servers
//provision_service('file')->sync();
}
class provisionService_file extends provisionService {
/**
* Perform tasks on a path.
*
* Perform tasks on a path, and logs error messages / codes on success or
* failure. This function will call another method which defines the
* functionality, and exists to provide a consistent interface for file
* operations with error logging integration.
*
* Many of the $op methods are really simple, but are wrapped in methods to
* provide a consistent interface for path to operate with.
*
* @param type
* The type of operation to perform. One of the following:
* writable - The $path can be written to.
* exists - The $path exists.
* is_dir - The $path is a directory.
* readable - The $path is readable.
* owner - The $path belongs to the user in $confirm.
* group - The $path belongs to the group in $confirm.
* mkdir - Create the $path directory.
* unlink - Delete the file $path.
* symlink - Create a symlink from $path to $confirm.
* rmdir - Delete the directory $path.
* chmod - Change the file permissions of $path to the octal value in $confirm.
* chown - Change the owner of $path to the user in $confirm.
* chgrp - Change the group of $path to the group in $confirm.
* switch_paths - Move $path to $confirm, and vice versa.
* fopen - Get a file pointer for writing.
*
* @param path
* The path you want to perform the file operation on.
*
* @param confirm
* Confirm that the final value of the file operation matches this value.
* This value defaults to TRUE, which is sufficient for most file operations.
*
* Certain tasks such as chmod, chown and chgp will attempt to change the
* properties of $path to match the value in $confirm, and then test that
* the change was completed succesfully afterwards.
*
* These exceptions are :
* symlink - $confirm is the path to the symlink being created
* chmod - $confirm is an octal value denoting the desired file permissions.
* chown - $confirm is the name or user id you wish to change the file ownership to.
* chgrp - $confirm is the name of group id you wish to change the file group ownership to.
* switch_paths - $confirm is the path that you want to replace the $path with.
* fopen - $confirm is the $mode
*
* @param succeed_message
* Log this as a notice into the logging system, if the operation completed succesfully.
*
* @param fail_message
* Log this as a error to the logging system, if the $error_codes parameter has been set,
* otherwise, log this as a warning. If the operation specifies an additional reason for
* the operation failing, it will be appended to this message.
*
* @param error_codes
* Generate these system level errors using the provision error bitmasks.
*
* @return
* Returns TRUE if the test against $confirm passed, otherwise returns FALSE.
*/
function path($op, $path, $confirm = TRUE, $succeed_message = NULL, $fail_message = NULL, $error_codes = NULL) {
if (method_exists($this, $op)) {
// The reason variable is passed into the operation function, to allow the function
// to specify an additional reason as to why the operation failed.
$reason = '';
$value = $this->$op($path, $confirm, $reason);
clearstatcache(); // this needs to be called, otherwise we get the old info
$tokens = array("@path" => $path, "@op" => $op, "@confirm" => $confirm);
if ($reason) {
$fail_message .= " (" . $reason . ")";
}
$status = is_array($value) ? ($value[0] == $confirm) : ($value == $confirm);
if ($status) {
if (!is_null($succeed_message)) {
drush_log(dt($succeed_message, $tokens), 'message');
}
}
else {
if ($error_codes) {
// Trigger a sysem halting error
if (!is_null($fail_message)) {
drush_set_error($error_codes, dt($fail_message, $tokens));
}
else {
drush_set_error($error_codes);
}
}
else {
// Trigger a warning
if (!is_null($fail_message)) {
drush_log(dt($fail_message, $tokens), 'warning');
}
}
}
return is_array($value) ? $value[1] : $status;
}
}
function writable($path) {
return is_writable($path);
}
function exists($path) {
return file_exists($path);
}
function is_dir($path) {
return is_dir($path);
}
function readable($path) {
return is_readable($path);
}
function owner($path) {
$info = posix_getpwuid(fileowner($path));
return $info['name'];
}
function group($path) {
return filegroup($path);
}
function mkdir($path) {
return mkdir($path, 0770, TRUE);
}
function rmdir($path) {
return rmdir($path);
}
function unlink($path) {
return unlink($path);
}
function fopen($path, $mode) {
$fp = fopen($path, $mode);
if ($fp === FALSE) {
return FALSE;
}
return array(TRUE, $fp);
}
/*
* This is where the more complex file operations start
*/
function chmod($path, &$perms, &$reason, $recursive = FALSE) {
$func = ($recursive) ? array($this, '_chmod_recursive') : 'chmod';
if (!@call_user_func($func, $path, $perms)) {
$reason = dt('chmod to @perm failed on @path', array('@perm' => sprintf('%o', $perms), '@path' => $path));
return false;
}
clearstatcache(); // this needs to be called, otherwise we get the old info
$value = substr(sprintf('%o', fileperms($path)), -4);
$perms = sprintf('%04o', $perms);
return $value;
}
function chown($path, &$owner, &$reason, $recursive = FALSE) {
$func = ($recursive) ? array($this, '_chown_recursive') : 'chown';
if ($owner = provision_posix_username($owner)) {
if (!call_user_func($func, $path, $owner)) {
$reason = dt("chown to @owner failed on @path", array('@owner' => $owner, '@path' => $path)) ;
}
}
else {
$reason = dt("the user does not exist");
}
clearstatcache(); // this needs to be called, otherwise we get the old info
return provision_posix_username(fileowner($path));
}
function chgrp($path, &$gid, &$reason, $recursive = FALSE) {
$func = ($recursive) ? array($this, '_chgrp_recursive') : 'chgrp';
if ($group = provision_posix_groupname($gid)) {
if (provision_user_in_group(drush_get_option('script_user'), $gid)) {
if (call_user_func($func, $path, $group)) {
return $group;
}
else {
$reason = dt("chgrp to @group failed on @path", array('@group' => $group, '@path' => $path));
}
}
else {
$reason = dt("@user is not in @group group", array("@user" => drush_get_option('script_user'), "@group" => $group));
}
}
elseif (!@call_user_func($func, $path, $gid)) { # try to change the group anyways
$reason = dt("the group does not exist");
}
clearstatcache(); // this needs to be called, otherwise we get the old info
return provision_posix_groupname(filegroup($path));
}
function chmod_recursive($path, &$perms, &$reason) {
return $this->chmod($path, $perms, $reason, TRUE);
}
function chown_recursive($path, &$owner, &$reason) {
return $this->chown($path, $owner, $reason, TRUE);
}
function chgrp_recursive($path, &$gid, &$reason) {
return $this->chgrp($path, $gid, $reason, TRUE);
}
function switch_paths($path1, &$path2, &$reason) {
//TODO : Add error reasons.
$temp = $path1 .'.tmp';
if (!file_exists($path1)) {
return rename($path2, $path1);
}
elseif (!file_exists($path2)) {
return rename($path1, $path2);
}
elseif (rename($path1, $temp)) {
if (rename($path2, $path1)) {
if (rename($temp, $path2)) {
return $path2; // path1 is now path2
}
else {
// same .. just in reverse
return rename($path1, $path2) && rename($temp, $path1);
}
}
else {
// same .. just in reverse
return rename($temp, $path1);
}
}
return FALSE;
}
function extract($path, &$target, &$reason) {
if (file_exists($path) && is_readable($path)) {
if (is_writeable(dirname($target)) && !file_exists($target) && !is_dir($target)) {
mkdir($target);
$oldcwd = getcwd();
// we need to do this because some retarded implementations of tar (e.g. SunOS) don't support -C
chdir($target);
// same here: some do not support -z
$command = 'gunzip -c %s | tar pxf -';
drush_log(dt('Running: %command in %target', array('%command' => sprintf($command, $path), '%target' => $target)));
$result = provision_shell_exec($command, $path);
chdir($oldcwd);
if ($result && is_writeable(dirname($target)) && is_readable(dirname($target)) && is_dir($target)) {
$target = TRUE;
return TRUE;
}
else {
$reason = dt("The file could not be extracted");
}
}
else {
$reason = dt("The target directory could not be written to");
return false;
}
}
else {
$reason = dt("Backup file could not be opened");
return false;
}
}
function symlink($path, &$target, &$reason) {
if (file_exists($target) && !is_link($target)) {
$reason = dt("A file already exists at @path");
return FALSE;
}
if (is_link($target) && (readlink($target) != $path)) {
$reason = dt("A symlink already exists at target, but it is pointing to @link", array("@link" => readlink($target)));
return FALSE;
}
if (is_link($target) && (readlink($target) == $path)) {
$target = TRUE;
return TRUE;
}
if (symlink($path, $target)) {
$target = TRUE;
return TRUE;
}
else {
$reason = dt('The symlink could not be created, an error has occured');
return FALSE;
}
}
/**
* Small helper function for creation of configuration directories.
*/
function create_dir($path, $name, $perms) {
$exists = $this->path("exists", $path, TRUE,
$name . ' ' . dt("path exists."),
$name . ' ' . dt("path does not exist.")
);
if (!$exists) {
$exists = $this->path("mkdir", $path, TRUE,
$name . ' ' . dt("path has been created."),
$name . ' ' . dt("path could not be created."),
'DRUSH_PERM_ERROR');
}
if ($exists) {
$this->path("chown", $path, drush_get_option('script_user'),
$name . ' ' . dt("ownership of path has been changed to @confirm."),
$name . ' ' . dt("ownership of path could not be changed to @confirm."),
'DRUSH_PERM_ERROR');
$this->path("chmod", $path, $perms,
$name . ' ' . dt("permissions of path have been changed to @confirm."),
$name . ' ' . dt("permissions of path could not be changed to @confirm."),
'DRUSH_PERM_ERROR' );
$writable = $this->path("writable", $path, TRUE,
$name . ' ' . dt("path is writable."),
$name . ' ' . dt("path is not writable."),
'DRUSH_PERM_ERROR');
}
return ($exists && $writable);
}
/**
* Walk the given tree recursively (depth first), calling a function on each file
*
* $func is not checked for existence and called directly with $path and $arg
* for every file encountered.
*
* @param string $func a valid callback, usually chmod, chown or chgrp
* @param string $path a path in the filesystem
* @param string $arg the second argument to $func
* @return boolean returns TRUE if every $func call returns true
*/
function _call_recursive($func, $path, $arg) {
$status = 1;
// do not follow symlinks as it could lead to a DOS attack
// consider someone creating a symlink from files/foo to ..: it would create an infinite loop
if (!is_link($path) && ($dh = @opendir($path))) {
while (($file = readdir($dh)) !== false) {
if ($file != '.' && $file != '..') {
$status = $this->_call_recursive($func, $path . "/" . $file, $arg) && $status;
}
}
closedir($dh);
}
$status = call_user_func($func, $path, $arg) && $status;
return $status;
}
/**
* Chmod a directory recursively
*
*/
function _chmod_recursive($path, $filemode) {
return $this->_call_recursive("chmod", $path, $filemode);
}
/**
* Chown a directory recursively
*/
function _chown_recursive($path, $owner) {
return $this->_call_recursive("chown", $path, $owner);
}
/**
* Chgrp a directory recursively
*/
function _chgrp_recursive($path, $owner) {
return $this->_call_recursive("chgrp", $path, $owner);
}
}
......@@ -26,7 +26,7 @@ function drush_provision_drupal_provision_backup_validate($url = NULL, $backup_f
}
if ($backup_file) {
if (provision_path("exists", $backup_file, FALSE,
if (provision_service('file')->path("exists", $backup_file, FALSE,
dt("Backing site up to @path."),
dt("Back up file @path already exists."),
'PROVISION_BACKUP_ALREADY_EXISTS')) {
......@@ -77,7 +77,7 @@ function drush_provision_drupal_provision_backup($url) {
function drush_provision_drupal_provision_backup_rollback() {
$backup_file = drush_get_option('backup_file');
if (file_exists($backup_file)) {
provision_path('unlink', $backup_file, TRUE,
provision_service('file')->path('unlink', $backup_file, TRUE,
dt("Removed stale backup file $backup_file"), dt("Failed deleting backup file $backup_file"));
}
}
......@@ -27,7 +27,7 @@ function drush_provision_drupal_pre_provision_clone($url, $new_url, $platform =
* Remove the extracted site directory
*/
function drush_provision_drupal_pre_provision_clone_rollback($url, $new_url, $platform = null) {
$success = provision_path("unlink", drush_get_option('backup_file'), TRUE, dt('Removed unused clone site package'), dt('Could not remove unused clone site package'));
$success = provision_service('file')->path("unlink", drush_get_option('backup_file'), TRUE, dt('Removed unused clone site package'), dt('Could not remove unused clone site package'));
}
/**
......
......@@ -21,7 +21,7 @@
function drush_provision_drupal_provision_deploy_validate($url = null, $backup_file = null) {
_provision_drupal_url_required();
$exists = provision_path("exists", $backup_file, TRUE,
$exists = provision_service('file')->path("exists", $backup_file, TRUE,
dt("Deploying site from @path"),
dt("Could not find backup file @path"),
'PROVISION_BACKUP_NOT_FOUND');
......@@ -36,7 +36,7 @@ function drush_provision_drupal_provision_deploy_validate($url = null, $backup_f
function drush_provision_drupal_pre_provision_deploy($url, $backup_file) {
// the url is likely to have changed in the deployment
drush_set_option('site_url', $url);
$extracted = provision_path("extract", drush_get_option('backup_file'), drush_get_option('sites_path') ."/$url",
$extracted = provision_service('file')->path("extract", drush_get_option('backup_file'), drush_get_option('sites_path') ."/$url",
dt('Successfully extracted the contents of @path'),
dt('Failed to extract the contents of @path'),
'PROVISION_BACKUP_EXTRACTION_FAILED');
......
......@@ -69,7 +69,7 @@ function drush_provision_drupal_provision_install_rollback($url) {
function drush_provision_drupal_post_provision_install($url) {
drush_set_option('aliases', drush_get_option('aliases'), 'site');
drush_set_option('installed', TRUE, 'site');
provision_path("chmod", "./sites/$url/settings.php", 0440, dt("Secured settings.php with safe permissions"));
provision_service('file')->path("chmod", "./sites/$url/settings.php", 0440, dt("Secured settings.php with safe permissions"));
_provision_drupal_rebuild_caches($url);
drush_set_option('packages', _scrub_object(provision_drupal_system_map()), 'site');
}
......
......@@ -49,7 +49,7 @@ function drush_provision_drupal_pre_provision_migrate_rollback($url, $platform =
drush_log(dt("Bringing site out of maintenance"));
drush_set_option('site_offline', 0);
_provision_drupal_create_settings_file($url);
$success = provision_path("unlink", drush_get_option('backup_file'), TRUE, dt('Removed unused migration site package'), dt('Could not remove unused migration site package'));
$success = provision_service('file')->path("unlink", drush_get_option('backup_file'), TRUE, dt('Removed unused migration site package'), dt('Could not remove unused migration site package'));
_provision_apache_create_vhost_config($url);
_provision_apache_restart_apache();
}
......
......@@ -194,23 +194,23 @@ function _provision_drupal_create_settings_file($url = NULL) {
$options['extra_config'] .= join("\n", drush_command_invoke_all('provision_drupal_config', $url, $options));
drush_log(dt("Generate settings.php file"));
if (provision_path("exists", "sites/$url/settings.php")) {
provision_path("chmod", "sites/$url/settings.php", 0640,
if (provision_service('file')->path("exists", "sites/$url/settings.php")) {
provision_service('file')->path("chmod", "sites/$url/settings.php", 0640,
dt('Changed permissions of settings.php to @confirm'),
dt('Could not change permissions of settings.php to @confirm'));
}
$fp = fopen("sites/$url/settings.php", "w");
$fp = provision_service('file')->path('fopen', 'sites/' . $url . '/settings.php', 'w');
$text = _provision_drupal_default_template();
fwrite($fp, "<?php\n". provision_render_config($text, $options));
fclose($fp);
# Change the permissions of the file
provision_path("chmod", "sites/$url/settings.php", 0440,
provision_service('file')->path("chmod", "sites/$url/settings.php", 0440,
dt('Changed permissions of settings.php to @confirm'),
dt('Could not change permissions of settings.php to @confirm'));
provision_path("chgrp", "sites/$url/settings.php", drush_get_option('web_group'),
provision_service('file')->path("chgrp", "sites/$url/settings.php", drush_get_option('web_group'),
dt('Change group ownership of settings.php to @confirm'),
dt('Could not change group ownership of settings.php to @confirm'));
}
......@@ -251,25 +251,25 @@ function _provision_drupal_create_directories($url, $profile = NULL) {
foreach ($mkdir as $path => $perm) {
if (!is_dir($path)) {
provision_path("mkdir", $path, TRUE,
provision_service('file')->path("mkdir", $path, TRUE,
dt("Created <code>@path</code>"),
dt("Could not create <code>@path</code>"),
'DRUSH_PERM_ERROR');
}
provision_path("chmod_recursive", $path, $perm,
provision_service('file')->path("chmod_recursive", $path, $perm,
dt("Changed permissions of <code>@path</code> to @confirm"),
dt("Could not change permissions <code>@path</code> to @confirm")
);
}
foreach ($chown as $path => $owner) {
provision_path("chown_recursive", $path, $owner,
provision_service('file')->path("chown_recursive", $path, $owner,
dt("Changed ownership of <code>@path</code>"),
dt("Could not change ownership <code>@path</code>"),
'DRUSH_PERM_ERROR' );
}
foreach ($chgrp as $path => $group) {
provision_path("chgrp_recursive", $path, $group,
provision_service('file')->path("chgrp_recursive", $path, $group,
dt("Changed group ownership of <code>@path</code>"),
dt("Could not change group ownership <code>@path</code>"));
}
......@@ -391,7 +391,7 @@ function _provision_drupal_maintain_aliases($url) {
}
foreach($aliases as $alias) {
if (trim($alias)) {
provision_path("symlink", $url, drush_get_option('docroot_path') . "/sites/" . $alias,
provision_service('file')->path("symlink", $url, drush_get_option('docroot_path') . "/sites/" . $alias,
dt("Created symlink for alias @alias", array("@alias" => $alias)),
dt("Could not create symlink for alias @alias", array("@alias" => $alias)));
}
......@@ -414,7 +414,7 @@ function _provision_drupal_delete_aliases($aliases, $silent = false) {
}
foreach ($aliases as $alias) {
if ($alias = trim($alias)) {
provision_path("unlink", drush_get_option('docroot_path') . "/sites/" . $alias, TRUE,
provision_service('file')->path("unlink", drush_get_option('docroot_path') . "/sites/" . $alias, TRUE,
dt("Removed symlink for alias @alias", array("@alias" => $alias)), $error);
}
}
......
......@@ -26,7 +26,7 @@
function drush_provision_drupal_provision_restore_validate($url = null, $restore_file = null) {
drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_SITE);
$exists = provision_path("exists", $restore_file, TRUE,
$exists = provision_service('file')->path("exists", $restore_file, TRUE,