idb/FBControlCore/Utility/FBControlCoreError.m

247 строки
5.8 KiB
Objective-C

/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "FBControlCoreError.h"
#import "FBControlCoreGlobalConfiguration.h"
#import "FBControlCoreLogger.h"
#import "FBProcessInfo.h"
#import "FBProcessFetcher.h"
NSString *const FBControlCoreErrorDomain = @"com.facebook.FBControlCore";
@interface FBControlCoreError ()
@property (nonatomic, copy, readwrite) NSString *domain;
@property (nonatomic, copy, readwrite) NSString *describedAs;
@property (nonatomic, copy, readwrite) NSError *cause;
@property (nonatomic, strong, readwrite) id<FBControlCoreLogger> logger;
@property (nonatomic, strong, readwrite) NSMutableDictionary *additionalInfo;
@property (nonatomic, assign, readwrite) BOOL describeRecursively;
@end
@implementation FBControlCoreError
- (instancetype)init
{
self = [super init];
if (!self) {
return nil;
}
_domain = FBControlCoreErrorDomain;
_additionalInfo = [NSMutableDictionary dictionary];
_describeRecursively = YES;
_logger = FBControlCoreGlobalConfiguration.defaultLogger;
return self;
}
+ (instancetype)describe:(NSString *)description
{
return [self.new describe:description];
}
- (instancetype)describe:(NSString *)description
{
self.describedAs = description;
return self;
}
+ (instancetype)describeFormat:(NSString *)format, ...
{
va_list args;
va_start(args, format);
NSString *string = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
return [self describe:string];
}
- (instancetype)describeFormat:(NSString *)format, ...
{
va_list args;
va_start(args, format);
NSString *string = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
return [self describe:string];
}
+ (instancetype)causedBy:(NSError *)cause
{
return [self.new causedBy:cause];
}
- (instancetype)causedBy:(NSError *)cause
{
self.cause = cause;
return self;
}
- (BOOL)failBool:(NSError **)error
{
if (error) {
*error = [self build];
}
return NO;
}
- (unsigned int)failUInt:(NSError **)error
{
if (error) {
*error = [self build];
}
return 0;
}
- (CGRect)failRect:(NSError **)error
{
if (error) {
*error = [self build];
}
return CGRectNull;
}
- (id)fail:(NSError **)error
{
if (error) {
*error = [self build];
}
return nil;
}
- (instancetype)extraInfo:(NSString *)key value:(id)value
{
if (!key || !value) {
return self;
}
self.additionalInfo[key] = value;
return self;
}
- (instancetype)recursiveDescription
{
self.describeRecursively = YES;
return self;
}
- (instancetype)noRecursiveDescription
{
self.describeRecursively = NO;
return self;
}
- (instancetype)attachProcessInfoForIdentifier:(pid_t)processIdentifier processFetcher:(FBProcessFetcher *)processFetcher
{
return [self
extraInfo:[NSString stringWithFormat:@"%d_process", processIdentifier]
value:[processFetcher processInfoFor:processIdentifier] ?: @"No Process Info"];
}
- (instancetype)logger:(id<FBControlCoreLogger>)logger
{
self.logger = logger;
return self;
}
- (instancetype)inDomain:(NSString *)domain
{
self.domain = domain;
return self;
}
- (NSError *)build
{
// If there's just a cause, there's no error to build
if (self.cause && !self.describedAs && self.additionalInfo.count == 0) {
return self.cause;
}
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
if (self.describedAs) {
userInfo[NSLocalizedDescriptionKey] = self.describedAs;
}
if (self.cause) {
userInfo[NSUnderlyingErrorKey] = self.underlyingError;
}
[userInfo addEntriesFromDictionary:self.additionalInfo];
NSError *error = [NSError errorWithDomain:self.domain code:0 userInfo:[userInfo copy]];
if (FBControlCoreGlobalConfiguration.debugLoggingEnabled) {
[self.logger.error logFormat:@"New Error Built ==> %@", error];
}
return error;
}
#pragma mark Private
- (NSError *)underlyingError
{
NSError *error = self.cause;
if (!self.describeRecursively) {
return error;
}
NSError *cause = self.cause;
if (!cause) {
return error;
}
NSMutableString *description = [NSMutableString stringWithFormat:@"%@", error.localizedDescription];
while (error.userInfo[NSUnderlyingErrorKey]) {
error = error.userInfo[NSUnderlyingErrorKey];
[description appendFormat:@"\nCaused By: %@", error.localizedDescription];
}
NSMutableDictionary *userInfo = [cause.userInfo mutableCopy];
userInfo[NSLocalizedDescriptionKey] = description;
return [NSError errorWithDomain:cause.domain code:cause.code userInfo:[userInfo copy]];
}
@end
@implementation FBControlCoreError (Constructors)
+ (NSError *)errorForDescription:(NSString *)description
{
return [[self describe:description] build];
}
+ (id)failWithErrorMessage:(NSString *)errorMessage errorOut:(NSError **)errorOut
{
return [[self describe:errorMessage] fail:errorOut];
}
+ (id)failWithError:(NSError *)failureCause errorOut:(NSError **)errorOut
{
return [[self causedBy:failureCause] fail:errorOut];
}
+ (id)failWithError:(NSError *)failureCause description:(NSString *)description errorOut:(NSError **)errorOut
{
return [[[self causedBy:failureCause] describe:description] fail:errorOut];
}
+ (BOOL)failBoolWithErrorMessage:(NSString *)errorMessage errorOut:(NSError **)errorOut
{
return [[self describe:errorMessage] failBool:errorOut];
}
+ (BOOL)failBoolWithError:(NSError *)failureCause errorOut:(NSError **)errorOut
{
return [[self causedBy:failureCause] failBool:errorOut];
}
+ (BOOL)failBoolWithError:(NSError *)failureCause description:(NSString *)description errorOut:(NSError **)errorOut
{
return [[[self causedBy:failureCause] describe:description] failBool:errorOut];
}
@end