2017-02-27 13:34:16 +00:00
|
|
|
open Import
|
|
|
|
open Sexp.Of_sexp
|
|
|
|
|
2017-04-24 11:27:13 +00:00
|
|
|
module Env_var_map = Context.Env_var_map
|
|
|
|
|
2017-03-03 11:49:40 +00:00
|
|
|
type var_expansion =
|
|
|
|
| Not_found
|
|
|
|
| Path of Path.t
|
|
|
|
| Paths of Path.t list
|
|
|
|
| Str of string
|
|
|
|
|
|
|
|
let expand_str ~dir ~f template =
|
|
|
|
String_with_vars.expand template ~f:(fun var ->
|
|
|
|
match f var with
|
|
|
|
| Not_found -> None
|
|
|
|
| Path path -> Some (Path.reach ~from:dir path)
|
|
|
|
| Paths l -> Some (List.map l ~f:(Path.reach ~from:dir) |> String.concat ~sep:" ")
|
|
|
|
| Str s -> Some s)
|
|
|
|
|
|
|
|
let expand_path ~dir ~f template =
|
|
|
|
match String_with_vars.just_a_var template with
|
|
|
|
| None -> expand_str ~dir ~f template |> Path.relative dir
|
|
|
|
| Some v ->
|
|
|
|
match f v with
|
|
|
|
| Not_found -> expand_str ~dir ~f template |> Path.relative dir
|
2017-03-03 13:23:44 +00:00
|
|
|
| Path p
|
|
|
|
| Paths [p] -> p
|
2017-03-03 11:49:40 +00:00
|
|
|
| Str s -> Path.relative dir s
|
|
|
|
| Paths l ->
|
|
|
|
List.map l ~f:(Path.reach ~from:dir)
|
|
|
|
|> String.concat ~sep:" "
|
2017-03-03 13:23:44 +00:00
|
|
|
|> Path.relative dir
|
2017-03-03 11:49:40 +00:00
|
|
|
|
2017-03-06 12:22:44 +00:00
|
|
|
let expand_prog ctx ~dir ~f template =
|
|
|
|
let resolve s =
|
|
|
|
if String.contains s '/' then
|
|
|
|
Path.relative dir s
|
|
|
|
else
|
|
|
|
match Context.which ctx s with
|
|
|
|
| Some p -> p
|
2017-03-31 16:31:55 +00:00
|
|
|
| None -> Utils.program_not_found ~context:ctx.name s
|
2017-03-06 12:22:44 +00:00
|
|
|
in
|
|
|
|
match String_with_vars.just_a_var template with
|
|
|
|
| None -> resolve (expand_str ~dir ~f template)
|
|
|
|
| Some v ->
|
|
|
|
match f v with
|
|
|
|
| Not_found -> resolve (expand_str ~dir ~f template)
|
|
|
|
| Path p
|
|
|
|
| Paths [p] -> p
|
|
|
|
| Str s -> resolve s
|
|
|
|
| Paths l ->
|
|
|
|
List.map l ~f:(Path.reach ~from:dir)
|
|
|
|
|> String.concat ~sep:" "
|
|
|
|
|> resolve
|
|
|
|
|
2017-02-27 13:34:16 +00:00
|
|
|
module Mini_shexp = struct
|
2017-03-03 12:59:52 +00:00
|
|
|
module Ast = struct
|
2017-03-13 08:10:33 +00:00
|
|
|
type outputs =
|
|
|
|
| Stdout
|
|
|
|
| Stderr
|
|
|
|
| Outputs (* Both Stdout and Stderr *)
|
|
|
|
|
|
|
|
let string_of_outputs = function
|
|
|
|
| Stdout -> "stdout"
|
|
|
|
| Stderr -> "stderr"
|
|
|
|
| Outputs -> "outputs"
|
|
|
|
|
2017-03-03 12:59:52 +00:00
|
|
|
type ('a, 'path) t =
|
|
|
|
| Run of 'path * 'a list
|
|
|
|
| Chdir of 'path * ('a, 'path) t
|
|
|
|
| Setenv of 'a * 'a * ('a, 'path) t
|
2017-03-13 08:10:33 +00:00
|
|
|
| Redirect of outputs * 'path * ('a, 'path) t
|
|
|
|
| Ignore of outputs * ('a, 'path) t
|
2017-03-03 12:59:52 +00:00
|
|
|
| Progn of ('a, 'path) t list
|
|
|
|
| Echo of 'a
|
|
|
|
| Create_file of 'path
|
|
|
|
| Cat of 'path
|
|
|
|
| Copy of 'path * 'path
|
|
|
|
| Symlink of 'path * 'path
|
|
|
|
| Copy_and_add_line_directive of 'path * 'path
|
|
|
|
| System of 'a
|
|
|
|
| Bash of 'a
|
2017-05-26 17:08:07 +00:00
|
|
|
| Update_file of 'path * 'a
|
2017-03-31 14:06:53 +00:00
|
|
|
| Rename of 'path * 'path
|
2017-05-26 17:08:07 +00:00
|
|
|
| Remove_tree of 'path
|
2017-02-27 13:34:16 +00:00
|
|
|
|
2017-03-03 12:59:52 +00:00
|
|
|
let rec t a p sexp =
|
|
|
|
sum
|
|
|
|
[ cstr_rest "run" (p @> nil) a (fun prog args -> Run (prog, args))
|
|
|
|
; cstr "chdir" (p @> t a p @> nil) (fun dn t -> Chdir (dn, t))
|
|
|
|
; cstr "setenv" (a @> a @> t a p @> nil) (fun k v t -> Setenv (k, v, t))
|
2017-03-13 08:10:33 +00:00
|
|
|
; cstr "with-stdout-to" (p @> t a p @> nil) (fun fn t -> Redirect (Stdout, fn, t))
|
|
|
|
; cstr "with-stderr-to" (p @> t a p @> nil) (fun fn t -> Redirect (Stderr, fn, t))
|
|
|
|
; cstr "with-outputs-to" (p @> t a p @> nil) (fun fn t -> Redirect (Outputs, fn, t))
|
|
|
|
; cstr "ignore-stdout" (t a p @> nil) (fun t -> Ignore (Stdout, t))
|
|
|
|
; cstr "ignore-stderr" (t a p @> nil) (fun t -> Ignore (Stderr, t))
|
|
|
|
; cstr "ignore-outputs" (t a p @> nil) (fun t -> Ignore (Outputs, t))
|
2017-03-03 12:59:52 +00:00
|
|
|
; cstr_rest "progn" nil (t a p) (fun l -> Progn l)
|
|
|
|
; cstr "echo" (a @> nil) (fun x -> Echo x)
|
|
|
|
; cstr "cat" (p @> nil) (fun x -> Cat x)
|
|
|
|
; cstr "create-file" (p @> nil) (fun x -> Create_file x)
|
|
|
|
; cstr "copy" (p @> p @> nil) (fun src dst -> Copy (src, dst))
|
2017-03-03 09:18:03 +00:00
|
|
|
(*
|
2017-03-03 12:59:52 +00:00
|
|
|
(* We don't expose symlink to the user yet since this might complicate things *)
|
|
|
|
; cstr "symlink" (a @> a @> nil) (fun src dst -> Symlink (dst, Cat src))
|
|
|
|
*)
|
|
|
|
; cstr "copy-and-add-line-directive" (p @> p @> nil) (fun src dst ->
|
|
|
|
Copy_and_add_line_directive (src, dst))
|
|
|
|
; cstr "system" (a @> nil) (fun cmd -> System cmd)
|
2017-03-03 13:18:52 +00:00
|
|
|
; cstr "bash" (a @> nil) (fun cmd -> Bash cmd)
|
2017-03-03 12:59:52 +00:00
|
|
|
]
|
|
|
|
sexp
|
2017-02-27 13:34:16 +00:00
|
|
|
|
2017-03-03 12:59:52 +00:00
|
|
|
let rec sexp_of_t f g : _ -> Sexp.t = function
|
|
|
|
| Run (a, xs) -> List (Atom "run" :: g a :: List.map xs ~f)
|
|
|
|
| Chdir (a, r) -> List [Atom "chdir" ; g a ; sexp_of_t f g r]
|
|
|
|
| Setenv (k, v, r) -> List [Atom "setenv" ; f k ; f v ; sexp_of_t f g r]
|
2017-03-13 08:10:33 +00:00
|
|
|
| Redirect (outputs, fn, r) ->
|
|
|
|
List [ Atom (sprintf "with-%s-to" (string_of_outputs outputs))
|
|
|
|
; g fn
|
|
|
|
; sexp_of_t f g r
|
|
|
|
]
|
|
|
|
| Ignore (outputs, r) ->
|
|
|
|
List [ Atom (sprintf "ignore-%s" (string_of_outputs outputs))
|
|
|
|
; sexp_of_t f g r
|
|
|
|
]
|
2017-03-03 12:59:52 +00:00
|
|
|
| Progn l -> List (Atom "progn" :: List.map l ~f:(sexp_of_t f g))
|
|
|
|
| Echo x -> List [Atom "echo"; f x]
|
|
|
|
| Cat x -> List [Atom "cat"; g x]
|
|
|
|
| Create_file x -> List [Atom "create-file"; g x]
|
|
|
|
| Copy (x, y) ->
|
|
|
|
List [Atom "copy"; g x; g y]
|
|
|
|
| Symlink (x, y) ->
|
|
|
|
List [Atom "symlink"; g x; g y]
|
|
|
|
| Copy_and_add_line_directive (x, y) ->
|
|
|
|
List [Atom "copy-and-add-line-directive"; g x; g y]
|
|
|
|
| System x -> List [Atom "system"; f x]
|
|
|
|
| Bash x -> List [Atom "bash"; f x]
|
2017-03-15 09:15:47 +00:00
|
|
|
| Update_file (x, y) -> List [Atom "update-file"; g x; f y]
|
2017-03-31 14:06:53 +00:00
|
|
|
| Rename (x, y) -> List [Atom "rename"; g x; g y]
|
2017-05-26 17:08:07 +00:00
|
|
|
| Remove_tree x -> List [Atom "remove-tree"; g x]
|
2017-02-27 13:34:16 +00:00
|
|
|
|
2017-03-03 12:59:52 +00:00
|
|
|
let rec fold t ~init:acc ~f =
|
|
|
|
match t with
|
|
|
|
| Run (prog, args) -> List.fold_left args ~init:(f acc prog) ~f
|
|
|
|
| Chdir (fn, t) -> fold t ~init:(f acc fn) ~f
|
|
|
|
| Setenv (var, value, t) -> fold t ~init:(f (f acc var) value) ~f
|
2017-03-13 08:10:33 +00:00
|
|
|
| Redirect (_, fn, t) -> fold t ~init:(f acc fn) ~f
|
|
|
|
| Ignore (_, t) -> fold t ~init:acc ~f
|
2017-03-03 12:59:52 +00:00
|
|
|
| Progn l -> List.fold_left l ~init:acc ~f:(fun init t -> fold t ~init ~f)
|
|
|
|
| Echo x -> f acc x
|
|
|
|
| Cat x -> f acc x
|
|
|
|
| Create_file x -> f acc x
|
|
|
|
| Copy (x, y) -> f (f acc x) y
|
|
|
|
| Symlink (x, y) -> f (f acc x) y
|
|
|
|
| Copy_and_add_line_directive (x, y) -> f (f acc x) y
|
|
|
|
| System x -> f acc x
|
|
|
|
| Bash x -> f acc x
|
2017-03-06 14:34:53 +00:00
|
|
|
| Update_file (x, y) -> f (f acc x) y
|
2017-03-31 14:06:53 +00:00
|
|
|
| Rename (x, y) -> f (f acc x) y
|
2017-05-26 17:08:07 +00:00
|
|
|
| Remove_tree x -> f acc x
|
2017-03-31 14:06:53 +00:00
|
|
|
|
2017-04-17 12:20:21 +00:00
|
|
|
let fold_one_step t ~init:acc ~f =
|
|
|
|
match t with
|
|
|
|
| Chdir (_, t)
|
|
|
|
| Setenv (_, _, t)
|
|
|
|
| Redirect (_, _, t)
|
|
|
|
| Ignore (_, t) -> f acc t
|
|
|
|
| Progn l -> List.fold_left l ~init:acc ~f
|
|
|
|
| Run _
|
|
|
|
| Echo _
|
|
|
|
| Cat _
|
|
|
|
| Create_file _
|
|
|
|
| Copy _
|
|
|
|
| Symlink _
|
|
|
|
| Copy_and_add_line_directive _
|
|
|
|
| System _
|
|
|
|
| Bash _
|
|
|
|
| Update_file _
|
2017-05-26 17:08:07 +00:00
|
|
|
| Rename _
|
|
|
|
| Remove_tree _ -> acc
|
2017-04-17 12:20:21 +00:00
|
|
|
|
2017-03-31 14:06:53 +00:00
|
|
|
let rec map
|
|
|
|
: 'a 'b 'c 'd. ('a, 'b) t -> f1:('a -> 'c) -> f2:('b -> 'd) -> ('c, 'd) t
|
|
|
|
= fun t ~f1 ~f2 ->
|
|
|
|
match t with
|
|
|
|
| Run (prog, args) ->
|
|
|
|
Run (f2 prog, List.map args ~f:f1)
|
|
|
|
| Chdir (fn, t) ->
|
|
|
|
Chdir (f2 fn, map t ~f1 ~f2)
|
|
|
|
| Setenv (var, value, t) ->
|
|
|
|
Setenv (f1 var, f1 value, map t ~f1 ~f2)
|
|
|
|
| Redirect (outputs, fn, t) ->
|
|
|
|
Redirect (outputs, f2 fn, map t ~f1 ~f2)
|
|
|
|
| Ignore (outputs, t) ->
|
|
|
|
Ignore (outputs, map t ~f1 ~f2)
|
|
|
|
| Progn l -> Progn (List.map l ~f:(fun t -> map t ~f1 ~f2))
|
|
|
|
| Echo x -> Echo (f1 x)
|
|
|
|
| Cat x -> Cat (f2 x)
|
|
|
|
| Create_file x -> Create_file (f2 x)
|
|
|
|
| Copy (x, y) -> Copy (f2 x, f2 y)
|
|
|
|
| Symlink (x, y) ->
|
|
|
|
Symlink (f2 x, f2 y)
|
|
|
|
| Copy_and_add_line_directive (x, y) ->
|
|
|
|
Copy_and_add_line_directive (f2 x, f2 y)
|
|
|
|
| System x -> System (f1 x)
|
|
|
|
| Bash x -> Bash (f1 x)
|
|
|
|
| Update_file (x, y) -> Update_file (f2 x, f1 y)
|
|
|
|
| Rename (x, y) -> Rename (f2 x, f2 y)
|
2017-05-26 17:08:07 +00:00
|
|
|
| Remove_tree x -> Remove_tree (f2 x)
|
2017-03-03 12:59:52 +00:00
|
|
|
end
|
|
|
|
open Ast
|
|
|
|
|
|
|
|
type t = (string, Path.t) Ast.t
|
|
|
|
let t = Ast.t string Path.t
|
|
|
|
let sexp_of_t = Ast.sexp_of_t Sexp.To_sexp.string Path.sexp_of_t
|
2017-02-27 13:34:16 +00:00
|
|
|
|
2017-03-07 10:14:16 +00:00
|
|
|
let updated_files =
|
|
|
|
let rec loop acc t =
|
2017-04-17 12:20:21 +00:00
|
|
|
let acc =
|
|
|
|
match t with
|
|
|
|
| Update_file (fn, _) -> Path.Set.add fn acc
|
|
|
|
| _ -> acc
|
|
|
|
in
|
|
|
|
Ast.fold_one_step t ~init:acc ~f:loop
|
2017-03-07 10:14:16 +00:00
|
|
|
in
|
|
|
|
fun t -> loop Path.Set.empty t
|
|
|
|
|
2017-05-25 15:20:10 +00:00
|
|
|
let chdirs =
|
|
|
|
let rec loop acc t =
|
|
|
|
let acc =
|
|
|
|
match t with
|
|
|
|
| Chdir (dir, _) -> Path.Set.add dir acc
|
|
|
|
| _ -> acc
|
|
|
|
in
|
|
|
|
Ast.fold_one_step t ~init:acc ~f:loop
|
|
|
|
in
|
|
|
|
fun t -> loop Path.Set.empty t
|
|
|
|
|
2017-03-03 12:59:52 +00:00
|
|
|
module Unexpanded = struct
|
|
|
|
type t = (String_with_vars.t, String_with_vars.t) Ast.t
|
|
|
|
let sexp_of_t = Ast.sexp_of_t String_with_vars.sexp_of_t String_with_vars.sexp_of_t
|
|
|
|
|
2017-03-03 13:47:51 +00:00
|
|
|
let t sexp =
|
|
|
|
match sexp with
|
|
|
|
| Atom _ ->
|
|
|
|
of_sexp_errorf sexp
|
|
|
|
"if you meant for this to be executed with bash, write (bash \"...\") instead"
|
|
|
|
| List _ -> Ast.t String_with_vars.t String_with_vars.t sexp
|
|
|
|
|
2017-03-03 12:59:52 +00:00
|
|
|
let fold_vars t ~init ~f =
|
|
|
|
Ast.fold t ~init ~f:(fun acc pat ->
|
|
|
|
String_with_vars.fold ~init:acc pat ~f)
|
|
|
|
|
2017-03-06 12:22:44 +00:00
|
|
|
let rec expand ctx dir t ~f : (string, Path.t) Ast.t =
|
2017-03-03 12:59:52 +00:00
|
|
|
match t with
|
|
|
|
| Run (prog, args) ->
|
2017-03-06 12:22:44 +00:00
|
|
|
Run (expand_prog ctx ~dir ~f prog,
|
2017-03-03 12:59:52 +00:00
|
|
|
List.map args ~f:(fun arg -> expand_str ~dir ~f arg))
|
|
|
|
| Chdir (fn, t) ->
|
|
|
|
let fn = expand_path ~dir ~f fn in
|
2017-03-06 12:22:44 +00:00
|
|
|
Chdir (fn, expand ctx fn t ~f)
|
2017-03-03 12:59:52 +00:00
|
|
|
| Setenv (var, value, t) ->
|
|
|
|
Setenv (expand_str ~dir ~f var, expand_str ~dir ~f value,
|
2017-03-06 12:22:44 +00:00
|
|
|
expand ctx dir t ~f)
|
2017-03-13 08:10:33 +00:00
|
|
|
| Redirect (outputs, fn, t) ->
|
|
|
|
Redirect (outputs, expand_path ~dir ~f fn, expand ctx dir t ~f)
|
|
|
|
| Ignore (outputs, t) ->
|
|
|
|
Ignore (outputs, expand ctx dir t ~f)
|
2017-03-06 12:22:44 +00:00
|
|
|
| Progn l -> Progn (List.map l ~f:(fun t -> expand ctx dir t ~f))
|
2017-03-03 12:59:52 +00:00
|
|
|
| Echo x -> Echo (expand_str ~dir ~f x)
|
|
|
|
| Cat x -> Cat (expand_path ~dir ~f x)
|
|
|
|
| Create_file x -> Create_file (expand_path ~dir ~f x)
|
|
|
|
| Copy (x, y) ->
|
|
|
|
Copy (expand_path ~dir ~f x, expand_path ~dir ~f y)
|
|
|
|
| Symlink (x, y) ->
|
|
|
|
Symlink (expand_path ~dir ~f x, expand_path ~dir ~f y)
|
|
|
|
| Copy_and_add_line_directive (x, y) ->
|
|
|
|
Copy_and_add_line_directive (expand_path ~dir ~f x, expand_path ~dir ~f y)
|
|
|
|
| System x -> System (expand_str ~dir ~f x)
|
|
|
|
| Bash x -> Bash (expand_str ~dir ~f x)
|
2017-03-06 14:34:53 +00:00
|
|
|
| Update_file (x, y) -> Update_file (expand_path ~dir ~f x, expand_str ~dir ~f y)
|
2017-03-31 14:06:53 +00:00
|
|
|
| Rename (x, y) ->
|
|
|
|
Rename (expand_path ~dir ~f x, expand_path ~dir ~f y)
|
2017-05-26 17:08:07 +00:00
|
|
|
| Remove_tree x ->
|
|
|
|
Remove_tree (expand_path ~dir ~f x)
|
2017-03-03 12:59:52 +00:00
|
|
|
end
|
2017-03-03 11:49:40 +00:00
|
|
|
|
|
|
|
open Future
|
|
|
|
|
2017-03-13 08:10:33 +00:00
|
|
|
let get_std_output : _ -> Future.std_output_to = function
|
|
|
|
| None -> Terminal
|
|
|
|
| Some (fn, oc) -> Opened_file { filename = fn; tail = false; desc = Channel oc }
|
|
|
|
|
2017-03-30 16:36:58 +00:00
|
|
|
let run ~purpose ~dir ~env ~env_extra ~stdout_to ~stderr_to prog args =
|
2017-03-13 08:10:33 +00:00
|
|
|
let stdout_to = get_std_output stdout_to in
|
|
|
|
let stderr_to = get_std_output stderr_to in
|
2017-03-03 11:49:40 +00:00
|
|
|
let env = Context.extend_env ~vars:env_extra ~env in
|
2017-03-30 16:36:58 +00:00
|
|
|
Future.run Strict ~dir:(Path.to_string dir) ~env ~stdout_to ~stderr_to ~purpose
|
2017-03-03 13:53:34 +00:00
|
|
|
(Path.reach_for_running ~from:dir prog) args
|
2017-03-03 11:49:40 +00:00
|
|
|
|
2017-03-30 16:36:58 +00:00
|
|
|
let rec exec t ~purpose ~dir ~env ~env_extra ~stdout_to ~stderr_to =
|
2017-03-03 11:49:40 +00:00
|
|
|
match t with
|
|
|
|
| Run (prog, args) ->
|
2017-03-30 16:36:58 +00:00
|
|
|
run ~purpose ~dir ~env ~env_extra ~stdout_to ~stderr_to prog args
|
2017-03-03 11:49:40 +00:00
|
|
|
| Chdir (dir, t) ->
|
2017-03-30 16:36:58 +00:00
|
|
|
exec t ~purpose ~env ~env_extra ~stdout_to ~stderr_to ~dir
|
2017-03-03 11:49:40 +00:00
|
|
|
| Setenv (var, value, t) ->
|
2017-03-30 16:36:58 +00:00
|
|
|
exec t ~purpose ~dir ~env ~stdout_to ~stderr_to
|
2017-04-24 11:27:13 +00:00
|
|
|
~env_extra:(Env_var_map.add env_extra ~key:var ~data:value)
|
2017-03-13 08:10:33 +00:00
|
|
|
| Redirect (outputs, fn, t) ->
|
2017-03-30 16:36:58 +00:00
|
|
|
redirect ~purpose outputs fn t ~dir ~env ~env_extra ~stdout_to ~stderr_to
|
2017-03-13 08:10:33 +00:00
|
|
|
| Ignore (outputs, t) ->
|
2017-03-30 16:36:58 +00:00
|
|
|
redirect ~purpose outputs Config.dev_null t ~dir ~env ~env_extra ~stdout_to ~stderr_to
|
2017-03-03 11:49:40 +00:00
|
|
|
| Progn l ->
|
2017-03-30 16:36:58 +00:00
|
|
|
exec_list l ~purpose ~dir ~env ~env_extra ~stdout_to ~stderr_to
|
2017-03-03 11:49:40 +00:00
|
|
|
| Echo str ->
|
|
|
|
return
|
|
|
|
(match stdout_to with
|
|
|
|
| None -> print_string str; flush stdout
|
2017-03-13 08:10:33 +00:00
|
|
|
| Some (_, oc) -> output_string oc str)
|
2017-03-03 11:49:40 +00:00
|
|
|
| Cat fn ->
|
2017-05-18 16:11:39 +00:00
|
|
|
Io.with_file_in (Path.to_string fn) ~f:(fun ic ->
|
2017-03-13 08:10:33 +00:00
|
|
|
let oc =
|
|
|
|
match stdout_to with
|
|
|
|
| None -> stdout
|
|
|
|
| Some (_, oc) -> oc
|
|
|
|
in
|
2017-05-18 16:11:39 +00:00
|
|
|
Io.copy_channels ic oc);
|
2017-03-03 11:49:40 +00:00
|
|
|
return ()
|
|
|
|
| Create_file fn ->
|
|
|
|
let fn = Path.to_string fn in
|
|
|
|
if Sys.file_exists fn then Sys.remove fn;
|
|
|
|
Unix.close (Unix.openfile fn [O_CREAT; O_TRUNC; O_WRONLY] 0o666);
|
|
|
|
return ()
|
|
|
|
| Copy (src, dst) ->
|
2017-05-18 16:11:39 +00:00
|
|
|
Io.copy_file ~src:(Path.to_string src) ~dst:(Path.to_string dst);
|
2017-03-03 11:49:40 +00:00
|
|
|
return ()
|
|
|
|
| Symlink (src, dst) ->
|
|
|
|
if Sys.win32 then
|
2017-05-18 16:11:39 +00:00
|
|
|
Io.copy_file ~src:(Path.to_string src) ~dst:(Path.to_string dst)
|
2017-03-03 11:49:40 +00:00
|
|
|
else begin
|
|
|
|
let src =
|
|
|
|
if Path.is_root dst then
|
|
|
|
Path.to_string src
|
|
|
|
else
|
|
|
|
Path.reach ~from:(Path.parent dst) src
|
|
|
|
in
|
|
|
|
let dst = Path.to_string dst in
|
|
|
|
match Unix.readlink dst with
|
|
|
|
| target ->
|
|
|
|
if target <> src then begin
|
|
|
|
Unix.unlink dst;
|
|
|
|
Unix.symlink src dst
|
|
|
|
end
|
|
|
|
| exception _ ->
|
|
|
|
Unix.symlink src dst
|
|
|
|
end;
|
|
|
|
return ()
|
|
|
|
| Copy_and_add_line_directive (src, dst) ->
|
2017-05-18 16:11:39 +00:00
|
|
|
Io.with_file_in (Path.to_string src) ~f:(fun ic ->
|
|
|
|
Io.with_file_out (Path.to_string dst) ~f:(fun oc ->
|
2017-05-12 14:05:07 +00:00
|
|
|
let fn = Path.drop_build_context src in
|
2017-03-03 11:49:40 +00:00
|
|
|
Printf.fprintf oc "# 1 %S\n" (Path.to_string fn);
|
2017-05-18 16:11:39 +00:00
|
|
|
Io.copy_channels ic oc));
|
2017-03-03 11:49:40 +00:00
|
|
|
return ()
|
2017-03-24 11:04:24 +00:00
|
|
|
| System cmd ->
|
|
|
|
let path, arg =
|
|
|
|
Utils.system_shell_exn ~needed_to:"interpret (system ...) actions"
|
2017-03-03 11:49:40 +00:00
|
|
|
in
|
2017-03-30 16:36:58 +00:00
|
|
|
run ~purpose ~dir ~env ~env_extra ~stdout_to ~stderr_to path [arg; cmd]
|
2017-03-03 12:59:52 +00:00
|
|
|
| Bash cmd ->
|
2017-03-30 16:36:58 +00:00
|
|
|
run ~purpose ~dir ~env ~env_extra ~stdout_to ~stderr_to
|
2017-03-24 11:04:24 +00:00
|
|
|
(Utils.bash_exn ~needed_to:"interpret (bash ...) actions")
|
2017-03-03 12:59:52 +00:00
|
|
|
["-e"; "-u"; "-o"; "pipefail"; "-c"; cmd]
|
2017-03-06 14:34:53 +00:00
|
|
|
| Update_file (fn, s) ->
|
2017-03-03 15:26:14 +00:00
|
|
|
let fn = Path.to_string fn in
|
2017-05-18 16:11:39 +00:00
|
|
|
if Sys.file_exists fn && Io.read_file fn = s then
|
2017-03-03 15:26:14 +00:00
|
|
|
()
|
|
|
|
else
|
2017-05-18 16:11:39 +00:00
|
|
|
Io.write_file fn s;
|
2017-03-03 15:26:14 +00:00
|
|
|
return ()
|
2017-03-31 14:06:53 +00:00
|
|
|
| Rename (src, dst) ->
|
|
|
|
Unix.rename (Path.to_string src) (Path.to_string dst);
|
|
|
|
return ()
|
2017-05-26 17:08:07 +00:00
|
|
|
| Remove_tree path ->
|
|
|
|
Path.rm_rf path;
|
|
|
|
return ()
|
2017-03-03 11:49:40 +00:00
|
|
|
|
2017-03-30 16:36:58 +00:00
|
|
|
and redirect outputs fn t ~purpose ~dir ~env ~env_extra ~stdout_to ~stderr_to =
|
2017-03-13 08:10:33 +00:00
|
|
|
let fn = Path.to_string fn in
|
2017-05-18 16:11:39 +00:00
|
|
|
let oc = Io.open_out fn in
|
2017-03-13 08:10:33 +00:00
|
|
|
let out = Some (fn, oc) in
|
|
|
|
let stdout_to, stderr_to =
|
|
|
|
match outputs with
|
|
|
|
| Stdout -> (out, stderr_to)
|
|
|
|
| Stderr -> (stdout_to, out)
|
|
|
|
| Outputs -> (out, out)
|
|
|
|
in
|
2017-03-30 16:36:58 +00:00
|
|
|
exec t ~purpose ~dir ~env ~env_extra ~stdout_to ~stderr_to >>| fun () ->
|
2017-03-13 08:10:33 +00:00
|
|
|
close_out oc
|
|
|
|
|
2017-03-30 16:36:58 +00:00
|
|
|
and exec_list l ~purpose ~dir ~env ~env_extra ~stdout_to ~stderr_to =
|
2017-03-03 11:49:40 +00:00
|
|
|
match l with
|
|
|
|
| [] ->
|
|
|
|
Future.return ()
|
|
|
|
| [t] ->
|
2017-03-30 16:36:58 +00:00
|
|
|
exec t ~purpose ~dir ~env ~env_extra ~stdout_to ~stderr_to
|
2017-03-03 11:49:40 +00:00
|
|
|
| t :: rest ->
|
2017-03-30 16:36:58 +00:00
|
|
|
exec t ~purpose ~dir ~env ~env_extra ~stdout_to ~stderr_to >>= fun () ->
|
|
|
|
exec_list rest ~purpose ~dir ~env ~env_extra ~stdout_to ~stderr_to
|
2017-02-27 13:34:16 +00:00
|
|
|
end
|
|
|
|
|
2017-03-03 09:18:03 +00:00
|
|
|
type t =
|
2017-03-03 11:49:40 +00:00
|
|
|
{ context : Context.t option
|
2017-03-03 12:59:52 +00:00
|
|
|
; action : Mini_shexp.t
|
2017-03-03 09:18:03 +00:00
|
|
|
}
|
2017-02-27 13:34:16 +00:00
|
|
|
|
2017-05-25 15:20:10 +00:00
|
|
|
let sexp_of_t { context; action } =
|
2017-03-03 11:49:40 +00:00
|
|
|
let fields : Sexp.t list =
|
2017-05-25 15:20:10 +00:00
|
|
|
[ List [ Atom "action" ; Mini_shexp.sexp_of_t action ]
|
2017-03-03 09:18:03 +00:00
|
|
|
]
|
2017-03-03 11:49:40 +00:00
|
|
|
in
|
|
|
|
let fields =
|
|
|
|
match context with
|
|
|
|
| None -> fields
|
|
|
|
| Some { name; _ } -> List [ Atom "context"; Atom name ] :: fields
|
|
|
|
in
|
|
|
|
Sexp.List fields
|
|
|
|
|
2017-05-25 15:20:10 +00:00
|
|
|
let exec ~targets { action; context } =
|
2017-03-03 11:49:40 +00:00
|
|
|
let env =
|
|
|
|
match context with
|
|
|
|
| None -> Lazy.force Context.initial_env
|
|
|
|
| Some c -> c.env
|
|
|
|
in
|
2017-03-30 16:36:58 +00:00
|
|
|
let targets = Path.Set.elements targets in
|
|
|
|
let purpose = Future.Build_job targets in
|
2017-05-25 15:20:10 +00:00
|
|
|
Mini_shexp.exec action ~purpose ~dir:Path.root ~env ~env_extra:Env_var_map.empty
|
2017-03-13 08:10:33 +00:00
|
|
|
~stdout_to:None ~stderr_to:None
|
2017-03-03 15:26:14 +00:00
|
|
|
|
2017-03-31 14:06:53 +00:00
|
|
|
let sandbox t ~sandboxed ~deps ~targets =
|
|
|
|
let action =
|
|
|
|
let module M = Mini_shexp.Ast in
|
|
|
|
M.Progn
|
2017-03-31 14:15:54 +00:00
|
|
|
[ M.Progn (List.filter_map deps ~f:(fun path ->
|
|
|
|
if Path.is_local path then
|
|
|
|
Some (M.Symlink (path, sandboxed path))
|
|
|
|
else
|
|
|
|
None))
|
2017-03-31 14:06:53 +00:00
|
|
|
; M.map t.action ~f1:(fun x -> x) ~f2:sandboxed
|
2017-03-31 14:15:54 +00:00
|
|
|
; M.Progn (List.filter_map targets ~f:(fun path ->
|
|
|
|
if Path.is_local path then
|
|
|
|
Some (M.Rename (sandboxed path, path))
|
|
|
|
else
|
|
|
|
None))
|
2017-03-31 14:06:53 +00:00
|
|
|
]
|
|
|
|
in
|
2017-05-25 15:20:10 +00:00
|
|
|
{ t with action }
|
2017-03-31 14:06:53 +00:00
|
|
|
|
2017-05-25 15:20:10 +00:00
|
|
|
type for_hash = string option * Mini_shexp.t
|
2017-03-03 15:26:14 +00:00
|
|
|
|
2017-05-25 15:20:10 +00:00
|
|
|
let for_hash { context; action } =
|
|
|
|
(Option.map context ~f:(fun c -> c.name), action)
|