fortrangoingonforty/fgof-devloop / c5b2e60

Browse files

Add devloop watch integration

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
c5b2e601fb0b37822bd7626dff53a91a7a7f2338
Parents
0ff2819
Tree
31ffc78

3 changed files

StatusFile+-
M fpm.toml 3 0
M src/fgof_devloop.f90 130 1
M src/fgof_devloop_types.f90 20 0
fpm.tomlmodified
@@ -18,3 +18,6 @@ library = true
1818
 implicit-typing = false
1919
 implicit-external = false
2020
 source-form = "free"
21
+
22
+[dependencies]
23
+fgof-watch = { git = "https://github.com/FortranGoingOnForty/fgof-watch.git", tag = "v0.1.0" }
src/fgof_devloop.f90modified
@@ -1,4 +1,12 @@
11
 module fgof_devloop
2
+  use fgof_watch_types, only : &
3
+    FGOF_WATCH_EVT_CREATED, &
4
+    FGOF_WATCH_EVT_MODIFIED, &
5
+    FGOF_WATCH_EVT_MOVED, &
6
+    FGOF_WATCH_EVT_NONE, &
7
+    FGOF_WATCH_EVT_REMOVED, &
8
+    watch_event, &
9
+    watch_options
210
   use fgof_devloop_types, only : &
311
     FGOF_DEVLOOP_DECISION_IDLE, &
412
     FGOF_DEVLOOP_DECISION_RESTART, &
@@ -12,7 +20,8 @@ module fgof_devloop
1220
     devloop_decision, &
1321
     devloop_options, &
1422
     devloop_state, &
15
-    devloop_trigger
23
+    devloop_trigger, &
24
+    devloop_watch_summary
1625
   implicit none
1726
   private
1827
 
@@ -24,6 +33,7 @@ module fgof_devloop
2433
   public :: clear_devloop_options
2534
   public :: clear_devloop_state
2635
   public :: clear_devloop_trigger
36
+  public :: clear_devloop_watch_summary
2737
   public :: devloop_backend_name
2838
   public :: devloop_change_trigger
2939
   public :: devloop_cycle
@@ -32,7 +42,12 @@ module fgof_devloop
3242
   public :: devloop_options
3343
   public :: devloop_start_trigger
3444
   public :: devloop_state
45
+  public :: devloop_summarize_watch_events
3546
   public :: devloop_trigger
47
+  public :: devloop_watch_failure_summary
48
+  public :: devloop_watch_options
49
+  public :: devloop_watch_summary
50
+  public :: devloop_watch_trigger
3651
   public :: finish_devloop_cycle
3752
   public :: FGOF_DEVLOOP_DECISION_IDLE
3853
   public :: FGOF_DEVLOOP_DECISION_RESTART
@@ -53,8 +68,12 @@ contains
5368
 
5469
     options%run_on_start = .true.
5570
     options%restart_on_change = .true.
71
+    options%restart_on_directory_change = .true.
72
+    options%ignore_hidden = .false.
5673
     options%stop_on_failure = .false.
5774
     options%max_failures = 0
75
+    options%min_restart_changes = 1
76
+    options%debounce_polls = 0
5877
   end function clear_devloop_options
5978
 
6079
   function clear_devloop_trigger() result(trigger)
@@ -89,6 +108,24 @@ contains
89108
     decision%reason = ""
90109
   end function clear_devloop_decision
91110
 
111
+  function clear_devloop_watch_summary() result(summary)
112
+    type(devloop_watch_summary) :: summary
113
+
114
+    summary%event_count = 0
115
+    summary%change_count = 0
116
+    summary%file_change_count = 0
117
+    summary%directory_change_count = 0
118
+    summary%created_count = 0
119
+    summary%modified_count = 0
120
+    summary%removed_count = 0
121
+    summary%moved_count = 0
122
+    summary%ignored_none_count = 0
123
+    summary%watch_error_code = 0
124
+    summary%has_changes = .false.
125
+    summary%watch_failed = .false.
126
+    summary%watch_error_message = ""
127
+  end function clear_devloop_watch_summary
128
+
92129
   function clear_devloop_state() result(state)
93130
     type(devloop_state) :: state
94131
 
@@ -165,6 +202,96 @@ contains
165202
     end if
166203
   end function devloop_manual_trigger
167204
 
205
+  function devloop_summarize_watch_events(events) result(summary)
206
+    type(watch_event), intent(in) :: events(:)
207
+    type(devloop_watch_summary) :: summary
208
+    integer :: index_value
209
+
210
+    summary = clear_devloop_watch_summary()
211
+    summary%event_count = size(events)
212
+
213
+    do index_value = 1, size(events)
214
+      select case (events(index_value)%kind)
215
+      case (FGOF_WATCH_EVT_CREATED)
216
+        summary%created_count = summary%created_count + 1
217
+      case (FGOF_WATCH_EVT_MODIFIED)
218
+        summary%modified_count = summary%modified_count + 1
219
+      case (FGOF_WATCH_EVT_REMOVED)
220
+        summary%removed_count = summary%removed_count + 1
221
+      case (FGOF_WATCH_EVT_MOVED)
222
+        summary%moved_count = summary%moved_count + 1
223
+      case default
224
+        summary%ignored_none_count = summary%ignored_none_count + 1
225
+        cycle
226
+      end select
227
+
228
+      summary%change_count = summary%change_count + 1
229
+      if (events(index_value)%is_directory) then
230
+        summary%directory_change_count = summary%directory_change_count + 1
231
+      else
232
+        summary%file_change_count = summary%file_change_count + 1
233
+      end if
234
+    end do
235
+
236
+    summary%has_changes = summary%change_count > 0
237
+  end function devloop_summarize_watch_events
238
+
239
+  function devloop_watch_failure_summary(error_code, message) result(summary)
240
+    integer, intent(in) :: error_code
241
+    character(len=*), intent(in) :: message
242
+    type(devloop_watch_summary) :: summary
243
+
244
+    summary = clear_devloop_watch_summary()
245
+    summary%watch_error_code = error_code
246
+    summary%watch_failed = error_code /= 0
247
+    summary%watch_error_message = message
248
+  end function devloop_watch_failure_summary
249
+
250
+  function devloop_watch_options(options) result(watch_config)
251
+    type(devloop_options), intent(in), optional :: options
252
+    type(watch_options) :: watch_config
253
+    type(devloop_options) :: local_options
254
+
255
+    local_options = clear_devloop_options()
256
+    if (present(options)) local_options = options
257
+    call normalize_options(local_options)
258
+
259
+    watch_config = watch_options()
260
+    watch_config%debounce_polls = local_options%debounce_polls
261
+    watch_config%ignore_hidden = local_options%ignore_hidden
262
+    watch_config%emit_directory_events = local_options%restart_on_directory_change
263
+  end function devloop_watch_options
264
+
265
+  function devloop_watch_trigger(summary, options, reason) result(trigger)
266
+    type(devloop_watch_summary), intent(in) :: summary
267
+    type(devloop_options), intent(in), optional :: options
268
+    character(len=*), intent(in), optional :: reason
269
+    type(devloop_trigger) :: trigger
270
+    type(devloop_options) :: local_options
271
+    integer :: effective_change_count
272
+
273
+    trigger = clear_devloop_trigger()
274
+    if (summary%watch_failed) return
275
+    if (.not. summary%has_changes) return
276
+
277
+    local_options = clear_devloop_options()
278
+    if (present(options)) local_options = options
279
+    call normalize_options(local_options)
280
+
281
+    effective_change_count = summary%change_count
282
+    if (.not. local_options%restart_on_directory_change) then
283
+      effective_change_count = summary%file_change_count
284
+    end if
285
+
286
+    if (effective_change_count < local_options%min_restart_changes) return
287
+
288
+    if (present(reason)) then
289
+      trigger = devloop_change_trigger(effective_change_count, reason)
290
+    else
291
+      trigger = devloop_change_trigger(effective_change_count, "watch")
292
+    end if
293
+  end function devloop_watch_trigger
294
+
168295
   function begin_devloop_cycle(state, trigger) result(cycle)
169296
     type(devloop_state), intent(inout) :: state
170297
     type(devloop_trigger), intent(in) :: trigger
@@ -239,6 +366,8 @@ contains
239366
     type(devloop_options), intent(inout) :: options
240367
 
241368
     if (options%max_failures < 0) options%max_failures = 0
369
+    if (options%min_restart_changes < 1) options%min_restart_changes = 1
370
+    if (options%debounce_polls < 0) options%debounce_polls = 0
242371
   end subroutine normalize_options
243372
 
244373
   logical function failure_limit_reached(state) result(reached)
src/fgof_devloop_types.f90modified
@@ -14,8 +14,12 @@ module fgof_devloop_types
1414
   type, public :: devloop_options
1515
     logical :: run_on_start = .true.
1616
     logical :: restart_on_change = .true.
17
+    logical :: restart_on_directory_change = .true.
18
+    logical :: ignore_hidden = .false.
1719
     logical :: stop_on_failure = .false.
1820
     integer :: max_failures = 0
21
+    integer :: min_restart_changes = 1
22
+    integer :: debounce_polls = 0
1923
   end type devloop_options
2024
 
2125
   type, public :: devloop_trigger
@@ -44,6 +48,22 @@ module fgof_devloop_types
4448
     character(len=:), allocatable :: reason
4549
   end type devloop_decision
4650
 
51
+  type, public :: devloop_watch_summary
52
+    integer :: event_count = 0
53
+    integer :: change_count = 0
54
+    integer :: file_change_count = 0
55
+    integer :: directory_change_count = 0
56
+    integer :: created_count = 0
57
+    integer :: modified_count = 0
58
+    integer :: removed_count = 0
59
+    integer :: moved_count = 0
60
+    integer :: ignored_none_count = 0
61
+    integer :: watch_error_code = 0
62
+    logical :: has_changes = .false.
63
+    logical :: watch_failed = .false.
64
+    character(len=:), allocatable :: watch_error_message
65
+  end type devloop_watch_summary
66
+
4767
   type, public :: devloop_state
4868
     type(devloop_options) :: options
4969
     type(devloop_cycle) :: last_cycle