/
KTerminalUsageWindowController.m
158 lines (137 loc) · 4.98 KB
/
KTerminalUsageWindowController.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
// Copyright (c) 2010-2011, Rasmus Andersson. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.
#import "common.h"
#import "kconf.h"
#import "KSudo.h"
#import "KTerminalUsageWindowController.h"
@implementation KTerminalUsageWindowController
- (NSString*)_canonicalizePath:(NSString*)path isDirectory:(BOOL)isDir {
path = [path stringByExpandingTildeInPath];
return [[[NSURL fileURLWithPath:path isDirectory:isDir] absoluteURL] path];
}
- (void)awakeFromNib {
static NSString * const possiblePaths[] = {
@"~/bin",
@"/usr/local/bin",
@"/usr/bin",
@"/bin",
nil
};
NSFileManager *fm = [NSFileManager defaultManager];
NSString *possiblePath;
NSUInteger i = 0;
NSString *homeDir = [NSHomeDirectory() stringByAppendingString:@"/"];
NSString *binPath = [kconf_url(@"cli/symlink/url", nil) path];
if (binPath) {
binPath = [binPath stringByDeletingLastPathComponent];
} else {
while ((possiblePath = possiblePaths[i++])) {
possiblePath = [self _canonicalizePath:possiblePath isDirectory:YES];
BOOL isDir;
if ([fm fileExistsAtPath:possiblePath isDirectory:&isDir] && isDir) {
binPath = possiblePath;
break;
}
}
}
if (binPath) {
if (binPath.length == homeDir.length-1 && [homeDir hasPrefix:binPath]) {
// case: binPath="/Users/john", homeDir="/Users/john/"
binPath = @"~";
} else if ([binPath hasPrefix:homeDir]) {
// case: binPath="/users/john/foo/bin", homeDir="/Users/john/"
binPath = [@"~/" stringByAppendingString:
[binPath substringFromIndex:homeDir.length]];
}
[binPathTextField_ setStringValue:binPath];
}
}
- (IBAction)createLink:(id)sender {
DLOG("%@ createLink:%@", self, sender);
NSFileManager *fm = [NSFileManager defaultManager];
NSBundle *bundle = kconf_bundle();
// build dst path
NSString *dstPath = [kconf_support_url(@"kod") path];
kassert([fm fileExistsAtPath:dstPath]);
NSString *binPath = [binPathTextField_ stringValue];
binPath = [self _canonicalizePath:binPath isDirectory:YES];
// check link path
NSError *error = nil;
BOOL isDir;
if (!binPath) {
error = [NSError kodErrorWithFormat:@"Invalid or empty path. Please enter "
"an absolute and valid path."];
} else if (![fm fileExistsAtPath:binPath isDirectory:&isDir]) {
error = [NSError kodErrorWithFormat:@"The directory '%@' does not exist",
binPath];
} else if (!isDir) {
error = [NSError kodErrorWithFormat:@"The file '%@' is not a directory",
binPath];
}
if (error) {
[NSApp presentError:error];
return;
}
// build link path
NSString *linkPath = [binPath stringByAppendingPathComponent:@"kod"];
// remove existing file if found
NSString *existingLinkDst = [fm destinationOfSymbolicLinkAtPath:linkPath
error:nil];
if (existingLinkDst) {
existingLinkDst = [self _canonicalizePath:existingLinkDst isDirectory:NO];
if ([existingLinkDst isEqualToString:linkPath]) {
// already same link
[self close];
return;
} else {
error = [NSError kodErrorWithFormat:@"Another file exists at '%@' -- "
"please remove that file and try again or chose another location",
linkPath];
[NSApp presentError:error];
return;
}
}
// need sudo to write?
if (![fm isWritableFileAtPath:binPath]) {
[binPathTextField_ setEnabled:NO];
[cancelButton_ setEnabled:NO];
[commitButton_ setEnabled:NO];
WLOG("sudo /bin/ln -fs '%@' '%@'", dstPath, linkPath);
[KSudo execute:@"/bin/ln"
arguments:[NSArray arrayWithObjects:@"-fs", dstPath, linkPath, nil]
callback:^(NSError *err, NSData *output){
[binPathTextField_ setEnabled:YES];
[cancelButton_ setEnabled:YES];
[commitButton_ setEnabled:YES];
if (err) {
NSInteger authCancelledOSError = -60006; // subject to endian bug?!
if (![[err domain] isEqualToString:NSOSStatusErrorDomain] ||
[err code] != authCancelledOSError) {
DLOG("failed to execute ln as root: %@", err);
[NSApp presentError:err];
} else {
DLOG("authorization request aborted by user");
}
} else {
kconf_set_url(@"cli/symlink/url", [NSURL fileURLWithPath:linkPath]);
DLOG("sudo ln appear to have succeeded (we currently are unable to test"
" return status, but are working on it)");
[self close];
}
}];
} else {
// create symbolic link
BOOL createLink = [fm createSymbolicLinkAtPath:linkPath
withDestinationPath:dstPath
error:&error];
if (!createLink) {
DLOG("error: %@", error);
[NSApp presentError:error];
} else {
kconf_set_url(@"cli/symlink/url", [NSURL fileURLWithPath:linkPath]);
[self close];
}
}
}
@end