package pfff

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

Source file overlay_code.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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
(* Yoann Padioleau
 *
 * Copyright (C) 2011 Facebook
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation, with the
 * special exception on linking described in file license.txt.
 * 
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the file
 * license.txt for more details.
 *)
open Common

(*****************************************************************************)
(* Prelude *)
(*****************************************************************************)
(*
 * Some code organizations are really bad. But because it's harder
 * to convince people to change it, sometimes it's simpler to create
 * a parallel organization, an "overlay" using simple symlinks
 * that represent a better organization. One can then show
 * statistics on those overlayed code organization, adapt layers,
 * etc
 * 
 * related: LFS on code.
 *)

(*****************************************************************************)
(* Types *)
(*****************************************************************************)
type overlay = {
  (* the filenames are in a readable path format *)
  orig_to_overlay: (Common.filename, Common.filename) Hashtbl.t;
  overlay_to_orig: (Common.filename, Common.filename) Hashtbl.t;
  data: (Common.filename (* overlay *) * Common.filename) list;

  (* in realpath format. This information is then specific
   * to one user ... but infering back the root_orig/root_overlay
   * from an arbitrary directory can be tedious.
   *)
  root_orig: Common.dirname;
  root_overlay: Common.dirname;
}

(*****************************************************************************)
(* IO *)
(*****************************************************************************)

let load_overlay file =
  Common2.get_value file

let save_overlay overlay file =
  Common2.write_value overlay file

(*****************************************************************************)
(* Check consistency *)
(*****************************************************************************)

let check_overlay ~dir_orig ~dir_overlay =
  let dir_orig = Common.fullpath dir_orig in
  let files = 
    Common.files_of_dir_or_files_no_vcs_nofilter [dir_orig] 
    |> Common.exclude (fun file -> file =~ ".*/OVERLAY/.*")
  in

  let dir_overlay = Common.fullpath dir_overlay in
  let links = 
    Common.cmd_to_list (spf "find %s -type l" dir_overlay) in

  let links = links |> Common.map_filter (fun file ->
    try Some (Common.fullpath file)
    with Failure s ->
      pr2 s;
      None
  )
  in
  let files2 = 
    links |> List.map (fun file_or_dir -> 
      Common.files_of_dir_or_files_no_vcs_nofilter [file_or_dir]
    ) |> List.flatten
  in
  pr2 (spf "#files orig = %d, #links overlay = %d, #files overlay = %d"
    (List.length files) (List.length links) (List.length files2)
  );
  let h = Hashtbl.create 101 in
  files2 |> List.iter (fun file ->
    if Hashtbl.mem h file
    then pr2 (spf "this one is a dupe: %s" file);
    Hashtbl.add h file true;
  );

  let (_common, only_in_orig, only_in_overlay) = 
    Common2.diff_set_eff files files2 in


  only_in_orig |> List.iter (fun l ->
    pr2 (spf "this one is missing: %s" l);
  );
  only_in_overlay |> List.iter (fun l ->
    pr2 (spf "this one is gone now: %s" l);
  );
  if not (null only_in_orig && null only_in_overlay)
  then failwith "Overlay is not OK"
  else pr2 "Overlay is OK"

(*****************************************************************************)
(* Generate equivalences *)
(*****************************************************************************)

let overlay_equivalences ~dir_orig ~dir_overlay  =
  let dir_overlay = Common.fullpath dir_overlay in
  let dir_orig = Common.fullpath dir_orig in
  
  let links = 
    Common.cmd_to_list (spf "find %s -type l" dir_overlay) in
  
  let equiv = 
    links |> List.map (fun link ->
      let stat = Common2.unix_stat_eff link in
      match stat.Unix.st_kind with
      | Unix.S_DIR ->
          let (children, _) = 
            Common2.cmd_to_list_and_status (spf 
              "cd %s; find * -type f" (link)) in
          let dir = Common.fullpath link in
          
          children |> List.map (fun child ->
            let overlay = Filename.concat link child in
            let orig = Filename.concat dir child in
            overlay, orig
          )
      | Unix.S_REG ->
          [(link, Common.fullpath link)]
      | _ ->
          []
    ) |> List.flatten
  in
  let data =
  equiv |> Common.map_filter (fun (overlay, orig) ->
    try 
      Some (
        Common.readable ~root:dir_overlay overlay,
        Common.readable ~root:dir_orig orig
      )
    with exn ->
      pr2 (spf "PB with %s, exn = %s" orig (Common.exn_to_s exn));
      None
  )
  in
  {
    data = data;
    overlay_to_orig = Common.hash_of_list data;
    orig_to_overlay = Common.hash_of_list (data |> List.map Common2.swap);
    root_overlay = dir_overlay;
    root_orig = dir_orig;
  }

let gen_overlay ~dir_orig ~dir_overlay ~output =
  let equiv = overlay_equivalences ~dir_orig ~dir_overlay in
  equiv.data |> List.iter pr2_gen;
  save_overlay equiv output

(*****************************************************************************)
(* Adapt layer *)
(*****************************************************************************)

let adapt_layer layer overlay =
  { layer with Layer_code.
    files = layer.Layer_code.files |> Common.map_filter (fun (file, info) ->
      try 
        Some (Hashtbl.find overlay.orig_to_overlay file, info)
      with Not_found ->
        pr2 (spf "PB could not find %s in overlay" file);
        None
    );
  }

(* copy paste of the one in main_codemap.ml *)
let layers_in_dir dir =
  Common2.readdir_to_file_list dir |> Common.map_filter (fun file ->
    if file =~ "layer.*marshall"
    then Some (Filename.concat dir file)
    else None
  )

let adapt_layers ~overlay ~dir_layers_orig ~dir_layers_overlay =
  let layers = layers_in_dir dir_layers_orig in
  
  layers |> List.iter (fun layer_filename ->
    pr2 (spf "processing %s" layer_filename);
    let layer = Layer_code.load_layer layer_filename in
    let layer' = adapt_layer layer overlay in
    Layer_code.save_layer layer' 
      (Filename.concat dir_layers_overlay (Common2.basename layer_filename))
  )


(*****************************************************************************)
(* Adapt database code *)
(*****************************************************************************)

let adapt_database db overlay =
  { db with Database_code.
    files = db.Database_code.files |> Common.map_filter (fun (file, info) ->
      try 
        Some (Hashtbl.find overlay.orig_to_overlay file, info)
      with Not_found ->
        pr2 (spf "PB could not find %s in overlay" file);
        None
    );
    entities = db.Database_code.entities |> Array.map (fun e ->
      { e with Database_code.
        e_file = 
          try 
            (Hashtbl.find overlay.orig_to_overlay e.Database_code.e_file)
          with Not_found ->
            "not_found_file_overlay";
      }
    );
  }
OCaml

Innovation. Community. Security.