* This avoids code duplication.
* Callers can safely start type-hinting StatusValue as well.
* Also moved the wrap() logic out of Status::__construct(), which
only wrap() was (and should have been) using. Use "static" as
well, so subclass behave properly.
* The docs and type-hints in /filebackend are updated as an example.
* A migration pattern is to inject a StatusValue wrapper
into the backend and use it on all returned statuses, so MediaWiki
will still get Status for message methods.
Change-Id: Iff9255f34870ea6b0c4b91f6ddc69eea95186aba
* developer of the calling code is reminded that the function can fail, and
* so that a lack of error-handling will be explicit.
*/
-class Status {
- /** @var StatusValue */
- protected $sv;
-
- /** @var mixed */
- public $value;
- /** @var array Map of (key => bool) to indicate success of each part of batch operations */
- public $success = [];
- /** @var int Counter for batch operations */
- public $successCount = 0;
- /** @var int Counter for batch operations */
- public $failCount = 0;
-
+class Status extends StatusValue {
/** @var callable */
public $cleanCallback = false;
- /**
- * @param StatusValue $sv [optional]
- */
- public function __construct( StatusValue $sv = null ) {
- $this->sv = ( $sv === null ) ? new StatusValue() : $sv;
- // B/C field aliases
- $this->value =& $this->sv->value;
- $this->successCount =& $this->sv->successCount;
- $this->failCount =& $this->sv->failCount;
- $this->success =& $this->sv->success;
- }
-
/**
* Succinct helper method to wrap a StatusValue
*
* @return Status
*/
public static function wrap( $sv ) {
- return $sv instanceof Status ? $sv : new self( $sv );
+ if ( $sv instanceof static ) {
+ return $sv;
+ }
+
+ $result = new static();
+ $result->ok =& $sv->ok;
+ $result->errors =& $sv->errors;
+ $result->value =& $sv->value;
+ $result->successCount =& $sv->successCount;
+ $result->failCount =& $sv->failCount;
+ $result->success =& $sv->success;
+
+ return $result;
}
/**
- * Factory function for fatal errors
+ * Backwards compatibility logic
*
- * @param string|Message $message Message name or object
- * @return Status
+ * @param string $name
+ * @return mixed
+ * @throws RuntimeException
*/
- public static function newFatal( $message /*, parameters...*/ ) {
- return new self( call_user_func_array(
- [ 'StatusValue', 'newFatal' ], func_get_args()
- ) );
+ function __get( $name ) {
+ if ( $name === 'ok' ) {
+ return $this->isOK();
+ } elseif ( $name === 'errors' ) {
+ return $this->getErrors();
+ }
+
+ throw new RuntimeException( "Cannot get '$name' property." );
}
/**
- * Factory function for good results
+ * Change operation result
+ * Backwards compatibility logic
*
+ * @param string $name
* @param mixed $value
- * @return Status
+ * @throws RuntimeException
*/
- public static function newGood( $value = null ) {
- $sv = new StatusValue();
- $sv->value = $value;
-
- return new self( $sv );
+ function __set( $name, $value ) {
+ if ( $name === 'ok' ) {
+ $this->setOK( $value );
+ } elseif ( !property_exists( $this, $name ) ) {
+ // Caller is using undeclared ad-hoc properties
+ $this->$name = $value;
+ } else {
+ throw new RuntimeException( "Cannot set '$name' property." );
+ }
}
/**
* Splits this Status object into two new Status objects, one which contains only
* the error messages, and one that contains the warnings, only. The returned array is
* defined as:
- * array(
- * 0 => object(Status) # the Status with error messages, only
- * 1 => object(Status) # The Status with warning messages, only
- * )
+ * [
+ * 0 => object(Status) # the Status with error messages, only
+ * 1 => object(Status) # The Status with warning messages, only
+ * ]
*
* @return array
*/
public function splitByErrorType() {
- list( $errorsOnlyStatusValue, $warningsOnlyStatusValue ) = $this->sv->splitByErrorType();
- $errorsOnlyStatus = new Status( $errorsOnlyStatusValue );
- $warningsOnlyStatus = new Status( $warningsOnlyStatusValue );
- $errorsOnlyStatus->cleanCallback = $warningsOnlyStatus->cleanCallback = $this->cleanCallback;
+ list( $errorsOnlyStatus, $warningsOnlyStatus ) = parent::splitByErrorType();
+ $errorsOnlyStatus->cleanCallback =
+ $warningsOnlyStatus->cleanCallback = $this->cleanCallback;
return [ $errorsOnlyStatus, $warningsOnlyStatus ];
}
- /**
- * Change operation result
- *
- * @param bool $ok Whether the operation completed
- * @param mixed $value
- */
- public function setResult( $ok, $value = null ) {
- $this->sv->setResult( $ok, $value );
- }
-
/**
* Returns the wrapped StatusValue object
* @return StatusValue
* @since 1.27
*/
public function getStatusValue() {
- return $this->sv;
- }
-
- /**
- * Returns whether the operation completed and didn't have any error or
- * warnings
- *
- * @return bool
- */
- public function isGood() {
- return $this->sv->isGood();
- }
-
- /**
- * Returns whether the operation completed
- *
- * @return bool
- */
- public function isOK() {
- return $this->sv->isOK();
- }
-
- /**
- * Add a new warning
- *
- * @param string|Message $message Message name or object
- */
- public function warning( $message /*, parameters... */ ) {
- call_user_func_array( [ $this->sv, 'warning' ], func_get_args() );
- }
-
- /**
- * Add an error, do not set fatal flag
- * This can be used for non-fatal errors
- *
- * @param string|Message $message Message name or object
- */
- public function error( $message /*, parameters... */ ) {
- call_user_func_array( [ $this->sv, 'error' ], func_get_args() );
- }
-
- /**
- * Add an error and set OK to false, indicating that the operation
- * as a whole was fatal
- *
- * @param string|Message $message Message name or object
- */
- public function fatal( $message /*, parameters... */ ) {
- call_user_func_array( [ $this->sv, 'fatal' ], func_get_args() );
+ return $this;
}
/**
public function getWikiText( $shortContext = false, $longContext = false, $lang = null ) {
$lang = $this->languageFromParam( $lang );
- $rawErrors = $this->sv->getErrors();
+ $rawErrors = $this->getErrors();
if ( count( $rawErrors ) == 0 ) {
- if ( $this->sv->isOK() ) {
- $this->sv->fatal( 'internalerror_info',
+ if ( $this->isOK() ) {
+ $this->fatal( 'internalerror_info',
__METHOD__ . " called for a good result, this is incorrect\n" );
} else {
- $this->sv->fatal( 'internalerror_info',
+ $this->fatal( 'internalerror_info',
__METHOD__ . ": Invalid result object: no error text but not OK\n" );
}
- $rawErrors = $this->sv->getErrors(); // just added a fatal
+ $rawErrors = $this->getErrors(); // just added a fatal
}
if ( count( $rawErrors ) == 1 ) {
$s = $this->getErrorMessage( $rawErrors[0], $lang )->plain();
*
* If both parameters are missing, and there is only one error, no bullet will be added.
*
- * @param string|string[] $shortContext A message name or an array of message names.
- * @param string|string[] $longContext A message name or an array of message names.
+ * @param string|string[]|bool $shortContext A message name or an array of message names.
+ * @param string|string[]|bool $longContext A message name or an array of message names.
* @param string|Language $lang Language to use for processing messages
* @return Message
*/
public function getMessage( $shortContext = false, $longContext = false, $lang = null ) {
$lang = $this->languageFromParam( $lang );
- $rawErrors = $this->sv->getErrors();
+ $rawErrors = $this->getErrors();
if ( count( $rawErrors ) == 0 ) {
- if ( $this->sv->isOK() ) {
- $this->sv->fatal( 'internalerror_info',
+ if ( $this->isOK() ) {
+ $this->fatal( 'internalerror_info',
__METHOD__ . " called for a good result, this is incorrect\n" );
} else {
- $this->sv->fatal( 'internalerror_info',
+ $this->fatal( 'internalerror_info',
__METHOD__ . ": Invalid result object: no error text but not OK\n" );
}
- $rawErrors = $this->sv->getErrors(); // just added a fatal
+ $rawErrors = $this->getErrors(); // just added a fatal
}
if ( count( $rawErrors ) == 1 ) {
$s = $this->getErrorMessage( $rawErrors[0], $lang );
}
/**
- * Return the message for a single error.
+ * Return the message for a single error
*
- * @param mixed $error With an array & two values keyed by
- * 'message' and 'params', use those keys-value pairs.
- * Otherwise, if its an array, just use the first value as the
- * message and the remaining items as the params.
+ * The code string can be used a message key with per-language versions.
+ * If $error is an array, the "params" field is a list of parameters for the message.
+ *
+ * @param array|string $error Code string or (key: code string, params: string[]) map
* @param string|Language $lang Language to use for processing messages
* @return Message
*/
$msg = wfMessage( $msgName,
array_map( 'wfEscapeWikiText', $this->cleanParams( $error ) ) );
}
- } else {
+ } elseif ( is_string( $error ) ) {
$msg = wfMessage( $error );
+ } else {
+ throw new UnexpectedValueException( "Got " . get_class( $error ) . " for key." );
}
$msg->inLanguage( $this->languageFromParam( $lang ) );
}
/**
- * Get the error message as HTML. This is done by parsing the wikitext error
- * message.
- * @param string $shortContext A short enclosing context message name, to
+ * Get the error message as HTML. This is done by parsing the wikitext error message
+ * @param string|bool $shortContext A short enclosing context message name, to
* be used when there is a single error
- * @param string $longContext A long enclosing context message name, for a list
- * @param string|Language $lang Language to use for processing messages
+ * @param string|bool $longContext A long enclosing context message name, for a list
+ * @param string|Language|null $lang Language to use for processing messages
* @return string
*/
public function getHTML( $shortContext = false, $longContext = false, $lang = null ) {
}, $errors );
}
- /**
- * Merge another status object into this one
- *
- * @param Status $other Other Status object
- * @param bool $overwriteValue Whether to override the "value" member
- */
- public function merge( $other, $overwriteValue = false ) {
- $this->sv->merge( $other->sv, $overwriteValue );
- }
-
/**
* Get the list of errors (but not warnings)
*
protected function getStatusArray( $type = false ) {
$result = [];
- foreach ( $this->sv->getErrors() as $error ) {
+ foreach ( $this->getErrors() as $error ) {
if ( $type === false || $error['type'] === $type ) {
if ( $error['message'] instanceof MessageSpecifier ) {
$result[] = array_merge(
return $result;
}
- /**
- * Returns a list of status messages of the given type, with message and
- * params left untouched, like a sane version of getStatusArray
- *
- * Each entry is a map of:
- * - message: string message key or MessageSpecifier
- * - params: array list of parameters
- *
- * @param string $type
- * @return array
- */
- public function getErrorsByType( $type ) {
- return $this->sv->getErrorsByType( $type );
- }
-
- /**
- * Returns true if the specified message is present as a warning or error
- *
- * @param string|Message $message Message key or object to search for
- *
- * @return bool
- */
- public function hasMessage( $message ) {
- return $this->sv->hasMessage( $message );
- }
-
- /**
- * If the specified source message exists, replace it with the specified
- * destination message, but keep the same parameters as in the original error.
- *
- * Note, due to the lack of tools for comparing Message objects, this
- * function will not work when using a Message object as the search parameter.
- *
- * @param Message|string $source Message key or object to search for
- * @param Message|string $dest Replacement message key or object
- * @return bool Return true if the replacement was done, false otherwise.
- */
- public function replaceMessage( $source, $dest ) {
- return $this->sv->replaceMessage( $source, $dest );
- }
-
- /**
- * @return mixed
- */
- public function getValue() {
- return $this->sv->getValue();
- }
-
- /**
- * Backwards compatibility logic
- *
- * @param string $name
- */
- function __get( $name ) {
- if ( $name === 'ok' ) {
- return $this->sv->isOK();
- } elseif ( $name === 'errors' ) {
- return $this->sv->getErrors();
- }
- throw new Exception( "Cannot get '$name' property." );
- }
-
- /**
- * Backwards compatibility logic
- *
- * @param string $name
- * @param mixed $value
- */
- function __set( $name, $value ) {
- if ( $name === 'ok' ) {
- $this->sv->setOK( $value );
- } elseif ( !property_exists( $this, $name ) ) {
- // Caller is using undeclared ad-hoc properties
- $this->$name = $value;
- } else {
- throw new Exception( "Cannot set '$name' property." );
- }
- }
-
- /**
- * @return string
- */
- public function __toString() {
- return $this->sv->__toString();
- }
-
/**
* Don't save the callback when serializing, because Closures can't be
* serialized and we're going to clear it in __wakeup anyway.
* Having directories with thousands of files will diminish performance.
* Sharding can be accomplished by using FileRepo-style hash paths.
*
- * Status messages should avoid mentioning the internal FS paths.
+ * StatusValue messages should avoid mentioning the internal FS paths.
* PHP warnings are assumed to be logged rather than output.
*
* @ingroup FileBackend
}
protected function doCreateInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$dest = $this->resolveToFSPath( $params['dst'] );
if ( $dest === null ) {
wfEscapeShellArg( $this->cleanPathSlashes( $tempFile->getPath() ) ),
wfEscapeShellArg( $this->cleanPathSlashes( $dest ) )
] );
- $handler = function ( $errors, Status $status, array $params, $cmd ) {
+ $handler = function ( $errors, StatusValue $status, array $params, $cmd ) {
if ( $errors !== '' && !( wfIsWindows() && $errors[0] === " " ) ) {
$status->fatal( 'backend-fail-create', $params['dst'] );
trigger_error( "$cmd\n$errors", E_USER_WARNING ); // command output
}
protected function doStoreInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$dest = $this->resolveToFSPath( $params['dst'] );
if ( $dest === null ) {
wfEscapeShellArg( $this->cleanPathSlashes( $params['src'] ) ),
wfEscapeShellArg( $this->cleanPathSlashes( $dest ) )
] );
- $handler = function ( $errors, Status $status, array $params, $cmd ) {
+ $handler = function ( $errors, StatusValue $status, array $params, $cmd ) {
if ( $errors !== '' && !( wfIsWindows() && $errors[0] === " " ) ) {
$status->fatal( 'backend-fail-store', $params['src'], $params['dst'] );
trigger_error( "$cmd\n$errors", E_USER_WARNING ); // command output
}
protected function doCopyInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$source = $this->resolveToFSPath( $params['src'] );
if ( $source === null ) {
wfEscapeShellArg( $this->cleanPathSlashes( $source ) ),
wfEscapeShellArg( $this->cleanPathSlashes( $dest ) )
] );
- $handler = function ( $errors, Status $status, array $params, $cmd ) {
+ $handler = function ( $errors, StatusValue $status, array $params, $cmd ) {
if ( $errors !== '' && !( wfIsWindows() && $errors[0] === " " ) ) {
$status->fatal( 'backend-fail-copy', $params['src'], $params['dst'] );
trigger_error( "$cmd\n$errors", E_USER_WARNING ); // command output
}
protected function doMoveInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$source = $this->resolveToFSPath( $params['src'] );
if ( $source === null ) {
wfEscapeShellArg( $this->cleanPathSlashes( $source ) ),
wfEscapeShellArg( $this->cleanPathSlashes( $dest ) )
] );
- $handler = function ( $errors, Status $status, array $params, $cmd ) {
+ $handler = function ( $errors, StatusValue $status, array $params, $cmd ) {
if ( $errors !== '' && !( wfIsWindows() && $errors[0] === " " ) ) {
$status->fatal( 'backend-fail-move', $params['src'], $params['dst'] );
trigger_error( "$cmd\n$errors", E_USER_WARNING ); // command output
}
protected function doDeleteInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$source = $this->resolveToFSPath( $params['src'] );
if ( $source === null ) {
wfIsWindows() ? 'DEL' : 'unlink',
wfEscapeShellArg( $this->cleanPathSlashes( $source ) )
] );
- $handler = function ( $errors, Status $status, array $params, $cmd ) {
+ $handler = function ( $errors, StatusValue $status, array $params, $cmd ) {
if ( $errors !== '' && !( wfIsWindows() && $errors[0] === " " ) ) {
$status->fatal( 'backend-fail-delete', $params['src'] );
trigger_error( "$cmd\n$errors", E_USER_WARNING ); // command output
* @param string $fullCont
* @param string $dirRel
* @param array $params
- * @return Status
+ * @return StatusValue
*/
protected function doPrepareInternal( $fullCont, $dirRel, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
list( , $shortCont, ) = FileBackend::splitStoragePath( $params['dir'] );
$contRoot = $this->containerFSRoot( $shortCont, $fullCont ); // must be valid
$dir = ( $dirRel != '' ) ? "{$contRoot}/{$dirRel}" : $contRoot;
}
protected function doSecureInternal( $fullCont, $dirRel, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
list( , $shortCont, ) = FileBackend::splitStoragePath( $params['dir'] );
$contRoot = $this->containerFSRoot( $shortCont, $fullCont ); // must be valid
$dir = ( $dirRel != '' ) ? "{$contRoot}/{$dirRel}" : $contRoot;
}
protected function doPublishInternal( $fullCont, $dirRel, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
list( , $shortCont, ) = FileBackend::splitStoragePath( $params['dir'] );
$contRoot = $this->containerFSRoot( $shortCont, $fullCont ); // must be valid
$dir = ( $dirRel != '' ) ? "{$contRoot}/{$dirRel}" : $contRoot;
}
protected function doCleanInternal( $fullCont, $dirRel, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
list( , $shortCont, ) = FileBackend::splitStoragePath( $params['dir'] );
$contRoot = $this->containerFSRoot( $shortCont, $fullCont ); // must be valid
$dir = ( $dirRel != '' ) ? "{$contRoot}/{$dirRel}" : $contRoot;
/**
* @param FSFileOpHandle[] $fileOpHandles
*
- * @return Status[]
+ * @return StatusValue[]
*/
protected function doExecuteOpHandlesInternal( array $fileOpHandles ) {
$statuses = [];
}
foreach ( $fileOpHandles as $index => $fileOpHandle ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$function = $fileOpHandle->call;
$function( $errs[$index], $status, $fileOpHandle->params, $fileOpHandle->cmd );
$statuses[$index] = $status;
/** @var FileJournal */
protected $fileJournal;
+ /** @var callable */
+ protected $statusWrapper;
+
/** Bitfield flags for supported features */
const ATTR_HEADERS = 1; // files can be tagged with standard HTTP headers
const ATTR_METADATA = 2; // files can be stored with metadata key/values
$this->concurrency = isset( $config['concurrency'] )
? (int)$config['concurrency']
: 50;
+ // @TODO: dependency inject this
+ $this->statusWrapper = [ 'Status', 'wrap' ];
}
/**
* during the operation. The 'failCount', 'successCount', and 'success' members
* will reflect each operation attempted.
*
- * The status will be "OK" unless:
+ * The StatusValue will be "OK" unless:
* - a) unexpected operation errors occurred (network partitions, disk full...)
* - b) significant operation errors occurred and 'force' was not set
*
* @param array $ops List of operations to execute in order
* @param array $opts Batch operation options
- * @return Status
+ * @return StatusValue
*/
final public function doOperations( array $ops, array $opts = [] ) {
if ( empty( $opts['bypassReadOnly'] ) && $this->isReadOnly() ) {
- return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
+ return $this->newStatus( 'backend-fail-readonly', $this->name, $this->readOnly );
}
if ( !count( $ops ) ) {
- return Status::newGood(); // nothing to do
+ return $this->newStatus(); // nothing to do
}
$ops = $this->resolveFSFileObjects( $ops );
*
* @param array $op Operation
* @param array $opts Operation options
- * @return Status
+ * @return StatusValue
*/
final public function doOperation( array $op, array $opts = [] ) {
return $this->doOperations( [ $op ], $opts );
*
* @param array $params Operation parameters
* @param array $opts Operation options
- * @return Status
+ * @return StatusValue
*/
final public function create( array $params, array $opts = [] ) {
return $this->doOperation( [ 'op' => 'create' ] + $params, $opts );
*
* @param array $params Operation parameters
* @param array $opts Operation options
- * @return Status
+ * @return StatusValue
*/
final public function store( array $params, array $opts = [] ) {
return $this->doOperation( [ 'op' => 'store' ] + $params, $opts );
*
* @param array $params Operation parameters
* @param array $opts Operation options
- * @return Status
+ * @return StatusValue
*/
final public function copy( array $params, array $opts = [] ) {
return $this->doOperation( [ 'op' => 'copy' ] + $params, $opts );
*
* @param array $params Operation parameters
* @param array $opts Operation options
- * @return Status
+ * @return StatusValue
*/
final public function move( array $params, array $opts = [] ) {
return $this->doOperation( [ 'op' => 'move' ] + $params, $opts );
*
* @param array $params Operation parameters
* @param array $opts Operation options
- * @return Status
+ * @return StatusValue
*/
final public function delete( array $params, array $opts = [] ) {
return $this->doOperation( [ 'op' => 'delete' ] + $params, $opts );
*
* @param array $params Operation parameters
* @param array $opts Operation options
- * @return Status
+ * @return StatusValue
* @since 1.21
*/
final public function describe( array $params, array $opts = [] ) {
* @par Return value:
* This returns a Status, which contains all warnings and fatals that occurred
* during the operation. The 'failCount', 'successCount', and 'success' members
- * will reflect each operation attempted for the given files. The status will be
+ * will reflect each operation attempted for the given files. The StatusValue will be
* considered "OK" as long as no fatal errors occurred.
*
* @param array $ops Set of operations to execute
* @param array $opts Batch operation options
- * @return Status
+ * @return StatusValue
* @since 1.20
*/
final public function doQuickOperations( array $ops, array $opts = [] ) {
if ( empty( $opts['bypassReadOnly'] ) && $this->isReadOnly() ) {
- return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
+ return $this->newStatus( 'backend-fail-readonly', $this->name, $this->readOnly );
}
if ( !count( $ops ) ) {
- return Status::newGood(); // nothing to do
+ return $this->newStatus(); // nothing to do
}
$ops = $this->resolveFSFileObjects( $ops );
* @see FileBackend::doQuickOperations()
*
* @param array $op Operation
- * @return Status
+ * @return StatusValue
* @since 1.20
*/
final public function doQuickOperation( array $op ) {
* @see FileBackend::doQuickOperation()
*
* @param array $params Operation parameters
- * @return Status
+ * @return StatusValue
* @since 1.20
*/
final public function quickCreate( array $params ) {
* @see FileBackend::doQuickOperation()
*
* @param array $params Operation parameters
- * @return Status
+ * @return StatusValue
* @since 1.20
*/
final public function quickStore( array $params ) {
* @see FileBackend::doQuickOperation()
*
* @param array $params Operation parameters
- * @return Status
+ * @return StatusValue
* @since 1.20
*/
final public function quickCopy( array $params ) {
* @see FileBackend::doQuickOperation()
*
* @param array $params Operation parameters
- * @return Status
+ * @return StatusValue
* @since 1.20
*/
final public function quickMove( array $params ) {
* @see FileBackend::doQuickOperation()
*
* @param array $params Operation parameters
- * @return Status
+ * @return StatusValue
* @since 1.20
*/
final public function quickDelete( array $params ) {
* @see FileBackend::doQuickOperation()
*
* @param array $params Operation parameters
- * @return Status
+ * @return StatusValue
* @since 1.21
*/
final public function quickDescribe( array $params ) {
* - srcs : ordered source storage paths (e.g. chunk1, chunk2, ...)
* - dst : file system path to 0-byte temp file
* - parallelize : try to do operations in parallel when possible
- * @return Status
+ * @return StatusValue
*/
abstract public function concatenate( array $params );
* - noAccess : try to deny file access (since 1.20)
* - noListing : try to deny file listing (since 1.20)
* - bypassReadOnly : allow writes in read-only mode (since 1.20)
- * @return Status
+ * @return StatusValue
*/
final public function prepare( array $params ) {
if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
- return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
+ return $this->newStatus( 'backend-fail-readonly', $this->name, $this->readOnly );
}
/** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
* - noAccess : try to deny file access
* - noListing : try to deny file listing
* - bypassReadOnly : allow writes in read-only mode (since 1.20)
- * @return Status
+ * @return StatusValue
*/
final public function secure( array $params ) {
if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
- return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
+ return $this->newStatus( 'backend-fail-readonly', $this->name, $this->readOnly );
}
/** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
* - access : try to allow file access
* - listing : try to allow file listing
* - bypassReadOnly : allow writes in read-only mode (since 1.20)
- * @return Status
+ * @return StatusValue
* @since 1.20
*/
final public function publish( array $params ) {
if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
- return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
+ return $this->newStatus( 'backend-fail-readonly', $this->name, $this->readOnly );
}
/** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
* - dir : storage directory
* - recursive : recursively delete empty subdirectories first (since 1.20)
* - bypassReadOnly : allow writes in read-only mode (since 1.20)
- * @return Status
+ * @return StatusValue
*/
final public function clean( array $params ) {
if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
- return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
+ return $this->newStatus( 'backend-fail-readonly', $this->name, $this->readOnly );
}
/** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
* - headless : only include the body (and headers from "headers") (since 1.28)
* - latest : use the latest available data
* - allowOB : preserve any output buffers (since 1.28)
- * @return Status
+ * @return StatusValue
*/
abstract public function streamFile( array $params );
* @param array $paths Storage paths
* @param int $type LockManager::LOCK_* constant
* @param int $timeout Timeout in seconds (0 means non-blocking) (since 1.24)
- * @return Status
+ * @return StatusValue
*/
final public function lockFiles( array $paths, $type, $timeout = 0 ) {
$paths = array_map( 'FileBackend::normalizeStoragePath', $paths );
*
* @param array $paths Storage paths
* @param int $type LockManager::LOCK_* constant
- * @return Status
+ * @return StatusValue
*/
final public function unlockFiles( array $paths, $type ) {
$paths = array_map( 'FileBackend::normalizeStoragePath', $paths );
/**
* Lock the files at the given storage paths in the backend.
* This will either lock all the files or none (on failure).
- * On failure, the status object will be updated with errors.
+ * On failure, the StatusValue object will be updated with errors.
*
* Once the return value goes out scope, the locks will be released and
- * the status updated. Unlock fatals will not change the status "OK" value.
+ * the StatusValue updated. Unlock fatals will not change the StatusValue "OK" value.
*
* @see ScopedLock::factory()
*
* @param array $paths List of storage paths or map of lock types to path lists
* @param int|string $type LockManager::LOCK_* constant or "mixed"
- * @param Status $status Status to update on lock/unlock
+ * @param StatusValue $status StatusValue to update on lock/unlock
* @param int $timeout Timeout in seconds (0 means non-blocking) (since 1.24)
* @return ScopedLock|null Returns null on failure
*/
- final public function getScopedFileLocks( array $paths, $type, Status $status, $timeout = 0 ) {
+ final public function getScopedFileLocks(
+ array $paths, $type, StatusValue $status, $timeout = 0
+ ) {
if ( $type === 'mixed' ) {
foreach ( $paths as &$typePaths ) {
$typePaths = array_map( 'FileBackend::normalizeStoragePath', $typePaths );
* @see FileBackend::doOperations()
*
* @param array $ops List of file operations to FileBackend::doOperations()
- * @param Status $status Status to update on lock/unlock
+ * @param StatusValue $status StatusValue to update on lock/unlock
* @return ScopedLock|null
* @since 1.20
*/
- abstract public function getScopedLocksForOps( array $ops, Status $status );
+ abstract public function getScopedLocksForOps( array $ops, StatusValue $status );
/**
* Get the root storage path of this backend.
return $path;
}
+
+ /**
+ * Yields the result of the status wrapper callback on either:
+ * - StatusValue::newGood() if this method is called without parameters
+ * - StatusValue::newFatal() with all parameters to this method if passed in
+ *
+ * @param ... string
+ * @return StatusValue
+ */
+ final protected function newStatus() {
+ $args = func_get_args();
+ if ( count( $args ) ) {
+ $sv = call_user_func_array( [ 'StatusValue', 'newFatal' ], $args );
+ } else {
+ $sv = StatusValue::newGood();
+ }
+
+ return $this->wrapStatus( $sv );
+ }
+
+ /**
+ * @param StatusValue $sv
+ * @return StatusValue Modified status or StatusValue subclass
+ */
+ final protected function wrapStatus( StatusValue $sv ) {
+ return $this->statusWrapper ? call_user_func( $this->statusWrapper, $sv ) : $sv;
+ }
}
/**
}
final protected function doOperationsInternal( array $ops, array $opts ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$mbe = $this->backends[$this->masterIndex]; // convenience
* Check that a set of files are consistent across all internal backends
*
* @param array $paths List of storage paths
- * @return Status
+ * @return StatusValue
*/
public function consistencyCheck( array $paths ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
if ( $this->syncChecks == 0 || count( $this->backends ) <= 1 ) {
return $status; // skip checks
}
* Check that a set of file paths are usable across all internal backends
*
* @param array $paths List of storage paths
- * @return Status
+ * @return StatusValue
*/
public function accessibilityCheck( array $paths ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
if ( count( $this->backends ) <= 1 ) {
return $status; // skip checks
}
*
* @param array $paths List of storage paths
* @param string|bool $resyncMode False, True, or "conservative"; see __construct()
- * @return Status
+ * @return StatusValue
*/
public function resyncFiles( array $paths, $resyncMode = true ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$mBackend = $this->backends[$this->masterIndex];
foreach ( $paths as $path ) {
}
protected function doQuickOperationsInternal( array $ops ) {
- $status = Status::newGood();
- // Do the operations on the master backend; setting Status fields...
+ $status = $this->newStatus();
+ // Do the operations on the master backend; setting StatusValue fields...
$realOps = $this->substOpBatchPaths( $ops, $this->backends[$this->masterIndex] );
$masterStatus = $this->backends[$this->masterIndex]->doQuickOperations( $realOps );
$status->merge( $masterStatus );
/**
* @param string $method One of (doPrepare,doSecure,doPublish,doClean)
* @param array $params Method arguments
- * @return Status
+ * @return StatusValue
*/
protected function doDirectoryOp( $method, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
$masterStatus = $this->backends[$this->masterIndex]->$method( $realParams );
return $this->backends[$index]->preloadFileStat( $realParams );
}
- public function getScopedLocksForOps( array $ops, Status $status ) {
+ public function getScopedLocksForOps( array $ops, StatusValue $status ) {
$realOps = $this->substOpBatchPaths( $ops, $this->backends[$this->masterIndex] );
$fileOps = $this->backends[$this->masterIndex]->getOperationsInternal( $realOps );
// Get the paths to lock from the master backend
* - content : the raw file contents
* - dst : destination storage path
* - headers : HTTP header name/value map
- * - async : Status will be returned immediately if supported.
- * If the status is OK, then its value field will be
+ * - async : StatusValue will be returned immediately if supported.
+ * If the StatusValue is OK, then its value field will be
* set to a FileBackendStoreOpHandle object.
* - dstExists : Whether a file exists at the destination (optimization).
* Callers can use "false" if no existing file is being changed.
*
* @param array $params
- * @return Status
+ * @return StatusValue
*/
final public function createInternal( array $params ) {
$ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
if ( strlen( $params['content'] ) > $this->maxFileSizeInternal() ) {
- $status = Status::newFatal( 'backend-fail-maxsize',
+ $status = $this->newStatus( 'backend-fail-maxsize',
$params['dst'], $this->maxFileSizeInternal() );
} else {
$status = $this->doCreateInternal( $params );
/**
* @see FileBackendStore::createInternal()
* @param array $params
- * @return Status
+ * @return StatusValue
*/
abstract protected function doCreateInternal( array $params );
* - src : source path on disk
* - dst : destination storage path
* - headers : HTTP header name/value map
- * - async : Status will be returned immediately if supported.
- * If the status is OK, then its value field will be
+ * - async : StatusValue will be returned immediately if supported.
+ * If the StatusValue is OK, then its value field will be
* set to a FileBackendStoreOpHandle object.
* - dstExists : Whether a file exists at the destination (optimization).
* Callers can use "false" if no existing file is being changed.
*
* @param array $params
- * @return Status
+ * @return StatusValue
*/
final public function storeInternal( array $params ) {
$ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
if ( filesize( $params['src'] ) > $this->maxFileSizeInternal() ) {
- $status = Status::newFatal( 'backend-fail-maxsize',
+ $status = $this->newStatus( 'backend-fail-maxsize',
$params['dst'], $this->maxFileSizeInternal() );
} else {
$status = $this->doStoreInternal( $params );
/**
* @see FileBackendStore::storeInternal()
* @param array $params
- * @return Status
+ * @return StatusValue
*/
abstract protected function doStoreInternal( array $params );
* - dst : destination storage path
* - ignoreMissingSource : do nothing if the source file does not exist
* - headers : HTTP header name/value map
- * - async : Status will be returned immediately if supported.
- * If the status is OK, then its value field will be
+ * - async : StatusValue will be returned immediately if supported.
+ * If the StatusValue is OK, then its value field will be
* set to a FileBackendStoreOpHandle object.
* - dstExists : Whether a file exists at the destination (optimization).
* Callers can use "false" if no existing file is being changed.
*
* @param array $params
- * @return Status
+ * @return StatusValue
*/
final public function copyInternal( array $params ) {
$ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
/**
* @see FileBackendStore::copyInternal()
* @param array $params
- * @return Status
+ * @return StatusValue
*/
abstract protected function doCopyInternal( array $params );
* $params include:
* - src : source storage path
* - ignoreMissingSource : do nothing if the source file does not exist
- * - async : Status will be returned immediately if supported.
- * If the status is OK, then its value field will be
+ * - async : StatusValue will be returned immediately if supported.
+ * If the StatusValue is OK, then its value field will be
* set to a FileBackendStoreOpHandle object.
*
* @param array $params
- * @return Status
+ * @return StatusValue
*/
final public function deleteInternal( array $params ) {
$ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
/**
* @see FileBackendStore::deleteInternal()
* @param array $params
- * @return Status
+ * @return StatusValue
*/
abstract protected function doDeleteInternal( array $params );
* - dst : destination storage path
* - ignoreMissingSource : do nothing if the source file does not exist
* - headers : HTTP header name/value map
- * - async : Status will be returned immediately if supported.
- * If the status is OK, then its value field will be
+ * - async : StatusValue will be returned immediately if supported.
+ * If the StatusValue is OK, then its value field will be
* set to a FileBackendStoreOpHandle object.
* - dstExists : Whether a file exists at the destination (optimization).
* Callers can use "false" if no existing file is being changed.
*
* @param array $params
- * @return Status
+ * @return StatusValue
*/
final public function moveInternal( array $params ) {
$ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
/**
* @see FileBackendStore::moveInternal()
* @param array $params
- * @return Status
+ * @return StatusValue
*/
protected function doMoveInternal( array $params ) {
unset( $params['async'] ); // two steps, won't work here :)
* $params include:
* - src : source storage path
* - headers : HTTP header name/value map
- * - async : Status will be returned immediately if supported.
- * If the status is OK, then its value field will be
+ * - async : StatusValue will be returned immediately if supported.
+ * If the StatusValue is OK, then its value field will be
* set to a FileBackendStoreOpHandle object.
*
* @param array $params
- * @return Status
+ * @return StatusValue
*/
final public function describeInternal( array $params ) {
$ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
$this->clearCache( [ $params['src'] ] );
$this->deleteFileCache( $params['src'] ); // persistent cache
} else {
- $status = Status::newGood(); // nothing to do
+ $status = $this->newStatus(); // nothing to do
}
return $status;
/**
* @see FileBackendStore::describeInternal()
* @param array $params
- * @return Status
+ * @return StatusValue
*/
protected function doDescribeInternal( array $params ) {
- return Status::newGood();
+ return $this->newStatus();
}
/**
* Do not call this function from places outside FileBackend and FileOp.
*
* @param array $params
- * @return Status
+ * @return StatusValue
*/
final public function nullInternal( array $params ) {
- return Status::newGood();
+ return $this->newStatus();
}
final public function concatenate( array $params ) {
$ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
- $status = Status::newGood();
+ $status = $this->newStatus();
// Try to lock the source files for the scope of this function
$scopeLockS = $this->getScopedFileLocks( $params['srcs'], LockManager::LOCK_UW, $status );
/**
* @see FileBackendStore::concatenate()
* @param array $params
- * @return Status
+ * @return StatusValue
*/
protected function doConcatenate( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$tmpPath = $params['dst']; // convenience
unset( $params['latest'] ); // sanity
final protected function doPrepare( array $params ) {
$ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
- $status = Status::newGood();
+ $status = $this->newStatus();
list( $fullCont, $dir, $shard ) = $this->resolveStoragePath( $params['dir'] );
if ( $dir === null ) {
* @param string $container
* @param string $dir
* @param array $params
- * @return Status
+ * @return StatusValue
*/
protected function doPrepareInternal( $container, $dir, array $params ) {
- return Status::newGood();
+ return $this->newStatus();
}
final protected function doSecure( array $params ) {
$ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
- $status = Status::newGood();
+ $status = $this->newStatus();
list( $fullCont, $dir, $shard ) = $this->resolveStoragePath( $params['dir'] );
if ( $dir === null ) {
* @param string $container
* @param string $dir
* @param array $params
- * @return Status
+ * @return StatusValue
*/
protected function doSecureInternal( $container, $dir, array $params ) {
- return Status::newGood();
+ return $this->newStatus();
}
final protected function doPublish( array $params ) {
$ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
- $status = Status::newGood();
+ $status = $this->newStatus();
list( $fullCont, $dir, $shard ) = $this->resolveStoragePath( $params['dir'] );
if ( $dir === null ) {
* @param string $container
* @param string $dir
* @param array $params
- * @return Status
+ * @return StatusValue
*/
protected function doPublishInternal( $container, $dir, array $params ) {
- return Status::newGood();
+ return $this->newStatus();
}
final protected function doClean( array $params ) {
$ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
- $status = Status::newGood();
+ $status = $this->newStatus();
// Recursive: first delete all empty subdirs recursively
if ( !empty( $params['recursive'] ) && !$this->directoriesAreVirtual() ) {
* @param string $container
* @param string $dir
* @param array $params
- * @return Status
+ * @return StatusValue
*/
protected function doCleanInternal( $container, $dir, array $params ) {
- return Status::newGood();
+ return $this->newStatus();
}
final public function fileExists( array $params ) {
final public function streamFile( array $params ) {
$ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
- $status = Status::newGood();
+ $status = $this->newStatus();
// Always set some fields for subclass convenience
$params['options'] = isset( $params['options'] ) ? $params['options'] : [];
/**
* @see FileBackendStore::streamFile()
* @param array $params
- * @return Status
+ * @return StatusValue
*/
protected function doStreamFile( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$flags = 0;
$flags |= !empty( $params['headless'] ) ? StreamFile::STREAM_HEADLESS : 0;
* An exception is thrown if an unsupported operation is requested.
*
* @param array $ops Same format as doOperations()
- * @return array List of FileOp objects
+ * @return FileOp[] List of FileOp objects
* @throws FileBackendError
*/
final public function getOperationsInternal( array $ops ) {
];
}
- public function getScopedLocksForOps( array $ops, Status $status ) {
+ public function getScopedLocksForOps( array $ops, StatusValue $status ) {
$paths = $this->getPathsToLockForOpsInternal( $this->getOperationsInternal( $ops ) );
return $this->getScopedFileLocks( $paths, 'mixed', $status );
final protected function doOperationsInternal( array $ops, array $opts ) {
$ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
- $status = Status::newGood();
+ $status = $this->newStatus();
// Fix up custom header name/value pairs...
$ops = array_map( [ $this, 'sanitizeOpHeaders' ], $ops );
$subStatus = FileOpBatch::attempt( $performOps, $opts, $this->fileJournal );
} else {
// If we could not even stat some files, then bail out...
- $subStatus = Status::newFatal( 'backend-fail-internal', $this->name );
+ $subStatus = $this->newStatus( 'backend-fail-internal', $this->name );
foreach ( $ops as $i => $op ) { // mark each op as failed
$subStatus->success[$i] = false;
++$subStatus->failCount;
" stat failure; aborted operations: " . FormatJson::encode( $ops ) );
}
- // Merge errors into status fields
+ // Merge errors into StatusValue fields
$status->merge( $subStatus );
$status->success = $subStatus->success; // not done in merge()
final protected function doQuickOperationsInternal( array $ops ) {
$ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
- $status = Status::newGood();
+ $status = $this->newStatus();
// Fix up custom header name/value pairs...
$ops = array_map( [ $this, 'sanitizeOpHeaders' ], $ops );
// Parallel ops may be disabled in config due to dependencies (e.g. needing popen())
$async = ( $this->parallelize === 'implicit' && count( $ops ) > 1 );
$maxConcurrency = $this->concurrency; // throttle
-
- $statuses = []; // array of (index => Status)
+ /** @var StatusValue[] $statuses */
+ $statuses = []; // array of (index => StatusValue)
$fileOpHandles = []; // list of (index => handle) arrays
$curFileOpHandles = []; // current handle batch
// Perform the sync-only ops and build up op handles for the async ops...
/**
* Execute a list of FileBackendStoreOpHandle handles in parallel.
- * The resulting Status object fields will correspond
+ * The resulting StatusValue object fields will correspond
* to the order in which the handles where given.
*
* @param FileBackendStoreOpHandle[] $fileOpHandles
*
* @throws FileBackendError
- * @return array Map of Status objects
+ * @return StatusValue[] Map of StatusValue objects
*/
final public function executeOpHandlesInternal( array $fileOpHandles ) {
$ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
* @param FileBackendStoreOpHandle[] $fileOpHandles
*
* @throws FileBackendError
- * @return Status[] List of corresponding Status objects
+ * @return StatusValue[] List of corresponding StatusValue objects
*/
protected function doExecuteOpHandlesInternal( array $fileOpHandles ) {
if ( count( $fileOpHandles ) ) {
* FileBackendStore helper class for performing asynchronous file operations.
*
* For example, calling FileBackendStore::createInternal() with the "async"
- * param flag may result in a Status that contains this object as a value.
+ * param flag may result in a StatusValue that contains this object as a value.
* This class is largely backend-specific and is mostly just "magic" to be
* passed to FileBackendStore::executeOpHandlesInternal().
*/
/**
* Check preconditions of the operation without writing anything.
* This must update $predicates for each path that the op can change
- * except when a failing status object is returned.
+ * except when a failing StatusValue object is returned.
*
* @param array $predicates
- * @return Status
+ * @return StatusValue
*/
final public function precheck( array &$predicates ) {
if ( $this->state !== self::STATE_NEW ) {
- return Status::newFatal( 'fileop-fail-state', self::STATE_NEW, $this->state );
+ return StatusValue::newFatal( 'fileop-fail-state', self::STATE_NEW, $this->state );
}
$this->state = self::STATE_CHECKED;
$status = $this->doPrecheck( $predicates );
/**
* @param array $predicates
- * @return Status
+ * @return StatusValue
*/
protected function doPrecheck( array &$predicates ) {
- return Status::newGood();
+ return StatusValue::newGood();
}
/**
* Attempt the operation
*
- * @return Status
+ * @return StatusValue
*/
final public function attempt() {
if ( $this->state !== self::STATE_CHECKED ) {
- return Status::newFatal( 'fileop-fail-state', self::STATE_CHECKED, $this->state );
+ return StatusValue::newFatal( 'fileop-fail-state', self::STATE_CHECKED, $this->state );
} elseif ( $this->failed ) { // failed precheck
- return Status::newFatal( 'fileop-fail-attempt-precheck' );
+ return StatusValue::newFatal( 'fileop-fail-attempt-precheck' );
}
$this->state = self::STATE_ATTEMPTED;
if ( $this->doOperation ) {
$this->logFailure( 'attempt' );
}
} else { // no-op
- $status = Status::newGood();
+ $status = StatusValue::newGood();
}
return $status;
}
/**
- * @return Status
+ * @return StatusValue
*/
protected function doAttempt() {
- return Status::newGood();
+ return StatusValue::newGood();
}
/**
* Attempt the operation in the background
*
- * @return Status
+ * @return StatusValue
*/
final public function attemptAsync() {
$this->async = true;
/**
* Check for errors with regards to the destination file already existing.
* Also set the destExists, overwriteSameCase and sourceSha1 member variables.
- * A bad status will be returned if there is no chance it can be overwritten.
+ * A bad StatusValue will be returned if there is no chance it can be overwritten.
*
* @param array $predicates
- * @return Status
+ * @return StatusValue
*/
protected function precheckDestExistence( array $predicates ) {
- $status = Status::newGood();
+ $status = StatusValue::newGood();
// Get hash of source file/string and the destination file
$this->sourceSha1 = $this->getSourceSha1Base36(); // FS file or data string
if ( $this->sourceSha1 === null ) { // file in storage?
}
protected function doPrecheck( array &$predicates ) {
- $status = Status::newGood();
+ $status = StatusValue::newGood();
// Check if the source data is too big
if ( strlen( $this->getParam( 'content' ) ) > $this->backend->maxFileSizeInternal() ) {
$status->fatal( 'backend-fail-maxsize',
return $this->backend->createInternal( $this->setFlags( $this->params ) );
}
- return Status::newGood();
+ return StatusValue::newGood();
}
protected function getSourceSha1Base36() {
}
protected function doPrecheck( array &$predicates ) {
- $status = Status::newGood();
+ $status = StatusValue::newGood();
// Check if the source file exists on the file system
if ( !is_file( $this->params['src'] ) ) {
$status->fatal( 'backend-fail-notexists', $this->params['src'] );
return $this->backend->storeInternal( $this->setFlags( $this->params ) );
}
- return Status::newGood();
+ return StatusValue::newGood();
}
protected function getSourceSha1Base36() {
}
protected function doPrecheck( array &$predicates ) {
- $status = Status::newGood();
+ $status = StatusValue::newGood();
// Check if the source file exists
if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
if ( $this->getParam( 'ignoreMissingSource' ) ) {
protected function doAttempt() {
if ( $this->overwriteSameCase ) {
- $status = Status::newGood(); // nothing to do
+ $status = StatusValue::newGood(); // nothing to do
} elseif ( $this->params['src'] === $this->params['dst'] ) {
// Just update the destination file headers
$headers = $this->getParam( 'headers' ) ?: [];
}
protected function doPrecheck( array &$predicates ) {
- $status = Status::newGood();
+ $status = StatusValue::newGood();
// Check if the source file exists
if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
if ( $this->getParam( 'ignoreMissingSource' ) ) {
if ( $this->overwriteSameCase ) {
if ( $this->params['src'] === $this->params['dst'] ) {
// Do nothing to the destination (which is also the source)
- $status = Status::newGood();
+ $status = StatusValue::newGood();
} else {
// Just delete the source as the destination file needs no changes
$status = $this->backend->deleteInternal( $this->setFlags(
}
protected function doPrecheck( array &$predicates ) {
- $status = Status::newGood();
+ $status = StatusValue::newGood();
// Check if the source file exists
if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
if ( $this->getParam( 'ignoreMissingSource' ) ) {
}
protected function doPrecheck( array &$predicates ) {
- $status = Status::newGood();
+ $status = StatusValue::newGood();
// Check if the source file exists
if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
$status->fatal( 'backend-fail-notexists', $this->params['src'] );
* - nonJournaled : Don't log this operation batch in the file journal.
* - concurrency : Try to do this many operations in parallel when possible.
*
- * The resulting Status will be "OK" unless:
+ * The resulting StatusValue will be "OK" unless:
* - a) unexpected operation errors occurred (network partitions, disk full...)
* - b) significant operation errors occurred and 'force' was not set
*
* @param FileOp[] $performOps List of FileOp operations
* @param array $opts Batch operation options
* @param FileJournal $journal Journal to log operations to
- * @return Status
+ * @return StatusValue
*/
public static function attempt( array $performOps, array $opts, FileJournal $journal ) {
- $status = Status::newGood();
+ $status = StatusValue::newGood();
$n = count( $performOps );
if ( $n > self::MAX_BATCH_SIZE ) {
if ( count( $entries ) ) {
$subStatus = $journal->logChangeBatch( $entries, $batchId );
if ( !$subStatus->isOK() ) {
- return $subStatus; // abort
+ $status->merge( $subStatus );
+
+ return $status; // abort
}
}
* This will abort remaining ops on failure.
*
* @param array $pPerformOps Batches of file ops (batches use original indexes)
- * @param Status $status
+ * @param StatusValue $status
*/
- protected static function runParallelBatches( array $pPerformOps, Status $status ) {
+ protected static function runParallelBatches( array $pPerformOps, StatusValue $status ) {
$aborted = false; // set to true on unexpected errors
foreach ( $pPerformOps as $performOpsBatch ) {
/** @var FileOp[] $performOpsBatch */
}
continue;
}
- /** @var Status[] $statuses */
+ /** @var StatusValue[] $statuses */
$statuses = [];
$opHandles = [];
// Get the backend; all sub-batch ops belong to a single backend
$backend = reset( $performOpsBatch )->getBackend();
// Get the operation handles or actually do it if there is just one.
- // If attemptAsync() returns a Status, it was either due to an error
+ // If attemptAsync() returns a StatusValue, it was either due to an error
// or the backend does not support async ops and did it synchronously.
foreach ( $performOpsBatch as $i => $fileOp ) {
if ( !isset( $status->success[$i] ) ) { // didn't already fail in precheck()
}
protected function doCreateInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$dst = $this->resolveHashKey( $params['dst'] );
if ( $dst === null ) {
}
protected function doStoreInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$dst = $this->resolveHashKey( $params['dst'] );
if ( $dst === null ) {
}
protected function doCopyInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$src = $this->resolveHashKey( $params['src'] );
if ( $src === null ) {
}
protected function doDeleteInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$src = $this->resolveHashKey( $params['src'] );
if ( $src === null ) {
/**
* @brief Class for an OpenStack Swift (or Ceph RGW) based file backend.
*
- * Status messages should avoid mentioning the Swift account name.
+ * StatusValue messages should avoid mentioning the Swift account name.
* Likewise, error suppression should be used to avoid path disclosure.
*
* @ingroup FileBackend
}
protected function doCreateInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
list( $dstCont, $dstRel ) = $this->resolveStoragePathReal( $params['dst'] );
if ( $dstRel === null ) {
] ];
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $method, $params ) {
+ $handler = function ( array $request, StatusValue $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 201 ) {
// good
}
protected function doStoreInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
list( $dstCont, $dstRel ) = $this->resolveStoragePathReal( $params['dst'] );
if ( $dstRel === null ) {
] ];
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $method, $params ) {
+ $handler = function ( array $request, StatusValue $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 201 ) {
// good
}
protected function doCopyInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $params['src'] );
if ( $srcRel === null ) {
] ];
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $method, $params ) {
+ $handler = function ( array $request, StatusValue $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 201 ) {
// good
}
protected function doMoveInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $params['src'] );
if ( $srcRel === null ) {
}
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $method, $params ) {
+ $handler = function ( array $request, StatusValue $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $request['method'] === 'PUT' && $rcode === 201 ) {
// good
}
protected function doDeleteInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $params['src'] );
if ( $srcRel === null ) {
] ];
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $method, $params ) {
+ $handler = function ( array $request, StatusValue $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 204 ) {
// good
}
protected function doDescribeInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $params['src'] );
if ( $srcRel === null ) {
] ];
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $method, $params ) {
+ $handler = function ( array $request, StatusValue $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 202 ) {
// good
}
protected function doPrepareInternal( $fullCont, $dir, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
// (a) Check if container already exists
$stat = $this->getContainerStat( $fullCont );
}
protected function doSecureInternal( $fullCont, $dir, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
if ( empty( $params['noAccess'] ) ) {
return $status; // nothing to do
}
}
protected function doPublishInternal( $fullCont, $dir, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$stat = $this->getContainerStat( $fullCont );
if ( is_array( $stat ) ) {
}
protected function doCleanInternal( $fullCont, $dir, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
// Only containers themselves can be removed, all else is virtual
if ( $dir != '' ) {
// Find prior metadata headers
$postHeaders += $this->getMetadataHeaders( $objHdrs );
- $status = Status::newGood();
+ $status = $this->newStatus();
/** @noinspection PhpUnusedLocalVariableInspection */
$scopeLockS = $this->getScopedFileLocks( [ $path ], LockManager::LOCK_UW, $status );
if ( $status->isOK() ) {
}
protected function doStreamFile( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$flags = !empty( $params['headless'] ) ? StreamFile::STREAM_HEADLESS : 0;
/**
* @param FileBackendStoreOpHandle[] $fileOpHandles
*
- * @return Status[]
+ * @return StatusValue[]
*/
protected function doExecuteOpHandlesInternal( array $fileOpHandles ) {
$statuses = [];
$auth = $this->getAuthentication();
if ( !$auth ) {
foreach ( $fileOpHandles as $index => $fileOpHandle ) {
- $statuses[$index] = Status::newFatal( 'backend-fail-connect', $this->name );
+ $statuses[$index] = $this->newStatus( 'backend-fail-connect', $this->name );
}
return $statuses;
$req['headers'] = $this->authTokenHeaders( $auth ) + $req['headers'];
$httpReqsByStage[$stage][$index] = $req;
}
- $statuses[$index] = Status::newGood();
+ $statuses[$index] = $this->newStatus();
}
// Run all requests for the first stage, then the next, and so on
* @param array $writeGrps A list of the possible criteria for a request to have
* access to write to a container. Each item is of the following format:
* - account:user : Grants access if the request is by the given user
- * @return Status
+ * @return StatusValue
*/
protected function setContainerAccess( $container, array $readGrps, array $writeGrps ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$auth = $this->getAuthentication();
if ( !$auth ) {
*
* @param string $container Container name
* @param array $params
- * @return Status
+ * @return StatusValue
*/
protected function createContainer( $container, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$auth = $this->getAuthentication();
if ( !$auth ) {
*
* @param string $container Container name
* @param array $params
- * @return Status
+ * @return StatusValue
*/
protected function deleteContainer( $container, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$auth = $this->getAuthentication();
if ( !$auth ) {
* @param string|null $after
* @param string|null $prefix
* @param string|null $delim
- * @return Status With the list as value
+ * @return StatusValue With the list as value
*/
private function objectListing(
$fullCont, $type, $limit, $after = null, $prefix = null, $delim = null
) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$auth = $this->getAuthentication();
if ( !$auth ) {
/**
* Log an unexpected exception for this backend.
- * This also sets the Status object to have a fatal error.
+ * This also sets the StatusValue object to have a fatal error.
*
- * @param Status|null $status
+ * @param StatusValue|null $status
* @param string $func
* @param array $params
* @param string $err Error string
* @param int $code HTTP status
- * @param string $desc HTTP status description
+ * @param string $desc HTTP StatusValue description
*/
public function onError( $status, $func, array $params, $err = '', $code = 0, $desc = '' ) {
- if ( $status instanceof Status ) {
+ if ( $status instanceof StatusValue ) {
$status->fatal( 'backend-fail-internal', $this->name );
}
if ( $code == 401 ) { // possibly a stale token
* @see FileJournal::logChangeBatch()
* @param array $entries
* @param string $batchId
- * @return Status
+ * @return StatusValue
*/
protected function doLogChangeBatch( array $entries, $batchId ) {
- $status = Status::newGood();
+ $status = StatusValue::newGood();
try {
$dbw = $this->getMasterDB();
/**
* @see FileJournal::purgeOldLogs()
- * @return Status
+ * @return StatusValue
* @throws DBError
*/
protected function doPurgeOldLogs() {
- $status = Status::newGood();
+ $status = StatusValue::newGood();
if ( $this->ttlDays <= 0 ) {
return $status; // nothing to do
}
* newSha1 : The final base 36 SHA-1 of the file
* Note that 'false' should be used as the SHA-1 for non-existing files.
* @param string $batchId UUID string that identifies the operation batch
- * @return Status
+ * @return StatusValue
*/
final public function logChangeBatch( array $entries, $batchId ) {
if ( !count( $entries ) ) {
- return Status::newGood();
+ return StatusValue::newGood();
}
return $this->doLogChangeBatch( $entries, $batchId );
*
* @param array $entries List of file operations (each an array of parameters)
* @param string $batchId UUID string that identifies the operation batch
- * @return Status
+ * @return StatusValue
*/
abstract protected function doLogChangeBatch( array $entries, $batchId );
/**
* Purge any old log entries
*
- * @return Status
+ * @return StatusValue
*/
final public function purgeOldLogs() {
return $this->doPurgeOldLogs();
/**
* @see FileJournal::purgeOldLogs()
- * @return Status
+ * @return StatusValue
*/
abstract protected function doPurgeOldLogs();
}
* @see FileJournal::doLogChangeBatch()
* @param array $entries
* @param string $batchId
- * @return Status
+ * @return StatusValue
*/
protected function doLogChangeBatch( array $entries, $batchId ) {
- return Status::newGood();
+ return StatusValue::newGood();
}
/**
/**
* @see FileJournal::doPurgeOldLogs()
- * @return Status
+ * @return StatusValue
*/
protected function doPurgeOldLogs() {
- return Status::newGood();
+ return StatusValue::newGood();
}
}
* @see LockManager::doLock()
* @param array $paths
* @param int $type
- * @return Status
+ * @return StatusValue
*/
protected function doLock( array $paths, $type ) {
$status = Status::newGood();
* @see LockManager::doUnlock()
* @param array $paths
* @param int $type
- * @return Status
+ * @return StatusValue
*/
protected function doUnlock( array $paths, $type ) {
$status = Status::newGood();
*
* @param string $path
* @param int $type
- * @return Status
+ * @return StatusValue
*/
protected function doSingleLock( $path, $type ) {
$status = Status::newGood();
*
* @param string $path
* @param int $type
- * @return Status
+ * @return StatusValue
*/
protected function doSingleUnlock( $path, $type ) {
$status = Status::newGood();
/**
* @param string $path
* @param array $handlesToClose
- * @return Status
+ * @return StatusValue
*/
private function closeLockHandles( $path, array $handlesToClose ) {
$status = Status::newGood();
/**
* @param string $path
- * @return Status
+ * @return StatusValue
*/
private function pruneKeyLockFiles( $path ) {
$status = Status::newGood();
* @param array $paths List of resource names
* @param int $type LockManager::LOCK_* constant
* @param int $timeout Timeout in seconds (0 means non-blocking) (since 1.21)
- * @return Status
+ * @return StatusValue
*/
final public function lock( array $paths, $type = self::LOCK_EX, $timeout = 0 ) {
return $this->lockByType( [ $type => $paths ], $timeout );
*
* @param array $pathsByType Map of LockManager::LOCK_* constants to lists of paths
* @param int $timeout Timeout in seconds (0 means non-blocking) (since 1.21)
- * @return Status
+ * @return StatusValue
* @since 1.22
*/
final public function lockByType( array $pathsByType, $timeout = 0 ) {
*
* @param array $paths List of paths
* @param int $type LockManager::LOCK_* constant
- * @return Status
+ * @return StatusValue
*/
final public function unlock( array $paths, $type = self::LOCK_EX ) {
return $this->unlockByType( [ $type => $paths ] );
* Unlock the resources at the given abstract paths
*
* @param array $pathsByType Map of LockManager::LOCK_* constants to lists of paths
- * @return Status
+ * @return StatusValue
* @since 1.22
*/
final public function unlockByType( array $pathsByType ) {
/**
* @see LockManager::lockByType()
* @param array $pathsByType Map of LockManager::LOCK_* constants to lists of paths
- * @return Status
+ * @return StatusValue
* @since 1.22
*/
protected function doLockByType( array $pathsByType ) {
*
* @param array $paths List of paths
* @param int $type LockManager::LOCK_* constant
- * @return Status
+ * @return StatusValue
*/
abstract protected function doLock( array $paths, $type );
/**
* @see LockManager::unlockByType()
* @param array $pathsByType Map of LockManager::LOCK_* constants to lists of paths
- * @return Status
+ * @return StatusValue
* @since 1.22
*/
protected function doUnlockByType( array $pathsByType ) {
*
* @param array $paths List of paths
* @param int $type LockManager::LOCK_* constant
- * @return Status
+ * @return StatusValue
*/
abstract protected function doUnlock( array $paths, $type );
}
* @param string $lockSrv
* @param array $paths
* @param string $type
- * @return Status
+ * @return StatusValue
*/
protected function doGetLocksOnServer( $lockSrv, array $paths, $type ) {
$status = Status::newGood();
* @param string $lockSrv
* @param array $paths
* @param string $type
- * @return Status
+ * @return StatusValue
*/
protected function doFreeLocksOnServer( $lockSrv, array $paths, $type ) {
$status = Status::newGood();
/**
* @see QuorumLockManager::releaseAllLocks()
- * @return Status
+ * @return StatusValue
*/
protected function releaseAllLocks() {
return Status::newGood(); // not supported
* @param string $lockSrv
* @param array $paths
* @param string $type
- * @return Status
+ * @return StatusValue
*/
protected function doGetLocksOnServer( $lockSrv, array $paths, $type ) {
$status = Status::newGood();
/**
* @see QuorumLockManager::releaseAllLocks()
- * @return Status
+ * @return StatusValue
*/
protected function releaseAllLocks() {
$status = Status::newGood();
/**
* @see QuorumLockManager::releaseAllLocks()
- * @return Status
+ * @return StatusValue
*/
protected function releaseAllLocks() {
$status = Status::newGood();
*
* @param int $bucket
* @param array $pathsByType Map of LockManager::LOCK_* constants to lists of paths
- * @return Status
+ * @return StatusValue
*/
final protected function doLockingRequestBucket( $bucket, array $pathsByType ) {
$status = Status::newGood();
*
* @param int $bucket
* @param array $pathsByType Map of LockManager::LOCK_* constants to lists of paths
- * @return Status
+ * @return StatusValue
*/
final protected function doUnlockingRequestBucket( $bucket, array $pathsByType ) {
$status = Status::newGood();
}
}
}
- // Set a bad status if the quorum was not met.
+ // Set a bad StatusValue if the quorum was not met.
// Assumes the same "up" servers as during the acquire step.
$status->setResult( $yesVotes >= $quorum );
*
* @param string $lockSrv
* @param array $pathsByType Map of LockManager::LOCK_* constants to lists of paths
- * @return Status
+ * @return StatusValue
*/
abstract protected function getLocksOnServer( $lockSrv, array $pathsByType );
*
* @param string $lockSrv
* @param array $pathsByType Map of LockManager::LOCK_* constants to lists of paths
- * @return Status
+ * @return StatusValue
*/
abstract protected function freeLocksOnServer( $lockSrv, array $pathsByType );
*
* Subclasses must effectively implement this or freeLocksOnServer().
*
- * @return Status
+ * @return StatusValue
*/
abstract protected function releaseAllLocks();
}
/** @var LockManager */
protected $manager;
- /** @var Status */
+ /** @var StatusValue */
protected $status;
/** @var array Map of lock types to resource paths */
/**
* @param LockManager $manager
* @param array $pathsByType Map of lock types to path lists
- * @param Status $status
+ * @param StatusValue $status
*/
- protected function __construct( LockManager $manager, array $pathsByType, Status $status ) {
+ protected function __construct( LockManager $manager, array $pathsByType, StatusValue $status ) {
$this->manager = $manager;
$this->pathsByType = $pathsByType;
$this->status = $status;
/**
* Get a ScopedLock object representing a lock on resource paths.
* Any locks are released once this object goes out of scope.
- * The status object is updated with any errors or warnings.
+ * The StatusValue object is updated with any errors or warnings.
*
* @param LockManager $manager
* @param array $paths List of storage paths or map of lock types to path lists
* @param int|string $type LockManager::LOCK_* constant or "mixed" and $paths
* can be a map of types to paths (since 1.22). Otherwise $type should be an
* integer and $paths should be a list of paths.
- * @param Status $status
+ * @param StatusValue $status
* @param int $timeout Timeout in seconds (0 means non-blocking) (since 1.22)
* @return ScopedLock|null Returns null on failure
*/
public static function factory(
- LockManager $manager, array $paths, $type, Status $status, $timeout = 0
+ LockManager $manager, array $paths, $type, StatusValue $status, $timeout = 0
) {
$pathsByType = is_integer( $type ) ? [ $type => $paths ] : $paths;
$lockStatus = $manager->lockByType( $pathsByType, $timeout );
}
/**
- * Release a scoped lock and set any errors in the attatched Status object.
+ * Release a scoped lock and set any errors in the attatched StatusValue object.
* This is useful for early release of locks before function scope is destroyed.
* This is the same as setting the lock object to null.
*
$wasOk = $this->status->isOK();
$this->status->merge( $this->manager->unlockByType( $this->pathsByType ) );
if ( $wasOk ) {
- // Make sure status is OK, despite any unlockFiles() fatals
+ // Make sure StatusValue is OK, despite any unlockFiles() fatals
$this->status->setResult( true, $this->status->value );
}
}
protected $dbs;
public function __construct( array $config ) {
- $config['name'] = $config['backend']->getName();
- $config['wikiId'] = $config['backend']->getWikiId();
+ /** @var FileBackend $backend */
+ $backend = $config['backend'];
+ $config['name'] = $backend->getName();
+ $config['wikiId'] = $backend->getWikiId();
parent::__construct( $config );
$this->backend = $config['backend'];
$this->repoName = $config['repoName'];
return $this->translateSrcParams( __FUNCTION__, $params );
}
- public function getScopedLocksForOps( array $ops, Status $status ) {
+ public function getScopedLocksForOps( array $ops, StatusValue $status ) {
return $this->backend->getScopedLocksForOps( $ops, $status );
}
* Splits this StatusValue object into two new StatusValue objects, one which contains only
* the error messages, and one that contains the warnings, only. The returned array is
* defined as:
- * array(
- * 0 => object(StatusValue) # the StatusValue with error messages, only
- * 1 => object(StatusValue) # The StatusValue with warning messages, only
- * )
+ * [
+ * 0 => object(StatusValue) # the StatusValue with error messages, only
+ * 1 => object(StatusValue) # The StatusValue with warning messages, only
+ * ]
*
* @return array
*/