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
18
 implicit-typing = false
18
 implicit-typing = false
19
 implicit-external = false
19
 implicit-external = false
20
 source-form = "free"
20
 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 @@
1
 module fgof_devloop
1
 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
2
   use fgof_devloop_types, only : &
10
   use fgof_devloop_types, only : &
3
     FGOF_DEVLOOP_DECISION_IDLE, &
11
     FGOF_DEVLOOP_DECISION_IDLE, &
4
     FGOF_DEVLOOP_DECISION_RESTART, &
12
     FGOF_DEVLOOP_DECISION_RESTART, &
@@ -12,7 +20,8 @@ module fgof_devloop
12
     devloop_decision, &
20
     devloop_decision, &
13
     devloop_options, &
21
     devloop_options, &
14
     devloop_state, &
22
     devloop_state, &
15
-    devloop_trigger
23
+    devloop_trigger, &
24
+    devloop_watch_summary
16
   implicit none
25
   implicit none
17
   private
26
   private
18
 
27
 
@@ -24,6 +33,7 @@ module fgof_devloop
24
   public :: clear_devloop_options
33
   public :: clear_devloop_options
25
   public :: clear_devloop_state
34
   public :: clear_devloop_state
26
   public :: clear_devloop_trigger
35
   public :: clear_devloop_trigger
36
+  public :: clear_devloop_watch_summary
27
   public :: devloop_backend_name
37
   public :: devloop_backend_name
28
   public :: devloop_change_trigger
38
   public :: devloop_change_trigger
29
   public :: devloop_cycle
39
   public :: devloop_cycle
@@ -32,7 +42,12 @@ module fgof_devloop
32
   public :: devloop_options
42
   public :: devloop_options
33
   public :: devloop_start_trigger
43
   public :: devloop_start_trigger
34
   public :: devloop_state
44
   public :: devloop_state
45
+  public :: devloop_summarize_watch_events
35
   public :: devloop_trigger
46
   public :: devloop_trigger
47
+  public :: devloop_watch_failure_summary
48
+  public :: devloop_watch_options
49
+  public :: devloop_watch_summary
50
+  public :: devloop_watch_trigger
36
   public :: finish_devloop_cycle
51
   public :: finish_devloop_cycle
37
   public :: FGOF_DEVLOOP_DECISION_IDLE
52
   public :: FGOF_DEVLOOP_DECISION_IDLE
38
   public :: FGOF_DEVLOOP_DECISION_RESTART
53
   public :: FGOF_DEVLOOP_DECISION_RESTART
@@ -53,8 +68,12 @@ contains
53
 
68
 
54
     options%run_on_start = .true.
69
     options%run_on_start = .true.
55
     options%restart_on_change = .true.
70
     options%restart_on_change = .true.
71
+    options%restart_on_directory_change = .true.
72
+    options%ignore_hidden = .false.
56
     options%stop_on_failure = .false.
73
     options%stop_on_failure = .false.
57
     options%max_failures = 0
74
     options%max_failures = 0
75
+    options%min_restart_changes = 1
76
+    options%debounce_polls = 0
58
   end function clear_devloop_options
77
   end function clear_devloop_options
59
 
78
 
60
   function clear_devloop_trigger() result(trigger)
79
   function clear_devloop_trigger() result(trigger)
@@ -89,6 +108,24 @@ contains
89
     decision%reason = ""
108
     decision%reason = ""
90
   end function clear_devloop_decision
109
   end function clear_devloop_decision
91
 
110
 
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
+
92
   function clear_devloop_state() result(state)
129
   function clear_devloop_state() result(state)
93
     type(devloop_state) :: state
130
     type(devloop_state) :: state
94
 
131
 
@@ -165,6 +202,96 @@ contains
165
     end if
202
     end if
166
   end function devloop_manual_trigger
203
   end function devloop_manual_trigger
167
 
204
 
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
+
168
   function begin_devloop_cycle(state, trigger) result(cycle)
295
   function begin_devloop_cycle(state, trigger) result(cycle)
169
     type(devloop_state), intent(inout) :: state
296
     type(devloop_state), intent(inout) :: state
170
     type(devloop_trigger), intent(in) :: trigger
297
     type(devloop_trigger), intent(in) :: trigger
@@ -239,6 +366,8 @@ contains
239
     type(devloop_options), intent(inout) :: options
366
     type(devloop_options), intent(inout) :: options
240
 
367
 
241
     if (options%max_failures < 0) options%max_failures = 0
368
     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
242
   end subroutine normalize_options
371
   end subroutine normalize_options
243
 
372
 
244
   logical function failure_limit_reached(state) result(reached)
373
   logical function failure_limit_reached(state) result(reached)
src/fgof_devloop_types.f90modified
@@ -14,8 +14,12 @@ module fgof_devloop_types
14
   type, public :: devloop_options
14
   type, public :: devloop_options
15
     logical :: run_on_start = .true.
15
     logical :: run_on_start = .true.
16
     logical :: restart_on_change = .true.
16
     logical :: restart_on_change = .true.
17
+    logical :: restart_on_directory_change = .true.
18
+    logical :: ignore_hidden = .false.
17
     logical :: stop_on_failure = .false.
19
     logical :: stop_on_failure = .false.
18
     integer :: max_failures = 0
20
     integer :: max_failures = 0
21
+    integer :: min_restart_changes = 1
22
+    integer :: debounce_polls = 0
19
   end type devloop_options
23
   end type devloop_options
20
 
24
 
21
   type, public :: devloop_trigger
25
   type, public :: devloop_trigger
@@ -44,6 +48,22 @@ module fgof_devloop_types
44
     character(len=:), allocatable :: reason
48
     character(len=:), allocatable :: reason
45
   end type devloop_decision
49
   end type devloop_decision
46
 
50
 
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
+
47
   type, public :: devloop_state
67
   type, public :: devloop_state
48
     type(devloop_options) :: options
68
     type(devloop_options) :: options
49
     type(devloop_cycle) :: last_cycle
69
     type(devloop_cycle) :: last_cycle