summaryrefslogtreecommitdiff
path: root/ocamlbuild/my_unix.ml
blob: fa1c5d45f4196ad5a38879734c4ce13bcfb155dc (plain)
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
(***********************************************************************)
(*                                                                     *)
(*                             ocamlbuild                              *)
(*                                                                     *)
(*  Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
(*                                                                     *)
(*  Copyright 2007 Institut National de Recherche en Informatique et   *)
(*  en Automatique.  All rights reserved.  This file is distributed    *)
(*  under the terms of the Q Public License version 1.0.               *)
(*                                                                     *)
(***********************************************************************)


(* Original author: Nicolas Pouillard *)
open My_std

type file_kind =
| FK_dir
| FK_file
| FK_link
| FK_other

type stats =
  {
    stat_file_kind : file_kind;
    stat_key       : string
  }

type implem =
  {
    mutable is_degraded   : bool;
    mutable is_link       : string -> bool;
    mutable run_and_open  : 'a . string -> (in_channel -> 'a) -> 'a;
    mutable readlink      : string -> string;
    mutable execute_many  : ?max_jobs:int ->
                            ?ticker:(unit -> unit) ->
                            ?period:float ->
                            ?display:((out_channel -> unit) -> unit) ->
                            ((unit -> string) list list) ->
                            (bool list * exn) option;
    mutable report_error  : Format.formatter -> exn -> unit;
    mutable at_exit_once  : (unit -> unit) -> unit;
    mutable gettimeofday  : unit -> float;
    mutable stdout_isatty : unit -> bool;
    mutable stat          : string -> stats;
    mutable lstat         : string -> stats;
  }

let is_degraded = true

let stat f =
  { stat_key = f;
    stat_file_kind =
      if sys_file_exists f then
        if Sys.is_directory f then
          FK_dir
        else
          FK_file
      else let _ = with_input_file f input_char in assert false }

let run_and_open s kont =
  with_temp_file "ocamlbuild" "out" begin fun tmp ->
    let s = Printf.sprintf "%s > '%s'" s tmp in
    let st = sys_command s in
    if st <> 0 then failwith (Printf.sprintf "Error while running: %s" s);
    with_input_file tmp kont
  end

exception Not_a_link
exception No_such_file
exception Link_to_directories_not_supported

let readlinkcmd =
  let cache = Hashtbl.create 32 in
  fun x ->
    try Hashtbl.find cache x
    with Not_found ->
      run_and_open (Printf.sprintf "readlink %s" (Filename.quote x)) begin fun ic ->
        let y = String.chomp (input_line ic) in
        Hashtbl.replace cache x y; y
      end

let rec readlink x =
  if sys_file_exists x then
    try
      let y = readlinkcmd x in
      if (lstat y).stat_file_kind = FK_dir then raise Link_to_directories_not_supported else y
    with Failure(_) -> raise Not_a_link
  else raise No_such_file

and is_link x =
  try ignore(readlink x); true with
  | No_such_file | Not_a_link -> false

and lstat x =
  if is_link x then { stat_key = x; stat_file_kind = FK_link } else stat x

let implem =
  {
    is_degraded = true;

    stat = stat;
    lstat = lstat;
    readlink = readlink;
    is_link = is_link;
    run_and_open = run_and_open;

    (* at_exit_once is at_exit in the degraded mode since fork is not accessible in this mode *)
    at_exit_once = at_exit;
    report_error = (fun _ -> raise);
    gettimeofday = (fun () -> assert false);
    stdout_isatty = (fun () -> false);
    execute_many = (fun ?max_jobs:(_) ?ticker:(_) ?period:(_) ?display:(_) _ -> assert false)
  }

let is_degraded = lazy implem.is_degraded
let stat x = implem.stat x
let lstat x = implem.lstat x
let readlink x = implem.readlink x
let is_link x = implem.is_link x
let run_and_open x = implem.run_and_open x
let at_exit_once x = implem.at_exit_once x
let report_error x = implem.report_error x
let gettimeofday x = implem.gettimeofday x
let stdout_isatty x = implem.stdout_isatty x
let execute_many ?max_jobs = implem.execute_many ?max_jobs

let run_and_read cmd =
  let bufsiz = 2048 in
  let buf = Bytes.create bufsiz in
  let totalbuf = Buffer.create 4096 in
  implem.run_and_open cmd begin fun ic ->
    let rec loop pos =
      let len = input ic buf 0 bufsiz in
      if len > 0 then begin
        Buffer.add_subbytes totalbuf buf 0 len;
        loop (pos + len)
      end
    in loop 0; Buffer.contents totalbuf
  end