1
+ #import " SSYTroubleZipper.h"
2
+ #import " NSFileManager+TempFile.h"
3
+ #import " SSYShellTasker.h"
4
+ #import " SSYAlert.h"
5
+ #import " SSYUuid.h"
6
+
7
+ NSString * const SSYTroubleZipperErrorDomain = @" SSYTroubleZipperErrorDomain" ;
8
+ NSString * const constKeySSYTroubleZipperURL = @" SSYTroubleZipperURL" ;
9
+
10
+ @interface SSYTroubleZipper ()
11
+
12
+ @property (retain ) NSURLDownload * download ;
13
+ @property (copy ) NSString * destinationPath ;
14
+ @property BOOL downloadDone ;
15
+
16
+ @end
17
+
18
+ @implementation SSYTroubleZipper
19
+
20
+ @synthesize download = m_download ;
21
+ @synthesize destinationPath = m_destinationPath ;
22
+ @synthesize downloadDone = m_downloadDone ;
23
+
24
+ - (void )dealloc {
25
+ [m_download release ] ;
26
+ [m_destinationPath release ] ;
27
+
28
+ [super dealloc ] ;
29
+ }
30
+
31
+ + (void )alertErrorCode : (NSInteger )code
32
+ underlyingError : (NSError *)error {
33
+ NSString * msg = [NSString stringWithFormat:
34
+ @" Could not download, unzip, or run Trouble Zipper from %@ " ,
35
+ [[NSBundle mainBundle ] objectForInfoDictionaryKey: constKeySSYTroubleZipperURL]] ;
36
+ error = [NSError errorWithDomain: SSYTroubleZipperErrorDomain
37
+ code: code
38
+ userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
39
+ msg, NSLocalizedDescriptionKey ,
40
+ @" Try again, maybe later" , NSLocalizedRecoverySuggestionErrorKey ,
41
+ constKeySSYTroubleZipperURL, @" Info.plist key where URL expected" ,
42
+ error, NSUnderlyingErrorKey , // may be nil
43
+ nil ]] ;
44
+ [SSYAlert performSelectorOnMainThread: @selector (alertError: )
45
+ withObject: error
46
+ waitUntilDone: NO ] ;
47
+ }
48
+
49
+ - (void )alertErrorCode : (NSInteger )code
50
+ underlyingError : (NSError *)error {
51
+ [SSYTroubleZipper alertErrorCode: code
52
+ underlyingError: error] ;
53
+ }
54
+
55
+ + (void )alertErrorCode : (NSInteger )code {
56
+ [self alertErrorCode: code
57
+ underlyingError: nil ] ;
58
+ }
59
+
60
+ - (void )alertErrorCode : (NSInteger )code {
61
+ [SSYTroubleZipper alertErrorCode: code] ;
62
+ }
63
+
64
+ - (id )init {
65
+ self = [super init ] ;
66
+ if (self) {
67
+ NSString * urlString = [[NSBundle mainBundle ] objectForInfoDictionaryKey: constKeySSYTroubleZipperURL] ;
68
+ if (urlString) {
69
+ [self setDestinationPath: [[[NSFileManager defaultManager ] temporaryFilePath ] stringByAppendingPathExtension: @" zip" ]] ;
70
+ NSURL * url = [NSURL URLWithString: urlString] ;
71
+ NSURLRequest * request = [NSURLRequest requestWithURL: url] ;
72
+ NSURLDownload * download = [[NSURLDownload alloc ] initWithRequest: request
73
+ delegate: self ] ;
74
+ [self setDownload: download] ;
75
+ [download release ] ;
76
+ [[self download ] setDestination: [self destinationPath ]
77
+ allowOverwrite: YES ] ;
78
+ }
79
+ else {
80
+ [self alertErrorCode: 159425 ] ;
81
+ [self release ] ;
82
+ self = nil ;
83
+ }
84
+ }
85
+
86
+ if (!self) {
87
+ // See http://lists.apple.com/archives/Objc-language/2008/Sep/msg00133.html ...
88
+ [SSYTroubleZipper alertErrorCode: 159426 ] ;
89
+ [super dealloc ] ;
90
+ }
91
+
92
+ return self ;
93
+ }
94
+
95
+ - (void )downloadDidFinish : (NSURLDownload *)download {
96
+ [self setDownloadDone: YES ] ;
97
+ }
98
+
99
+ - (void ) download : (NSURLDownload *)download
100
+ didFailWithError : (NSError *)error {
101
+ [self alertErrorCode: 159427 ] ;
102
+ [self setDownloadDone: YES ] ;
103
+ }
104
+
105
+ + (void )troubleZipper {
106
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc ] init ] ;
107
+
108
+ SSYTroubleZipper* instance = [[SSYTroubleZipper alloc ] init ] ;
109
+
110
+ while (![instance downloadDone ] && [[NSRunLoop currentRunLoop ] runMode: NSDefaultRunLoopMode
111
+ beforeDate: [NSDate distantFuture ]]) {
112
+ }
113
+
114
+ NSError * error = nil ;
115
+ NSString * directory = [[instance destinationPath ] stringByDeletingLastPathComponent ] ;
116
+ // Create a subdirectory as a sibling of the destinationPath,
117
+ // and unzip into this subdirectory, because otherwise we
118
+ // have no way to positively identify which extracted file
119
+ // in the temporary directory is ours.
120
+ NSString * extractionDirectory = [directory stringByAppendingPathComponent: [SSYUuid compactUuid ]] ;
121
+
122
+ BOOL ok = [[NSFileManager defaultManager ] createDirectoryAtPath: extractionDirectory
123
+ withIntermediateDirectories: YES
124
+ attributes: nil
125
+ error: &error] ;
126
+
127
+ if (ok) {
128
+ NSInteger result = [SSYShellTasker doShellTaskCommand: @" /usr/bin/unzip"
129
+ arguments: [NSArray arrayWithObjects: @" -o" , @" -d" , extractionDirectory, [instance destinationPath ], nil ]
130
+ inDirectory: directory
131
+ stdinData: nil
132
+ stdoutData_p: NULL
133
+ stderrData_p: NULL
134
+ timeout: 5.0
135
+ error_p: &error] ;
136
+ if (result == 0 ) {
137
+ NSArray * filenames = [[NSFileManager defaultManager ] contentsOfDirectoryAtPath: extractionDirectory
138
+ error: NULL ] ;
139
+ NSString * appFilename = nil ;
140
+ for (NSString * filename in filenames) {
141
+ if ([[filename pathExtension ] isEqualToString: @" app" ]) {
142
+ appFilename = filename ;
143
+ }
144
+ }
145
+
146
+ if (appFilename) {
147
+ NSString * appleScriptAppPath = [extractionDirectory stringByAppendingPathComponent: appFilename] ;
148
+ BOOL ok = [[NSWorkspace sharedWorkspace ] launchApplication: appleScriptAppPath] ;
149
+ if (!ok) {
150
+ [self alertErrorCode: 159433
151
+ underlyingError: error] ;
152
+ }
153
+ }
154
+ else {
155
+ [self alertErrorCode: 159429 ] ;
156
+ }
157
+ }
158
+ else {
159
+ [self alertErrorCode: 159430
160
+ underlyingError: error] ;
161
+ }
162
+ }
163
+ else {
164
+ [self alertErrorCode: 159431
165
+ underlyingError: error] ;
166
+ }
167
+
168
+ [[NSFileManager defaultManager ] removeItemAtPath: [instance destinationPath ]
169
+ error: NULL ] ;
170
+
171
+ [instance release ] ;
172
+ [pool release ] ;
173
+ }
174
+
175
+ + (void )getAndRun {
176
+ [NSThread detachNewThreadSelector: @selector (troubleZipper )
177
+ toTarget: self
178
+ withObject: nil ] ;
179
+ }
180
+
181
+ @end
0 commit comments