diff options
author | Li Jin <dragon-fly@qq.com> | 2022-11-15 17:23:46 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2022-11-15 17:52:09 +0800 |
commit | 94f8330613877b3582d32bd11abd83a97b4399ad (patch) | |
tree | 5359de314be1ebde17f8d1e48632a97d18f9e50f /src/3rdParty/efsw/WatcherFSEvents.cpp | |
parent | 60f8f00a022ac08701792b2897b72d8c99b50f52 (diff) | |
download | yuescript-94f8330613877b3582d32bd11abd83a97b4399ad.tar.gz yuescript-94f8330613877b3582d32bd11abd83a97b4399ad.tar.bz2 yuescript-94f8330613877b3582d32bd11abd83a97b4399ad.zip |
adding -w option to Yuescript tool.
Diffstat (limited to 'src/3rdParty/efsw/WatcherFSEvents.cpp')
-rwxr-xr-x | src/3rdParty/efsw/WatcherFSEvents.cpp | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/src/3rdParty/efsw/WatcherFSEvents.cpp b/src/3rdParty/efsw/WatcherFSEvents.cpp new file mode 100755 index 0000000..6ccf527 --- /dev/null +++ b/src/3rdParty/efsw/WatcherFSEvents.cpp | |||
@@ -0,0 +1,216 @@ | |||
1 | #include <efsw/Debug.hpp> | ||
2 | #include <efsw/FileSystem.hpp> | ||
3 | #include <efsw/FileWatcherFSEvents.hpp> | ||
4 | #include <efsw/WatcherFSEvents.hpp> | ||
5 | |||
6 | #if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS | ||
7 | |||
8 | namespace efsw { | ||
9 | |||
10 | WatcherFSEvents::WatcherFSEvents() : | ||
11 | Watcher(), FWatcher( NULL ), FSStream( NULL ), WatcherGen( NULL ), initializedAsync( false ) {} | ||
12 | |||
13 | WatcherFSEvents::WatcherFSEvents( WatchID id, std::string directory, FileWatchListener* listener, | ||
14 | bool recursive, WatcherFSEvents* parent ) : | ||
15 | Watcher( id, directory, listener, recursive ), | ||
16 | FWatcher( NULL ), | ||
17 | FSStream( NULL ), | ||
18 | WatcherGen( NULL ), | ||
19 | initializedAsync( false ) {} | ||
20 | |||
21 | WatcherFSEvents::~WatcherFSEvents() { | ||
22 | if ( NULL != FSStream ) { | ||
23 | if ( initializedAsync ) { | ||
24 | FSEventStreamStop( FSStream ); | ||
25 | } | ||
26 | |||
27 | FSEventStreamInvalidate( FSStream ); | ||
28 | FSEventStreamRelease( FSStream ); | ||
29 | } | ||
30 | |||
31 | efSAFE_DELETE( WatcherGen ); | ||
32 | } | ||
33 | |||
34 | void WatcherFSEvents::init() { | ||
35 | CFStringRef CFDirectory = | ||
36 | CFStringCreateWithCString( NULL, Directory.c_str(), kCFStringEncodingUTF8 ); | ||
37 | CFArrayRef CFDirectoryArray = CFArrayCreate( NULL, (const void**)&CFDirectory, 1, NULL ); | ||
38 | |||
39 | Uint32 streamFlags = kFSEventStreamCreateFlagNone; | ||
40 | |||
41 | if ( FileWatcherFSEvents::isGranular() ) { | ||
42 | streamFlags = efswFSEventStreamCreateFlagFileEvents; | ||
43 | } else { | ||
44 | WatcherGen = new WatcherGeneric( ID, Directory, Listener, FWatcher.load(), Recursive ); | ||
45 | } | ||
46 | |||
47 | FSEventStreamContext ctx; | ||
48 | /* Initialize context */ | ||
49 | ctx.version = 0; | ||
50 | ctx.info = this; | ||
51 | ctx.retain = NULL; | ||
52 | ctx.release = NULL; | ||
53 | ctx.copyDescription = NULL; | ||
54 | |||
55 | FSStream = | ||
56 | FSEventStreamCreate( kCFAllocatorDefault, &FileWatcherFSEvents::FSEventCallback, &ctx, | ||
57 | CFDirectoryArray, kFSEventStreamEventIdSinceNow, 0.25, streamFlags ); | ||
58 | FWatcher.load()->mNeedInitMutex.lock(); | ||
59 | FWatcher.load()->mNeedInit.push_back( this ); | ||
60 | FWatcher.load()->mNeedInitMutex.unlock(); | ||
61 | |||
62 | CFRelease( CFDirectoryArray ); | ||
63 | CFRelease( CFDirectory ); | ||
64 | } | ||
65 | |||
66 | void WatcherFSEvents::initAsync() { | ||
67 | FSEventStreamScheduleWithRunLoop( FSStream, FWatcher.load()->mRunLoopRef.load(), | ||
68 | kCFRunLoopDefaultMode ); | ||
69 | FSEventStreamStart( FSStream ); | ||
70 | initializedAsync = true; | ||
71 | } | ||
72 | |||
73 | void WatcherFSEvents::sendFileAction( WatchID watchid, const std::string& dir, | ||
74 | const std::string& filename, Action action, | ||
75 | std::string oldFilename ) { | ||
76 | Listener->handleFileAction( watchid, FileSystem::precomposeFileName( dir ), | ||
77 | FileSystem::precomposeFileName( filename ), action, oldFilename ); | ||
78 | } | ||
79 | |||
80 | void WatcherFSEvents::handleAddModDel( const Uint32& flags, const std::string& path, | ||
81 | std::string& dirPath, std::string& filePath ) { | ||
82 | if ( flags & efswFSEventStreamEventFlagItemCreated ) { | ||
83 | if ( FileInfo::exists( path ) ) { | ||
84 | sendFileAction( ID, dirPath, filePath, Actions::Add ); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | if ( flags & efswFSEventsModified ) { | ||
89 | sendFileAction( ID, dirPath, filePath, Actions::Modified ); | ||
90 | } | ||
91 | |||
92 | if ( flags & efswFSEventStreamEventFlagItemRemoved ) { | ||
93 | // Since i don't know the order, at least i try to keep the data consistent with the real | ||
94 | // state | ||
95 | if ( !FileInfo::exists( path ) ) { | ||
96 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); | ||
97 | } | ||
98 | } | ||
99 | } | ||
100 | |||
101 | void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) { | ||
102 | size_t esize = events.size(); | ||
103 | |||
104 | for ( size_t i = 0; i < esize; i++ ) { | ||
105 | FSEvent& event = events[i]; | ||
106 | |||
107 | if ( event.Flags & | ||
108 | ( kFSEventStreamEventFlagUserDropped | kFSEventStreamEventFlagKernelDropped | | ||
109 | kFSEventStreamEventFlagEventIdsWrapped | kFSEventStreamEventFlagHistoryDone | | ||
110 | kFSEventStreamEventFlagMount | kFSEventStreamEventFlagUnmount | | ||
111 | kFSEventStreamEventFlagRootChanged ) ) { | ||
112 | continue; | ||
113 | } | ||
114 | |||
115 | if ( !Recursive ) { | ||
116 | /** In case that is not recursive the watcher, ignore the events from subfolders */ | ||
117 | if ( event.Path.find_last_of( FileSystem::getOSSlash() ) != Directory.size() - 1 ) { | ||
118 | continue; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | if ( FileWatcherFSEvents::isGranular() ) { | ||
123 | std::string dirPath( FileSystem::pathRemoveFileName( event.Path ) ); | ||
124 | std::string filePath( FileSystem::fileNameFromPath( event.Path ) ); | ||
125 | |||
126 | if ( event.Flags & | ||
127 | ( efswFSEventStreamEventFlagItemCreated | efswFSEventStreamEventFlagItemRemoved | | ||
128 | efswFSEventStreamEventFlagItemRenamed ) ) { | ||
129 | if ( dirPath != Directory ) { | ||
130 | DirsChanged.insert( dirPath ); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | // This is a mess. But it's FSEvents faults, because shrinks events from the same file | ||
135 | // in one single event ( so there's no order for them ) For example a file could have | ||
136 | // been added modified and erased, but i can't know if first was erased and then added | ||
137 | // and modified, or added, then modified and then erased. I don't know what they were | ||
138 | // thinking by doing this... | ||
139 | efDEBUG( "Event in: %s - flags: %ld\n", event.Path.c_str(), event.Flags ); | ||
140 | |||
141 | if ( event.Flags & efswFSEventStreamEventFlagItemRenamed ) { | ||
142 | if ( ( i + 1 < esize ) && | ||
143 | ( events[i + 1].Flags & efswFSEventStreamEventFlagItemRenamed ) && | ||
144 | ( events[i + 1].Id == event.Id + 1 ) ) { | ||
145 | FSEvent& nEvent = events[i + 1]; | ||
146 | std::string newDir( FileSystem::pathRemoveFileName( nEvent.Path ) ); | ||
147 | std::string newFilepath( FileSystem::fileNameFromPath( nEvent.Path ) ); | ||
148 | |||
149 | if ( event.Path != nEvent.Path ) { | ||
150 | if ( dirPath == newDir ) { | ||
151 | if ( !FileInfo::exists( event.Path ) ) { | ||
152 | sendFileAction( ID, dirPath, newFilepath, Actions::Moved, | ||
153 | filePath ); | ||
154 | } else { | ||
155 | sendFileAction( ID, dirPath, filePath, Actions::Moved, | ||
156 | newFilepath ); | ||
157 | } | ||
158 | } else { | ||
159 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); | ||
160 | sendFileAction( ID, newDir, newFilepath, Actions::Add ); | ||
161 | |||
162 | if ( nEvent.Flags & efswFSEventsModified ) { | ||
163 | sendFileAction( ID, newDir, newFilepath, Actions::Modified ); | ||
164 | } | ||
165 | } | ||
166 | } else { | ||
167 | handleAddModDel( nEvent.Flags, nEvent.Path, dirPath, filePath ); | ||
168 | } | ||
169 | |||
170 | if ( nEvent.Flags & ( efswFSEventStreamEventFlagItemCreated | | ||
171 | efswFSEventStreamEventFlagItemRemoved | | ||
172 | efswFSEventStreamEventFlagItemRenamed ) ) { | ||
173 | if ( newDir != Directory ) { | ||
174 | DirsChanged.insert( newDir ); | ||
175 | } | ||
176 | } | ||
177 | |||
178 | // Skip the renamed file | ||
179 | i++; | ||
180 | } else if ( FileInfo::exists( event.Path ) ) { | ||
181 | sendFileAction( ID, dirPath, filePath, Actions::Add ); | ||
182 | |||
183 | if ( event.Flags & efswFSEventsModified ) { | ||
184 | sendFileAction( ID, dirPath, filePath, Actions::Modified ); | ||
185 | } | ||
186 | } else { | ||
187 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); | ||
188 | } | ||
189 | } else { | ||
190 | handleAddModDel( event.Flags, event.Path, dirPath, filePath ); | ||
191 | } | ||
192 | } else { | ||
193 | efDEBUG( "Directory: %s changed\n", event.Path.c_str() ); | ||
194 | DirsChanged.insert( event.Path ); | ||
195 | } | ||
196 | } | ||
197 | } | ||
198 | |||
199 | void WatcherFSEvents::process() { | ||
200 | std::set<std::string>::iterator it = DirsChanged.begin(); | ||
201 | |||
202 | for ( ; it != DirsChanged.end(); it++ ) { | ||
203 | if ( !FileWatcherFSEvents::isGranular() ) { | ||
204 | WatcherGen->watchDir( ( *it ) ); | ||
205 | } else { | ||
206 | sendFileAction( ID, FileSystem::pathRemoveFileName( ( *it ) ), | ||
207 | FileSystem::fileNameFromPath( ( *it ) ), Actions::Modified ); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | DirsChanged.clear(); | ||
212 | } | ||
213 | |||
214 | } // namespace efsw | ||
215 | |||
216 | #endif | ||