guard 1.0.3 → 1.1.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/CHANGELOG.md +0 -6
  2. data/README.md +38 -30
  3. data/lib/guard.rb +158 -285
  4. data/lib/guard/cli.rb +16 -2
  5. data/lib/guard/dsl.rb +41 -20
  6. data/lib/guard/dsl_describer.rb +1 -1
  7. data/lib/guard/group.rb +1 -1
  8. data/lib/guard/guard.rb +39 -5
  9. data/lib/guard/guardfile.rb +70 -0
  10. data/lib/guard/runner.rb +179 -0
  11. data/lib/guard/ui.rb +1 -1
  12. data/lib/guard/version.rb +2 -4
  13. data/lib/guard/watcher.rb +1 -0
  14. metadata +16 -77
  15. data/bin/fsevent_watch_guard_guard +0 -0
  16. data/lib/guard/listener.rb +0 -376
  17. data/lib/guard/listeners/darwin.rb +0 -62
  18. data/lib/guard/listeners/linux.rb +0 -93
  19. data/lib/guard/listeners/polling.rb +0 -55
  20. data/lib/guard/listeners/windows.rb +0 -63
  21. data/lib/vendor/darwin/Gemfile +0 -6
  22. data/lib/vendor/darwin/Guardfile +0 -8
  23. data/lib/vendor/darwin/LICENSE +0 -20
  24. data/lib/vendor/darwin/README.rdoc +0 -255
  25. data/lib/vendor/darwin/Rakefile +0 -21
  26. data/lib/vendor/darwin/bin/fsevent_watch +0 -0
  27. data/lib/vendor/darwin/ext/fsevent_watch/Info.plist +0 -38
  28. data/lib/vendor/darwin/ext/fsevent_watch/LICENSE +0 -21
  29. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch.xcodeproj/project.pbxproj +0 -254
  30. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/TSICTString.c +0 -394
  31. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/TSICTString.h +0 -74
  32. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/cli.c +0 -160
  33. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/cli.h +0 -45
  34. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/common.h +0 -34
  35. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/compat.c +0 -20
  36. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/compat.h +0 -40
  37. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/main.c +0 -509
  38. data/lib/vendor/darwin/ext/fsevent_watch/xcconfig/Common.xcconfig +0 -82
  39. data/lib/vendor/darwin/ext/fsevent_watch/xcconfig/Debug.xcconfig +0 -19
  40. data/lib/vendor/darwin/ext/fsevent_watch/xcconfig/Release.xcconfig +0 -23
  41. data/lib/vendor/darwin/ext/fsevent_watch/xcconfig/fsevent_watch.xcconfig +0 -17
  42. data/lib/vendor/darwin/ext/rakefile.rb +0 -47
  43. data/lib/vendor/darwin/ext/rb-fsevent.xcconfig +0 -33
  44. data/lib/vendor/darwin/lib/rb-fsevent.rb +0 -2
  45. data/lib/vendor/darwin/lib/rb-fsevent/fsevent.rb +0 -111
  46. data/lib/vendor/darwin/lib/rb-fsevent/version.rb +0 -3
  47. data/lib/vendor/darwin/rb-fsevent.gemspec +0 -25
  48. data/lib/vendor/darwin/spec/fixtures/folder1/file1.txt +0 -0
  49. data/lib/vendor/darwin/spec/fixtures/folder1/folder2/file2.txt +0 -0
  50. data/lib/vendor/darwin/spec/rb-fsevent/fsevent_spec.rb +0 -88
  51. data/lib/vendor/darwin/spec/spec_helper.rb +0 -23
  52. data/lib/vendor/linux/MIT-LICENSE +0 -20
  53. data/lib/vendor/linux/README.md +0 -66
  54. data/lib/vendor/linux/Rakefile +0 -54
  55. data/lib/vendor/linux/VERSION +0 -1
  56. data/lib/vendor/linux/lib/rb-inotify.rb +0 -17
  57. data/lib/vendor/linux/lib/rb-inotify/event.rb +0 -139
  58. data/lib/vendor/linux/lib/rb-inotify/native.rb +0 -31
  59. data/lib/vendor/linux/lib/rb-inotify/native/flags.rb +0 -89
  60. data/lib/vendor/linux/lib/rb-inotify/notifier.rb +0 -308
  61. data/lib/vendor/linux/lib/rb-inotify/watcher.rb +0 -83
  62. data/lib/vendor/linux/rb-inotify.gemspec +0 -53
  63. data/lib/vendor/windows/Gemfile +0 -4
  64. data/lib/vendor/windows/README.md +0 -34
  65. data/lib/vendor/windows/Rakefile +0 -18
  66. data/lib/vendor/windows/lib/rb-fchange.rb +0 -14
  67. data/lib/vendor/windows/lib/rb-fchange/event.rb +0 -29
  68. data/lib/vendor/windows/lib/rb-fchange/native.rb +0 -45
  69. data/lib/vendor/windows/lib/rb-fchange/native/flags.rb +0 -78
  70. data/lib/vendor/windows/lib/rb-fchange/notifier.rb +0 -149
  71. data/lib/vendor/windows/lib/rb-fchange/version.rb +0 -3
  72. data/lib/vendor/windows/lib/rb-fchange/watcher.rb +0 -99
  73. data/lib/vendor/windows/rb-fchange.gemspec +0 -34
  74. data/lib/vendor/windows/spec/fixtures/folder1/file1.txt +0 -0
  75. data/lib/vendor/windows/spec/fixtures/folder1/folder2/file2.txt +0 -0
  76. data/lib/vendor/windows/spec/rb-fchange/fchange_spec.rb +0 -119
  77. data/lib/vendor/windows/spec/spec_helper.rb +0 -21
@@ -1,74 +0,0 @@
1
- //
2
- // TSICTString.h
3
- // TSITString
4
- //
5
- // Created by Travis Tilley on 9/27/11.
6
- //
7
-
8
- #ifndef TSICTString_H
9
- #define TSICTString_H
10
-
11
- #include <CoreFoundation/CoreFoundation.h>
12
-
13
-
14
- typedef enum {
15
- kTSITStringTagString = 0,
16
- kTSITStringTagNumber = 1,
17
- kTSITStringTagFloat = 2,
18
- kTSITStringTagBool = 3,
19
- kTSITStringTagNull = 4,
20
- kTSITStringTagDict = 5,
21
- kTSITStringTagList = 6,
22
- kTSITStringTagInvalid = 7,
23
- } TSITStringTag;
24
-
25
- extern const char* const TNetstringTypes;
26
- extern const char* const OTNetstringTypes;
27
- extern const UInt8 TNetstringSeparator;
28
-
29
- typedef enum {
30
- kTSITStringFormatDefault = 0,
31
- kTSITStringFormatOTNetstring = 1,
32
- kTSITStringFormatTNetstring = 2,
33
- } TSITStringFormat;
34
-
35
- extern TSITStringFormat TSITStringDefaultFormat;
36
-
37
- typedef struct TSITStringIntermediate {
38
- CFDataRef data;
39
- char* length;
40
- TSITStringTag type;
41
- TSITStringFormat format;
42
- } TStringIRep;
43
-
44
- typedef struct {
45
- CFMutableDataRef buffer;
46
- TSITStringFormat format;
47
- } TStringCollectionCallbackContext;
48
-
49
-
50
- void Init_TSICTString(void);
51
-
52
- void TSICTStringSetDefaultFormat(TSITStringFormat format);
53
- TSITStringFormat TSICTStringGetDefaultFormat(void);
54
-
55
- void TSICTStringDestroy(TStringIRep* rep);
56
-
57
- CFDataRef TSICTStringCreateRenderedData(TStringIRep* rep);
58
- CFDataRef TSICTStringCreateRenderedDataFromObjectWithFormat(CFTypeRef object, TSITStringFormat format);
59
-
60
- CFStringRef TSICTStringCreateRenderedString(TStringIRep* rep);
61
- CFStringRef TSICTStringCreateRenderedStringFromObjectWithFormat(CFTypeRef object, TSITStringFormat format);
62
-
63
- TStringIRep* TSICTStringCreateWithObjectAndFormat(CFTypeRef object, TSITStringFormat format);
64
- TStringIRep* TSICTStringCreateWithStringAndFormat(CFStringRef string, TSITStringFormat format);
65
- TStringIRep* TSICTStringCreateWithNumberAndFormat(CFNumberRef number, TSITStringFormat format);
66
- TStringIRep* TSICTStringCreateTrueWithFormat(TSITStringFormat format);
67
- TStringIRep* TSICTStringCreateFalseWithFormat(TSITStringFormat format);
68
- TStringIRep* TSICTStringCreateNullWithFormat(TSITStringFormat format);
69
- TStringIRep* TSICTStringCreateInvalidWithFormat(TSITStringFormat format);
70
- TStringIRep* TSICTStringCreateWithArrayAndFormat(CFArrayRef array, TSITStringFormat format);
71
- TStringIRep* TSICTStringCreateWithDictionaryAndFormat(CFDictionaryRef dictionary, TSITStringFormat format);
72
-
73
-
74
- #endif
@@ -1,160 +0,0 @@
1
- #include <getopt.h>
2
- #include "cli.h"
3
-
4
- const char* cli_info_purpose = "A flexible command-line interface for the FSEvents API";
5
- const char* cli_info_usage = "Usage: fsevent_watch [OPTIONS]... [PATHS]...";
6
- const char* cli_info_help[] = {
7
- " -h, --help you're looking at it",
8
- " -V, --version print version number and exit",
9
- " -s, --since-when=EventID fire historical events since ID",
10
- " -l, --latency=seconds latency period (default='0.5')",
11
- " -n, --no-defer enable no-defer latency modifier",
12
- " -r, --watch-root watch for when the root path has changed",
13
- // " -i, --ignore-self ignore current process",
14
- " -F, --file-events provide file level event data",
15
- " -f, --format=name output format (classic, niw, \n"
16
- " tnetstring, otnetstring)",
17
- 0
18
- };
19
-
20
- static void default_args (struct cli_info* args_info)
21
- {
22
- args_info->since_when_arg = kFSEventStreamEventIdSinceNow;
23
- args_info->latency_arg = 0.5;
24
- args_info->no_defer_flag = false;
25
- args_info->watch_root_flag = false;
26
- args_info->ignore_self_flag = false;
27
- args_info->file_events_flag = false;
28
- args_info->format_arg = kFSEventWatchOutputFormatClassic;
29
- }
30
-
31
- static void cli_parser_release (struct cli_info* args_info)
32
- {
33
- unsigned int i;
34
-
35
- for (i=0; i < args_info->inputs_num; ++i) {
36
- free(args_info->inputs[i]);
37
- }
38
-
39
- if (args_info->inputs_num) {
40
- free(args_info->inputs);
41
- }
42
-
43
- args_info->inputs_num = 0;
44
- }
45
-
46
- void cli_parser_init (struct cli_info* args_info)
47
- {
48
- default_args(args_info);
49
-
50
- args_info->inputs = 0;
51
- args_info->inputs_num = 0;
52
- }
53
-
54
- void cli_parser_free (struct cli_info* args_info)
55
- {
56
- cli_parser_release(args_info);
57
- }
58
-
59
- void cli_print_version (void)
60
- {
61
- printf("%s %s\n", CLI_NAME, CLI_VERSION);
62
- #ifdef COMPILED_AT
63
- printf("Compiled %s\n", COMPILED_AT);
64
- #endif
65
- }
66
-
67
- void cli_print_help (void)
68
- {
69
- cli_print_version();
70
-
71
- printf("\n%s\n", cli_info_purpose);
72
- printf("\n%s\n", cli_info_usage);
73
- printf("\n");
74
-
75
- int i = 0;
76
- while (cli_info_help[i]) {
77
- printf("%s\n", cli_info_help[i++]);
78
- }
79
- }
80
-
81
- int cli_parser (int argc, const char** argv, struct cli_info* args_info)
82
- {
83
- static struct option longopts[] = {
84
- { "help", no_argument, NULL, 'h' },
85
- { "version", no_argument, NULL, 'V' },
86
- { "since-when", required_argument, NULL, 's' },
87
- { "latency", required_argument, NULL, 'l' },
88
- { "no-defer", no_argument, NULL, 'n' },
89
- { "watch-root", no_argument, NULL, 'r' },
90
- { "ignore-self", no_argument, NULL, 'i' },
91
- { "file-events", no_argument, NULL, 'F' },
92
- { "format", required_argument, NULL, 'f' },
93
- { 0, 0, 0, 0 }
94
- };
95
-
96
- const char* shortopts = "hVs:l:nriFf:";
97
-
98
- int c = -1;
99
-
100
- while ((c = getopt_long(argc, (char * const*)argv, shortopts, longopts, NULL)) != -1) {
101
- switch(c) {
102
- case 's': // since-when
103
- args_info->since_when_arg = strtoull(optarg, NULL, 0);
104
- break;
105
- case 'l': // latency
106
- args_info->latency_arg = strtod(optarg, NULL);
107
- break;
108
- case 'n': // no-defer
109
- args_info->no_defer_flag = true;
110
- break;
111
- case 'r': // watch-root
112
- args_info->watch_root_flag = true;
113
- break;
114
- case 'i': // ignore-self
115
- args_info->ignore_self_flag = true;
116
- break;
117
- case 'F': // file-events
118
- args_info->file_events_flag = true;
119
- break;
120
- case 'f': // format
121
- if (strcmp(optarg, "classic") == 0) {
122
- args_info->format_arg = kFSEventWatchOutputFormatClassic;
123
- } else if (strcmp(optarg, "niw") == 0) {
124
- args_info->format_arg = kFSEventWatchOutputFormatNIW;
125
- } else if (strcmp(optarg, "tnetstring") == 0) {
126
- args_info->format_arg = kFSEventWatchOutputFormatTNetstring;
127
- } else if (strcmp(optarg, "otnetstring") == 0) {
128
- args_info->format_arg = kFSEventWatchOutputFormatOTNetstring;
129
- } else {
130
- fprintf(stderr, "Unknown output format: %s\n", optarg);
131
- exit(EXIT_FAILURE);
132
- }
133
- break;
134
- case 'V': // version
135
- cli_print_version();
136
- exit(EXIT_SUCCESS);
137
- break;
138
- case 'h': // help
139
- case '?': // invalid option
140
- case ':': // missing argument
141
- cli_print_help();
142
- exit((c == 'h') ? EXIT_SUCCESS : EXIT_FAILURE);
143
- break;
144
- }
145
- }
146
-
147
- if (optind < argc) {
148
- int i = 0;
149
- args_info->inputs_num = (unsigned int)(argc - optind);
150
- args_info->inputs =
151
- (char**)(malloc ((args_info->inputs_num)*sizeof(char*)));
152
- while (optind < argc)
153
- if (argv[optind++] != argv[0]) {
154
- args_info->inputs[i++] = strdup(argv[optind-1]);
155
- }
156
- }
157
-
158
- return EXIT_SUCCESS;
159
- }
160
-
@@ -1,45 +0,0 @@
1
- #ifndef CLI_H
2
- #define CLI_H
3
-
4
- #ifndef CLI_NAME
5
- #define CLI_NAME "fsevent_watch"
6
- #endif /* CLI_NAME */
7
-
8
- #ifndef PROJECT_VERSION
9
- #error "PROJECT_VERSION not set"
10
- #endif /* PROJECT_VERSION */
11
-
12
- #ifndef CLI_VERSION
13
- #define _str(s) #s
14
- #define _xstr(s) _str(s)
15
- #define CLI_VERSION _xstr(PROJECT_VERSION)
16
- #endif /* CLI_VERSION */
17
-
18
- #include "common.h"
19
-
20
- struct cli_info {
21
- UInt64 since_when_arg;
22
- double latency_arg;
23
- bool no_defer_flag;
24
- bool watch_root_flag;
25
- bool ignore_self_flag;
26
- bool file_events_flag;
27
- enum FSEventWatchOutputFormat format_arg;
28
-
29
- char** inputs;
30
- unsigned inputs_num;
31
- };
32
-
33
- extern const char* cli_info_purpose;
34
- extern const char* cli_info_usage;
35
- extern const char* cli_info_help[];
36
-
37
- void cli_print_help(void);
38
- void cli_print_version(void);
39
-
40
- int cli_parser (int argc, const char** argv, struct cli_info* args_info);
41
- void cli_parser_init (struct cli_info* args_info);
42
- void cli_parser_free (struct cli_info* args_info);
43
-
44
-
45
- #endif /* CLI_H */
@@ -1,34 +0,0 @@
1
- #ifndef fsevent_watch_common_h
2
- #define fsevent_watch_common_h
3
-
4
- #include <CoreFoundation/CoreFoundation.h>
5
- #ifdef __OBJC__
6
- #import <Foundation/Foundation.h>
7
- #endif
8
-
9
- #include <CoreServices/CoreServices.h>
10
- #include <unistd.h>
11
- #include "compat.h"
12
- #include "TSICTString.h"
13
-
14
- #define COMPILED_AT __DATE__ " " __TIME__
15
-
16
- #define FLAG_CHECK(flags, flag) ((flags) & (flag))
17
-
18
- #define FPRINTF_FLAG_CHECK(flags, flag, msg, fd) \
19
- do { \
20
- if (FLAG_CHECK(flags, flag)) { \
21
- fprintf(fd, "%s", msg "\n"); } } \
22
- while (0)
23
-
24
- #define FLAG_CHECK_STDERR(flags, flag, msg) \
25
- FPRINTF_FLAG_CHECK(flags, flag, msg, stderr)
26
-
27
- enum FSEventWatchOutputFormat {
28
- kFSEventWatchOutputFormatClassic,
29
- kFSEventWatchOutputFormatNIW,
30
- kFSEventWatchOutputFormatTNetstring,
31
- kFSEventWatchOutputFormatOTNetstring
32
- };
33
-
34
- #endif /* fsevent_watch_common_h */
@@ -1,20 +0,0 @@
1
- #include "compat.h"
2
-
3
- #if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
4
- FSEventStreamCreateFlags kFSEventStreamCreateFlagIgnoreSelf = 0x00000008;
5
- #endif
6
-
7
- #if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
8
- FSEventStreamCreateFlags kFSEventStreamCreateFlagFileEvents = 0x00000010;
9
- FSEventStreamEventFlags kFSEventStreamEventFlagItemCreated = 0x00000100;
10
- FSEventStreamEventFlags kFSEventStreamEventFlagItemRemoved = 0x00000200;
11
- FSEventStreamEventFlags kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400;
12
- FSEventStreamEventFlags kFSEventStreamEventFlagItemRenamed = 0x00000800;
13
- FSEventStreamEventFlags kFSEventStreamEventFlagItemModified = 0x00001000;
14
- FSEventStreamEventFlags kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000;
15
- FSEventStreamEventFlags kFSEventStreamEventFlagItemChangeOwner = 0x00004000;
16
- FSEventStreamEventFlags kFSEventStreamEventFlagItemXattrMod = 0x00008000;
17
- FSEventStreamEventFlags kFSEventStreamEventFlagItemIsFile = 0x00010000;
18
- FSEventStreamEventFlags kFSEventStreamEventFlagItemIsDir = 0x00020000;
19
- FSEventStreamEventFlags kFSEventStreamEventFlagItemIsSymlink = 0x00040000;
20
- #endif
@@ -1,40 +0,0 @@
1
- /**
2
- * @headerfile compat.h
3
- * FSEventStream flag compatibility shim
4
- *
5
- * In order to compile a binary against an older SDK yet still support the
6
- * features present in later OS releases, we need to define any missing enum
7
- * constants not present in the older SDK. This allows us to safely defer
8
- * feature detection to runtime (and avoid recompilation).
9
- */
10
-
11
-
12
- #ifndef fsevent_watch_compat_h
13
- #define fsevent_watch_compat_h
14
-
15
- #ifndef __CORESERVICES__
16
- #include <CoreServices/CoreServices.h>
17
- #endif // __CORESERVICES__
18
-
19
- #if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
20
- // ignoring events originating from the current process introduced in 10.6
21
- extern FSEventStreamCreateFlags kFSEventStreamCreateFlagIgnoreSelf;
22
- #endif
23
-
24
- #if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
25
- // file-level events introduced in 10.7
26
- extern FSEventStreamCreateFlags kFSEventStreamCreateFlagFileEvents;
27
- extern FSEventStreamEventFlags kFSEventStreamEventFlagItemCreated,
28
- kFSEventStreamEventFlagItemRemoved,
29
- kFSEventStreamEventFlagItemInodeMetaMod,
30
- kFSEventStreamEventFlagItemRenamed,
31
- kFSEventStreamEventFlagItemModified,
32
- kFSEventStreamEventFlagItemFinderInfoMod,
33
- kFSEventStreamEventFlagItemChangeOwner,
34
- kFSEventStreamEventFlagItemXattrMod,
35
- kFSEventStreamEventFlagItemIsFile,
36
- kFSEventStreamEventFlagItemIsDir,
37
- kFSEventStreamEventFlagItemIsSymlink;
38
- #endif
39
-
40
- #endif // fsevent_watch_compat_h
@@ -1,509 +0,0 @@
1
- #include "common.h"
2
- #include "cli.h"
3
-
4
- // TODO: set on fire. cli.{h,c} handle both parsing and defaults, so there's
5
- // no need to set those here. also, in order to scope metadata by path,
6
- // each stream will need its own configuration... so this won't work as
7
- // a global any more. In the end the goal is to make the output format
8
- // able to declare not just that something happened and what flags were
9
- // attached, but what path it was watching that caused those events (so
10
- // that the path itself can be used for routing that information to the
11
- // relevant callback).
12
- //
13
- // Structure for storing metadata parsed from the commandline
14
- static struct {
15
- FSEventStreamEventId sinceWhen;
16
- CFTimeInterval latency;
17
- FSEventStreamCreateFlags flags;
18
- CFMutableArrayRef paths;
19
- enum FSEventWatchOutputFormat format;
20
- } config = {
21
- (UInt64) kFSEventStreamEventIdSinceNow,
22
- (double) 0.3,
23
- (CFOptionFlags) kFSEventStreamCreateFlagNone,
24
- NULL,
25
- kFSEventWatchOutputFormatClassic
26
- };
27
-
28
- // Prototypes
29
- static void append_path(const char* path);
30
- static inline void parse_cli_settings(int argc, const char* argv[]);
31
- static void callback(FSEventStreamRef streamRef,
32
- void* clientCallBackInfo,
33
- size_t numEvents,
34
- void* eventPaths,
35
- const FSEventStreamEventFlags eventFlags[],
36
- const FSEventStreamEventId eventIds[]);
37
-
38
-
39
- // Resolve a path and append it to the CLI settings structure
40
- // The FSEvents API will, internally, resolve paths using a similar scheme.
41
- // Performing this ahead of time makes things less confusing, IMHO.
42
- static void append_path(const char* path)
43
- {
44
- #ifdef DEBUG
45
- fprintf(stderr, "\n");
46
- fprintf(stderr, "append_path called for: %s\n", path);
47
- #endif
48
-
49
- #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
50
-
51
- #ifdef DEBUG
52
- fprintf(stderr, "compiled against 10.6+, using CFURLCreateFileReferenceURL\n");
53
- #endif
54
-
55
- CFURLRef url = CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8*)path, (CFIndex)strlen(path), false);
56
- CFURLRef placeholder = CFURLCopyAbsoluteURL(url);
57
- CFRelease(url);
58
-
59
- CFMutableArrayRef imaginary = NULL;
60
-
61
- // if we don't have an existing url, spin until we get to a parent that
62
- // does exist, saving any imaginary components for appending back later
63
- while(!CFURLResourceIsReachable(placeholder, NULL)) {
64
- #ifdef DEBUG
65
- fprintf(stderr, "path does not exist\n");
66
- #endif
67
-
68
- CFStringRef child;
69
-
70
- if (imaginary == NULL) {
71
- imaginary = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
72
- }
73
-
74
- child = CFURLCopyLastPathComponent(placeholder);
75
- CFArrayInsertValueAtIndex(imaginary, 0, child);
76
- CFRelease(child);
77
-
78
- url = CFURLCreateCopyDeletingLastPathComponent(NULL, placeholder);
79
- CFRelease(placeholder);
80
- placeholder = url;
81
-
82
- #ifdef DEBUG
83
- fprintf(stderr, "parent: ");
84
- CFShow(placeholder);
85
- #endif
86
- }
87
-
88
- #ifdef DEBUG
89
- fprintf(stderr, "path exists\n");
90
- #endif
91
-
92
- // realpath() doesn't always return the correct case for a path, so this
93
- // is a funky workaround that converts a path into a (volId/inodeId) pair
94
- // and asks what the path should be for that. since it looks at the actual
95
- // inode instead of returning the same case passed in like realpath()
96
- // appears to do for HFS+, it should always be correct.
97
- url = CFURLCreateFileReferenceURL(NULL, placeholder, NULL);
98
- CFRelease(placeholder);
99
- placeholder = CFURLCreateFilePathURL(NULL, url, NULL);
100
- CFRelease(url);
101
-
102
- #ifdef DEBUG
103
- fprintf(stderr, "path resolved to: ");
104
- CFShow(placeholder);
105
- #endif
106
-
107
- // if we stripped off any imaginary path components, append them back on
108
- if (imaginary != NULL) {
109
- CFIndex count = CFArrayGetCount(imaginary);
110
- for (CFIndex i = 0; i<count; i++) {
111
- CFStringRef component = CFArrayGetValueAtIndex(imaginary, i);
112
- #ifdef DEBUG
113
- fprintf(stderr, "appending component: ");
114
- CFShow(component);
115
- #endif
116
- url = CFURLCreateCopyAppendingPathComponent(NULL, placeholder, component, false);
117
- CFRelease(placeholder);
118
- placeholder = url;
119
- }
120
- CFRelease(imaginary);
121
- }
122
-
123
- #ifdef DEBUG
124
- fprintf(stderr, "result: ");
125
- CFShow(placeholder);
126
- #endif
127
-
128
- CFStringRef cfPath = CFURLCopyFileSystemPath(placeholder, kCFURLPOSIXPathStyle);
129
- CFArrayAppendValue(config.paths, cfPath);
130
- CFRelease(cfPath);
131
- CFRelease(placeholder);
132
-
133
- #else
134
-
135
- #ifdef DEBUG
136
- fprintf(stderr, "compiled against 10.5, using realpath()\n");
137
- #endif
138
-
139
- char fullPath[PATH_MAX + 1];
140
-
141
- if (realpath(path, fullPath) == NULL) {
142
- #ifdef DEBUG
143
- fprintf(stderr, " realpath not directly resolvable from path\n");
144
- #endif
145
-
146
- if (path[0] != '/') {
147
- #ifdef DEBUG
148
- fprintf(stderr, " passed path is not absolute\n");
149
- #endif
150
- size_t len;
151
- getcwd(fullPath, sizeof(fullPath));
152
- #ifdef DEBUG
153
- fprintf(stderr, " result of getcwd: %s\n", fullPath);
154
- #endif
155
- len = strlen(fullPath);
156
- fullPath[len] = '/';
157
- strlcpy(&fullPath[len + 1], path, sizeof(fullPath) - (len + 1));
158
- } else {
159
- #ifdef DEBUG
160
- fprintf(stderr, " assuming path does not YET exist\n");
161
- #endif
162
- strlcpy(fullPath, path, sizeof(fullPath));
163
- }
164
- }
165
-
166
- #ifdef DEBUG
167
- fprintf(stderr, " resolved path to: %s\n", fullPath);
168
- fprintf(stderr, "\n");
169
- #endif
170
-
171
- CFStringRef pathRef = CFStringCreateWithCString(kCFAllocatorDefault,
172
- fullPath,
173
- kCFStringEncodingUTF8);
174
- CFArrayAppendValue(config.paths, pathRef);
175
- CFRelease(pathRef);
176
-
177
- #endif
178
- }
179
-
180
- // Parse commandline settings
181
- static inline void parse_cli_settings(int argc, const char* argv[])
182
- {
183
- // runtime os version detection
184
- SInt32 osMajorVersion, osMinorVersion;
185
- if (!(Gestalt(gestaltSystemVersionMajor, &osMajorVersion) == noErr)) {
186
- osMajorVersion = 0;
187
- }
188
- if (!(Gestalt(gestaltSystemVersionMinor, &osMinorVersion) == noErr)) {
189
- osMinorVersion = 0;
190
- }
191
-
192
- if ((osMajorVersion == 10) & (osMinorVersion < 5)) {
193
- fprintf(stderr, "The FSEvents API is unavailable on this version of macos!\n");
194
- exit(EXIT_FAILURE);
195
- }
196
-
197
- struct cli_info args_info;
198
- cli_parser_init(&args_info);
199
-
200
- if (cli_parser(argc, argv, &args_info) != 0) {
201
- exit(EXIT_FAILURE);
202
- }
203
-
204
- config.paths = CFArrayCreateMutable(NULL,
205
- (CFIndex)0,
206
- &kCFTypeArrayCallBacks);
207
-
208
- config.sinceWhen = args_info.since_when_arg;
209
- config.latency = args_info.latency_arg;
210
- config.format = args_info.format_arg;
211
-
212
- if (args_info.no_defer_flag) {
213
- config.flags |= kFSEventStreamCreateFlagNoDefer;
214
- }
215
- if (args_info.watch_root_flag) {
216
- config.flags |= kFSEventStreamCreateFlagWatchRoot;
217
- }
218
-
219
- if (args_info.ignore_self_flag) {
220
- if ((osMajorVersion == 10) & (osMinorVersion >= 6)) {
221
- config.flags |= kFSEventStreamCreateFlagIgnoreSelf;
222
- } else {
223
- fprintf(stderr, "MacOSX 10.6 or later is required for --ignore-self\n");
224
- exit(EXIT_FAILURE);
225
- }
226
- }
227
-
228
- if (args_info.file_events_flag) {
229
- if ((osMajorVersion == 10) & (osMinorVersion >= 7)) {
230
- config.flags |= kFSEventStreamCreateFlagFileEvents;
231
- } else {
232
- fprintf(stderr, "MacOSX 10.7 or later required for --file-events\n");
233
- exit(EXIT_FAILURE);
234
- }
235
- }
236
-
237
- if (args_info.inputs_num == 0) {
238
- append_path(".");
239
- } else {
240
- for (unsigned int i=0; i < args_info.inputs_num; ++i) {
241
- append_path(args_info.inputs[i]);
242
- }
243
- }
244
-
245
- cli_parser_free(&args_info);
246
-
247
- #ifdef DEBUG
248
- fprintf(stderr, "config.sinceWhen %llu\n", config.sinceWhen);
249
- fprintf(stderr, "config.latency %f\n", config.latency);
250
-
251
- // STFU clang
252
- #if __LP64__
253
- fprintf(stderr, "config.flags %#.8x\n", config.flags);
254
- #else
255
- fprintf(stderr, "config.flags %#.8lx\n", config.flags);
256
- #endif
257
-
258
- FLAG_CHECK_STDERR(config.flags, kFSEventStreamCreateFlagUseCFTypes,
259
- " Using CF instead of C types");
260
- FLAG_CHECK_STDERR(config.flags, kFSEventStreamCreateFlagNoDefer,
261
- " NoDefer latency modifier enabled");
262
- FLAG_CHECK_STDERR(config.flags, kFSEventStreamCreateFlagWatchRoot,
263
- " WatchRoot notifications enabled");
264
- FLAG_CHECK_STDERR(config.flags, kFSEventStreamCreateFlagIgnoreSelf,
265
- " IgnoreSelf enabled");
266
- FLAG_CHECK_STDERR(config.flags, kFSEventStreamCreateFlagFileEvents,
267
- " FileEvents enabled");
268
-
269
- fprintf(stderr, "config.paths\n");
270
-
271
- long numpaths = CFArrayGetCount(config.paths);
272
-
273
- for (long i = 0; i < numpaths; i++) {
274
- char path[PATH_MAX];
275
- CFStringGetCString(CFArrayGetValueAtIndex(config.paths, i),
276
- path,
277
- PATH_MAX,
278
- kCFStringEncodingUTF8);
279
- fprintf(stderr, " %s\n", path);
280
- }
281
-
282
- fprintf(stderr, "\n");
283
- #endif
284
- }
285
-
286
- // original output format for rb-fsevent
287
- static void classic_output_format(size_t numEvents,
288
- char** paths)
289
- {
290
- for (size_t i = 0; i < numEvents; i++) {
291
- fprintf(stdout, "%s:", paths[i]);
292
- }
293
- fprintf(stdout, "\n");
294
- }
295
-
296
- // output format used in the Yoshimasa Niwa branch of rb-fsevent
297
- static void niw_output_format(size_t numEvents,
298
- char** paths,
299
- const FSEventStreamEventFlags eventFlags[],
300
- const FSEventStreamEventId eventIds[])
301
- {
302
- for (size_t i = 0; i < numEvents; i++) {
303
- fprintf(stdout, "%lu:%llu:%s\n",
304
- (unsigned long)eventFlags[i],
305
- (unsigned long long)eventIds[i],
306
- paths[i]);
307
- }
308
- fprintf(stdout, "\n");
309
- }
310
-
311
- static void tstring_output_format(size_t numEvents,
312
- char** paths,
313
- const FSEventStreamEventFlags eventFlags[],
314
- const FSEventStreamEventId eventIds[],
315
- TSITStringFormat format)
316
- {
317
- CFMutableArrayRef events = CFArrayCreateMutable(kCFAllocatorDefault,
318
- 0, &kCFTypeArrayCallBacks);
319
-
320
- for (size_t i = 0; i < numEvents; i++) {
321
- CFMutableDictionaryRef event = CFDictionaryCreateMutable(kCFAllocatorDefault,
322
- 0,
323
- &kCFTypeDictionaryKeyCallBacks,
324
- &kCFTypeDictionaryValueCallBacks);
325
-
326
- CFStringRef path = CFStringCreateWithBytes(kCFAllocatorDefault,
327
- (const UInt8*)paths[i],
328
- (CFIndex)strlen(paths[i]),
329
- kCFStringEncodingUTF8,
330
- false);
331
- CFDictionarySetValue(event, CFSTR("path"), path);
332
-
333
- CFNumberRef flags = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &eventFlags[i]);
334
- CFDictionarySetValue(event, CFSTR("flags"), flags);
335
-
336
- CFNumberRef ident = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, &eventIds[i]);
337
- CFDictionarySetValue(event, CFSTR("id"), ident);
338
-
339
- CFArrayAppendValue(events, event);
340
-
341
- CFRelease(event);
342
- CFRelease(path);
343
- CFRelease(flags);
344
- CFRelease(ident);
345
- }
346
-
347
- CFMutableDictionaryRef meta = CFDictionaryCreateMutable(kCFAllocatorDefault,
348
- 0,
349
- &kCFTypeDictionaryKeyCallBacks,
350
- &kCFTypeDictionaryValueCallBacks);
351
- CFDictionarySetValue(meta, CFSTR("events"), events);
352
-
353
- CFNumberRef num = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &numEvents);
354
- CFDictionarySetValue(meta, CFSTR("numEvents"), num);
355
-
356
- CFDataRef data = TSICTStringCreateRenderedDataFromObjectWithFormat(meta, format);
357
- fprintf(stdout, "%s", CFDataGetBytePtr(data));
358
-
359
- CFRelease(events);
360
- CFRelease(num);
361
- CFRelease(meta);
362
- CFRelease(data);
363
- }
364
-
365
- static void callback(__attribute__((unused)) FSEventStreamRef streamRef,
366
- __attribute__((unused)) void* clientCallBackInfo,
367
- size_t numEvents,
368
- void* eventPaths,
369
- const FSEventStreamEventFlags eventFlags[],
370
- const FSEventStreamEventId eventIds[])
371
- {
372
- char** paths = eventPaths;
373
-
374
-
375
- #ifdef DEBUG
376
- fprintf(stderr, "\n");
377
- fprintf(stderr, "FSEventStreamCallback fired!\n");
378
- fprintf(stderr, " numEvents: %lu\n", numEvents);
379
-
380
- for (size_t i = 0; i < numEvents; i++) {
381
- fprintf(stderr, "\n");
382
- fprintf(stderr, " event ID: %llu\n", eventIds[i]);
383
-
384
- // STFU clang
385
- #if __LP64__
386
- fprintf(stderr, " event flags: %#.8x\n", eventFlags[i]);
387
- #else
388
- fprintf(stderr, " event flags: %#.8lx\n", eventFlags[i]);
389
- #endif
390
-
391
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagMustScanSubDirs,
392
- " Recursive scanning of directory required");
393
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagUserDropped,
394
- " Buffering problem: events dropped user-side");
395
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagKernelDropped,
396
- " Buffering problem: events dropped kernel-side");
397
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagEventIdsWrapped,
398
- " Event IDs have wrapped");
399
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagHistoryDone,
400
- " All historical events have been processed");
401
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagRootChanged,
402
- " Root path has changed");
403
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagMount,
404
- " A new volume was mounted at this path");
405
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagUnmount,
406
- " A volume was unmounted from this path");
407
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagItemCreated,
408
- " Item created");
409
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagItemRemoved,
410
- " Item removed");
411
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagItemInodeMetaMod,
412
- " Item metadata modified");
413
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagItemRenamed,
414
- " Item renamed");
415
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagItemModified,
416
- " Item modified");
417
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagItemFinderInfoMod,
418
- " Item Finder Info modified");
419
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagItemChangeOwner,
420
- " Item changed ownership");
421
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagItemXattrMod,
422
- " Item extended attributes modified");
423
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagItemIsFile,
424
- " Item is a file");
425
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagItemIsDir,
426
- " Item is a directory");
427
- FLAG_CHECK_STDERR(eventFlags[i], kFSEventStreamEventFlagItemIsSymlink,
428
- " Item is a symbolic link");
429
-
430
- fprintf(stderr, " event path: %s\n", paths[i]);
431
- fprintf(stderr, "\n");
432
- }
433
-
434
- fprintf(stderr, "\n");
435
- #endif
436
-
437
- if (config.format == kFSEventWatchOutputFormatClassic) {
438
- classic_output_format(numEvents, paths);
439
- } else if (config.format == kFSEventWatchOutputFormatNIW) {
440
- niw_output_format(numEvents, paths, eventFlags, eventIds);
441
- } else if (config.format == kFSEventWatchOutputFormatTNetstring) {
442
- tstring_output_format(numEvents, paths, eventFlags, eventIds,
443
- kTSITStringFormatTNetstring);
444
- } else if (config.format == kFSEventWatchOutputFormatOTNetstring) {
445
- tstring_output_format(numEvents, paths, eventFlags, eventIds,
446
- kTSITStringFormatOTNetstring);
447
- }
448
-
449
- fflush(stdout);
450
- }
451
-
452
- int main(int argc, const char* argv[])
453
- {
454
- /*
455
- * a subprocess will initially inherit the process group of its parent. the
456
- * process group may have a control terminal associated with it, which would
457
- * be the first tty device opened by the group leader. typically the group
458
- * leader is your shell and the control terminal is your login device. a
459
- * subset of signals triggered on the control terminal are sent to all members
460
- * of the process group, in large part to facilitate sane and consistent
461
- * cleanup (ex: control terminal was closed).
462
- *
463
- * so why the overly descriptive lecture style comment?
464
- * 1. SIGINT and SIGQUIT are among the signals with this behavior
465
- * 2. a number of applications gank the above for their own use
466
- * 3. ruby's insanely useful "guard" is one of these applications
467
- * 4. despite having some level of understanding of POSIX signals and a few
468
- * of the scenarios that might cause problems, i learned this one only
469
- * after reading ruby 1.9's process.c
470
- * 5. if left completely undocumented, even slightly obscure bugfixes
471
- * may be removed as cruft by a future maintainer
472
- *
473
- * hindsight is 20/20 addition: if you're single-threaded and blocking on IO
474
- * with a subprocess, then handlers for deferrable signals might not get run
475
- * when you expect them to. In the case of Ruby 1.8, that means making use of
476
- * IO::select, which will preserve correct signal handling behavior.
477
- */
478
- if (setpgid(0,0) < 0) {
479
- fprintf(stderr, "Unable to set new process group.\n");
480
- return 1;
481
- }
482
-
483
- parse_cli_settings(argc, argv);
484
-
485
- FSEventStreamContext context = {0, NULL, NULL, NULL, NULL};
486
- FSEventStreamRef stream;
487
- stream = FSEventStreamCreate(kCFAllocatorDefault,
488
- (FSEventStreamCallback)&callback,
489
- &context,
490
- config.paths,
491
- config.sinceWhen,
492
- config.latency,
493
- config.flags);
494
-
495
- #ifdef DEBUG
496
- FSEventStreamShow(stream);
497
- fprintf(stderr, "\n");
498
- #endif
499
-
500
- FSEventStreamScheduleWithRunLoop(stream,
501
- CFRunLoopGetCurrent(),
502
- kCFRunLoopDefaultMode);
503
- FSEventStreamStart(stream);
504
- CFRunLoopRun();
505
- FSEventStreamFlushSync(stream);
506
- FSEventStreamStop(stream);
507
-
508
- return 0;
509
- }