this repo has no description
at main 178 lines 5.4 kB view raw
1(* TODO: Add content-addressed output paths (like day10's jtw_gen.ml) so that 2 worker.js, .cma.js, and .cmi files are served from paths containing a 3 content hash. This prevents stale browser caches after rebuilds. 4 See day10/bin/jtw_gen.ml for the reference implementation: 5 - compiler/<version>/<hash>/worker.js 6 - p/<pkg>/<version>/<hash>/lib/<name>/... 7 - findlib_index.json references hashed paths *) 8 9open Bos 10 11let opam = Cmd.v "opam" 12let switch = ref None 13let prefix = ref None 14 15type package = { name : string; version : string } 16 17let pp fmt p = Format.fprintf fmt "%s.%s" p.name p.version 18 19let rec get_switch () = 20 match !switch with 21 | None -> 22 let cur_switch = 23 Util.lines_of_process Cmd.(opam % "switch" % "show") |> List.hd 24 in 25 switch := Some cur_switch; 26 get_switch () 27 | Some s -> s 28 29let prefix () = 30 match !prefix with 31 | Some p -> p 32 | None -> 33 let p = 34 Util.lines_of_process 35 Cmd.(opam % "var" % "--switch" % get_switch () % "prefix") 36 |> List.hd 37 in 38 prefix := Some p; 39 p 40 41let deps_of_opam_result line = 42 match Astring.String.fields ~empty:false line with 43 | [ name; version ] -> [ { name; version } ] 44 | _ -> [] 45 46let all_opam_packages () = 47 Util.lines_of_process 48 Cmd.( 49 opam % "list" % "--switch" % get_switch () % "--columns=name,version" 50 % "--color=never" % "--short") 51 |> List.map deps_of_opam_result 52 |> List.flatten 53 54let pkg_contents { name; _ } = 55 let prefix = Fpath.v (prefix ()) in 56 let changes_file = 57 Format.asprintf "%a/.opam-switch/install/%s.changes" Fpath.pp prefix name 58 in 59 let file = OpamFilename.raw changes_file in 60 let filename = 61 OpamFile.make @@ OpamFilename.raw @@ Filename.basename changes_file 62 in 63 let changed = 64 OpamFilename.with_contents 65 (fun str -> 66 OpamFile.Changes.read_from_string ~filename 67 @@ 68 (* Field [opam-version] is invalid in [*.changes] files, displaying a warning. *) 69 if String.starts_with ~prefix:"opam-version" str then 70 match OpamStd.String.cut_at str '\n' with 71 | Some (_, str) -> str 72 | None -> assert false 73 else str) 74 file 75 in 76 let added = 77 OpamStd.String.Map.fold 78 (fun file x acc -> 79 match x with 80 | OpamDirTrack.Added _ -> ( 81 try 82 if not @@ Sys.is_directory Fpath.(to_string (prefix // v file)) 83 then file :: acc 84 else acc 85 with _ -> 86 acc 87 (* dose (and maybe others) sometimes creates a symlink to something that doesn't exist *) 88 ) 89 | _ -> acc) 90 changed [] 91 in 92 List.map Fpath.v added 93 94(* let opam_file { name; version } = *) 95(* let prefix = Fpath.v (prefix ()) in *) 96(* let opam_file = *) 97(* Format.asprintf "%a/.opam-switch/packages/%s.%s/opam" Fpath.pp prefix name *) 98(* version *) 99(* in *) 100(* let ic = open_in opam_file in *) 101(* try *) 102(* let lines = Util.lines_of_channel ic in *) 103(* close_in ic; *) 104(* Some lines *) 105(* with _ -> *) 106(* close_in ic; *) 107(* None *) 108 109type installed_files = { 110 libs : Fpath.set; 111 odoc_pages : Fpath.set; 112 other_docs : Fpath.set; 113} 114 115type package_of_fpath = package Fpath.map 116 117(* Here we use an associative list *) 118type fpaths_of_package = (package * installed_files) list 119 120let pkg_to_dir_map () = 121 let pkgs = all_opam_packages () in 122 let prefix = prefix () in 123 let pkg_content = 124 List.map 125 (fun p -> 126 let contents = pkg_contents p in 127 let libs = 128 List.fold_left 129 (fun set fpath -> 130 match Fpath.segs fpath with 131 | "lib" :: "stublibs" :: _ -> set 132 | "lib" :: _ :: _ :: _ when Fpath.has_ext ".cmi" fpath -> 133 Fpath.Set.add 134 Fpath.(v prefix // fpath |> split_base |> fst) 135 set 136 | _ -> set) 137 Fpath.Set.empty contents 138 in 139 let odoc_pages, other_docs = 140 List.fold_left 141 (fun (odoc_pages, others) fpath -> 142 match Fpath.segs fpath with 143 | "doc" :: _pkg :: "odoc-pages" :: _ -> 144 Logs.debug (fun m -> m "Found odoc page: %a" Fpath.pp fpath); 145 146 (Fpath.Set.add Fpath.(v prefix // fpath) odoc_pages, others) 147 | "doc" :: _ -> 148 Logs.debug (fun m -> m "Found other doc: %a" Fpath.pp fpath); 149 (odoc_pages, Fpath.Set.add Fpath.(v prefix // fpath) others) 150 | _ -> (odoc_pages, others)) 151 Fpath.Set.(empty, empty) 152 contents 153 in 154 Logs.debug (fun m -> 155 m "Found %d odoc pages, %d other docs" 156 (Fpath.Set.cardinal odoc_pages) 157 (Fpath.Set.cardinal other_docs)); 158 (p, { libs; odoc_pages; other_docs })) 159 pkgs 160 in 161 let map = 162 List.fold_left 163 (fun map (p, { libs; _ }) -> 164 Fpath.Set.fold 165 (fun dir map -> 166 Fpath.Map.update dir 167 (function 168 | None -> Some p 169 | Some x -> 170 Logs.debug (fun m -> 171 m "Multiple packages (%a,%a) found for dir %a" pp x pp p 172 Fpath.pp dir); 173 Some p) 174 map) 175 libs map) 176 Fpath.Map.empty pkg_content 177 in 178 (pkg_content, map)