TNLCLI/TNLCLIExecutionContext.m (126 lines of code) (raw):
//
// TNLCLIExecutionContext.m
// TNLCLI
//
// Created on 9/11/19.
// Copyright © 2020 Twitter. All rights reserved.
//
#import "TNLCLIError.h"
#import "TNLCLIExecutionContext.h"
#import "TNLCLIPrint.h"
#pragma mark - Static Functions
static NSArray<NSString *> *parseArgs(int argc, const char * argv[])
{
NSMutableArray<NSString *> *args = [[NSMutableArray alloc] init];
for (int c = 0; c < argc; c++) {
[args addObject:@(argv[c])];
}
return [args copy];
}
#define FAIL(err) \
({\
_contextError = (err); \
TNLCLIPrintError(_contextError); \
return; \
})
#define SOFT_FAIL(err) \
({\
NSError *err__ = (err); \
TNLCLIPrintError(err__); \
if (!_contextError) { \
_contextError = err__; \
} \
})
#pragma mark - TNLCLIExecutionContext
@implementation TNLCLIExecutionContext
#pragma mark Init
- (instancetype)initWithArgC:(int)argc argV:(const char **)argv
{
NSArray<NSString *> *args = parseArgs(argc, argv);
return [self initWithArgs:args];
}
- (instancetype)initWithArgs:(NSArray<NSString *> *)args
{
if (self = [super init]) {
[self digestArgs:args];
}
return self;
}
- (void)digestArgs:(NSArray<NSString *> *)args
{
if (args.count == 0) {
FAIL(TNLCLICreateError(TNLCLIErrorEmptyMainFunctionArguments, @"Expected args for main(...) function"));
}
NSString *str;
str = @(getenv("PWD"));
if (!str) {
FAIL(TNLCLICreateError(TNLCLIErrorMissingPWDEnvironmentVariable, @"Missing PWD environment variable"));
} else {
_currentDirectory = [str stringByExpandingTildeInPath];
}
str = args.firstObject;
if (!str.isAbsolutePath) {
str = [_currentDirectory stringByAppendingPathComponent:str];
} else {
str = [str stringByExpandingTildeInPath];
}
_executableName = str.lastPathComponent;
_executableDirectory = [str stringByDeletingLastPathComponent];
if (args.count == 1) {
FAIL(TNLCLICreateError(TNLCLIErrorMissingRequestURLArgument, @"Missing `url` for request (final argument to be passed in)"));
}
if (args.count == 2 && [args[1] isEqualToString:@"--version"]) {
_printVersion = YES;
return;
}
NSMutableArray<NSString *> *headers = [[NSMutableArray alloc] init];
NSMutableArray<NSString *> *configs = [[NSMutableArray alloc] init];
NSMutableArray<NSString *> *globals = [[NSMutableArray alloc] init];
for (NSUInteger i = 1; i < args.count - 1; ) {
NSString *option = args[i++];
if ([option isEqualToString:@"--verbose"]) {
_verbose = YES;
continue;
}
if ([option isEqualToString:@"--version"]) {
_printVersion = YES;
continue;
}
NSString *value = args[i++];
if (i == args.count) {
FAIL(TNLCLICreateError(TNLCLIErrorMissingRequestURLArgument, @"Missing `url` for request (final argument to be passed in)"));
}
#define CASE(arg, ivar) \
if ([option isEqualToString: (arg) ]) { \
ivar = [value copy]; \
continue; \
} \
CASE(@"--request-config-file", _requestConfigurationFilePath);
CASE(@"--request-headers-file", _requestHeadersFilePath);
CASE(@"--request-body-file", _requestBodyFilePath);
CASE(@"--request-method", _requestMethodValueString);
CASE(@"--response-body-file", _responseBodyTargetFilePath);
CASE(@"--response-headers-file", _responseHeadersTargetFilePath);
CASE(@"--dump-cert-chain-directory", _certificateChainDumpDirectory);
if ([option isEqualToString:@"--request-header"]) {
[headers addObject:value];
continue;
}
if ([option isEqualToString:@"--request-config"]) {
[configs addObject:value];
continue;
}
if ([option isEqualToString:@"--global-config"]) {
[globals addObject:value];
continue;
}
if ([option isEqualToString:@"--response-body-mode"]) {
_responseBodyOutputModes = [value componentsSeparatedByString:@","];
continue;
}
if ([option isEqualToString:@"--response-headers-mode"]) {
_responseHeadersOutputModes = [value componentsSeparatedByString:@","];
continue;
}
TNLCLIPrintWarning([NSString stringWithFormat:@"`%@` is an unknown argument. Skipping it and its value `%@`", option, value]);
#undef CASE
}
_requestHeaders = [headers copy];
_requestConfigurations = [configs copy];
_globalConfigurations = [globals copy];
_requestURLString = [args.lastObject copy];
}
@end