fortrangoingonforty/fgof-process / 02c19e3

Browse files

Initial fgof-process scaffold

Authored by espadonne
SHA
02c19e3e7ba4d36cb320c92799347a2682446cf2
Tree
21c0fd5

7 changed files

StatusFile+-
A .gitignore 2 0
A LICENSE 21 0
A README.md 62 0
A docs/ROADMAP.md 23 0
A fpm.toml 20 0
A src/fgof_process.f90 88 0
A test/test_command.f90 15 0
.gitignoreadded
@@ -0,0 +1,2 @@
1
+build/
2
+.DS_Store
LICENSEadded
@@ -0,0 +1,21 @@
1
+MIT License
2
+
3
+Copyright (c) 2026 FortranGoingOnForty
4
+
5
+Permission is hereby granted, free of charge, to any person obtaining a copy
6
+of this software and associated documentation files (the "Software"), to deal
7
+in the Software without restriction, including without limitation the rights
8
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+copies of the Software, and to permit persons to whom the Software is
10
+furnished to do so, subject to the following conditions:
11
+
12
+The above copyright notice and this permission notice shall be included in all
13
+copies or substantial portions of the Software.
14
+
15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+SOFTWARE.
README.mdadded
@@ -0,0 +1,62 @@
1
+# fgof-process
2
+
3
+POSIX-first process and subprocess helpers for modern Fortran applications.
4
+
5
+`fgof-process` is intended to be a small, standalone library that gives Fortran tools a more ergonomic process API than raw `execute_command_line` or ad hoc C interop.
6
+
7
+Initial scope:
8
+
9
+- argv-first command construction
10
+- synchronous process execution
11
+- environment overrides
12
+- working-directory overrides
13
+- stdout and stderr capture
14
+- exit-status reporting
15
+- timeout-aware execution
16
+
17
+Future scope:
18
+
19
+- streaming process handles
20
+- async spawn and wait
21
+- signal helpers
22
+- PTY-friendly integration points for a future `fgof-pty`
23
+
24
+## Status
25
+
26
+Early scaffold.
27
+
28
+This repository is being created as the first package in the FortranGoingOnForty reusable library family and is intended to be consumed standalone or via the umbrella catalog repo at `lib-modules`.
29
+
30
+## Package Goals
31
+
32
+- keep the API small and predictable
33
+- prefer argv-based execution over shell-string execution
34
+- make tests easy to write
35
+- stay useful for shells, editors, TUI apps, and developer tooling
36
+
37
+## Planned API Shape
38
+
39
+Primary module:
40
+
41
+- `fgof_process`
42
+
43
+Initial public types:
44
+
45
+- `process_command`
46
+- `process_result`
47
+- `process_options`
48
+
49
+Initial public procedures:
50
+
51
+- `command`
52
+- `run`
53
+
54
+## Development Notes
55
+
56
+- POSIX first: macOS and Linux
57
+- standalone `fpm` package
58
+- intended to remain independently versioned and releasable
59
+
60
+## License
61
+
62
+TBD
docs/ROADMAP.mdadded
@@ -0,0 +1,23 @@
1
+# Roadmap
2
+
3
+## v0.1
4
+
5
+- establish standalone repo and `fpm` package
6
+- define initial public types
7
+- implement argv-first command construction
8
+- implement synchronous `run`
9
+- add basic tests
10
+
11
+## v0.2
12
+
13
+- stdout and stderr capture
14
+- cwd and env overrides
15
+- timeout handling
16
+- richer errors
17
+
18
+## v0.3
19
+
20
+- async spawn or wait
21
+- process handles
22
+- kill and terminate helpers
23
+- integration-test utilities
fpm.tomladded
@@ -0,0 +1,20 @@
1
+name = "fgof-process"
2
+version = "0.1.0"
3
+license = "MIT"
4
+author = "FortranGoingOnForty"
5
+maintainer = "FortranGoingOnForty"
6
+copyright = "2026"
7
+description = "POSIX-first process and subprocess helpers for modern Fortran applications"
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_process.f90added
@@ -0,0 +1,88 @@
1
+module fgof_process
2
+  implicit none
3
+  private
4
+
5
+  public :: process_command
6
+  public :: process_options
7
+  public :: process_result
8
+  public :: command
9
+  public :: run
10
+
11
+  type :: process_command
12
+    character(len=:), allocatable :: program
13
+    character(len=:), allocatable :: argv(:)
14
+  end type process_command
15
+
16
+  type :: process_options
17
+    character(len=:), allocatable :: cwd
18
+    logical :: capture_stdout = .false.
19
+    logical :: capture_stderr = .false.
20
+    integer :: timeout_ms = 0
21
+    character(len=:), allocatable :: env(:)
22
+  end type process_options
23
+
24
+  type :: process_result
25
+    integer :: exit_code = -1
26
+    logical :: timed_out = .false.
27
+    character(len=:), allocatable :: stdout
28
+    character(len=:), allocatable :: stderr
29
+    character(len=:), allocatable :: error_message
30
+  end type process_result
31
+
32
+contains
33
+
34
+  function command(program, argv) result(cmd)
35
+    character(len=*), intent(in) :: program
36
+    character(len=*), intent(in), optional :: argv(:)
37
+    type(process_command) :: cmd
38
+    integer :: i
39
+
40
+    cmd%program = trim(program)
41
+
42
+    if (present(argv)) then
43
+      allocate(character(len=len_trim(program)) :: cmd%argv(0))
44
+      deallocate(cmd%argv)
45
+      allocate(character(len=max(1, max_trimmed_length(argv))) :: cmd%argv(size(argv)))
46
+      do i = 1, size(argv)
47
+        cmd%argv(i) = trim(argv(i))
48
+      end do
49
+    else
50
+      allocate(character(len=1) :: cmd%argv(0))
51
+    end if
52
+  end function command
53
+
54
+  function run(cmd, options) result(res)
55
+    type(process_command), intent(in) :: cmd
56
+    type(process_options), intent(in), optional :: options
57
+    type(process_result) :: res
58
+
59
+    res%exit_code = -1
60
+    res%timed_out = .false.
61
+    res%stdout = ""
62
+    res%stderr = ""
63
+    res%error_message = "run() is not implemented yet"
64
+
65
+    if (.not. allocated(cmd%program)) then
66
+      res%error_message = "command program is not set"
67
+      return
68
+    end if
69
+
70
+    if (present(options)) then
71
+      if (options%timeout_ms < 0) then
72
+        res%error_message = "timeout_ms must be >= 0"
73
+        return
74
+      end if
75
+    end if
76
+  end function run
77
+
78
+  integer function max_trimmed_length(values) result(max_len)
79
+    character(len=*), intent(in) :: values(:)
80
+    integer :: i
81
+
82
+    max_len = 1
83
+    do i = 1, size(values)
84
+      max_len = max(max_len, len_trim(values(i)))
85
+    end do
86
+  end function max_trimmed_length
87
+
88
+end module fgof_process
test/test_command.f90added
@@ -0,0 +1,15 @@
1
+program test_command
2
+  use fgof_process, only : process_command, command
3
+  implicit none
4
+
5
+  type(process_command) :: cmd
6
+
7
+  cmd = command("printf", ["hello", "world"])
8
+
9
+  if (.not. allocated(cmd%program)) error stop "program not allocated"
10
+  if (cmd%program /= "printf") error stop "program mismatch"
11
+  if (.not. allocated(cmd%argv)) error stop "argv not allocated"
12
+  if (size(cmd%argv) /= 2) error stop "argv size mismatch"
13
+  if (cmd%argv(1) /= "hello") error stop "argv(1) mismatch"
14
+  if (cmd%argv(2) /= "world") error stop "argv(2) mismatch"
15
+end program test_command