summaryrefslogtreecommitdiff
path: root/lib/working_directory.ml
blob: 0c2a055c3f953029822533d61bb71a08c53544af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
(*─────────────────────────────────────────────────────────────────────────────┐
│ SPDX-FileCopyrightText: 2025 toastal <https://toast.al/contact/>             │
│ SPDX-License-Identifier: LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception │
└─────────────────────────────────────────────────────────────────────────────*)
let working_directory : [`Dir] Eio.Path.t option ref = ref None

let get () =
	match !working_directory with
	| Some dir -> dir
	| None -> failwith "Working directory not set up"

let set ~directory =
	working_directory := Some directory

let set_default ~env () =
	let new_dir =
		let cwd = Eio.Stdenv.cwd env in
		Eio.Path.(cwd / "nix" / "tamal")
	in
	working_directory := Some new_dir

let pp_native_path =
	Fmt.using
		Eio.Path.native
		(Fmt.option (fun ppf -> Fmt.pf ppf " @@ %a" Fmt.string))

let silo_dir = ".silo"

let darcs_context_dir = "darcs_context"

(* Without the need for magic strings, we can use tabs in Nix! *)
let root_editor_config_content =
	{|root = true

[*]
charset = utf-8
end_of_line = lf
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true

[lock.json]
insert_final_newline = unset
|}

let root_ignore_content =
	let open Fmt in
	str
		"%a@."
		(list ~sep: (Fmt.any "@.") string)
		[
			silo_dir;
			darcs_context_dir
		]

let set_up_editor_config ~dir ~content =
	let editor_config_file = Eio.Path.(dir / ".editorconfig") in
	Logs.info (fun m -> m "Writing new Nixtamal EditorConfig%a …" pp_native_path editor_config_file);
	Eio.Path.with_open_out ~create: (`Or_truncate 0o644) editor_config_file @@ fun flow ->
	Eio.Buf_write.with_flow flow @@ fun writer ->
	Eio.Buf_write.string writer content

let set_up_ignore ~dir ~content =
	let ignore_file = Eio.Path.(dir / ".ignore") in
	Logs.info (fun m -> m "Writing new Nixtamal ignore%a …" pp_native_path ignore_file);
	Eio.Path.with_open_out ~create: (`Or_truncate 0o644) ignore_file @@ fun flow ->
	Eio.Buf_write.with_flow flow @@ fun writer ->
	Eio.Buf_write.string writer content

let set_up_silo () =
	let dir = Eio.Path.(get () / silo_dir) in
	match Eio.Path.kind ~follow: true dir with
	| `Directory ->
		()
	| `Not_found ->
		Logs.info (fun m -> m "Making Nixtamal’s silo directory%a" pp_native_path dir);
		Eio.Path.mkdirs ~perm: 0o755 dir;
	| _ ->
		failwith @@ Fmt.str "There is a Nixtamal path, but is not a directory%a" pp_native_path dir

let set_up_root () =
	let dir = get () in
	match Eio.Path.kind ~follow: true dir with
	| `Not_found ->
		Logs.info (fun m -> m "Making Nixtamal directory%a" pp_native_path dir);
		Eio.Path.mkdirs ~perm: 0o755 dir;
		set_up_editor_config ~dir ~content: root_editor_config_content;
		set_up_silo ();
		set_up_ignore ~dir ~content: root_ignore_content
	| `Directory ->
		Logs.warn (fun m -> m "Nixtamal directory already exists%a" pp_native_path dir)
	| _ ->
		failwith @@ Fmt.str "There is a Nixtamal path, but is not a directory%a" pp_native_path dir

let darcs_context_editor_config_content =
	{|root = true
|}

let set_up_darcs_context_if_needed () : (unit, string) result =
	let dir = Eio.Path.(get () / darcs_context_dir) in
	match Eio.Path.kind ~follow: true dir with
	| `Directory ->
		Ok ()
	| `Not_found ->
		Logs.info (fun m -> m "Making Nixtamal’s darcs_context directory%a" pp_native_path dir);
		Eio.Path.mkdirs ~perm: 0o755 dir;
		(* as these files are just copied over, unset rules *)
		set_up_editor_config ~dir ~content: darcs_context_editor_config_content;
		Ok ()
	| _ ->
		Error (Fmt.str "There is a Nixtamal path, but is not a directory%a" pp_native_path dir)