3 exception NoRootFor of string
7 if String.length path > 0 && path.[0] <> '/' then
8 Sys.getcwd () ^ "/" ^ path
12 HExtlib.normalize_path path
17 let path = absolutize path in
18 let paths = List.rev (Str.split (Str.regexp "/") path) in
19 let rec build = function
20 | he::tl as l -> ("/" ^ String.concat "/" (List.rev l) ^ "/") :: build tl
23 let paths = List.map HExtlib.normalize_path (build paths) in
24 try HExtlib.find_in paths "root"
25 with Failure "find_in" ->
26 raise (NoRootFor (path ^ " (" ^ String.concat ", " paths ^ ")"))
29 let ensure_trailing_slash s =
30 if s = "" then "/" else
31 if s.[String.length s-1] <> '/' then s^"/" else s
34 let remove_trailing_slash s =
35 if s = "" then "" else
36 let len = String.length s in
37 if s.[len-1] = '/' then String.sub s 0 (len-1) else s
40 let load_root_file rootpath =
41 let data = HExtlib.input_file rootpath in
42 let lines = Str.split (Str.regexp "\n") data in
44 Pcre.replace ~pat:"[ \t]+" ~templ:" "
45 (Pcre.replace ~pat:"^ *" (Pcre.replace ~pat:" *$" s))
49 match Str.split (Str.regexp "=") l with
50 | [k;v] -> clean k, Http_getter_misc.strip_trailing_slash (clean v)
51 | _ -> raise (Failure ("Malformed root file: " ^ rootpath)))
55 let find_root_for ~include_paths file =
56 let include_paths = "" :: Sys.getcwd () :: include_paths in
58 let path = HExtlib.find_in include_paths file in
59 let path = absolutize path in
60 (* HLog.debug ("file "^file^" resolved as "^path); *)
61 let rootpath, root, buri =
63 let mburi = Helm_registry.get "matita.baseuri" in
64 match Str.split (Str.regexp " ") mburi with
65 | [root; buri] when HExtlib.is_prefix_of root path ->
66 ":registry:", root, buri
67 | _ -> raise (Helm_registry.Key_not_found "matita.baseuri")
68 with Helm_registry.Key_not_found "matita.baseuri" ->
69 let rootpath = find_root path in
70 let buri = List.assoc "baseuri" (load_root_file rootpath) in
71 rootpath, Filename.dirname rootpath, buri
73 (* HLog.debug ("file "^file^" rooted by "^rootpath^""); *)
74 let uri = Http_getter_misc.strip_trailing_slash buri in
75 if String.length uri < 5 || String.sub uri 0 5 <> "cic:/" then
76 HLog.error (rootpath ^ " sets an incorrect baseuri: " ^ buri);
77 ensure_trailing_slash root, remove_trailing_slash uri, path
78 with Failure "find_in" ->
79 HLog.error ("We are in: " ^ Sys.getcwd ());
80 HLog.error ("Unable to find: "^file^"\nPaths explored:");
81 List.iter (fun x -> HLog.error (" - "^x)) include_paths;
82 raise (NoRootFor file)
85 let mk_baseuri root extra =
87 assert(Filename.check_suffix name ".ma" ||
88 Filename.check_suffix name ".mma");
89 try Filename.chop_extension name
90 with Invalid_argument "Filename.chop_extension" -> name
92 remove_trailing_slash (HExtlib.normalize_path (root ^ "/" ^ chop extra))
95 let baseuri_of_script ~include_paths file =
96 let root, buri, path = find_root_for ~include_paths file in
97 let path = HExtlib.normalize_path path in
98 let root = HExtlib.normalize_path root in
99 let lpath = Str.split (Str.regexp "/") path in
100 let lroot = Str.split (Str.regexp "/") root in
101 let rec substract l1 l2 =
103 | h1::tl1,h2::tl2 when h1 = h2 -> substract tl1 tl2
105 | _ -> raise (NoRootFor (file ^" "^path^" "^root))
107 let extra_buri = substract lpath lroot in
108 let extra = String.concat "/" extra_buri in
110 mk_baseuri buri extra,
115 let find_roots_in_dir dir =
116 HExtlib.find ~test:(fun f ->
117 Filename.basename f = "root" &&
118 try (Unix.stat f).Unix.st_kind = Unix.S_REG
119 with Unix.Unix_error _ -> false)
124 let load_deps_file f =
126 let ic = open_in f in
130 let l = input_line ic in
131 match Str.split (Str.regexp " ") l with
133 HLog.error ("Malformed deps file: " ^ f);
134 raise (Failure ("Malformed deps file: " ^ f))
135 | he::tl -> deps := (he,tl) :: !deps
138 with End_of_file -> !deps
141 type options = (string * string) list
147 val load_deps_file: string -> (source_object * source_object list) list
148 val string_of_source_object: source_object -> string
149 val string_of_target_object: target_object -> string
150 val build: options -> source_object -> bool
151 val root_and_target_of:
152 options -> source_object -> string option * target_object
153 val mtime_of_source_object: source_object -> float option
154 val mtime_of_target_object: target_object -> float option
155 val is_readonly_buri_of: options -> source_object -> bool
158 module Make = functor (F:Format) -> struct
160 let say s = if debug then prerr_endline ("make: "^s);;
162 let unopt_or_call x f y = match x with Some _ -> x | None -> f y;;
164 let younger_s_t (_,cs,ct) a b =
165 let a = try Hashtbl.find cs a with Not_found -> assert false in
168 match Hashtbl.find ct b with
171 match F.mtime_of_target_object b with
174 Hashtbl.add ct b x; x
176 with Not_found -> assert false
179 | Some a, Some b -> a < b
183 let younger_t_t (_,_,ct) a b =
186 match Hashtbl.find ct a with
189 match F.mtime_of_target_object a with
192 Hashtbl.add ct a x; x
194 with Not_found -> assert false
198 match Hashtbl.find ct b with
201 match F.mtime_of_target_object b with
204 Hashtbl.add ct b x; x
206 with Not_found -> assert false
209 | Some a, Some b -> a < b
213 let is_built opts t tgt =
214 younger_s_t opts t tgt
217 let assoc4 l k = List.find (fun (k1,_,_,_) -> k1 = k) l;;
219 let fst4 = function (x,_,_,_) -> x;;
221 let rec needs_build opts deps compiled (t,dependencies,root,tgt) =
222 say ("Checking if "^F.string_of_source_object t^ " needs to be built");
223 if List.mem t compiled then
224 (say "already compiled"; false)
226 if not (is_built opts t tgt) then
227 (say(F.string_of_source_object t^" is not built, thus needs to be built");
233 (needs_build opts deps compiled)
234 (List.map (assoc4 deps) dependencies)
236 say (F.string_of_source_object t^" depends on "^
237 F.string_of_source_object (fst4 unsat)^
238 " that needs to be built, thus needs to be built");
244 (fun (_,_,_,tgt1) -> younger_t_t opts tgt tgt1)
245 (List.map (assoc4 deps) dependencies)
248 (F.string_of_source_object t^" depends on "^F.string_of_target_object
249 unsat^" and "^F.string_of_source_object t^".o is younger than "^
250 F.string_of_target_object unsat^", thus needs to be built");
252 with Not_found -> false
255 let is_buildable opts compiled deps (t,dependencies,root,tgt as what) =
256 say ("Checking if "^F.string_of_source_object t^" is buildable");
257 let b = needs_build opts deps compiled what in
259 (say (F.string_of_source_object t^
260 " does not need to be built, thus it not buildable");
265 List.find (needs_build opts deps compiled)
266 (List.map (assoc4 deps) dependencies)
268 say (F.string_of_source_object t^" depends on "^
269 F.string_of_source_object unsat^
270 " that needs build, thus is not buildable");
274 ("None of "^F.string_of_source_object t^
275 " dependencies needs to be built, thus it is buildable");
279 let rec purge_unwanted_roots wanted deps =
283 not (List.exists (fun (_,d1,_,_) -> List.mem t d1) deps))
286 let newroots = List.filter (fun (t,_,_,_) -> List.mem t wanted) roots in
287 if newroots = roots then
290 purge_unwanted_roots wanted (newroots @ rest)
293 let is_not_ro (opts,_,_) (f,_,r,_) =
295 | Some root -> not (F.is_readonly_buri_of opts f)
296 | None -> assert false
299 let rec make_aux root (lo,_,ct as opts) compiled failed deps =
300 let todo = List.filter (is_buildable opts compiled deps) deps in
301 let todo = List.filter (fun (f,_,_,_)->not (List.mem f failed)) todo in
304 List.partition (fun (_,_,froot,_) -> froot = Some root) todo
306 let local, skipped = List.partition (is_not_ro opts) local in
309 HLog.warn("Read only baseuri for: "^F.string_of_source_object(fst4 x)))
314 let compiled, failed =
316 (fun (c,f) (file,_,froot,tgt) ->
319 | Some froot when froot = root ->
320 Hashtbl.remove ct tgt;
321 Hashtbl.add ct tgt None;
323 | Some froot -> make froot [file]
325 HLog.error ("No root for: "^F.string_of_source_object file);
328 if rc then (file::c,f)
330 (compiled,failed) todo
332 make_aux root opts compiled failed deps
336 and make root targets =
337 HLog.debug ("Entering directory '"^root^"'");
338 let old_root = Sys.getcwd () in
340 let deps = F.load_deps_file (root^"/depends") in
341 let local_options = load_root_file (root^"/root") in
342 let caches,cachet = Hashtbl.create 73, Hashtbl.create 73 in
343 (* deps are enriched with these informations to sped up things later *)
347 let r,tgt = F.root_and_target_of local_options file in
348 Hashtbl.add caches file (F.mtime_of_source_object file);
349 Hashtbl.add cachet tgt (F.mtime_of_target_object tgt);
353 let opts = local_options, caches, cachet in
354 let _compiled, failed =
356 make_aux root opts [] [] deps
358 make_aux root opts [] []
359 (purge_unwanted_roots targets deps)
361 HLog.debug ("Leaving directory '"^root^"'");
368 let write_deps_file where deps = match where with
370 let oc = open_out (root ^ "/depends") in
371 let map (t, d) = output_string oc (t^" "^String.concat " " d^"\n") in
372 List.iter map deps; close_out oc;
373 HLog.message ("Generated: " ^ root ^ "/depends")
375 print_endline (String.concat " " (List.flatten (List.map snd deps)))
377 (* FG ***********************************************************************)
379 (* scheme uri part as defined in URI Generic Syntax (RFC 3986) *)
380 let uri_scheme_rex = Pcre.regexp "^[[:alpha:]][[:alnum:]\-+.]*:"
383 Pcre.pmatch ~rex:uri_scheme_rex str