package bisect_ppx

  1. Overview
  2. Docs

Source file common.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
(* This Source Code Form is subject to the terms of the Mozilla Public License,
   v. 2.0. If a copy of the MPL was not distributed with this file, You can
   obtain one at http://mozilla.org/MPL/2.0/. *)



type point_definition = {
    offset : int;
    identifier : int;
  }

(* Utility functions *)

let try_finally x f h =
  let res =
    try
      f x
    with e ->
      (try h x with _ -> ());
      raise e in
  (try h x with _ -> ());
  res

let try_in_channel bin x f =
  let open_ch = if bin then open_in_bin else open_in in
  try_finally (open_ch x) f (close_in_noerr)

let try_out_channel bin x f =
  let open_ch = if bin then open_out_bin else open_out in
  try_finally (open_ch x) f (close_out_noerr)


(* I/O functions *)

(* filename + reason *)
exception Invalid_file of string * string

exception Unsupported_version of string

exception Modified_file of string

let magic_number_rtd = Bytes.of_string "BISECT-RTD"

let supported_versions = [
  2, 0
]

let format_version = (2, 0)

let write_channel channel magic write_digest x =
  output_bytes channel magic;
  output_value channel format_version;
  (match write_digest with
  | Some file -> output_value channel (Digest.file file)
  | None -> ());
  output_value channel x

let check_channel channel filename magic check_digest =
  let magic_length = Bytes.length magic in
  let file_magic = Bytes.create magic_length in
  really_input channel file_magic 0 magic_length;
  let file_version =
    if file_magic = magic then
      let file_version : (int * int) = input_value channel in
      if not (List.mem file_version supported_versions) then
        raise (Unsupported_version filename)
      else
        file_version
    else
      raise (Invalid_file (filename, "bad magic number")) in
  (match check_digest with
  | Some file ->
      let file_digest : string = input_value channel in
      let digest = Digest.file file in
      if file_digest <> digest then raise (Modified_file filename)
  | None -> ());
  file_version

let write_runtime_data channel content =
  write_channel channel magic_number_rtd None (Array.of_list content)

let write_points points =
  let points_array = Array.of_list points in
  Array.sort compare points_array;
  Marshal.to_string points_array []

let read_runtime_data' filename =
  try_in_channel
    true
    filename
    (fun channel ->
      let version = check_channel channel filename magic_number_rtd None in
      match version with
      | 2, 0 ->
          let file_content : (string * (int array * string)) array =
            (try input_value channel
             with | e -> raise (Invalid_file (filename, "exception reading data: " ^ Printexc.to_string e))
            ) in
          Array.to_list file_content
      | _ -> assert false)

let read_points' s =
  let points_array : point_definition array = Marshal.from_string s 0 in
  Array.sort compare points_array;
  Array.to_list points_array

(* Simulate the old behavior for current ocveralls. This is quite fragile,
   because it depends on two things:
   - read_points is only called after all .out files are read with
     read_runtime_data.
   - There are no duplicate source file names anywhere in the project. This is
     necessary because read_runtime_data finds unprefixed source file names,
     while read_points receives file names with the -I option already
     applied. *)
let points : (string, point_definition list) Hashtbl.t = Hashtbl.create 17

let read_runtime_data filename =
  let data = read_runtime_data' filename in
  data |> List.map (fun (source_file, (counts, file_points)) ->
    let basename = Filename.basename source_file in
    Hashtbl.replace points basename (read_points' file_points);
    source_file, counts)

let read_points filename =
  Hashtbl.find points (Filename.basename filename)
OCaml

Innovation. Community. Security.