diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..21d4f1b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,8 @@ +##Changelog For AppleSimulatorUtils + + +##### 19-Sept-2017 + +* Add `--list` option to utils, with optional filter +* Sort devices by OS version (descending) then by name (ascending) + diff --git a/README.md b/README.md index 37fa45e..2080517 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,15 @@ brew install --HEAD applesimutils ```shell Usage: applesimutils --simulator --bundle --setPermissions ", , ..." applesimutils --simulator --restartSB + applesimutils --list ["[, OS=]"] [--maxResults ] Options: --simulator The simulator identifier or simulator name & operating system version (e.g. "iPhone 7 Plus, OS = 10.3") --bundle The app bundle identifier --setPermissions Sets the specified permissions and restarts SpringBoard for the changes to take effect --restartSB Restarts SpringBoard + --list Lists available simulators; an optional filter can be provided: simulator name is required, os version is optional + --maxResults Limits the number of results returned from --list --help, -h Prints usage Available permissions: diff --git a/applesimutils/applesimutils.xcodeproj/xcshareddata/xcschemes/applesimutils.xcscheme b/applesimutils/applesimutils.xcodeproj/xcshareddata/xcschemes/applesimutils.xcscheme index 63b81f9..0864209 100644 --- a/applesimutils/applesimutils.xcodeproj/xcshareddata/xcschemes/applesimutils.xcscheme +++ b/applesimutils/applesimutils.xcodeproj/xcshareddata/xcschemes/applesimutils.xcscheme @@ -65,16 +65,20 @@ + argument = "--simulator "iPhone 8 Plus, OS=11.0"" + isEnabled = "NO"> + isEnabled = "NO"> + isEnabled = "NO"> + + + isEnabled = "YES"> diff --git a/applesimutils/applesimutils/main.m b/applesimutils/applesimutils/main.m index d9911ae..8c7de82 100644 --- a/applesimutils/applesimutils/main.m +++ b/applesimutils/applesimutils/main.m @@ -24,12 +24,15 @@ static void printUsage(NSString* prependMessage, LNLogLevel logLevel) LNLog(LNLogLevelStdOut, @"Usage: %@ --simulator --bundle --setPermissions \", , ...\"", utilName); LNLog(LNLogLevelStdOut, @" %@ --simulator --restartSB", utilName); + LNLog(LNLogLevelStdOut, @" %@ --list [\"[, OS=]\"] [--maxResults ]", utilName); LNLog(LNLogLevelStdOut, @""); LNLog(LNLogLevelStdOut, @"Options:"); LNLog(LNLogLevelStdOut, @" --simulator The simulator identifier or simulator name & operating system version (e.g. \"iPhone 7 Plus, OS = 10.3\")"); LNLog(LNLogLevelStdOut, @" --bundle The app bundle identifier"); LNLog(LNLogLevelStdOut, @" --setPermissions Sets the specified permissions and restarts SpringBoard for the changes to take effect"); LNLog(LNLogLevelStdOut, @" --restartSB Restarts SpringBoard"); + LNLog(LNLogLevelStdOut, @" --list Lists available simulators; an optional filter can be provided: simulator name is required, os version is optional"); + LNLog(LNLogLevelStdOut, @" --maxResults Limits the number of results returned from --list"); LNLog(LNLogLevelStdOut, @" --help, -h Prints usage"); LNLog(LNLogLevelStdOut, @""); LNLog(LNLogLevelStdOut, @"Available permissions:"); @@ -119,9 +122,59 @@ static void restartSpringBoard(NSString* simulatorId) [allDevices addObjectsFromArray:runtimeDevices]; }]; - return [allDevices sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"os.name" ascending:YES comparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) { + return [allDevices sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"os.version" ascending:NO comparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) { return [obj1 compare:obj2 options:NSNumericSearch]; - }]]]; + }], [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]]]; +} + +static NSArray* filteredDeviceList(NSArray* simulatorDevices, NSString* simulatorFilterRequest) +{ + if(simulatorDevices == nil) + { + return nil; + } + + if(simulatorFilterRequest == nil) + { + return simulatorDevices; + } + + NSRegularExpression* expr = [NSRegularExpression regularExpressionWithPattern:@"(.*?)(?:,\\s*OS\\s*=\\s*(\\d{1,2}\\.\\d{1,2})\\s*|)$" options:NSRegularExpressionCaseInsensitive error:NULL]; + NSArray * matches = [expr matchesInString:simulatorFilterRequest options:0 range:NSMakeRange(0, simulatorFilterRequest.length)]; + + NSPredicate* filterPredicate = nil; + + if(matches.count > 0 && matches.firstObject.numberOfRanges == 3) + { + NSString* simName = [simulatorFilterRequest substringWithRange:[matches.firstObject rangeAtIndex:1]]; + NSRange osRange = [matches.firstObject rangeAtIndex:2]; + if(osRange.location != NSNotFound) + { + NSString* osVer = [simulatorFilterRequest substringWithRange:osRange]; + filterPredicate = [NSPredicate predicateWithFormat:@"name CONTAINS[cd] %@ && os.version ==[cd] %@", simName, osVer]; + } + else + { + filterPredicate = [NSPredicate predicateWithFormat:@"name CONTAINS[cd] %@", simName]; + } + + NSTextCheckingResult* result = matches.firstObject; + for(NSUInteger i = 0; i < result.numberOfRanges; i++) + { + NSRange range = [result rangeAtIndex:i]; + if(range.location != NSNotFound) + { + // NSLog(@"%@", [simulatorFilterRequest substringWithRange:range]); + } + } + } + + if(filterPredicate != nil) + { + return [simulatorDevices filteredArrayUsingPredicate:filterPredicate]; + } + + return nil; } @@ -251,12 +304,10 @@ int main(int argc, char** argv) { [parser registerOption:@"restartSB" requirement:GBValueNone]; [parser registerOption:@"help" shortcut:'h' requirement:GBValueNone]; [parser registerOption:@"simulator" requirement:GBValueRequired]; + [parser registerOption:@"list" requirement:GBValueOptional]; + [parser registerOption:@"maxResults" requirement:GBValueRequired]; [parser registerOption:@"bundle" requirement:GBValueRequired]; -// [parser registerOption:@"photos" requirement:GBValueRequired]; -// [parser registerOption:@"notifications" requirement:GBValueRequired]; -// [parser registerOption:@"simulator" requirement:GBValueRequired]; - GBSettings *settings = [GBSettings settingsWithName:@"CLI" parent:nil]; [parser registerSettings:settings]; @@ -264,12 +315,52 @@ int main(int argc, char** argv) { if([settings boolForKey:@"help"] || (![settings objectForKey:@"setPermissions"] && - ![settings boolForKey:@"restartSB"])) + ![settings boolForKey:@"restartSB"] && + ![settings objectForKey:@"list"])) { printUsage(nil, LNLogLevelStdOut); return [settings boolForKey:@"help"] ? 0 : -1; } + NSArray* simulatorDevices = simulatorDevicesList(); + + if([settings objectForKey:@"list"] != nil) + { + id value = [settings objectForKey:@"list"]; + NSString* simulatorFilterRequest; + + if([value isKindOfClass:[NSString class]]) + { + simulatorFilterRequest = value; + } + + NSArray* filteredSimulators = filteredDeviceList(simulatorDevices, simulatorFilterRequest); + if(filteredSimulators == nil) + { + printUsage(@"Error: Unable to list simulators", LNLogLevelError); + } + + NSUInteger maxResults = NSUIntegerMax; + if([settings objectForKey:@"maxResults"]) + { + maxResults = [settings unsignedIntegerForKey:@"maxResults"]; + } + + if(maxResults < 1) + { + printUsage(@"Error: Invalid value for --maxResults", LNLogLevelError); + } + + if(maxResults != NSUIntegerMax) + { + filteredSimulators = [filteredSimulators subarrayWithRange:NSMakeRange(0, MIN(filteredSimulators.count, maxResults))]; + } + + LNLog(LNLogLevelStdOut, @"%@", [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:filteredSimulators options:NSJSONWritingPrettyPrinted error:NULL] encoding:NSUTF8StringEncoding]); + + return 0; + } + NSString* simulatorId = [settings objectForKey:@"simulator"]; if(simulatorId.length == 0) { @@ -278,50 +369,15 @@ int main(int argc, char** argv) { return -1; } - NSArray* simulatorDevices = simulatorDevicesList(); - if([[NSUUID alloc] initWithUUIDString:simulatorId] == nil) { NSString* simulatorFilterRequest = simulatorId; - if(simulatorDevices == nil) - { - return -1; - } - - NSRegularExpression* expr = [NSRegularExpression regularExpressionWithPattern:@"(.*?)(?:,\\s*OS\\s*=\\s*(\\d{1,2}\\.\\d{1,2})\\s*|)$" options:NSRegularExpressionCaseInsensitive error:NULL]; - NSArray * matches = [expr matchesInString:simulatorFilterRequest options:0 range:NSMakeRange(0, simulatorFilterRequest.length)]; - - NSPredicate* filterPredicate = nil; - - if(matches.count > 0 && matches.firstObject.numberOfRanges == 3) - { - NSString* simName = [simulatorFilterRequest substringWithRange:[matches.firstObject rangeAtIndex:1]]; - NSRange osRange = [matches.firstObject rangeAtIndex:2]; - if(osRange.location != NSNotFound) - { - NSString* osVer = [simulatorFilterRequest substringWithRange:osRange]; - filterPredicate = [NSPredicate predicateWithFormat:@"name ==[cd] %@ && os.version ==[cd] %@", simName, osVer]; - } - else - { - filterPredicate = [NSPredicate predicateWithFormat:@"name ==[cd] %@", simName]; - } - - NSTextCheckingResult* result = matches.firstObject; - for(NSUInteger i = 0; i < result.numberOfRanges; i++) - { - NSRange range = [result rangeAtIndex:i]; - if(range.location != NSNotFound) - { -// NSLog(@"%@", [simulatorFilterRequest substringWithRange:range]); - } - } - } + NSArray* filteredSimulators = filteredDeviceList(simulatorDevices, simulatorFilterRequest); - if(filterPredicate != nil) + if(filteredSimulators != nil) { - simulatorId = [[simulatorDevices filteredArrayUsingPredicate:filterPredicate] lastObject][@"udid"]; + simulatorId = filteredSimulators.firstObject[@"udid"]; } if(simulatorId.length == 0)