···4646 let@ dir_to_copy = List.iter @~ dirs_to_copy in
4747 Forester.copy_contents_of_dir ~env @@ Eio_util.path_of_dir ~env dir_to_copy
48484949+let export ~env _ config_filename dev =
5050+ let config = Config_parser.parse_forest_config_file config_filename in
5151+ Logs.debug (fun m -> m "Parsed config file %s" config_filename);
5252+ let forest = Forester.plant_raw_forest_from_dirs ~env ~dev ~config in
5353+ forest
5454+ |> State.diagnostics
5555+ |> Diagnostic_store.iter (fun _ d -> List.iter Reporter.Tty.display d);
5656+ Forester.render_forest ~dev ~forest;
5757+ (* let dirs_to_copy = (if not no_theme then [config.theme] else []) in *)
5858+ (* let@ dir_to_copy = List.iter @~ dirs_to_copy in *)
5959+ Forester.export ~forest
6060+4961let new_tree ~env config_filename prefix template random =
5062 let@ () = Reporter.silence in
5163 let config = Config_parser.parse_forest_config_file config_filename in
···196208 $ arg_no_theme
197209 )
198210211211+let export_cmd ~env =
212212+ let arg_dev =
213213+ let doc = "Run forester in development mode; this will attach source file locations to the generated json." in
214214+ Arg.value @@ Arg.flag @@ Arg.info ["dev"] ~doc
215215+ in
216216+ let doc = "Export the forest" in
217217+ let man =
218218+ [
219219+ ]
220220+ in
221221+ let info = Cmd.info "export" ~version ~doc ~man in
222222+ Cmd.v
223223+ info
224224+ Term.(
225225+ const (export ~env)
226226+ $ arg_logs
227227+ $ arg_config
228228+ $ arg_dev
229229+ )
230230+199231let new_tree_cmd ~env =
200232 let arg_prefix =
201233 let doc = "The namespace prefix for the created tree." in
···351383 info
352384 [
353385 build_cmd ~env;
386386+ export_cmd ~env;
354387 new_tree_cmd ~env;
355388 complete_cmd ~env;
356389 init_cmd ~env;
+12
lib/compiler/Forest.ml
···257257 )
258258 |> List.of_seq
259259260260+let get_all_assets resources =
261261+ resources
262262+ |> to_seq_values
263263+ |> Seq.filter_map
264264+ (
265265+ fun r ->
266266+ match r with
267267+ | T.Asset a -> Some a
268268+ | T.Article _ -> None
269269+ )
270270+ |> List.of_seq
271271+260272let get_all_resources resources =
261273 resources
262274 |> to_seq_values
+3
lib/compiler/Forest.mli
···6060val get_all_articles :
6161 'a T.resource t -> 'a T.article list
62626363+val get_all_assets :
6464+ 'a T.resource t -> T.asset list
6565+6366val get_all_resources :
6467 'a t -> 'a list
+37
lib/compiler/Phases.ml
···385385 match Forest.find_opt forest.resources iri with
386386 | None -> assert false
387387 | Some _ -> forest
388388+389389+let implant_foreign
390390+ : Eio.Fs.dir_ty Eio.Path.t list -> transition
391391+ = fun foreign_paths state ->
392392+ begin
393393+ let module EP = Eio.Path in
394394+ let@ path = List.iter @~ foreign_paths in
395395+ let path_str = EP.native_exn path in
396396+ let@ () = Reporter.profile @@ Format.sprintf "Implant foreign forest from `%s'" path_str in
397397+ let blob = try EP.load path with _ -> Reporter.fatalf IO_error "Could not read foreign forest blob at `%s`" path_str in
398398+ match Repr.of_json_string (T.forest_t T.content_t) blob with
399399+ | Ok foreign_forest ->
400400+ List.iter (fun r -> Forest.plant_resource r state.graphs state.resources) foreign_forest
401401+ | Error (`Msg err) ->
402402+ Reporter.fatalf Parse_error "Could not parse foreign forest blob: %s" err
403403+ | exception (Iri.Error err) ->
404404+ Reporter.fatalf Parse_error "Encountered error while decoding foreign forest blob: %s" (Iri.string_of_error err)
405405+ | exception exn ->
406406+ Reporter.fatalf Parse_error "Encountered unknown error while decoding foreign forest blob: %s" (Printexc.to_string exn)
407407+ end;
408408+ state
409409+410410+let plant_assets
411411+ : Eio.Fs.dir_ty Eio.Path.t list -> transition
412412+ = fun asset_dirs state ->
413413+ let paths = Dir_scanner.scan_directories asset_dirs in
414414+ let module EP = Eio.Path in
415415+ Logs.debug (fun m -> m "planting %i assets" (Seq.length paths));
416416+ begin
417417+ let@ source_path = Seq.iter @~ paths in
418418+ let source_path = String.concat "/" source_path in
419419+ let cwd = Eio.Stdenv.cwd state.env in
420420+ let content = EP.load EP.(cwd / source_path) in
421421+ let iri = Asset_router.install ~host: state.config.host ~source_path ~content in
422422+ Forest.plant_resource (T.Asset { iri; host = state.config.host; content }) state.graphs state.resources;
423423+ end;
424424+ state
···44 * SPDX-License-Identifier: GPL-3.0-or-later
55 *)
6677+open Forester_prelude
78open Forester_core
89open Forester_compiler
9101011module T = Types
1111-module Cmp = Phases
12121313type state = State.t
1414···1616 | Quit
1717 | Build_import_graph
1818 | Build_dependency_graph of iri
1919+ | Plant_assets of (Eio.Fs.dir_ty Eio.Path.t list [@opaque ])
2020+ | Plant_foreign of (Eio.Fs.dir_ty Eio.Path.t list [@opaque ])
1921 | Do_nothing
2022 | Load_all
2123 | Parse_all
···6769 end
6870 | Quit -> exit 0
6971 | Load_all ->
7070- (Parse_all, Cmp.load_configured_dirs state, Nothing)
7272+ (Parse_all, Phases.load_configured_dirs state, Nothing)
7173 | Parse_all ->
7274 log "Parse trees";
7375 (
7476 Build_import_graph,
7575- Cmp.parse ~quit_on_error: false state,
7777+ Phases.parse ~quit_on_error: false state,
7678 Nothing
7779 )
7880 | Build_import_graph ->
7981 (
8082 Expand_all,
8181- Cmp.build_import_graph state,
8383+ Phases.build_import_graph state,
8284 Nothing
8385 )
8486 | Build_dependency_graph iri ->
8587 (
8688 Expand_only iri,
8787- Cmp.build_import_graph_for ~addr: iri state,
8989+ Phases.build_import_graph_for ~addr: iri state,
8890 Nothing
8991 )
9092 | Expand_all ->
9193 log "Expand, evaluate and analyse forest";
9294 (
9395 Eval_all,
9494- Cmp.expand ~quit_on_error: false state,
9696+ Phases.expand ~quit_on_error: false state,
9597 Nothing
9698 )
9799 | Expand_only iri ->
98100 (
99101 Eval_only iri,
100100- Cmp.expand_only iri state,
102102+ Phases.expand_only iri state,
101103 Nothing
102104 )
103105 | Eval_all ->
104106 (
105107 Do_nothing,
106106- Cmp.eval ~dev: true state,
108108+ Phases.eval ~dev: true state,
107109 Nothing
108110 )
109111 | Eval_only iri ->
110112 (
111113 Do_nothing,
112112- Cmp.eval_only iri state,
114114+ Phases.eval_only iri state,
113115 Nothing
114116 )
117117+ | Plant_assets paths ->
118118+ (Do_nothing, Phases.plant_assets paths state, Nothing)
119119+ | Plant_foreign path ->
120120+ (Do_nothing, Phases.implant_foreign path state, Nothing)
115121 | Parse _
116122 | Cache_results _ ->
117123 (Do_nothing, state, Nothing)
118124 | Do_nothing ->
119125 (Do_nothing, state, Nothing)
120126121121-let run_action action ~(until : 'a action) state : state * ('r, 'e) result =
127127+let run_action action ~(until : 'a action) state : state =
122128 let rec go action state =
123129 match update action state with
124130 | (new_action, new_state, result) ->
···127133 go new_action new_state
128134 in
129135 go action state
136136+ |> fst
130137131138let rec force
132139 : 'a action list -> state -> ('r, 'e) result
···137144 let _discard, new_state, _ = update msg state in
138145 force remaining new_state
139146140140-let batch_run ~env ~config ~dev =
147147+let implant_foreign paths state =
148148+ state
149149+ |> run_action
150150+ (Plant_foreign paths)
151151+ ~until: Do_nothing
152152+153153+let plant_assets paths state =
154154+ state
155155+ |> run_action
156156+ (Plant_assets paths)
157157+ ~until: Do_nothing
158158+159159+let batch_run ~env ~(config : Config.t) ~dev =
160160+ let asset_paths = Eio_util.paths_of_dirs ~env config.assets in
161161+ let foreign_paths = Eio_util.paths_of_dirs ~env config.foreign in
141162 Phases.init ~env ~config ~dev
163163+ |> plant_assets asset_paths
164164+ |> implant_foreign foreign_paths
142165 |> run_action Load_all ~until: Do_nothing
143143- |> fst
144166145167let language_server
146168 : state -> unit
147169 = fun _ -> ()
148170149171let render_tree ~env ~config ~dev target iri =
150150- let (forest, _) =
151151- Cmp.init ~env ~config ~dev
172172+ let forest =
173173+ Phases.init ~env ~config ~dev
152174 |> run_action (Build_dependency_graph iri) ~until: Do_nothing
153175 in
154176 match Forest.get_article iri forest.resources with
+1-4
test/Test_import_graph.ml
···1616let () =
1717 let@ env = Eio_main.run in
1818 let open Alcotest in
1919- let forest, _ =
1919+ let forest =
2020 State_machine.(
2121 Phases.init ~env ~config ~dev: false
2222 |> run_action Load_all ~until: Expand_all
2323 )
2424- (* load (Eio_util.paths_of_dirs ~env config.trees) *)
2525- (* |> parse ~quit_on_error: false *)
2626- (* ) *)
2724 in
2825 let batch_graph =
2926 Imports.run_builder
+1-1
test/Test_transclusion.ml
···4545 let@ () = Reporter.easy_run in
4646 (* Needs to be false to make tests reproducible. The source path depends on the host *)
4747 let tree_dirs = Eio_util.paths_of_dirs ~env config.trees in
4848- let forest, _ =
4848+ let forest =
4949 Phases.init ~env ~config ~dev: false
5050 |> State_machine.(run_action Load_all ~until: Do_nothing)
5151 in
···11+[forest]
22+host = "foreign"
33+trees = ["for_export" ] # The directories in which your trees are stored
44+assets = [] # The directories in which your assets are stored
55+theme = "theme" # The directory in which your theme is stored
66+home = "index"
77+prefixes = ["test"]
···11[forest]
22host = "lsp-test"
33trees = ["trees" ] # The directories in which your trees are stored
44-assets = [] # The directories in which your assets are stored
44+assets = ["assets"] # The directories in which your assets are stored
55theme = "theme" # The directory in which your theme is stored
66home = "index"
77prefixes = ["test"]
88+foreign = ["export/foreign.json"]