build-files-monitor 0.3.0 → 0.4.0
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/build/files/monitor/handle.rb +23 -6
- data/lib/build/files/monitor/native.rb +54 -0
- data/lib/build/files/monitor/polling.rb +32 -7
- data/lib/build/files/monitor/version.rb +1 -1
- data/lib/build/files/monitor.rb +12 -16
- data/license.md +1 -1
- data/readme.md +28 -15
- data/releases.md +23 -0
- data.tar.gz.sig +0 -0
- metadata +12 -30
- metadata.gz.sig +0 -0
- data/lib/build/files/monitor/fsevent.rb +0 -40
- data/lib/build/files/monitor/inotify.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 435b84b61738b4e31fed992817a7580797c30f2099e1d3e4188e3ce535f92cf0
|
4
|
+
data.tar.gz: ea1f935718b7982f5469a2609603527758b5287f0869058f98d6ba6451fff82b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5efe0b08fd6565f8a9e4b8a6f63839f226b76412854e24b5b65361ce1dc40ae06c63a4da9cdb4fe3fa3bdfdd9378a2de37e78730ff4b20eb095fdddfa5b0343
|
7
|
+
data.tar.gz: 9f628a544ac79fad1d0d908e8f9253c4180ec3cfd54d539fb319f53c297d0d5a626978cde1373df708b96f71fa8ce42e539413f9f4e11c0f12579fe01c7ff201
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -1,30 +1,46 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2021-
|
4
|
+
# Copyright, 2021-2025, by Samuel Williams.
|
5
5
|
|
6
|
-
require
|
6
|
+
require "build/files/state"
|
7
7
|
|
8
8
|
module Build
|
9
9
|
module Files
|
10
10
|
module Monitor
|
11
|
+
# Represents a tracked set of files with an associated callback.
|
12
|
+
#
|
13
|
+
# A handle is created when you call {Polling#track_changes} and connects a set of files to a callback block that fires when changes are detected. The handle maintains the state of monitored files and can be removed from the monitor when no longer needed.
|
11
14
|
class Handle
|
15
|
+
# Initialize a new handle.
|
16
|
+
#
|
17
|
+
# @parameter monitor [Polling] The monitor that owns this handle.
|
18
|
+
# @parameter files [List] The list of files to track.
|
19
|
+
# @parameter block [Proc] The callback to invoke when changes are detected.
|
12
20
|
def initialize(monitor, files, &block)
|
13
21
|
@monitor = monitor
|
14
22
|
@state = State.new(files)
|
15
23
|
@block = block
|
16
24
|
end
|
17
|
-
|
25
|
+
|
26
|
+
# @attribute [Polling] The monitor that owns this handle.
|
18
27
|
attr :monitor
|
19
|
-
|
28
|
+
|
29
|
+
# Update the internal state of tracked files.
|
30
|
+
#
|
31
|
+
# This method forces an update of the file state without invoking the callback.
|
20
32
|
def commit!
|
21
33
|
@state.update!
|
22
34
|
end
|
23
|
-
|
35
|
+
|
36
|
+
# @returns [Array(Path)] The root directories being monitored by this handle.
|
24
37
|
def directories
|
25
38
|
@state.files.roots
|
26
39
|
end
|
27
|
-
|
40
|
+
|
41
|
+
# Remove this handle from the monitor.
|
42
|
+
#
|
43
|
+
# After calling this method, the callback will no longer be invoked when changes are detected.
|
28
44
|
def remove!
|
29
45
|
@monitor.delete(self)
|
30
46
|
end
|
@@ -37,6 +53,7 @@ module Build
|
|
37
53
|
end
|
38
54
|
end
|
39
55
|
|
56
|
+
# @returns [String] A string representation of the handle.
|
40
57
|
def to_s
|
41
58
|
"\#<#{self.class} @state=#{@state} @block=#{@block}>"
|
42
59
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2021-2025, by Samuel Williams.
|
5
|
+
|
6
|
+
require_relative "polling"
|
7
|
+
require "io/watch"
|
8
|
+
|
9
|
+
module Build
|
10
|
+
module Files
|
11
|
+
module Monitor
|
12
|
+
# A platform-specific filesystem monitor using native OS APIs.
|
13
|
+
#
|
14
|
+
# This implementation uses platform-specific APIs (FSEvent on macOS, INotify on Linux) for efficient, event-driven file monitoring. It extends {Polling} but replaces the polling mechanism with native filesystem events.
|
15
|
+
class Native < Polling
|
16
|
+
# Run the monitor using native filesystem events.
|
17
|
+
#
|
18
|
+
# This method blocks until interrupted via `throw :interrupt`. Unlike {Polling#run}, this uses native OS events rather than polling.
|
19
|
+
#
|
20
|
+
# @yields After each filesystem event.
|
21
|
+
def run(**options, &block)
|
22
|
+
catch(:interrupt) do
|
23
|
+
while true
|
24
|
+
run_roots(self.roots, **options, &block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Monitor the specified roots for changes using native events.
|
30
|
+
#
|
31
|
+
# @parameter roots [Array(String)] The root directories to monitor.
|
32
|
+
# @yields {...} After each filesystem event.
|
33
|
+
# @returns [Boolean] True if the set of monitored directories was updated.
|
34
|
+
def run_roots(roots, **options, &block)
|
35
|
+
monitor = IO::Watch::Monitor.new(self.roots, **options)
|
36
|
+
|
37
|
+
monitor.run do |event|
|
38
|
+
if root = event[:root]
|
39
|
+
self.update([root])
|
40
|
+
|
41
|
+
yield if block_given?
|
42
|
+
|
43
|
+
if self.updated
|
44
|
+
return true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
return false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -1,17 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2021-
|
4
|
+
# Copyright, 2021-2025, by Samuel Williams.
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
6
|
+
require "set"
|
7
|
+
require "logger"
|
8
8
|
|
9
|
-
require_relative
|
9
|
+
require_relative "handle"
|
10
10
|
|
11
11
|
module Build
|
12
12
|
module Files
|
13
13
|
module Monitor
|
14
|
+
# A cross-platform filesystem monitor that uses polling to detect changes.
|
15
|
+
#
|
16
|
+
# This implementation works on all platforms by periodically checking file modification times. While less efficient than platform-specific native implementations, it provides a reliable fallback for platforms without native filesystem event support.
|
14
17
|
class Polling
|
18
|
+
# Initialize a new polling monitor.
|
19
|
+
#
|
20
|
+
# @parameter logger [Logger] Optional logger for debugging monitor activity.
|
15
21
|
def initialize(logger: nil)
|
16
22
|
@directories = Hash.new do |hash, key|
|
17
23
|
hash[key] = Set.new
|
@@ -24,6 +30,7 @@ module Build
|
|
24
30
|
@logger = logger || Logger.new(nil)
|
25
31
|
end
|
26
32
|
|
33
|
+
# @attribute [Boolean] Whether the set of monitored directories has been updated.
|
27
34
|
attr :updated
|
28
35
|
|
29
36
|
# Notify the monitor that files in these directories have changed.
|
@@ -44,10 +51,14 @@ module Build
|
|
44
51
|
end
|
45
52
|
end
|
46
53
|
|
54
|
+
# @returns [Array(String)] The root directories currently being monitored.
|
47
55
|
def roots
|
48
56
|
@directories.keys
|
49
57
|
end
|
50
58
|
|
59
|
+
# Delete a handle from the monitor.
|
60
|
+
#
|
61
|
+
# @parameter handle [Handle] The handle to remove.
|
51
62
|
def delete(handle)
|
52
63
|
if @deletions
|
53
64
|
@logger.debug{"Delayed delete handle: #{handle}"}
|
@@ -57,12 +68,22 @@ module Build
|
|
57
68
|
end
|
58
69
|
end
|
59
70
|
|
71
|
+
# Track changes to a set of files.
|
72
|
+
#
|
73
|
+
# @parameter files [List] The list of files to monitor.
|
74
|
+
# @yields {|state| ...} When changes are detected.
|
75
|
+
# @parameter state [State] The current state with information about added, changed, and removed files.
|
76
|
+
# @returns [Handle] A handle that can be used to stop tracking these files.
|
60
77
|
def track_changes(files, &block)
|
61
78
|
handle = Handle.new(self, files, &block)
|
62
79
|
|
63
80
|
add(handle)
|
64
81
|
end
|
65
82
|
|
83
|
+
# Add a handle to the monitor.
|
84
|
+
#
|
85
|
+
# @parameter handle [Handle] The handle to add.
|
86
|
+
# @returns [Handle] The added handle.
|
66
87
|
def add(handle)
|
67
88
|
@logger.debug{"Adding handle: #{handle}"}
|
68
89
|
|
@@ -82,9 +103,13 @@ module Build
|
|
82
103
|
handle
|
83
104
|
end
|
84
105
|
|
85
|
-
|
86
|
-
|
87
|
-
|
106
|
+
# Run the monitor loop, checking for changes at regular intervals.
|
107
|
+
#
|
108
|
+
# This method blocks until interrupted via `throw :interrupt`. It continuously polls the filesystem for changes and invokes registered callbacks.
|
109
|
+
#
|
110
|
+
# @parameter latency [Numeric] The time in seconds to wait between checks (default: 0.1).
|
111
|
+
# @yields After each check cycle.
|
112
|
+
def run(latency: 0.1, **options, &block)
|
88
113
|
catch(:interrupt) do
|
89
114
|
while true
|
90
115
|
self.update(self.roots)
|
data/lib/build/files/monitor.rb
CHANGED
@@ -1,27 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2021-
|
4
|
+
# Copyright, 2021-2025, by Samuel Williams.
|
5
5
|
|
6
|
+
require_relative "monitor/native"
|
7
|
+
|
8
|
+
# @namespace
|
6
9
|
module Build
|
10
|
+
# @namespace
|
7
11
|
module Files
|
12
|
+
# @namespace
|
8
13
|
module Monitor
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
when /darwin/i
|
15
|
-
require_relative 'monitor/fsevent'
|
16
|
-
Native = FSEvent
|
17
|
-
Default = Native
|
18
|
-
else
|
19
|
-
require_relative 'monitor/polling'
|
20
|
-
Default = Polling
|
21
|
-
end
|
22
|
-
|
14
|
+
# Create a new monitor instance.
|
15
|
+
#
|
16
|
+
# This factory method creates a monitor that uses platform-specific native filesystem event APIs (FSEvent on macOS, INotify on Linux, etc.) via the `io-watch` gem for efficient, event-driven file monitoring.
|
17
|
+
#
|
18
|
+
# @returns [Native] A new native monitor instance.
|
23
19
|
def self.new(*arguments, **options)
|
24
|
-
|
20
|
+
Native.new(*arguments, **options)
|
25
21
|
end
|
26
22
|
end
|
27
23
|
end
|
data/license.md
CHANGED
data/readme.md
CHANGED
@@ -6,22 +6,35 @@ Efficiently monitor the filesystem for changes.
|
|
6
6
|
|
7
7
|
## Usage
|
8
8
|
|
9
|
-
|
10
|
-
require 'build/files/path'
|
11
|
-
require 'build/files/directory'
|
12
|
-
require 'build/files/monitor'
|
9
|
+
Please see the [project documentation](https://ioquatix.github.io/build-files-monitor/) for more details.
|
13
10
|
|
14
|
-
|
11
|
+
- [Getting Started](https://ioquatix.github.io/build-files-monitor/guides/getting-started/index) - This guide explains how to use `build-files-monitor` to efficiently monitor the filesystem for changes.
|
15
12
|
|
16
|
-
|
17
|
-
directory = Build::Files::Directory.new(root)
|
13
|
+
## Releases
|
18
14
|
|
19
|
-
monitor
|
20
|
-
pp state.added
|
21
|
-
end
|
15
|
+
Please see the [project releases](https://ioquatix.github.io/build-files-monitor/releases/index) for all releases.
|
22
16
|
|
23
|
-
|
24
|
-
|
17
|
+
### v0.4.0
|
18
|
+
|
19
|
+
- Use `io-watch` for filesystem monitoring.
|
20
|
+
|
21
|
+
### v0.3.0
|
22
|
+
|
23
|
+
- Internal refactoring.
|
24
|
+
|
25
|
+
### v0.2.1
|
26
|
+
|
27
|
+
- Fixed compatibility of keyword arguments in `Monitor.new` to properly forward both positional and keyword arguments.
|
28
|
+
|
29
|
+
### v0.2.0
|
30
|
+
|
31
|
+
- Moved `State` class to `build-files` gem. Users should now `require 'build/files/state'` instead of `require 'build/files/monitor/state'`.
|
32
|
+
|
33
|
+
### v0.1.0
|
34
|
+
|
35
|
+
- Initial release.
|
36
|
+
- Support for filesystem monitoring with platform-specific implementations (`Build::Files::Monitor::Native` using FSEvent/INotify).
|
37
|
+
- Fallback polling implementation (`Build::Files::Monitor::Polling`).
|
25
38
|
|
26
39
|
## Contributing
|
27
40
|
|
@@ -35,8 +48,8 @@ We welcome contributions to this project.
|
|
35
48
|
|
36
49
|
### Developer Certificate of Origin
|
37
50
|
|
38
|
-
|
51
|
+
In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
|
39
52
|
|
40
|
-
###
|
53
|
+
### Community Guidelines
|
41
54
|
|
42
|
-
This project is
|
55
|
+
This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers.
|
data/releases.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Releases
|
2
|
+
|
3
|
+
## v0.4.0
|
4
|
+
|
5
|
+
- Use `io-watch` for filesystem monitoring.
|
6
|
+
|
7
|
+
## v0.3.0
|
8
|
+
|
9
|
+
- Internal refactoring.
|
10
|
+
|
11
|
+
## v0.2.1
|
12
|
+
|
13
|
+
- Fixed compatibility of keyword arguments in `Monitor.new` to properly forward both positional and keyword arguments.
|
14
|
+
|
15
|
+
## v0.2.0
|
16
|
+
|
17
|
+
- Moved `State` class to `build-files` gem. Users should now `require 'build/files/state'` instead of `require 'build/files/monitor/state'`.
|
18
|
+
|
19
|
+
## v0.1.0
|
20
|
+
|
21
|
+
- Initial release.
|
22
|
+
- Support for filesystem monitoring with platform-specific implementations (`Build::Files::Monitor::Native` using FSEvent/INotify).
|
23
|
+
- Fallback polling implementation (`Build::Files::Monitor::Polling`).
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: build-files-monitor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain:
|
11
10
|
- |
|
@@ -37,7 +36,7 @@ cert_chain:
|
|
37
36
|
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
38
37
|
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
39
38
|
-----END CERTIFICATE-----
|
40
|
-
date:
|
39
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
41
40
|
dependencies:
|
42
41
|
- !ruby/object:Gem::Dependency
|
43
42
|
name: build-files
|
@@ -54,54 +53,38 @@ dependencies:
|
|
54
53
|
- !ruby/object:Gem::Version
|
55
54
|
version: '1.8'
|
56
55
|
- !ruby/object:Gem::Dependency
|
57
|
-
name:
|
56
|
+
name: io-watch
|
58
57
|
requirement: !ruby/object:Gem::Requirement
|
59
58
|
requirements:
|
60
|
-
- - "
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
version: '0'
|
63
|
-
type: :runtime
|
64
|
-
prerelease: false
|
65
|
-
version_requirements: !ruby/object:Gem::Requirement
|
66
|
-
requirements:
|
67
|
-
- - ">="
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '0'
|
70
|
-
- !ruby/object:Gem::Dependency
|
71
|
-
name: rb-inotify
|
72
|
-
requirement: !ruby/object:Gem::Requirement
|
73
|
-
requirements:
|
74
|
-
- - ">="
|
59
|
+
- - "~>"
|
75
60
|
- !ruby/object:Gem::Version
|
76
|
-
version: '0'
|
61
|
+
version: '0.2'
|
77
62
|
type: :runtime
|
78
63
|
prerelease: false
|
79
64
|
version_requirements: !ruby/object:Gem::Requirement
|
80
65
|
requirements:
|
81
|
-
- - "
|
66
|
+
- - "~>"
|
82
67
|
- !ruby/object:Gem::Version
|
83
|
-
version: '0'
|
84
|
-
description:
|
85
|
-
email:
|
68
|
+
version: '0.2'
|
86
69
|
executables: []
|
87
70
|
extensions: []
|
88
71
|
extra_rdoc_files: []
|
89
72
|
files:
|
90
73
|
- lib/build/files/monitor.rb
|
91
|
-
- lib/build/files/monitor/fsevent.rb
|
92
74
|
- lib/build/files/monitor/handle.rb
|
93
|
-
- lib/build/files/monitor/
|
75
|
+
- lib/build/files/monitor/native.rb
|
94
76
|
- lib/build/files/monitor/polling.rb
|
95
77
|
- lib/build/files/monitor/version.rb
|
96
78
|
- license.md
|
97
79
|
- readme.md
|
80
|
+
- releases.md
|
98
81
|
homepage: https://github.com/ioquatix/build-files-monitor
|
99
82
|
licenses:
|
100
83
|
- MIT
|
101
84
|
metadata:
|
85
|
+
documentation_uri: https://ioquatix.github.io/build-files-monitor/
|
102
86
|
funding_uri: https://github.com/sponsors/ioquatix/
|
103
87
|
source_code_uri: https://github.com/ioquatix/build-files-monitor.git
|
104
|
-
post_install_message:
|
105
88
|
rdoc_options: []
|
106
89
|
require_paths:
|
107
90
|
- lib
|
@@ -109,15 +92,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
109
92
|
requirements:
|
110
93
|
- - ">="
|
111
94
|
- !ruby/object:Gem::Version
|
112
|
-
version: '3.
|
95
|
+
version: '3.2'
|
113
96
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
97
|
requirements:
|
115
98
|
- - ">="
|
116
99
|
- !ruby/object:Gem::Version
|
117
100
|
version: '0'
|
118
101
|
requirements: []
|
119
|
-
rubygems_version: 3.
|
120
|
-
signing_key:
|
102
|
+
rubygems_version: 3.6.9
|
121
103
|
specification_version: 4
|
122
104
|
summary: Efficiently monitor changes to the file system.
|
123
105
|
test_files: []
|
metadata.gz.sig
CHANGED
Binary file
|
@@ -1,40 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Released under the MIT License.
|
4
|
-
# Copyright, 2021-2024, by Samuel Williams.
|
5
|
-
|
6
|
-
require_relative 'polling'
|
7
|
-
|
8
|
-
require 'rb-fsevent'
|
9
|
-
|
10
|
-
module Build
|
11
|
-
module Files
|
12
|
-
module Monitor
|
13
|
-
class FSEvent < Polling
|
14
|
-
def run(**options, &block)
|
15
|
-
notifier = ::FSEvent.new
|
16
|
-
|
17
|
-
catch(:interrupt) do
|
18
|
-
while true
|
19
|
-
notifier.watch(self.roots) do |directories|
|
20
|
-
directories.collect! do |directory|
|
21
|
-
File.expand_path(directory)
|
22
|
-
end
|
23
|
-
|
24
|
-
self.update(directories)
|
25
|
-
|
26
|
-
yield if block_given?
|
27
|
-
|
28
|
-
if self.updated
|
29
|
-
notifier.stop
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
notifier.run
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Released under the MIT License.
|
4
|
-
# Copyright, 2021-2024, by Samuel Williams.
|
5
|
-
|
6
|
-
require_relative 'polling'
|
7
|
-
|
8
|
-
require 'rb-inotify'
|
9
|
-
|
10
|
-
module Build
|
11
|
-
module Files
|
12
|
-
module Monitor
|
13
|
-
class INotify < Polling
|
14
|
-
def run(**options, &block)
|
15
|
-
notifier = ::INotify::Notifier.new
|
16
|
-
|
17
|
-
catch(:interrupt) do
|
18
|
-
while true
|
19
|
-
self.roots.each do |root|
|
20
|
-
notifier.watch root, :create, :modify, :attrib, :delete do |event|
|
21
|
-
self.update([root])
|
22
|
-
|
23
|
-
yield if block_given?
|
24
|
-
|
25
|
-
if self.updated
|
26
|
-
notifier.stop
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
notifier.run
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|