package forester

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file Eio_util.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
(*
 * SPDX-FileCopyrightText: 2024 The Forester Project Contributors
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 *)

open Eio
open Forester_prelude
open Forester_core

let path_of_dir ~env dir =
  try
    let path = Path.(Eio.Stdenv.fs env / (Unix.realpath dir)) in
    assert (Path.is_directory path);
    path
  with
    | Unix.Unix_error (e, _, m) ->
      Reporter.fatal
        IO_error
        ~extra_remarks: [
          Asai.Diagnostic.loctextf "%s: %s" (Unix.error_message e) m
        ]
    | Assert_failure (_, _, _) ->
      Reporter.fatal
        Configuration_error
        ~extra_remarks: [Asai.Diagnostic.loctextf "%s is not a directory" dir]

let path_of_file ~env file =
  try
    let path = Path.(Eio.Stdenv.fs env / (Unix.realpath file)) in
    assert (Path.is_file path);
    path
  with
    | Unix.Unix_error (e, _, m) ->
      Reporter.fatal Configuration_error ~extra_remarks: [Asai.Diagnostic.loctextf "%s: %s" (Unix.error_message e) m]

let paths_of_dirs ~env =
  List.map (path_of_dir ~env)

let paths_of_files ~env =
  List.map (path_of_file ~env)

module NullSink : Flow.Pi.SINK with type t = unit = struct
  type t = unit
  let single_write _ _ = 0
  let copy _ ~src: _ = ()
end

let null_sink () : Flow.sink_ty Resource.t =
  let ops = Eio.Flow.Pi.sink (module NullSink) in
  Eio.Resource.T ((), ops)

let ensure_context_of_path ~perm (path : _ Path.t) =
  let@ path', _ = Option.iter @~ Path.split path in
  Path.mkdirs ~exists_ok: true ~perm path'

let ensure_remove_file path =
  try
    Eio.Path.unlink path
  with
    | Eio.Exn.Io (Eio.Fs.E (Eio.Fs.Not_found _), _) -> ()

let with_open_tmp_dir ~env kont =
  let dir_name = string_of_int @@ Oo.id (object end) in
  let cwd = Eio.Stdenv.cwd env in
  let tmp = "_tmp" in
  let tmp_path = Eio.Path.(cwd / tmp / dir_name) in
  Path.mkdirs ~exists_ok: true ~perm: 0o755 tmp_path;
  let@ p = Eio.Path.with_open_dir tmp_path in
  let result = kont p in
  Path.rmtree ~missing_ok: true tmp_path;
  result

let run_process ?(quiet = false) ~env ~cwd cmd =
  let mgr = Eio.Stdenv.process_mgr env in
  let outbuf = Buffer.create 100 in
  let errbuf = Buffer.create 100 in
  let errsink = Eio.Flow.buffer_sink errbuf in
  let outsink = Eio.Flow.buffer_sink outbuf in
  if not quiet then
    Eio.traceln "Running %s" (String.concat " " cmd);
  try
    Eio.Process.run ~cwd ~stdout: outsink ~stderr: errsink mgr cmd
  with
    | exn ->
      Eio.traceln "Error: %s" (Buffer.contents errbuf);
      Eio.traceln "Output: %s" (Buffer.contents outbuf);
      raise exn

let file_exists path =
  try
    let@ _ = Eio.Path.with_open_in path in
    true
  with
    | Eio.Io (Eio.Fs.E (Eio.Fs.Not_found _), _) -> false

let try_create_dir ~cwd dname =
  let (/) = Path.(/) in
  if Eio.Path.is_directory (cwd / dname) then
    Reporter.emit
      Initialization_warning
      ~extra_remarks: [Asai.Diagnostic.loctextf "`%s` already exists" dname]
  else
    try
      Eio.Path.mkdir ~perm: 0o755 (cwd / dname)
    with
      | exn ->
        Forester_core.Reporter.emit Initialization_warning ~extra_remarks: [Asai.Diagnostic.loctextf "Failed to create directory `%s`: %a" dname Eio.Exn.pp exn]

let try_create_file ~cwd ?(content = "") fname =
  let (/) = Path.(/) in
  if Eio.Path.is_file (cwd / fname) then
    Forester_core.Reporter.emit Initialization_warning ~extra_remarks: [Asai.Diagnostic.loctextf "`%s` already exists" fname]
  else
    try
      Eio.Path.save ~create: (`Exclusive 0o644) (cwd / fname) content
    with
      | exn ->
        Forester_core.Reporter.emit Initialization_warning ~extra_remarks: [Asai.Diagnostic.loctextf "Failed to create file `%s`: %a" fname Eio.Exn.pp exn]

(* TODO: test this! *)
let copy_to_dir ~env ~cwd ~source ~dest_dir =
  let path = Path.(cwd / dest_dir) in
  Path.mkdirs ~exists_ok: true ~perm: 0o755 path;
  if Sys.unix then
    run_process ~quiet: true ~env ~cwd ["cp"; "-R"; source; dest_dir]
  else
    run_process ~quiet: true ~env ~cwd ["xcopy"; source; dest_dir ^ "/"]
OCaml

Innovation. Community. Security.