package dune-action-plugin

  1. Overview
  2. Docs

Source file protocol.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
open Import

let run_by_dune_env_variable = "DUNE_DYNAMIC_RUN_CLIENT"

module Error = Sexpable_intf.Error

module Dependency = struct
  module T = struct
    type t =
      | File of string
      | Directory of string
      | Glob of
          { path : string
          ; glob : string
          }

    let conv =
      let open Conv in
      let file = constr "File" string (fun s -> File s) in
      let directory = constr "Directory" string (fun s -> Directory s) in
      let glob_cstr =
        constr "Glob" (pair string string) (fun (path, glob) -> Glob { path; glob })
      in
      sum
        [ econstr file; econstr directory; econstr glob_cstr ]
        (function
          | File s -> case s file
          | Directory s -> case s directory
          | Glob { path; glob } -> case (path, glob) glob_cstr)
    ;;

    let compare x y =
      match x, y with
      | File x, File y -> String.compare x y
      | File _, _ -> Lt
      | _, File _ -> Gt
      | Directory x, Directory y -> String.compare x y
      | Directory _, _ -> Lt
      | _, Directory _ -> Gt
      | Glob { path; glob }, Glob t ->
        let open Ordering.O in
        let= () = String.compare path t.path in
        String.compare glob t.glob
    ;;

    let to_dyn = Dyn.opaque
  end

  include T
  module O = Comparable.Make (T)
  module Map = O.Map

  module Set = struct
    include O.Set

    let conv : t Conv.value = Conv.iso (Conv.list conv) of_list to_list
  end
end

module Greeting = struct
  module T = struct
    type t =
      { run_arguments_fn : string
      ; response_fn : string
      }

    let conv =
      let open Conv in
      let to_ (run_arguments_fn, response_fn) = { run_arguments_fn; response_fn } in
      let from { run_arguments_fn; response_fn } = run_arguments_fn, response_fn in
      iso (pair string string) to_ from
    ;;

    let version = 0
  end

  include T
  include Sexpable_intf.Make (T)
end

module Run_arguments = struct
  module T = struct
    type t =
      { prepared_dependencies : Dependency.Set.t
      ; targets : String.Set.t
      }

    let conv =
      let from { prepared_dependencies; targets } = prepared_dependencies, targets in
      let to_ (prepared_dependencies, targets) = { prepared_dependencies; targets } in
      let string_set =
        Conv.iso Conv.(list string) String.Set.of_list String.Set.to_list
      in
      let conv = Conv.pair Dependency.Set.conv string_set in
      Conv.iso conv to_ from
    ;;

    let version = 0
  end

  include T
  include Sexpable_intf.Make (T)
end

module Response = struct
  module T = struct
    type t =
      | Done
      | Need_more_deps of Dependency.Set.t

    let conv =
      let open Conv in
      let done_ = constr "Done" unit (fun () -> Done) in
      let need_more_deps =
        constr "Need_more_deps" Dependency.Set.conv (fun deps -> Need_more_deps deps)
      in
      sum
        [ econstr done_; econstr need_more_deps ]
        (function
          | Done -> case () done_
          | Need_more_deps deps -> case deps need_more_deps)
    ;;

    let version = 0
  end

  include T
  include Sexpable_intf.Make (T)
end

module Context = struct
  type t =
    { response_fn : string
    ; prepared_dependencies : Dependency.Set.t
    ; targets : String.Set.t
    }

  type create_result =
    | Ok of t
    | Run_outside_of_dune
    | Error of string

  let cannot_parse_error = Error "Can not parse dune message."

  let version_mismatch_error =
    Error
      "Dune version is incompatible with dune-action-plugin library version that was \
       used to build this executable."
  ;;

  let cannot_read_file = Error "Cannot read file containing dune message."
  let file_not_found_error = Error "Cannot find file containing dune message."

  let create () =
    match Sys.getenv_opt run_by_dune_env_variable with
    | None -> Run_outside_of_dune
    | Some value ->
      (match Csexp.parse_string value with
       | Error _ -> cannot_parse_error
       | Ok sexp ->
         (match Greeting.of_sexp sexp with
          | Error (Version_mismatch _) -> version_mismatch_error
          | Error Parse_error -> cannot_parse_error
          | Ok greeting ->
            (match
               ( Result.try_with (fun () ->
                   Io.String_path.read_file greeting.run_arguments_fn)
               , Sys.file_exists greeting.response_fn )
             with
             | _, false -> file_not_found_error
             | Error _, _ -> cannot_read_file
             | Ok data, true ->
               (match Csexp.parse_string data with
                | Error _ -> cannot_parse_error
                | Ok sexp ->
                  (match Run_arguments.of_sexp sexp with
                   | Error (Version_mismatch _) -> version_mismatch_error
                   | Error Parse_error -> cannot_parse_error
                   | Ok { prepared_dependencies; targets } ->
                     Ok
                       { response_fn = greeting.response_fn
                       ; prepared_dependencies
                       ; targets
                       })))))
  ;;

  let prepared_dependencies (t : t) = t.prepared_dependencies
  let targets (t : t) = t.targets

  let respond (t : t) response =
    let data = Response.to_sexp response |> Csexp.to_string in
    Io.String_path.write_file t.response_fn data
  ;;
end
OCaml

Innovation. Community. Security.