feat(install): copy installable outputs under a prefix

Destinations come from each target's install field, the executable bit is
preserved, and a dry run prints the plan without touching anything.
This commit is contained in:
milner committed 2022-06-21 02:23:23 +00:00
1 parent 12111f2b55
commit 38dbe2b8ee
1 file changed
+49
+49
View File
@@ -0,0 +1,49 @@
open Types
let dest_dir p = function
| "bin" -> Filename.concat p.prefix "bin"
| "lib" -> Filename.concat p.prefix "lib"
| "include" -> Filename.concat p.prefix "include"
| other -> if Filename.is_relative other then Filename.concat p.prefix other else other
let plan p =
let from_targets =
List.filter_map
(fun (t : target) ->
match t.install with
| None -> None
| Some where ->
let src = Build.out_of p t in
Some (src, Filename.concat (dest_dir p where) (Filename.basename src)))
p.targets
in
let from_blocks =
List.map (fun i -> (i.from, Filename.concat (dest_dir p i.dest) (Filename.basename i.from)))
p.installs
in
from_targets @ from_blocks
let copy ~mode src dst =
Fs.mkdir_p (Filename.dirname dst);
let ic = open_in_bin src in
let n = in_channel_length ic in
let data = really_input_string ic n in
close_in ic;
let oc = open_out_gen [ Open_wronly; Open_creat; Open_trunc; Open_binary ] mode dst in
output_string oc data;
close_out oc;
Unix.chmod dst mode
let executable src =
match Unix.stat src with
| { Unix.st_perm; _ } -> st_perm land 0o111 <> 0
| exception Unix.Unix_error _ -> false
let execute ?(dry = false) p =
let items = plan p in
List.iter
(fun (src, dst) ->
if not (Sys.file_exists src) then Diag.error "%s has not been built yet" src;
if not dry then copy ~mode:(if executable src then 0o755 else 0o644) src dst)
items;
items