Scaffold watch package
- SHA
7c88440d41b16bbed0c920949e8e68d5ba2f7a1a- Parents
-
c80e253 - Tree
93c9ab5
7c88440
7c88440d41b16bbed0c920949e8e68d5ba2f7a1ac80e253
93c9ab5| Status | File | + | - |
|---|---|---|---|
| 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 | |