Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions bin/common.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1380,8 +1380,8 @@ let init_with_root ~(root : Workspace_root.t) (builder : Builder.t) =
];
Log.info
[ Pp.textf
"Shared cache location: %s"
(Path.to_string (Lazy.force Dune_cache_storage.Layout.root_dir))
"Shared build cache location: %s"
(Path.to_string (Lazy.force Dune_cache_storage.Layout.build_cache_dir))
];
Dune_rules.Main.init
~stats:c.stats
Expand Down Expand Up @@ -1505,8 +1505,15 @@ let envs =
~doc:"If different than $(b,0), ANSI colors should be enabled no matter what."
"CLICOLOR_FORCE"
; info
~doc:
"If set, determines the location of all the different caches used by dune. \
Defaults to XDG_CACHE_HOME/dune if unset."
"DUNE_CACHE_HOME"
; info
~doc:
"If set, determines the location of the machine-global shared cache. This is \
the main build cache used by dune. Defaults to DUNE_CACHE_HOME/db if unset"
"DUNE_CACHE_ROOT"
~doc:"If set, determines the location of the machine-global shared cache."
]
;;

Expand Down
4 changes: 4 additions & 0 deletions doc/changes/fixed/11612.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- Introduce a new variable `$DUNE_CACHE_HOME` encompassing all dune caches,
instead of relying only on `$XDG_CACHE_HOME` in the case of toolchains /
git-repo / rev-store caches. `$DUNE_CACHE_ROOT` still exists and has priority,
but might be removed in the future. (#11612, fixes #11584, @ElectreAAS)
2 changes: 1 addition & 1 deletion src/dune_cache_storage/dune_cache_storage.ml
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I haven't changed the semantics of dune cache clear so it would also delete the revstore & toolchains cache, but that's debatable

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good question. In theory it changes the behavior but I guess it does make sense that dune cache clear removes all the cached data. Before we didn't have a way to clean out the rev-store nor the toolchains so I'd argue that this is an improvement.

One could extend the command to allow clearing only selected caches, but I don't see an urgent need for that, so I'd be willing to wait for users actually requesting this.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any kind of change to the caching command seems like it should land separately in any case.

Original file line number Diff line number Diff line change
Expand Up @@ -376,5 +376,5 @@ let clear () =
rm_rf (Lazy.force Layout.temp_dir);
(* Do not catch errors when deleting the root directory so that they are
reported to the user. *)
Path.rmdir (Lazy.force Layout.root_dir)
Path.rmdir (Lazy.force Layout.build_cache_dir)
;;
27 changes: 13 additions & 14 deletions src/dune_cache_storage/layout.ml
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
open Stdune
open Import

let default_root_dir =
lazy
(let cache_dir = Xdg.cache_dir (Lazy.force Dune_util.xdg) in
Path.L.relative (Path.of_filename_relative_to_initial_cwd cache_dir) [ "dune"; "db" ])
;;
let ( / ) = Path.relative

let root_dir =
let build_cache_dir =
lazy
(let var = "DUNE_CACHE_ROOT" in
match Sys.getenv_opt var with
| None -> Lazy.force default_root_dir
| Some path ->
if Filename.is_relative path
then failwith (sprintf "%s should be an absolute path, but is %s" var path);
Path.of_filename_relative_to_initial_cwd path)
then
User_error.raise
[ Pp.paragraphf "$%s should be an absolute path, but is %S" var path ];
Path.external_ (Path.External.of_string path)
| None -> Lazy.force Dune_util.cache_home_dir / "db")
;;

let ( / ) = Path.relative
let temp_dir = lazy (Lazy.force root_dir / "temp")
let temp_dir = lazy (Lazy.force build_cache_dir / "temp")

let cache_path ~dir ~hex =
let two_first_chars = sprintf "%c%c" hex.[0] hex.[1] in
Expand Down Expand Up @@ -52,13 +49,15 @@ let list_entries ~storage =

module Versioned = struct
let metadata_storage_dir t =
lazy (Lazy.force root_dir / "meta" / Version.Metadata.to_string t)
lazy (Lazy.force build_cache_dir / "meta" / Version.Metadata.to_string t)
;;

let file_storage_dir t = lazy (Lazy.force root_dir / "files" / Version.File.to_string t)
let file_storage_dir t =
lazy (Lazy.force build_cache_dir / "files" / Version.File.to_string t)
;;

let value_storage_dir t =
lazy (Lazy.force root_dir / "values" / Version.Value.to_string t)
lazy (Lazy.force build_cache_dir / "values" / Version.Value.to_string t)
;;

let metadata_path t ~rule_or_action_digest =
Expand Down
6 changes: 4 additions & 2 deletions src/dune_cache_storage/layout.mli
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
open Stdune
open Import

(** The path to the root directory of the cache. *)
val root_dir : Path.t Lazy.t
(** The directory containing the build cache.
Set to [$DUNE_CACHE_ROOT] if it exists, or
[Dune_util.cache_home_dir/db] otherwise. *)
val build_cache_dir : Path.t Lazy.t

(** Create a few subdirectories in [root_dir]. We expose this function because
we don't want to modify the file system when the cache is disabled.
Expand Down
37 changes: 17 additions & 20 deletions src/dune_pkg/rev_store.ml
Original file line number Diff line number Diff line change
Expand Up @@ -145,33 +145,28 @@ module Cache = struct
Dune_config.Config.make_toggle ~name:"rev_store_cache" ~default:`Disabled
;;

let cache_dir =
let revision_store_dir =
lazy
(let path =
Path.L.relative
(Lazy.force Dune_util.xdg
|> Xdg.cache_dir
|> Path.Outside_build_dir.of_string
|> Path.outside_build_dir)
[ "dune"; "rev_store" ]
in
(let path = Path.relative (Lazy.force Dune_util.cache_home_dir) "rev_store" in
let rev_store_cache = Dune_config.Config.get rev_store_cache in
Dune_util.Log.info
[ Pp.textf
"Revision store cache: %s"
(Dune_config.Config.Toggle.to_string rev_store_cache)
];
match rev_store_cache, Path.mkdir_p path with
| `Enabled, () ->
(* Why do we create the directory in all cases, and not just when enabled? *)
Path.mkdir_p path;
match rev_store_cache with
| `Enabled ->
Dune_util.Log.info
[ Pp.textf "Revision store cache location: %s" (Path.to_string path) ];
Some path
| `Disabled, () -> None)
| `Disabled -> None)
;;

let db =
lazy
(Lazy.force cache_dir
(Lazy.force revision_store_dir
|> Option.map ~f:(fun path ->
Lmdb.Env.create
~map_size:(Int64.to_int 5_000_000_000L) (* 5 GB *)
Expand Down Expand Up @@ -1220,13 +1215,15 @@ let content_of_files t files =
| None -> Cache.Key.Map.find_exn to_write key)
;;

let git_repo_dir =
lazy
(let dir = Path.relative (Lazy.force Dune_util.cache_home_dir) "git-repo" in
Dune_util.Log.info
[ Pp.textf "Git repository cache location: %s" (Path.to_string dir) ];
dir)
;;

let get =
Fiber.Lazy.create (fun () ->
let dir =
Path.L.relative
(Path.of_string (Xdg.cache_dir (Lazy.force Dune_util.xdg)))
[ "dune"; "git-repo" ]
in
load_or_create ~dir)
Fiber.Lazy.create (fun () -> load_or_create ~dir:(Lazy.force git_repo_dir))
|> Fiber.Lazy.force
;;
30 changes: 15 additions & 15 deletions src/dune_rules/pkg_toolchain.ml
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
open Import

let base_dir =
lazy
(let dir = Path.relative (Lazy.force Dune_util.cache_home_dir) "toolchains" in
Dune_util.Log.info [ Pp.textf "Toolchains cache location: %s" (Path.to_string dir) ];
Path.as_outside_build_dir_exn dir)
;;

let base_dir () =
let cache_dir =
Lazy.force Dune_util.xdg |> Xdg.cache_dir |> Path.Outside_build_dir.of_string
in
let path =
Path.Outside_build_dir.relative
(Path.Outside_build_dir.relative cache_dir "dune")
"toolchains"
in
(let path = Path.outside_build_dir path in
if not (Path.Untracked.exists path) then Path.mkdir_p path;
if not (Path.Untracked.is_directory path)
then
User_error.raise
[ Pp.textf "Expected %s to be a directory but it is not." (Path.to_string path) ]);
path
let base_dir = Lazy.force base_dir in
let path = Path.outside_build_dir base_dir in
if not (Path.Untracked.exists path) then Path.mkdir_p path;
if not (Path.Untracked.is_directory path)
then
User_error.raise
[ Pp.textf "Expected %s to be a directory but it is not." (Path.to_string path) ];
base_dir
;;

let pkg_dir (pkg : Dune_pkg.Lock_dir.Pkg.t) =
Expand Down
5 changes: 3 additions & 2 deletions src/dune_rules/pkg_toolchain.mli
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
open Import

(** The path to the directory that will contain all toolchain
versions. Creates the directory if it doesn't already exist. *)
versions. Creates the directory if it doesn't already exist.
Set to [Dune_util.cache_home_dir/toolchains]. *)
val base_dir : unit -> Path.Outside_build_dir.t

(** Dune will download and build the ocaml-base-compiler and
Expand All @@ -21,7 +22,7 @@ val is_compiler_and_toolchains_enabled : Package.Name.t -> bool

(** Returns the path to the directory containing the given package within the
toolchain directory. This will be something like
$XDG_CACHE_HOME/dune/toolchains/ocaml-base-compiler.5.2.1.XXXXXXXX where
[base_dir/ocaml-base-compiler.5.2.1.XXXXXXXX] where
XXXXXXXX is a hash of the package's lockfile. *)
val installation_prefix : Lock_dir.Pkg.t -> Path.Outside_build_dir.t

Expand Down
34 changes: 29 additions & 5 deletions src/dune_util/dune_util.ml
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
module Action = Action
module Alias_name = Alias_name
module Build_path_prefix_map = Build_path_prefix_map0
module Gc = Gc
module Global_lock = Global_lock
module Log = Log
module Persistent = Persistent
module Report_error = Report_error
module Stringlike = Stringlike

module type Stringlike = Stringlike_intf.S

module Build_path_prefix_map = Build_path_prefix_map0
module Global_lock = Global_lock
module Action = Action
module Alias_name = Alias_name
module Gc = Gc
open Stdune

let manual_xdg = ref None
Expand Down Expand Up @@ -38,6 +38,30 @@ let override_xdg : Xdg.t -> unit =
else manual_xdg := Some new_xdg
;;

let ( / ) = Path.relative

(** The default directory of all caches (build and others), used when
environment variables are unset.
Set to [$XDG_CACHE_HOME/dune]. *)
let default_cache_dir =
lazy
(let cache_dir = Xdg.cache_dir (Lazy.force xdg) in
Path.of_filename_relative_to_initial_cwd cache_dir / "dune")
;;

let cache_home_dir =
lazy
(let var = "DUNE_CACHE_HOME" in
match Sys.getenv_opt var with
| Some path ->
if Filename.is_relative path
then
User_error.raise
[ Pp.paragraphf "$%s should be an absolute path, but is %S" var path ];
Path.external_ (Path.External.of_string path)
| None -> Lazy.force default_cache_dir)
;;

let frames_per_second () =
match Dune_config.Config.(get threaded_console_frames_per_second) with
| `Custom fps -> fps
Expand Down
23 changes: 23 additions & 0 deletions src/dune_util/dune_util.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Action = Action
module Alias_name = Alias_name
module Build_path_prefix_map = Build_path_prefix_map0
module Gc = Gc
module Global_lock = Global_lock
module Log = Log
module Persistent = Persistent
module Report_error = Report_error
module Stringlike = Stringlike

module type Stringlike = Stringlike_intf.S

open Stdune

val xdg : Xdg.t Lazy.t
val override_xdg : Xdg.t -> unit

(** The directory containing all caches (build and others).
Set to [$DUNE_CACHE_HOME] if it exists, or
[$XDG_CACHE_HOME/dune] otherwise. *)
val cache_home_dir : Path.t Lazy.t

val frames_per_second : unit -> int
14 changes: 13 additions & 1 deletion test/blackbox-tests/test-cases/pkg/toolchain-installation.t
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ name so the output is consistent across test runs.
> sed 's/\(ocaml-base-compiler.1-\)[^/]*/\1HASH/'
> }

Attempt to build the project. This will fail due to the fake compiler
Attempt to build the project. This will fail due to the fake compiler,
but the fake compiler will end up installed as a toolchain package.
Also test that XDG_CACHE_HOME is respected.
$ XDG_CACHE_HOME=$PWD/fake-cache DUNE_CONFIG__TOOLCHAINS=enabled build_pkg ocaml-base-compiler 2>&1 | remove_hash

Enumerate the contents of the fake toolchains directory:
Expand All @@ -87,3 +88,14 @@ Enumerate the contents of the fake toolchains directory:
fake-cache/dune/toolchains/ocaml-base-compiler.1-HASH/target
fake-cache/dune/toolchains/ocaml-base-compiler.1-HASH/target/bin
fake-cache/dune/toolchains/ocaml-base-compiler.1-HASH/target/bin/ocamlc

Also test that DUNE_CACHE_HOME is respected.
$ DUNE_CACHE_HOME=$PWD/other-fake-cache DUNE_CONFIG__TOOLCHAINS=enabled build_pkg ocaml-base-compiler 2>&1 | remove_hash

Enumerate the contents of the fake toolchains directory:
$ find other-fake-cache/toolchains/ | sort | remove_hash
other-fake-cache/toolchains/
other-fake-cache/toolchains/ocaml-base-compiler.1-HASH
other-fake-cache/toolchains/ocaml-base-compiler.1-HASH/target
other-fake-cache/toolchains/ocaml-base-compiler.1-HASH/target/bin
other-fake-cache/toolchains/ocaml-base-compiler.1-HASH/target/bin/ocamlc
Loading