Skip to content

Commit

Permalink
fix: replace directory symlinking with copying
Browse files Browse the repository at this point in the history
Signed-off-by: Rudi Grinberg <me@rgrinberg.com>
  • Loading branch information
rgrinberg committed Dec 12, 2023
1 parent 01ba720 commit 46011a8
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 13 deletions.
12 changes: 6 additions & 6 deletions otherlibs/stdune/src/fpath.ml
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ let rm_rf fn =
;;

let traverse_files =
let rec loop root stack acc f =
let rec loop root stack acc on_file on_dir =
match stack with
| [] -> acc
| dir :: dirs ->
Expand All @@ -172,18 +172,18 @@ let traverse_files =
let stack, acc =
List.fold_left entries ~init:(dirs, acc) ~f:(fun (stack, acc) (fname, kind) ->
match (kind : Unix.file_kind) with
| S_DIR -> Filename.concat dir fname :: stack, acc
| S_REG -> stack, f ~dir fname acc
| S_DIR -> Filename.concat dir fname :: stack, on_dir ~dir fname acc
| S_REG -> stack, on_file ~dir fname acc
| S_LNK ->
let path = Filename.concat dir_path fname in
(match (Unix.stat path).st_kind with
| exception Unix.Unix_error (Unix.ENOENT, _, _) -> stack, acc
| S_DIR -> Filename.concat dir fname :: stack, acc
| S_REG -> stack, f ~dir fname acc
| S_REG -> stack, on_file ~dir fname acc
| _ -> stack, acc)
| _ -> stack, acc)
in
loop root stack acc f)
loop root stack acc on_file on_dir)
in
fun ~dir ~init ~f -> loop dir [ "" ] init f
fun ~dir ~init ~on_file ~on_dir -> loop dir [ "" ] init on_file on_dir
;;
3 changes: 2 additions & 1 deletion otherlibs/stdune/src/fpath.mli
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,6 @@ val is_root : string -> bool
val traverse_files
: dir:string
-> init:'acc
-> f:(dir:string -> Filename.t -> 'acc -> 'acc)
-> on_file:(dir:string -> Filename.t -> 'acc -> 'acc)
-> on_dir:(dir:string -> Filename.t -> 'acc -> 'acc)
-> 'acc
3 changes: 2 additions & 1 deletion src/dune_pkg/opam_repo.ml
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@ let scan_files_entries path =
Fpath.traverse_files
~dir:(Path.to_string path)
~init:[]
~f:(fun ~dir filename acc ->
~on_dir:(fun ~dir:_ _ acc -> acc)
~on_file:(fun ~dir filename acc ->
let local_path = Path.Local.relative (Path.Local.of_string dir) filename in
local_path :: acc)
with
Expand Down
71 changes: 66 additions & 5 deletions src/dune_rules/install_rules.ml
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,58 @@ let symlink_source_dir ~dir ~dst =
suffix, dst, Action_builder.symlink ~src ~dst)
;;

module Copy_dir = struct
module Spec = struct
type ('path, 'target) t = 'path * 'target

let name = "copy-dir"
let version = 1
let bimap (src, dst) f g = f src, g dst
let is_useful_to ~memoize = memoize

let encode (src, dst) f g =
Dune_sexp.List [ Dune_sexp.atom_or_quoted_string name; f src; g dst ]
;;

let action (src, dst) ~ectx:_ ~eenv:_ =
let all =
Fpath.traverse_files
~dir:(Path.to_string src)
~init:[]
~on_file:(fun ~dir fname acc -> `File (Filename.concat dir fname) :: acc)
~on_dir:(fun ~dir fname acc -> `Dir (Filename.concat dir fname) :: acc)
in
List.iter all ~f:(fun p ->
let dir, file =
match p with
| `Dir p -> p, None
| `File p -> Filename.dirname p, Some p
in
(* CR-rgrinberg: too many unnecesasry stat and mkdir calls here *)
let perms = (Path.Untracked.stat_exn (Path.relative src dir)).st_perm in
Path.mkdir_p ~perms (Path.build (Path.Build.relative dst dir));
Option.iter file ~f:(fun f ->
let src = Path.relative src f in
let dst = Path.build @@ Path.Build.relative dst f in
Io.copy_file ~src ~dst ()));
Fiber.return ()
;;
end

let action ~src ~dst =
let module M = struct
type path = Path.t
type target = Path.Build.t

module Spec = Spec

let v = src, dst
end
in
Action.Extension (module M)
;;
end

let symlink_installed_artifacts_to_build_install
sctx
(entries : Install.Entry.Sourced.t list)
Expand Down Expand Up @@ -949,11 +1001,20 @@ let symlink_installed_artifacts_to_build_install
{ s with entry }
in
let action =
(match kind with
| `File -> Action_builder.symlink
| `Directory -> Action_builder.symlink_dir)
~src
~dst
match kind with
| `File -> Action_builder.symlink ~src ~dst
| `Directory ->
let action =
let open Action_builder.O in
let+ () = Action_builder.dep (Dep.file src) in
Copy_dir.action ~src ~dst |> Action.Full.make
in
Action_builder.with_targets
action
~targets:
(Targets.create
~dirs:(Path.Build.Set.singleton dst)
~files:Path.Build.Set.empty)
in
Memo.return [ entry, rule action ])
;;
Expand Down

0 comments on commit 46011a8

Please sign in to comment.