fortrangoingonforty/fgof-watch / 7c88440

Browse files

Scaffold watch package

Authored by espadonne
SHA
7c88440d41b16bbed0c920949e8e68d5ba2f7a1a
Parents
c80e253
Tree
93c9ab5

5 changed files

StatusFile+-
A README.md 47 0
A fpm.toml 20 0
A src/fgof_watch.f90 48 0
A src/fgof_watch_types.f90 26 0
A test/test_scaffold.f90 27 0
README.mdadded
@@ -0,0 +1,47 @@
1
+# fgof-watch
2
+
3
+Portable file watching helpers for modern Fortran tools.
4
+
5
+`fgof-watch` is intended to be a small, standalone library for directory and file watching in shells, editors, live-reload tools, sync utilities, and developer loops.
6
+
7
+It is part of the [FortranGoingOnForty lib-modules](https://github.com/FortranGoingOnForty/lib-modules) catalog, but it is intended to stand on its own as a normal `fpm` package.
8
+
9
+Current v1 target:
10
+
11
+- high-level watch-session API
12
+- portable polling backend as a dependable baseline
13
+- normalized events for create, modify, remove, and move
14
+- room for future native backends without breaking callers
15
+- clean composition with `fgof-process` and future `fgof-devloop`
16
+
17
+## Status
18
+
19
+Initial scaffold is in place.
20
+
21
+Implemented today:
22
+
23
+- public `fgof_watch` and `fgof_watch_types` modules
24
+- baseline watch-session, watch-options, and watch-event types
25
+- minimal initialization, reset, and polling helpers
26
+- smoke-test coverage
27
+
28
+Still to implement:
29
+
30
+- real directory snapshots and change detection
31
+- recursive traversal and filtering
32
+- debounce, coalescing, and native backend strategy
33
+
34
+## Build And Test
35
+
36
+```bash
37
+fpm test
38
+```
39
+
40
+## Supported Platforms
41
+
42
+- macOS
43
+- Linux
44
+
45
+## License
46
+
47
+MIT
fpm.tomladded
@@ -0,0 +1,20 @@
1
+name = "fgof-watch"
2
+version = "0.1.0"
3
+license = "MIT"
4
+author = "FortranGoingOnForty"
5
+maintainer = "FortranGoingOnForty"
6
+copyright = "2026"
7
+description = "Portable file watching helpers for modern Fortran tools"
8
+
9
+[build]
10
+auto-executables = false
11
+auto-tests = true
12
+auto-examples = false
13
+
14
+[install]
15
+library = true
16
+
17
+[fortran]
18
+implicit-typing = false
19
+implicit-external = false
20
+source-form = "free"
src/fgof_watch.f90added
@@ -0,0 +1,48 @@
1
+module fgof_watch
2
+  use fgof_watch_types, only : FGOF_WATCH_EVT_NONE, watch_event, watch_options, watch_session
3
+  implicit none
4
+  private
5
+
6
+  public :: init_watch
7
+  public :: poll_watch
8
+  public :: reset_watch
9
+
10
+contains
11
+
12
+  subroutine init_watch(session, root, options)
13
+    type(watch_session), intent(out) :: session
14
+    character(len=*), intent(in) :: root
15
+    type(watch_options), intent(in), optional :: options
16
+
17
+    if (present(options)) then
18
+      session%options = options
19
+    end if
20
+
21
+    session%root = root
22
+    session%active = len_trim(root) > 0
23
+  end subroutine init_watch
24
+
25
+  function poll_watch(session) result(event)
26
+    type(watch_session), intent(in) :: session
27
+    type(watch_event) :: event
28
+
29
+    event%kind = FGOF_WATCH_EVT_NONE
30
+    if (allocated(session%root)) then
31
+      event%path = session%root
32
+    else
33
+      event%path = ""
34
+    end if
35
+  end function poll_watch
36
+
37
+  subroutine reset_watch(session)
38
+    type(watch_session), intent(inout) :: session
39
+
40
+    if (allocated(session%root)) then
41
+      deallocate(session%root)
42
+    end if
43
+
44
+    session%options = watch_options()
45
+    session%active = .false.
46
+  end subroutine reset_watch
47
+
48
+end module fgof_watch
src/fgof_watch_types.f90added
@@ -0,0 +1,26 @@
1
+module fgof_watch_types
2
+  implicit none
3
+  private
4
+
5
+  integer, parameter, public :: FGOF_WATCH_EVT_NONE = 0
6
+
7
+  public :: watch_event
8
+  public :: watch_options
9
+  public :: watch_session
10
+
11
+  type :: watch_event
12
+    integer :: kind = FGOF_WATCH_EVT_NONE
13
+    character(len=:), allocatable :: path
14
+  end type watch_event
15
+
16
+  type :: watch_options
17
+    integer :: poll_interval_ms = 250
18
+    logical :: recursive = .true.
19
+  end type watch_options
20
+
21
+  type :: watch_session
22
+    character(len=:), allocatable :: root
23
+    type(watch_options) :: options
24
+    logical :: active = .false.
25
+  end type watch_session
26
+end module fgof_watch_types
test/test_scaffold.f90added
@@ -0,0 +1,27 @@
1
+program test_scaffold
2
+  use fgof_watch, only : init_watch, poll_watch, reset_watch
3
+  use fgof_watch_types, only : FGOF_WATCH_EVT_NONE, watch_event, watch_options, watch_session
4
+  implicit none
5
+
6
+  type(watch_event) :: event
7
+  type(watch_options) :: options
8
+  type(watch_session) :: session
9
+
10
+  options = watch_options(poll_interval_ms=100, recursive=.false.)
11
+  call init_watch(session, "src", options)
12
+
13
+  if (.not. session%active) error stop "watch session should be active"
14
+  if (.not. allocated(session%root)) error stop "watch root should be allocated"
15
+  if (session%root /= "src") error stop "watch root should match init input"
16
+  if (session%options%poll_interval_ms /= 100) error stop "poll interval should be stored"
17
+  if (session%options%recursive) error stop "recursive flag should follow options"
18
+
19
+  event = poll_watch(session)
20
+  if (event%kind /= FGOF_WATCH_EVT_NONE) error stop "scaffold poll should report none"
21
+  if (.not. allocated(event%path)) error stop "scaffold poll should return a path"
22
+  if (event%path /= "src") error stop "scaffold poll should echo root path"
23
+
24
+  call reset_watch(session)
25
+  if (session%active) error stop "reset should deactivate session"
26
+  if (allocated(session%root)) error stop "reset should clear root path"
27
+end program test_scaffold