frank_afc_proxy 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []