//
// P4DepotItem.m
// Perforce
//
// Created by Adam Czubernat on 29.05.2013.
// Copyright (c) 2013 Perforce Software, Inc. All rights reserved.
//
#import "P4DepotItem.h"
@interface P4DepotItem ()
- (void)loadDepots;
- (void)loadMappings;
- (id)initFile:(NSDictionary *)dictionary parentItem:(P4DepotItem *)parent;
- (id)initDirectory:(NSDictionary *)dictionary parentItem:(P4DepotItem *)parent;
- (id)initDepot:(NSDictionary *)dictionary parentItem:(P4DepotItem *)parent;
@end
@implementation P4DepotItem
#pragma mark - P4Item Override
- (id)init {
if (self = [super init]) {
flags.directory = YES;
name = @"All files";
remotePath = @"//";
localPath = [P4Workspace sharedInstance].root;
[[P4Workspace sharedInstance] addObserver:self];
}
return self;
}
- (NSString *)path {
return remotePath;
}
- (id)defaultAction {
if (flags.directory)
return nil;
return [P4ItemAction
actionForItem:self name:@"Open read only"
selector:@selector(openFromDepot)];
}
- (NSArray *)actions {
P4ItemAction *action;
NSMutableArray *actions = [NSMutableArray array];
BOOL dir = NO;
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:localPath
isDirectory:&dir];
if (localPath.length && !flags.directory) {
action = [P4ItemAction
actionForItem:self name:@"Open"
selector:@selector(openWithCheckout)];
action.disabled = !exists || dir;
[actions addObject:action];
action = [P4ItemAction
actionForItem:self name:@"Open read only"
selector:@selector(open)];
action.disabled = !exists || dir;
[actions addObject:action];
}
if (self.isDirectory && parent) {
NSString *mapping = nil;
SEL selector;
if (self.isIgnored) {
selector = @selector(mapToWorkspace);
mapping = @"Stop ignoring folder";
} else if (self.isMapped) {
selector = @selector(unmapFromWorkspace);
mapping = @"Unmap from workspace";
} else if (self.isTracked) {
selector = @selector(unmapFromWorkspace);
mapping = @"Ignore folder";
} else {
selector = @selector(mapToWorkspace);
mapping = @"Map to workspace";
}
[actions insertObject:[P4ItemAction
actionForItem:self name:mapping
selector:selector] atIndex:0];
}
if (!self.isDirectory){
[actions addObject:[P4ItemAction
actionForItem:self name:@"Open file from depot"
selector:@selector(openFromDepot)]];
}
if (localPath.length) {
action = [P4ItemAction
actionForItem:self name:@"Show in Finder"
selector:@selector(showInFinder)];
action.disabled = !exists || dir != flags.directory;
[actions addObject:action];
}
if (!flags.directory) {
[actions addObject:[P4ItemAction
actionForItem:self name:@"Show Versions"
selector:@selector(showVersions)]];
}
if (parent)
[actions addObject:[P4ItemAction
actionForItem:self name:@"Copy link"
selector:@selector(copyShareLink)]];
return actions;
}
- (void)loadPath:(NSString *)preloadPath {
NSAssert([preloadPath hasSuffix:@"/"], @"Loading path without trailing slash");
NSAssert([preloadPath hasPrefix:@"//"], @"Loading depot path without // prefix");
children = nil;
flags.loading = YES;
NSString *relative = [preloadPath stringByRemovingPrefix:remotePath];
relative = [relative stringByRemovingSuffix:@"/"];
NSString *subPath = remotePath;
NSMutableArray *subPaths = [NSMutableArray arrayWithObject:subPath];
for (NSString *component in [relative pathComponents]) {
subPath = [subPath stringByAppendingFormat:@"%@/", component];
[subPaths addObject:subPath];
}
[[P4Workspace sharedInstance]
listDepotFiles:subPaths
response:^(P4Operation *operation, NSArray *response) {
[operation ignoreErrorsWithCode:P4ErrorMustReferToClient];
if (operation.errors && ([self failWithError:operation.error], 1))
return;
NSMutableDictionary *records = [NSMutableDictionary dictionary];
for (NSDictionary *record in response) {
NSString *subPath = ([record objectForKey:@"depotFile"] ?:
[[record objectForKey:@"dir"] stringByAppendingString:@"/"]);
[records setObject:record forKey:subPath];
}
P4DepotItem *subPathItem = nil;
NSMutableDictionary *subPathParents = [NSMutableDictionary dictionary];
for (NSString *subPath in subPaths) {
NSDictionary *record = [records objectForKey:subPath];
if (!record && subPathItem) {
[self failWithError:
[NSError errorWithFormat:@"Couldn't find directory at %@", subPath]];
children = nil;
return;
}
[records removeObjectForKey:subPath];
P4DepotItem *item;
if (subPathItem) {
item = [[P4DepotItem alloc] initDirectory:record parentItem:subPathItem];
[(NSMutableArray *)subPathItem->children addObject:item];
} else {
item = self;
}
item->children = [NSMutableArray array];
[subPathParents setObject:item forKey:subPath];
subPathItem = item;
}
[records enumerateKeysAndObjectsUsingBlock:
^(NSString *subPath, NSDictionary *record, BOOL *stop) {
NSString *parentPath = [subPath stringByDeletingPath];
P4DepotItem *subPathParent = [subPathParents objectForKey:parentPath];
P4DepotItem *item = nil;
if ([record objectForKey:@"dir"])
item = [[P4DepotItem alloc] initDirectory:record parentItem:subPathParent];
else
item = [[P4DepotItem alloc] initFile:record parentItem:subPathParent];
[(NSMutableArray *)subPathParent->children addObject:item];
}];
for (P4DepotItem *subPathParent in subPathParents.allValues) {
[subPathParent sortChildren];
[subPathParent loadMappings];
}
[self finishLoading];
}];
}
#pragma mark - Private
- (void)loadDepots {
[[P4Workspace sharedInstance]
listDepots:^(P4Operation *operation, NSArray *response) {
if (operation.errors) {
[self failWithError:operation.error];
return;
}
NSMutableArray *depots = [NSMutableArray array];
for (NSDictionary *depotDict in response) {
P4DepotItem *depot = [[P4DepotItem alloc]
initDepot:depotDict
parentItem:self];
[depots addObject:depot];
}
// Sort files alphanumerically
children = depots;
[self sortChildren];
[self loadMappings];
[self finishLoading];
}];
}
- (void)loadMappings {
NSArray *mapping = [[P4Workspace sharedInstance]
mappingForPaths:[children valueForKey:@"remotePath"]];
[children enumerateObjectsUsingBlock:^(P4Item *child, NSUInteger idx, BOOL *stop) {
if (!child->flags.directory)
return;
NSDictionary *childMapping = [mapping objectAtIndex:idx];
NSString *action = [childMapping objectForKey:@"action"];
NSString *clientFile = [childMapping objectForKey:@"clientFile"];
child->flags.tracked = NO;
child->flags.hasMapped = NO;
child->flags.mapped = NO;
child->flags.ignored = NO;
if ([action isEqualToString:@"mapped"])
child->flags.mapped = child->flags.tracked = YES;
else if ([action isEqualToString:@"tracked"])
child->flags.tracked = YES;
else if ([action isEqualToString:@"have"])
child->flags.hasMapped = YES;
else if ([action isEqualToString:@"ignored"])
child->flags.ignored = YES;
child->localPath = clientFile;
}];
}
- (id)initFile:(NSDictionary *)dictionary parentItem:(P4DepotItem *)parentItem {
if (self = [super init]) {
parent = parentItem;
metadata = dictionary;
remotePath = [metadata objectForKey:@"depotFile"];
// Make path by appending name to parent
name = remotePath.lastPathComponent;
localPath = ([metadata objectForKey:@"clientFile"] ?:
[parentItem.localPath stringByAppendingPath:name]);
// Set metadata
status = [metadata objectForKey:@"action"];
NSString *user = [metadata objectForKey:@"otherOpen0"];
NSDictionary *info = [[P4Workspace sharedInstance] userInfo:user];
statusOwner = [info objectForKey:@"Email"] ?: user;
flags.tracked = [metadata objectForKey:@"isMapped"] != nil;
[self refreshTags];
}
return self;
}
- (id)initDirectory:(NSDictionary *)dictionary parentItem:(P4DepotItem *)parentItem {
if (self = [super init]) {
parent = parentItem;
metadata = dictionary;
flags.directory = YES;
remotePath = [metadata objectForKey:@"dir"];
remotePath = [remotePath stringByAppendingString:@"/"];
// Make path by appending name to parent
name = remotePath.lastPathComponent;
localPath = [parentItem.localPath stringByAppendingPath:name];
// Check if tracked
BOOL directory;
flags.tracked = [[NSFileManager defaultManager]
fileExistsAtPath:localPath isDirectory:&directory] && directory;
}
return self;
}
- (id)initDepot:(NSDictionary *)dictionary parentItem:(P4DepotItem *)parentItem {
if (self = [super init]) {
parent = parentItem;
metadata = dictionary;
flags.directory = YES;
// Make path by appending name to parent
name = [metadata objectForKey:@"name"];
localPath = [parentItem.localPath stringByAppendingPath:name];
remotePath = [parentItem.remotePath stringByAppendingFormat:@"%@/", name];
}
return self;
}
@end