frank_afc_proxy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ # Xcode
2
+ .DS_Store
3
+ build/
4
+ *.pbxuser
5
+ !default.pbxuser
6
+ *.mode1v3
7
+ !default.mode1v3
8
+ *.mode2v3
9
+ !default.mode2v3
10
+ *.perspectivev3
11
+ !default.perspectivev3
12
+ *.xcworkspace
13
+ !default.xcworkspace
14
+ xcuserdata
15
+ profile
16
+ *.moved-aside
17
+ DerivedData
18
+ .idea/
@@ -0,0 +1,260 @@
1
+ // !$*UTF8*$!
2
+ {
3
+ archiveVersion = 1;
4
+ classes = {
5
+ };
6
+ objectVersion = 46;
7
+ objects = {
8
+
9
+ /* Begin PBXBuildFile section */
10
+ 524888DF177B0C9B0032EEA1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 524888DE177B0C9B0032EEA1 /* Foundation.framework */; };
11
+ 524888E4177B0C9B0032EEA1 /* FrankAfcProxy.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 524888E3177B0C9B0032EEA1 /* FrankAfcProxy.h */; };
12
+ 524888E6177B0C9B0032EEA1 /* FrankAfcProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 524888E5177B0C9B0032EEA1 /* FrankAfcProxy.m */; };
13
+ 524888F0177B0D930032EEA1 /* FileChangeObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 524888ED177B0D930032EEA1 /* FileChangeObserver.m */; };
14
+ 524888F1177B0D930032EEA1 /* FrankAfcProxyLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 524888EF177B0D930032EEA1 /* FrankAfcProxyLoader.m */; };
15
+ /* End PBXBuildFile section */
16
+
17
+ /* Begin PBXCopyFilesBuildPhase section */
18
+ 524888D9177B0C9B0032EEA1 /* CopyFiles */ = {
19
+ isa = PBXCopyFilesBuildPhase;
20
+ buildActionMask = 2147483647;
21
+ dstPath = "include/${PRODUCT_NAME}";
22
+ dstSubfolderSpec = 16;
23
+ files = (
24
+ 524888E4177B0C9B0032EEA1 /* FrankAfcProxy.h in CopyFiles */,
25
+ );
26
+ runOnlyForDeploymentPostprocessing = 0;
27
+ };
28
+ /* End PBXCopyFilesBuildPhase section */
29
+
30
+ /* Begin PBXFileReference section */
31
+ 524888DB177B0C9B0032EEA1 /* libFrankAfcProxy.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFrankAfcProxy.a; sourceTree = BUILT_PRODUCTS_DIR; };
32
+ 524888DE177B0C9B0032EEA1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
33
+ 524888E2177B0C9B0032EEA1 /* FrankAfcProxy-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FrankAfcProxy-Prefix.pch"; sourceTree = "<group>"; };
34
+ 524888E3177B0C9B0032EEA1 /* FrankAfcProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FrankAfcProxy.h; sourceTree = "<group>"; };
35
+ 524888E5177B0C9B0032EEA1 /* FrankAfcProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FrankAfcProxy.m; sourceTree = "<group>"; };
36
+ 524888EC177B0D930032EEA1 /* FileChangeObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileChangeObserver.h; sourceTree = "<group>"; };
37
+ 524888ED177B0D930032EEA1 /* FileChangeObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FileChangeObserver.m; sourceTree = "<group>"; };
38
+ 524888EE177B0D930032EEA1 /* FrankAfcProxyLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FrankAfcProxyLoader.h; sourceTree = "<group>"; };
39
+ 524888EF177B0D930032EEA1 /* FrankAfcProxyLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FrankAfcProxyLoader.m; sourceTree = "<group>"; };
40
+ /* End PBXFileReference section */
41
+
42
+ /* Begin PBXFrameworksBuildPhase section */
43
+ 524888D8177B0C9B0032EEA1 /* Frameworks */ = {
44
+ isa = PBXFrameworksBuildPhase;
45
+ buildActionMask = 2147483647;
46
+ files = (
47
+ 524888DF177B0C9B0032EEA1 /* Foundation.framework in Frameworks */,
48
+ );
49
+ runOnlyForDeploymentPostprocessing = 0;
50
+ };
51
+ /* End PBXFrameworksBuildPhase section */
52
+
53
+ /* Begin PBXGroup section */
54
+ 524888D2177B0C9B0032EEA1 = {
55
+ isa = PBXGroup;
56
+ children = (
57
+ 524888E0177B0C9B0032EEA1 /* FrankAfcProxy */,
58
+ 524888DD177B0C9B0032EEA1 /* Frameworks */,
59
+ 524888DC177B0C9B0032EEA1 /* Products */,
60
+ );
61
+ sourceTree = "<group>";
62
+ };
63
+ 524888DC177B0C9B0032EEA1 /* Products */ = {
64
+ isa = PBXGroup;
65
+ children = (
66
+ 524888DB177B0C9B0032EEA1 /* libFrankAfcProxy.a */,
67
+ );
68
+ name = Products;
69
+ sourceTree = "<group>";
70
+ };
71
+ 524888DD177B0C9B0032EEA1 /* Frameworks */ = {
72
+ isa = PBXGroup;
73
+ children = (
74
+ 524888DE177B0C9B0032EEA1 /* Foundation.framework */,
75
+ );
76
+ name = Frameworks;
77
+ sourceTree = "<group>";
78
+ };
79
+ 524888E0177B0C9B0032EEA1 /* FrankAfcProxy */ = {
80
+ isa = PBXGroup;
81
+ children = (
82
+ 524888EC177B0D930032EEA1 /* FileChangeObserver.h */,
83
+ 524888ED177B0D930032EEA1 /* FileChangeObserver.m */,
84
+ 524888EE177B0D930032EEA1 /* FrankAfcProxyLoader.h */,
85
+ 524888EF177B0D930032EEA1 /* FrankAfcProxyLoader.m */,
86
+ 524888E3177B0C9B0032EEA1 /* FrankAfcProxy.h */,
87
+ 524888E5177B0C9B0032EEA1 /* FrankAfcProxy.m */,
88
+ 524888E1177B0C9B0032EEA1 /* Supporting Files */,
89
+ );
90
+ path = FrankAfcProxy;
91
+ sourceTree = "<group>";
92
+ };
93
+ 524888E1177B0C9B0032EEA1 /* Supporting Files */ = {
94
+ isa = PBXGroup;
95
+ children = (
96
+ 524888E2177B0C9B0032EEA1 /* FrankAfcProxy-Prefix.pch */,
97
+ );
98
+ name = "Supporting Files";
99
+ sourceTree = "<group>";
100
+ };
101
+ /* End PBXGroup section */
102
+
103
+ /* Begin PBXNativeTarget section */
104
+ 524888DA177B0C9B0032EEA1 /* FrankAfcProxy */ = {
105
+ isa = PBXNativeTarget;
106
+ buildConfigurationList = 524888E9177B0C9B0032EEA1 /* Build configuration list for PBXNativeTarget "FrankAfcProxy" */;
107
+ buildPhases = (
108
+ 524888D7177B0C9B0032EEA1 /* Sources */,
109
+ 524888D8177B0C9B0032EEA1 /* Frameworks */,
110
+ 524888D9177B0C9B0032EEA1 /* CopyFiles */,
111
+ );
112
+ buildRules = (
113
+ );
114
+ dependencies = (
115
+ );
116
+ name = FrankAfcProxy;
117
+ productName = FrankAfcProxy;
118
+ productReference = 524888DB177B0C9B0032EEA1 /* libFrankAfcProxy.a */;
119
+ productType = "com.apple.product-type.library.static";
120
+ };
121
+ /* End PBXNativeTarget section */
122
+
123
+ /* Begin PBXProject section */
124
+ 524888D3177B0C9B0032EEA1 /* Project object */ = {
125
+ isa = PBXProject;
126
+ attributes = {
127
+ LastUpgradeCheck = 0460;
128
+ ORGANIZATIONNAME = suzumura_ss;
129
+ };
130
+ buildConfigurationList = 524888D6177B0C9B0032EEA1 /* Build configuration list for PBXProject "FrankAfcProxy" */;
131
+ compatibilityVersion = "Xcode 3.2";
132
+ developmentRegion = English;
133
+ hasScannedForEncodings = 0;
134
+ knownRegions = (
135
+ en,
136
+ );
137
+ mainGroup = 524888D2177B0C9B0032EEA1;
138
+ productRefGroup = 524888DC177B0C9B0032EEA1 /* Products */;
139
+ projectDirPath = "";
140
+ projectRoot = "";
141
+ targets = (
142
+ 524888DA177B0C9B0032EEA1 /* FrankAfcProxy */,
143
+ );
144
+ };
145
+ /* End PBXProject section */
146
+
147
+ /* Begin PBXSourcesBuildPhase section */
148
+ 524888D7177B0C9B0032EEA1 /* Sources */ = {
149
+ isa = PBXSourcesBuildPhase;
150
+ buildActionMask = 2147483647;
151
+ files = (
152
+ 524888E6177B0C9B0032EEA1 /* FrankAfcProxy.m in Sources */,
153
+ 524888F0177B0D930032EEA1 /* FileChangeObserver.m in Sources */,
154
+ 524888F1177B0D930032EEA1 /* FrankAfcProxyLoader.m in Sources */,
155
+ );
156
+ runOnlyForDeploymentPostprocessing = 0;
157
+ };
158
+ /* End PBXSourcesBuildPhase section */
159
+
160
+ /* Begin XCBuildConfiguration section */
161
+ 524888E7177B0C9B0032EEA1 /* Debug */ = {
162
+ isa = XCBuildConfiguration;
163
+ buildSettings = {
164
+ ALWAYS_SEARCH_USER_PATHS = NO;
165
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
166
+ CLANG_CXX_LIBRARY = "libc++";
167
+ CLANG_ENABLE_OBJC_ARC = YES;
168
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
169
+ CLANG_WARN_EMPTY_BODY = YES;
170
+ CLANG_WARN_ENUM_CONVERSION = YES;
171
+ CLANG_WARN_INT_CONVERSION = YES;
172
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
173
+ COPY_PHASE_STRIP = NO;
174
+ GCC_C_LANGUAGE_STANDARD = gnu99;
175
+ GCC_DYNAMIC_NO_PIC = NO;
176
+ GCC_OPTIMIZATION_LEVEL = 0;
177
+ GCC_PREPROCESSOR_DEFINITIONS = (
178
+ "DEBUG=1",
179
+ "$(inherited)",
180
+ );
181
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
182
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
183
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
184
+ GCC_WARN_UNUSED_VARIABLE = YES;
185
+ IPHONEOS_DEPLOYMENT_TARGET = 5.0;
186
+ ONLY_ACTIVE_ARCH = YES;
187
+ SDKROOT = iphoneos;
188
+ };
189
+ name = Debug;
190
+ };
191
+ 524888E8177B0C9B0032EEA1 /* Release */ = {
192
+ isa = XCBuildConfiguration;
193
+ buildSettings = {
194
+ ALWAYS_SEARCH_USER_PATHS = NO;
195
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
196
+ CLANG_CXX_LIBRARY = "libc++";
197
+ CLANG_ENABLE_OBJC_ARC = YES;
198
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
199
+ CLANG_WARN_EMPTY_BODY = YES;
200
+ CLANG_WARN_ENUM_CONVERSION = YES;
201
+ CLANG_WARN_INT_CONVERSION = YES;
202
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
203
+ COPY_PHASE_STRIP = YES;
204
+ GCC_C_LANGUAGE_STANDARD = gnu99;
205
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
206
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
207
+ GCC_WARN_UNUSED_VARIABLE = YES;
208
+ IPHONEOS_DEPLOYMENT_TARGET = 5.0;
209
+ SDKROOT = iphoneos;
210
+ VALIDATE_PRODUCT = YES;
211
+ };
212
+ name = Release;
213
+ };
214
+ 524888EA177B0C9B0032EEA1 /* Debug */ = {
215
+ isa = XCBuildConfiguration;
216
+ buildSettings = {
217
+ DSTROOT = /tmp/FrankAfcProxy.dst;
218
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
219
+ GCC_PREFIX_HEADER = "FrankAfcProxy/FrankAfcProxy-Prefix.pch";
220
+ PRODUCT_NAME = "$(TARGET_NAME)";
221
+ SKIP_INSTALL = YES;
222
+ };
223
+ name = Debug;
224
+ };
225
+ 524888EB177B0C9B0032EEA1 /* Release */ = {
226
+ isa = XCBuildConfiguration;
227
+ buildSettings = {
228
+ DSTROOT = /tmp/FrankAfcProxy.dst;
229
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
230
+ GCC_PREFIX_HEADER = "FrankAfcProxy/FrankAfcProxy-Prefix.pch";
231
+ PRODUCT_NAME = "$(TARGET_NAME)";
232
+ SKIP_INSTALL = YES;
233
+ };
234
+ name = Release;
235
+ };
236
+ /* End XCBuildConfiguration section */
237
+
238
+ /* Begin XCConfigurationList section */
239
+ 524888D6177B0C9B0032EEA1 /* Build configuration list for PBXProject "FrankAfcProxy" */ = {
240
+ isa = XCConfigurationList;
241
+ buildConfigurations = (
242
+ 524888E7177B0C9B0032EEA1 /* Debug */,
243
+ 524888E8177B0C9B0032EEA1 /* Release */,
244
+ );
245
+ defaultConfigurationIsVisible = 0;
246
+ defaultConfigurationName = Release;
247
+ };
248
+ 524888E9177B0C9B0032EEA1 /* Build configuration list for PBXNativeTarget "FrankAfcProxy" */ = {
249
+ isa = XCConfigurationList;
250
+ buildConfigurations = (
251
+ 524888EA177B0C9B0032EEA1 /* Debug */,
252
+ 524888EB177B0C9B0032EEA1 /* Release */,
253
+ );
254
+ defaultConfigurationIsVisible = 0;
255
+ defaultConfigurationName = Release;
256
+ };
257
+ /* End XCConfigurationList section */
258
+ };
259
+ rootObject = 524888D3177B0C9B0032EEA1 /* Project object */;
260
+ }
@@ -0,0 +1,52 @@
1
+ //
2
+ // FileChangeObserver.h
3
+ //
4
+ // Created by Toshiyuki Suzumura on 2013/06/11.
5
+ // Copyright (c) 2013 Toshiyuki Suzumura All rights reserved.
6
+ //
7
+
8
+ #import <Foundation/Foundation.h>
9
+ #include <sys/types.h>
10
+ #include <sys/event.h>
11
+ #include <sys/time.h>
12
+
13
+ typedef enum {
14
+ kFileChangeType_Delete = NOTE_DELETE,
15
+ kFileChangeType_Write = NOTE_WRITE,
16
+ kFileChangeType_DirectoryContentsChanged = kFileChangeType_Write
17
+ //#define NOTE_WRITE 0x00000002 /* data contents changed */
18
+ //#define NOTE_EXTEND 0x00000004 /* size increased */
19
+ //#define NOTE_ATTRIB 0x00000008 /* attributes changed */
20
+ //#define NOTE_LINK 0x00000010 /* link count changed */
21
+ //#define NOTE_RENAME 0x00000020 /* vnode was renamed */
22
+ //#define NOTE_REVOKE 0x00000040 /* vnode access was revoked */
23
+ //#define NOTE_NONE 0x00000080 /* No specific vnode event: to test for EVFILT_READ activation*/
24
+ } FileChangeNotificationType;
25
+
26
+ @class FileChangeObserver;
27
+
28
+
29
+ @protocol FileChangeObserverDelegate<NSObject>
30
+
31
+ @required
32
+ - (void)fileChanged:(FileChangeObserver*)observer typeMask:(FileChangeNotificationType)type;
33
+
34
+ @end
35
+
36
+
37
+ @interface FileChangeObserver : NSObject
38
+
39
+ @property (nonatomic, copy) NSURL * url;
40
+ @property (nonatomic, weak) id<FileChangeObserverDelegate> delegate;
41
+
42
+ + (instancetype)observerForURL:(NSURL*)url types:(FileChangeNotificationType)types delegate:(id<FileChangeObserverDelegate>)delegate;
43
+ - (void)invalidate;
44
+
45
+ @end
46
+
47
+
48
+ @interface NSString (FileChangeObserver)
49
+
50
+ + (NSString*)stringWithKEventFFlags:(FileChangeNotificationType)flags;
51
+
52
+ @end
@@ -0,0 +1,160 @@
1
+ //
2
+ // FileChangeObserver.m
3
+ //
4
+ // Created by Toshiyuki Suzumura on 2013/06/11.
5
+ // Copyright (c) 2013 Toshiyuki Suzumura All rights reserved.
6
+ //
7
+
8
+ #import "FileChangeObserver.h"
9
+ #include <sys/stat.h>
10
+
11
+ #undef Assert
12
+ #define Assert(COND) { if (!(COND)) { raise( SIGINT ) ; } }
13
+
14
+
15
+ @interface FileChangeObserver ()
16
+
17
+ @property (nonatomic, readonly) int kqueue;
18
+ @property (nonatomic) FileChangeNotificationType typeMask;
19
+
20
+ @end
21
+
22
+
23
+
24
+ @implementation FileChangeObserver
25
+ @synthesize kqueue = _kqueue ;
26
+
27
+ + (instancetype)observerForURL:(NSURL*)url types:(FileChangeNotificationType)types delegate:(id<FileChangeObserverDelegate>)delegate
28
+ {
29
+ if (!url) { return nil; }
30
+
31
+ FileChangeObserver * result = [[[self class] alloc] init];
32
+ result.url = url;
33
+ result.delegate = delegate;
34
+ result.typeMask = types;
35
+
36
+ [result startObserving];
37
+ return result;
38
+ }
39
+
40
+ -(void)dealloc
41
+ {
42
+ [self stopObserving];
43
+ }
44
+
45
+
46
+ //
47
+ // kqueue_main
48
+ //
49
+ static void (^kqueue_main)(FileChangeObserver *) = ^(__unsafe_unretained FileChangeObserver* self)
50
+ {
51
+ while (true) {
52
+ int fd = open([[self.url path] fileSystemRepresentation], O_EVTONLY);
53
+ if (fd<0) {
54
+ usleep(100);
55
+ continue;
56
+ }
57
+
58
+ int q = self.kqueue;
59
+ {
60
+ struct kevent event = {
61
+ .ident = fd,
62
+ .filter = EVFILT_VNODE,
63
+ .flags = EV_ADD | EV_CLEAR,
64
+ .fflags = self.typeMask,
65
+ };
66
+ int error = kevent(q, &event, 1, NULL, 0, NULL);
67
+ Assert(error == 0);
68
+ }
69
+
70
+ struct kevent event = {0};
71
+ while (true) {
72
+ int nEvents = kevent(q, NULL, 0, &event, 1, NULL);
73
+ if (nEvents!=1) {
74
+ NSLog(@"kevent() failed - %s", strerror(errno));
75
+ break;
76
+ }
77
+ __block FileChangeNotificationType e = event.fflags;
78
+ dispatch_async(dispatch_get_main_queue(), ^{
79
+ [self.delegate fileChanged:self typeMask:e];
80
+ });
81
+ if (e & NOTE_DELETE) {
82
+ NSLog(@"DELETE detected.");
83
+ break;
84
+ }
85
+ }
86
+ close(fd);
87
+ }
88
+ };
89
+
90
+
91
+ -(void)stopObserving
92
+ {
93
+ @synchronized(self)
94
+ {
95
+ close(self.kqueue);
96
+ }
97
+ }
98
+
99
+ -(void)invalidate
100
+ {
101
+ [self stopObserving];
102
+ }
103
+
104
+ -(void)startObserving
105
+ {
106
+ @synchronized(self)
107
+ {
108
+ static dispatch_queue_t __q ;
109
+ static dispatch_once_t onceToken;
110
+ dispatch_once(&onceToken, ^{
111
+ __q = dispatch_queue_create("file observer queue", DISPATCH_QUEUE_CONCURRENT);
112
+ });
113
+
114
+ // this is __unsafe_unretained to avoid retaining 'self'.
115
+ // using __weak isn't a strong enough to prevent ARC from retaining 'self'.
116
+ // This allows the observer to be torn down simply be releasing it,
117
+ // instead of requiring the client to invoke -invalidate.
118
+ __unsafe_unretained id unsafe_self = self ;
119
+ dispatch_async( __q, ^{
120
+ kqueue_main(unsafe_self);
121
+ });
122
+ }
123
+ }
124
+
125
+ -(int)kqueue
126
+ {
127
+ if (!_kqueue) { _kqueue = kqueue(); }
128
+ return _kqueue;
129
+ }
130
+
131
+ @end
132
+
133
+
134
+ @implementation NSString (FileChangeObserver)
135
+
136
+ + (NSString*)stringWithKEventFFlags:(FileChangeNotificationType)flags
137
+ {
138
+ NSMutableArray * array = [NSMutableArray array];
139
+ static const struct {
140
+ const char* name;
141
+ } bitNames[] = {
142
+ { "NOTE_DELETE" },
143
+ { "NOTE_WRITE" },
144
+ { "NOTE_EXTEND" },
145
+ { "NOTE_ATTRIB" },
146
+ { "NOTE_LINK" },
147
+ { "NOTE_RENAME" },
148
+ { "NOTE_REVOKE" },
149
+ { "NOTE_NONE" }
150
+ };
151
+
152
+ for(int index=0, count=sizeof(bitNames)/sizeof(bitNames[0]); index<count; ++index) {
153
+ if ((flags&(1<<index))!=0) {
154
+ [array addObject:[NSString stringWithCString:bitNames[index].name encoding:NSUTF8StringEncoding]];
155
+ }
156
+ }
157
+ return [array componentsJoinedByString:@" "];
158
+ }
159
+
160
+ @end
@@ -0,0 +1,7 @@
1
+ //
2
+ // Prefix header for all source files of the 'FrankAfcProxy' target in the 'FrankAfcProxy' project
3
+ //
4
+
5
+ #ifdef __OBJC__
6
+ #import <Foundation/Foundation.h>
7
+ #endif
@@ -0,0 +1,14 @@
1
+ //
2
+ // FrankAfcProxy.h
3
+ //
4
+ // Created by Toshiyuki Suzumura on 2013/06/11.
5
+ // Copyright (c) 2013 Toshiyuki Suzumura All rights reserved.
6
+ //
7
+
8
+ #import <Foundation/Foundation.h>
9
+
10
+ @interface FrankAfcProxy : NSObject
11
+
12
+ + (void)run;
13
+
14
+ @end
@@ -0,0 +1,137 @@
1
+ //
2
+ // FrankAfcProxy.m
3
+ //
4
+ // Created by Toshiyuki Suzumura on 2013/06/11.
5
+ // Copyright (c) 2013 Toshiyuki Suzumura All rights reserved.
6
+ //
7
+
8
+ #import "FrankAfcProxy.h"
9
+ #import "FileChangeObserver.h"
10
+
11
+ #ifndef FRANKAFCPROXY_PRODUCT_VERSION
12
+ #define FRANKAFCPROXY_PRODUCT_VERSION UNKNOWN
13
+ #endif
14
+
15
+ #define xstr(s) str(s)
16
+ #define str(s) #s
17
+ #define VERSIONED_NAME "FrankAfcProxy iOS Server " xstr(FRANKAFCPROXY_PRODUCT_VERSION)
18
+ const unsigned char frankAfcProxy_version[] = "@(#)" VERSIONED_NAME "\n";
19
+
20
+ @interface FrankAfcProxy () <FileChangeObserverDelegate>
21
+ {
22
+ NSOperationQueue* _queueHTTPRequest;
23
+ FileChangeObserver* _header_observer;
24
+ NSString* _in_header;
25
+ NSString* _in_body;
26
+ NSString* _out_header;
27
+ NSString* _out_body;
28
+ }
29
+ @end
30
+
31
+
32
+ @implementation FrankAfcProxy
33
+
34
+ - (void)httpRequestWithHeaderData:(NSData*)headerData bodyData:(NSData*)bodyData
35
+ {
36
+ if (!headerData) {
37
+ [@"Bad request: header is nil.\n" writeToFile:_out_body atomically:NO encoding:NSUTF8StringEncoding error:nil];
38
+ [@{@"Status": @400} writeToFile:_out_header atomically:NO];
39
+ NSLog(@"header is nil");
40
+ return;
41
+ }
42
+
43
+ NSMutableDictionary* headers = [NSJSONSerialization JSONObjectWithData:headerData
44
+ options:NSJSONReadingMutableContainers
45
+ error:nil];
46
+
47
+ NSMutableURLRequest* req = [[NSMutableURLRequest alloc] init];
48
+ [req setURL:[NSURL URLWithString:[headers objectForKey:@"URI"]]];
49
+ [req setHTTPMethod:[headers objectForKey:@"Method"]];
50
+ [headers removeObjectForKey:@"URI"];
51
+ [headers removeObjectForKey:@"Method"];
52
+
53
+ for (NSString* key in headers.keyEnumerator) {
54
+ [req setValue:[headers objectForKey:key] forHTTPHeaderField:key];
55
+ }
56
+ [req setHTTPBody:bodyData];
57
+
58
+ NSLog(@"\n%@ %@\n%@\n%@", req.HTTPMethod, req.URL.description, req.allHTTPHeaderFields.description, req.HTTPBody.description);
59
+
60
+ [NSURLConnection sendAsynchronousRequest:req
61
+ queue:_queueHTTPRequest
62
+ completionHandler:^(NSURLResponse* res_, NSData* response_body, NSError* response_error) {
63
+ NSHTTPURLResponse* res = (NSHTTPURLResponse*)res_;
64
+ NSLog(@"=> %d", res.statusCode);
65
+
66
+ [response_body writeToFile:_out_body atomically:NO];
67
+ NSMutableDictionary* result_headers = [NSMutableDictionary dictionaryWithDictionary:res.allHeaderFields];
68
+ [result_headers setObject:[NSNumber numberWithInteger:res.statusCode]
69
+ forKey:@"Status"];
70
+ NSData* header = [NSJSONSerialization dataWithJSONObject:result_headers
71
+ options:0
72
+ error:nil];
73
+ [header writeToFile:_out_header atomically:NO];
74
+ NSLog(@"%@ => %d", req.URL, header.length);
75
+ }];
76
+ }
77
+
78
+
79
+
80
+ #pragma mark - FileChangeObserverDelegate
81
+
82
+ - (void)fileChanged:(FileChangeObserver*)observer typeMask:(FileChangeNotificationType)type
83
+ {
84
+ NSLog(@"header in: %@:", [NSString stringWithKEventFFlags:type]);
85
+ if (type & NOTE_DELETE) {
86
+ return;
87
+ }
88
+ NSData* headerData = [NSData dataWithContentsOfFile:_in_header];
89
+ NSData* bodyData = [NSData dataWithContentsOfFile:_in_body];
90
+ truncate(_in_header.UTF8String, 0);
91
+ truncate(_in_body.UTF8String, 0);
92
+ [self httpRequestWithHeaderData:headerData bodyData:bodyData];
93
+ }
94
+
95
+
96
+
97
+ #pragma mark - Life cycle.
98
+
99
+ + (void)run
100
+ {
101
+ static FrankAfcProxy* proxy;
102
+ static dispatch_once_t onceToken;
103
+ dispatch_once(&onceToken, ^{
104
+ proxy = [[FrankAfcProxy alloc] init];
105
+ });
106
+ }
107
+
108
+ - (id)init
109
+ {
110
+ self = [super init];
111
+ if (self) {
112
+ _queueHTTPRequest = [[NSOperationQueue alloc] init];
113
+ _queueHTTPRequest.maxConcurrentOperationCount = 1;
114
+
115
+ NSError* err;
116
+ NSString* dir = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
117
+ _in_header = [dir stringByAppendingPathComponent:@"in.header"];
118
+ _in_body = [dir stringByAppendingPathComponent:@"in.body"];
119
+ _out_header = [dir stringByAppendingPathComponent:@"out.header"];
120
+ _out_body = [dir stringByAppendingPathComponent:@"out.body"];
121
+
122
+ NSFileManager* fm = [NSFileManager defaultManager];
123
+ [fm createDirectoryAtPath:dir withIntermediateDirectories:YES attributes:nil error:&err];
124
+ [fm createFileAtPath:_in_header contents:nil attributes:nil];
125
+ [fm createFileAtPath:_in_body contents:nil attributes:nil];
126
+ [fm createFileAtPath:_out_header contents:nil attributes:nil];
127
+ [fm createFileAtPath:_out_body contents:nil attributes:nil];
128
+
129
+ _header_observer = [FileChangeObserver observerForURL:[[NSURL alloc] initFileURLWithPath:_in_header]
130
+ types:kFileChangeType_Delete|kFileChangeType_Write
131
+ delegate:self];
132
+ NSLog(@"Target: %@/\n", dir);
133
+ }
134
+ return self;
135
+ }
136
+
137
+ @end
@@ -0,0 +1,12 @@
1
+ //
2
+ // FrankAfcProxyLoader.h
3
+ //
4
+ // Created by Toshiyuki Terashita on 2013/06/26.
5
+ // Copyright (c) 2013 Toshiyuki Suzumura. All rights reserved.
6
+ //
7
+
8
+ #import <Foundation/Foundation.h>
9
+
10
+ @interface FrankAfcProxyLoader : NSObject
11
+
12
+ @end
@@ -0,0 +1,30 @@
1
+ //
2
+ // FrankAfcProxyLoader.m
3
+ //
4
+ // Created by Toshiyuki Terashita on 2013/06/26.
5
+ // Copyright (c) 2013 Toshiyuki Suzumura. All rights reserved.
6
+ //
7
+
8
+ #import "FrankAfcProxyLoader.h"
9
+ #import "FrankAfcProxy.h"
10
+
11
+ @implementation FrankAfcProxyLoader
12
+
13
+ + (void)applicationDidBecomeActive:(NSNotification*)notification
14
+ {
15
+ [FrankAfcProxy run];
16
+ }
17
+
18
+ + (void)load
19
+ {
20
+ NSLog(@"Injecting FrankAfcProxy");
21
+
22
+ NSString *notificationName = @"UIApplicationDidBecomeActiveNotification";
23
+
24
+ [[NSNotificationCenter defaultCenter] addObserver:[self class]
25
+ selector:@selector(applicationDidBecomeActive:)
26
+ name:notificationName
27
+ object:nil];
28
+ }
29
+
30
+ @end
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in FrankProxy.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Toshiyuki Suzumura
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # FrankAfcProxy
2
+
3
+ Connect to FrankServer with iPhone USB cable via afc.
4
+
5
+
6
+ ## Installation
7
+
8
+ Required gem io_afc, and libimobiledevice version 1.1.5 or later.
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'frank_afc_proxy'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install frank_afc_proxy
21
+
22
+
23
+ ## Usage
24
+
25
+
26
+ 1. First, run frank setup In your application project directory.
27
+
28
+ $ frank setup
29
+
30
+ 2. And install frankAfcProxy into your application.
31
+
32
+ $ frankAfcProxy-install
33
+
34
+ 3. Build and launch your application with fruitstrap.
35
+
36
+ http://www.testingwithfrank.com/device.html
37
+
38
+ 4. Start frankAfcProxy with your application bundle identifer.
39
+
40
+ $ frankAfcProxy start --appid=<bundle identifer>
41
+
42
+ You can check bundle identifiers in the following ways.
43
+
44
+ $ frankAfcProxy list
45
+
46
+ 5. Run frank console with --server option.
47
+
48
+ $ frank console --server=http://localhost:4000/
49
+
50
+ Or, Run test with server_base_url settings.
51
+
52
+ Frank::Cucumber::FrankHelper.server_base_url = "http://localhost:4000/"
53
+
54
+ 6. Access to device with FrankHelper.
55
+
56
+
57
+
58
+ ## Contributing
59
+
60
+ 1. Fork it
61
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
62
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
63
+ 4. Push to the branch (`git push origin my-new-feature`)
64
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,60 @@
1
+ require "bundler/gem_tasks"
2
+ require File.expand_path('../lib/frank_afc_proxy/version', __FILE__)
3
+
4
+ def discover_latest_sdk_for(platform)
5
+ `xcodebuild -showsdks | grep -o "#{platform}.*$" | sort | tail -n 1`.chomp
6
+ end
7
+
8
+ def build_dir
9
+ File.expand_path('../build', __FILE__)
10
+ end
11
+
12
+ def build_ios_library(platform)
13
+ sdk = discover_latest_sdk_for(platform)
14
+ puts "building #{{sdk:sdk}}"
15
+ preprocessor_flag = %Q|GCC_PREPROCESSOR_DEFINITIONS='$(inherited) FRANKAFCPROXY_PRODUCT_VERSION=\"#{FrankAfcProxy::VERSION}\"'|
16
+ sh "xcodebuild -project FrankAfcProxy.xcodeproj -configuration Release -sdk #{sdk} BUILD_DIR=\"#{build_dir}\" #{preprocessor_flag} clean build"
17
+ end
18
+
19
+ task :build_iphone_lib do
20
+ build_ios_library('iphoneos')
21
+ end
22
+
23
+ task :build_simulator_lib do
24
+ build_ios_library('iphonesimulator')
25
+ end
26
+
27
+ task :combine_libraries do
28
+ `lipo -create -output "dist/libFrankAfcProxy.a" "#{build_dir}/Release-iphoneos/libFrankAfcProxy.a" "#{build_dir}/Release-iphonesimulator/libFrankAfcProxy.a"`
29
+ end
30
+
31
+ task :build_ios_lib => [:build_iphone_lib, :build_simulator_lib, :combine_libraries]
32
+
33
+
34
+ desc "clean build artifacts"
35
+ task :clean do
36
+ rm_rf 'dist'
37
+ rm_rf "#{build_dir}"
38
+ rm_rf 'FrankAfcProxy.xcodeproj/project.xcworkspace'
39
+ rm_rf 'FrankAfcProxy.xcodeproj/xcuserdata'
40
+ end
41
+
42
+ task :prep_dist do
43
+ mkdir_p 'dist'
44
+ mkdir_p "#{build_dir}"
45
+ end
46
+
47
+ desc "build library"
48
+ task :build_lib => [:clean, :prep_dist, :build_ios_lib]
49
+
50
+
51
+ task :copy_to_skeleton do
52
+ sh "cp -r dist/* frankAfcProxy-skeleton/"
53
+ end
54
+
55
+ desc "build and copy into the skeleton dir."
56
+ task :build_for_release => [:build_lib, :copy_to_skeleton]
57
+
58
+
59
+ desc "build library and build gem."
60
+ task :all => [:build_for_release, :build]
data/bin/frankAfcProxy ADDED
@@ -0,0 +1,203 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'webrick'
4
+ require 'io/afc'
5
+ require 'json'
6
+ require 'daemon_spawn'
7
+ require 'thor'
8
+ require 'pp'
9
+
10
+
11
+ module FrankAfcProxy
12
+
13
+ class Server < WEBrick::HTTPServlet::AbstractServlet
14
+ def pp_logger(obj)
15
+ print "\x1b[1m"
16
+ pp obj
17
+ print "\x1b[m"
18
+ end
19
+
20
+ def initialize(server, opt)
21
+ super(server, opt)
22
+ @opt = opt
23
+ @in_header = '/Documents/in.header'
24
+ @in_body = '/Documents/in.body'
25
+ @out_header = '/Documents/out.header'
26
+ @out_body = '/Documents/out.body'
27
+ @@afc.truncate(@out_body, 0)
28
+ @@afc.truncate(@out_header, 0)
29
+ @@runloop = true
30
+ end
31
+
32
+ def parseopt(req)
33
+ opt = req.header
34
+ opt.delete("host")
35
+ opt.inject({}){|s, v| s[v[0]] = v[1][0]; s}
36
+ end
37
+
38
+ def request_to_frank(method, req, res)
39
+ uri = req.request_uri
40
+ uri.port=37265
41
+ uri.host="localhost"
42
+
43
+ opt = parseopt(req)
44
+ opt["URI"] = uri.to_s
45
+ opt["Method"] = method.to_s
46
+ pp_logger [method, opt["URI"]]
47
+
48
+ begin
49
+ @@afc.truncate(@out_body, 0)
50
+ @@afc.truncate(@out_header, 0)
51
+ @@afc.open(@in_body, IO::WRONLY){|f| f.write(req.body)}
52
+ @@afc.open(@in_header, IO::WRONLY){|f| f.write(opt.to_json)}
53
+ pp_logger [:waiting_response, opt["URI"]]
54
+
55
+ retry_cont = 2
56
+ while @@runloop
57
+ s = @@afc.getattr(@out_header)[:st_size]
58
+ if s==0
59
+ sleep 0.01
60
+ next
61
+ end
62
+ res.body = body = @@afc.open(@out_body){|f| f.read(-1)}
63
+ pp_logger [method, opt["URI"], s, body.size]
64
+ if body.size==0 and retry_cont>0
65
+ retry_cont-=1
66
+ sleep 0.01
67
+ next
68
+ end
69
+
70
+ begin
71
+ header = JSON.parse(@@afc.open(@out_header){|f| f.read(-1)})
72
+ res["Content-Type"] = header["Content-Type"]
73
+ res.status = header["Status"]
74
+ rescue JSON::ParserError => e
75
+ pp_logger e
76
+ res.status = 500
77
+ end
78
+ break
79
+ end
80
+ rescue => e
81
+ pp_logger [method, opt["URI"], e, e.backtrace[0..5]]
82
+ ensure
83
+ @@afc.truncate(@out_header, 0)
84
+ @@afc.truncate(@out_body, 0)
85
+ end
86
+ end
87
+
88
+ def do_GET(req, res)
89
+ request_to_frank(:GET, req, res)
90
+ end
91
+
92
+ def do_POST(req, res)
93
+ request_to_frank(:POST, req, res)
94
+ end
95
+
96
+ def self.start(opt)
97
+ @@afc = opt[:afc]
98
+ @@server = WEBrick::HTTPServer.new({:Port => opt['port'], :BindAddress => '0.0.0.0', :MaxClients=>1})
99
+ @@server.mount('/', self, opt)
100
+
101
+ trap('INT') {
102
+ @@server.stop
103
+ }
104
+ @@server.start
105
+ end
106
+
107
+ def self.stop
108
+ @@runloop = false
109
+ @@server.shutdown
110
+ @@afc.close
111
+ end
112
+ end
113
+
114
+
115
+ class Daemon < DaemonSpawn::Base
116
+ def self.exec(command, options)
117
+ @@opt = options.to_hash
118
+ @@opt[:afc] = IO::AFC.connect(options) if %w{start restart}.include?(command)
119
+ body = File.expand_path(File.join(options[:log], "#{File.basename(__FILE__, ".rb")}_#{options[:port]}"))
120
+ opt = {
121
+ :working_dir => '/',
122
+ :pid_file => body + '.pid',
123
+ :log_file => body + '.log',
124
+ :sync_log => true,
125
+ :singleton => false,
126
+ }
127
+ ARGV.clear
128
+ ARGV << command
129
+ if options[:debug]
130
+ Server.start(@@opt)
131
+ else
132
+ self.spawn!(opt)
133
+ end
134
+ end
135
+
136
+ def start(args)
137
+ Server.start(@@opt)
138
+ end
139
+
140
+ def stop
141
+ Server.stop
142
+ end
143
+ end
144
+
145
+
146
+ class Cli < Thor
147
+
148
+ desc "start [option]", "Start frankAfcProxy."
149
+ option :appid, :type=>:string, :desc=>"Bundle identifer of your application.", :aliases=>'-a', :required=>true
150
+ option :udid, :type=>:string, :desc=>"UDID of the device you want to connect. Default is 'auto detect'.", :default=>nil
151
+ option :port, :type=>:numeric, :desc=>"Listen port.", :default=>4000, :aliases=>'-p'
152
+ option :log, :type=>:string, :desc=>"Log/pid files directory.", :default=>"/var/log", :aliases=>'-l'
153
+ option :debug, :type=>:boolean, :desc=>"Debug mode.", :aliases=>'-d'
154
+ def start
155
+ Daemon.exec('start', options)
156
+ end
157
+
158
+ desc "stop [option]", "Stop frankAfcProxy."
159
+ option :port, :type=>:numeric, :desc=>"Listen port.", :default=>4000, :aliases=>'-p'
160
+ option :log, :type=>:string, :desc=>"Log/pid files directory.", :default=>"/var/log", :aliases=>'-l'
161
+ def stop
162
+ Daemon.exec('stop', options)
163
+ end
164
+
165
+ desc "restart [option]", "Restart frankAfcProxy."
166
+ option :appid, :type=>:string, :desc=>"Bundle identifer of your application.", :aliases=>'-a', :required=>true
167
+ option :udid, :type=>:string, :desc=>"UDID of the device you want to connect. Default is 'auto detect'.", :default=>nil
168
+ option :port, :type=>:numeric, :desc=>"Listen port.", :default=>4000, :aliases=>'-p'
169
+ option :log, :type=>:string, :desc=>"Log/pid files directory.", :default=>"/var/log", :aliases=>'-l'
170
+ def restart
171
+ Daemon.exec('restart', options)
172
+ end
173
+
174
+ desc "status [option]", "Show frankAfcProxy status."
175
+ option :port, :type=>:numeric, :desc=>"Listen port.", :default=>4000, :aliases=>'-p'
176
+ option :log, :type=>:string, :desc=>"Log/pid files directory.", :default=>"/var/log", :aliases=>'-l'
177
+ def status
178
+ Daemon.exec('status', options)
179
+ end
180
+
181
+ desc "list [option]", "List installed applications."
182
+ option :udid, :type=>:string, :desc=>"UDID of the device you want to connect. Default is 'auto detect'.", :default=>nil
183
+ def list
184
+ begin
185
+ afc = IO::AFC.connect(:udid=>options[:udid])
186
+ rescue IO::AFC::NoDevice, IO::AFC::PasswordProtected, IO::AFC::ConnectFailed, StandardError => e
187
+ $stderr.puts e
188
+ return 1
189
+ end
190
+ puts "udid : #{afc.device_udid}"
191
+ apps = afc.applications
192
+ apps.each{|k, v|
193
+ puts "#{k} : #{v['CFBundleDisplayName']}"
194
+ }
195
+ puts "#{apps.size} application(s) is installed."
196
+ return 0
197
+ end
198
+ end
199
+
200
+ end
201
+
202
+
203
+ FrankAfcProxy::Cli.start(ARGV)
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'frank-cucumber/version'
4
+ require 'fileutils'
5
+
6
+ FRANKIFY_XCCONFIG = 'Frank/frankify.xcconfig'
7
+ LIBPROXYFLAG = '-lFrankAfcProxy'
8
+
9
+
10
+ puts "Patching Frank-Cucumber evniroments..."
11
+ begin
12
+ config = []
13
+ File.open(FRANKIFY_XCCONFIG).each_line{|line|
14
+ line.strip!
15
+ if line=~%r{^FRANK_LDFLAGS} and !(line=~/#{LIBPROXYFLAG}/)
16
+ line += " #{LIBPROXYFLAG}"
17
+ end
18
+ config << line
19
+ }
20
+ File.open(FRANKIFY_XCCONFIG, "w"){|f|
21
+ f.write config.join("\n")
22
+ }
23
+ rescue Errno::ENOENT => e
24
+ puts "... patch failed. #{e}"
25
+ puts "Please run the `frank setup` first."
26
+ exit 1
27
+ end
28
+
29
+
30
+ puts 'Installing `libFrankAfcProxy`...'
31
+ FileUtils.cp( File.expand_path('../../frankAfcProxy-skeleton/libFrankAfcProxy.a', __FILE__), 'Frank/' )
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'frank_afc_proxy/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "frank_afc_proxy"
8
+ spec.version = FrankAfcProxy::VERSION
9
+ spec.authors = ["Toshiyuki Suzumura"]
10
+ spec.email = ["suz.labo@amail.plala.or.jp"]
11
+ spec.description = %q{Connect to FrankServer with iPhone USB cable via afc.}
12
+ spec.summary = %q{Connect to FrankServer with iPhone USB cable via afc.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_dependency "frank-cucumber", "~> 1.1.12"
24
+ spec.add_dependency "io-afc"
25
+ spec.add_dependency "daemon-spawn"
26
+ end
@@ -0,0 +1,5 @@
1
+ require "frank_afc_proxy/version"
2
+
3
+ module FrankAfcProxy
4
+ # Your code goes here...
5
+ end
@@ -0,0 +1,3 @@
1
+ module FrankAfcProxy
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: frank_afc_proxy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Toshiyuki Suzumura
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: frank-cucumber
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 1.1.12
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.1.12
62
+ - !ruby/object:Gem::Dependency
63
+ name: io-afc
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: daemon-spawn
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ description: Connect to FrankServer with iPhone USB cable via afc.
95
+ email:
96
+ - suz.labo@amail.plala.or.jp
97
+ executables:
98
+ - frankAfcProxy
99
+ - frankAfcProxy-install
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - .gitignore
104
+ - FrankAfcProxy.xcodeproj/project.pbxproj
105
+ - FrankAfcProxy/FileChangeObserver.h
106
+ - FrankAfcProxy/FileChangeObserver.m
107
+ - FrankAfcProxy/FrankAfcProxy-Prefix.pch
108
+ - FrankAfcProxy/FrankAfcProxy.h
109
+ - FrankAfcProxy/FrankAfcProxy.m
110
+ - FrankAfcProxy/FrankAfcProxyLoader.h
111
+ - FrankAfcProxy/FrankAfcProxyLoader.m
112
+ - Gemfile
113
+ - LICENSE.txt
114
+ - README.md
115
+ - Rakefile
116
+ - bin/frankAfcProxy
117
+ - bin/frankAfcProxy-install
118
+ - frankAfcProxy-skeleton/libFrankAfcProxy.a
119
+ - frank_afc_proxy.gemspec
120
+ - lib/frank_afc_proxy.rb
121
+ - lib/frank_afc_proxy/version.rb
122
+ homepage: ''
123
+ licenses:
124
+ - MIT
125
+ post_install_message:
126
+ rdoc_options: []
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ! '>='
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ segments:
136
+ - 0
137
+ hash: 1475162288700299665
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ! '>='
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ segments:
145
+ - 0
146
+ hash: 1475162288700299665
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 1.8.25
150
+ signing_key:
151
+ specification_version: 3
152
+ summary: Connect to FrankServer with iPhone USB cable via afc.
153
+ test_files: []