forked from gnachman/iTerm2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathiTermMigrationHelper.m
212 lines (186 loc) · 8.28 KB
/
iTermMigrationHelper.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
//
// iTermMigrationHelper.m
// iTerm2SharedARC
//
// Created by George Nachman on 6/1/18.
//
#import "iTermMigrationHelper.h"
#import "DebugLogging.h"
#import "ITAddressBookMgr.h"
#import "iTermDisclosableView.h"
#import "iTermProfilePreferences.h"
#import "NSFileManager+iTerm.h"
@implementation iTermMigrationHelper
+ (BOOL)removeLegacyAppSupportFolderIfPossible {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *legacy = [fileManager legacyApplicationSupportDirectory];
if (![fileManager itemIsDirectory:legacy]) {
return NO;
}
BOOL foundVersionTxt = NO;
for (NSString *file in [fileManager enumeratorAtPath:legacy]) {
if ([file isEqualToString:@"version.txt"]) {
foundVersionTxt = YES;
} else {
return NO;
}
}
if (foundVersionTxt) {
NSError *error = nil;
[fileManager removeItemAtPath:[legacy stringByAppendingPathComponent:@"version.txt"] error:&error];
if (error) {
return NO;
}
}
NSError *error = nil;
[fileManager removeItemAtPath:legacy error:&error];
return error == nil;
}
+ (void)migrateApplicationSupportDirectoryIfNeeded {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *modern = [fileManager applicationSupportDirectory];
NSString *legacy = [fileManager legacyApplicationSupportDirectory];
if ([fileManager itemIsSymlink:legacy]) {
// Looks migrated, or crazy and impossible to reason about.
return;
}
if ([self removeLegacyAppSupportFolderIfPossible]) {
return;
}
if ([fileManager itemIsDirectory:modern] && [fileManager itemIsDirectory:legacy]) {
// This is the normal code path for migrating users.
const BOOL legacyEmpty = [fileManager directoryEmpty:legacy];
if (legacyEmpty) {
[fileManager removeItemAtPath:legacy error:nil];
[fileManager createSymbolicLinkAtPath:legacy withDestinationPath:modern error:nil];
return;
}
const BOOL modernEmpty = [fileManager directoryEmpty:modern];
if (modernEmpty) {
[fileManager removeItemAtPath:modern error:nil];
[fileManager moveItemAtPath:legacy toPath:modern error:nil];
[fileManager createSymbolicLinkAtPath:legacy withDestinationPath:modern error:nil];
return;
}
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = @"Manual Update Needed";
alert.informativeText = @"iTerm2's Application Support directory has changed.\n\n"
@"Previously, both these directories were supported:\n~/Library/Application Support/iTerm\n~/Library/Application Support/iTerm2.\n\n"
@"Now, only the iTerm2 version is supported. But you have files in both so please move everything from iTerm to iTerm2.";
NSMutableArray<NSString *> *files = [NSMutableArray array];
int over = 0;
for (NSString *file in [fileManager enumeratorAtPath:legacy]) {
if (files.count > 5) {
over++;
} else {
[files addObject:file];
}
}
[files sortUsingSelector:@selector(compare:)];
NSString *message;
if (over == 0) {
message = [files componentsJoinedByString:@"\n"];
} else {
message = [NSString stringWithFormat:@"%@\n…and %@ more", [files componentsJoinedByString:@"\n"], @(over)];
}
iTermDisclosableView *accessory = [[iTermDisclosableView alloc] initWithFrame:NSZeroRect
prompt:@"Directory Listing"
message:message];
accessory.frame = NSMakeRect(0, 0, accessory.intrinsicContentSize.width, accessory.intrinsicContentSize.height);
accessory.textView.selectable = YES;
accessory.requestLayout = ^{
[alert layout];
};
alert.accessoryView = accessory;
[alert addButtonWithTitle:@"Open in Finder"];
[alert addButtonWithTitle:@"I Fixed It"];
[alert addButtonWithTitle:@"Not Now"];
switch ([alert runModal]) {
case NSAlertFirstButtonReturn:
[[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs:@[ [NSURL fileURLWithPath:legacy],
[NSURL fileURLWithPath:modern] ]];
[self migrateApplicationSupportDirectoryIfNeeded];
break;
case NSAlertThirdButtonReturn:
return;
default:
[self migrateApplicationSupportDirectoryIfNeeded];
break;
}
}
}
+ (void)copyProfileToBookmark:(NSMutableDictionary *)dict
{
NSString* plistFile = [[NSBundle bundleForClass:[self class]] pathForResource:@"MigrationMap"
ofType:@"plist"];
NSDictionary* fileDict = [NSDictionary dictionaryWithContentsOfFile: plistFile];
NSUserDefaults* prefs = [NSUserDefaults standardUserDefaults];
NSDictionary* keybindingProfiles = [prefs objectForKey: @"KeyBindings"];
NSDictionary* displayProfiles = [prefs objectForKey: @"Displays"];
NSDictionary* terminalProfiles = [prefs objectForKey: @"Terminals"];
NSArray* xforms = [fileDict objectForKey:@"Migration Map"];
for (int i = 0; i < [xforms count]; ++i) {
NSDictionary* xform = [xforms objectAtIndex:i];
NSString* destination = [xform objectForKey:@"Destination"];
if ([dict objectForKey:destination]) {
continue;
}
NSString* prefix = [xform objectForKey:@"Prefix"];
NSString* suffix = [xform objectForKey:@"Suffix"];
id defaultValue = [xform objectForKey:@"Default"];
NSDictionary* parent = nil;
if ([prefix isEqualToString:@"Terminal"]) {
parent = [terminalProfiles objectForKey:[dict objectForKey:KEY_TERMINAL_PROFILE]];
} else if ([prefix isEqualToString:@"Displays"]) {
parent = [displayProfiles objectForKey:[dict objectForKey:KEY_DISPLAY_PROFILE]];
} else if ([prefix isEqualToString:@"KeyBindings"]) {
parent = [keybindingProfiles objectForKey:[dict objectForKey:KEY_KEYBOARD_PROFILE]];
} else {
ITAssertWithMessage(0, @"Bad prefix");
}
id value = nil;
if (parent) {
value = [parent objectForKey:suffix];
}
if (!value) {
value = defaultValue;
}
[dict setObject:value forKey:destination];
}
}
+ (void)recursiveMigrateBookmarks:(NSDictionary*)node path:(NSArray*)path {
NSDictionary* data = [node objectForKey:@"Data"];
if ([data objectForKey:KEY_COMMAND_LINE]) {
// Not just a folder if it has a command.
NSMutableDictionary* temp = [NSMutableDictionary dictionaryWithDictionary:data];
[self copyProfileToBookmark:temp];
[temp setObject:[ProfileModel freshGuid] forKey:KEY_GUID];
[temp setObject:path forKey:KEY_TAGS];
[temp setObject:kProfilePreferenceCommandTypeCustomValue forKey:KEY_CUSTOM_COMMAND];
NSString* dir = [data objectForKey:KEY_WORKING_DIRECTORY];
if (dir && [dir length] > 0) {
[temp setObject:kProfilePreferenceInitialDirectoryCustomValue
forKey:KEY_CUSTOM_DIRECTORY];
} else if (dir && [dir length] == 0) {
[temp setObject:kProfilePreferenceInitialDirectoryRecycleValue
forKey:KEY_CUSTOM_DIRECTORY];
} else {
[temp setObject:kProfilePreferenceInitialDirectoryHomeValue
forKey:KEY_CUSTOM_DIRECTORY];
}
[[ProfileModel sharedInstance] addBookmark:temp];
}
NSArray* entries = [node objectForKey:@"Entries"];
for (int i = 0; i < [entries count]; ++i) {
NSMutableArray* childPath = [NSMutableArray arrayWithArray:path];
NSDictionary* dataDict = [node objectForKey:@"Data"];
if (dataDict) {
NSString* name = [dataDict objectForKey:@"Name"];
if (name) {
[childPath addObject:name];
}
}
[self recursiveMigrateBookmarks:[entries objectAtIndex:i] path:childPath];
}
}
@end