~jonsterling/forester-devel

Improve init subcommand v3 APPLIED

Kento Okura: 1
 Improve init subcommand

 4 files changed, 81 insertions(+), 47 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~jonsterling/forester-devel/patches/55435/mbox | git am -3
Learn more about email & git

[PATCH v3] Improve init subcommand Export this patch

- `init` accepts an optional argument --dir=DIR, which allows to
  initialize forests in a specified directory. By default it initializes
  the forest in the current directory.

- The git subroutine which initializes the theme is improved:
  It no longer fails quietly, and no longer fails with status 141.
  (This had to do with the arguments to Eio.Process.run)

- factoring out `try_create_dir` and `try_create_file` means that all
  attempts to create files are reported properly by Asai, rather than
  dumping a stack trace.

Since the `build` command can't build a forest outside of the current
working directory, we currently can't call it at the end of
initialization.
---
 bin/forester/dune        | 14 +++++-
 bin/forester/main.ml     | 92 ++++++++++++++++++++--------------------
 lib/frontend/Eio_util.ml | 21 +++++++++
 lib/frontend/dune        |  1 +
 4 files changed, 81 insertions(+), 47 deletions(-)
diff --git a/bin/forester/dune b/bin/forester/dune
index 24ea6be..7d50324 100644
--- a/bin/forester/dune
@@ -5,4 +5,16 @@
 (link_flags (-g))
 (preprocess
  (pps ppx_deriving.show))
 (libraries forester.prelude forester.core forester.frontend cmdliner dune-build-info asai eio eio.unix bwd eio_main))
  (libraries
   forester.prelude
   forester.core
   forester.frontend
   cmdliner
   dune-build-info
   asai
   eio
   eio.core
   eio.unix
   bwd
   eio_main
   fmt))
diff --git a/bin/forester/main.ml b/bin/forester/main.ml
index e257c4b..3233676 100644
--- a/bin/forester/main.ml
@@ -51,27 +51,16 @@ let query_all ~env config_filename =
  Forester.plant_forest_from_dirs ~env ~host: config.host ~dev: true @@ paths_of_dirs ~env config.trees;
  Forester.json_manifest ~host: config.host ~home: config.home ~dev: true |> Format.printf "%s"

let init ~env () =
  let default_theme_url = "https://git.sr.ht/~jonsterling/forester-base-theme" in
  let theme_version = "4.3.0" in
  let fs = Eio.Stdenv.fs env in
  let try_create_dir name =
    try
      EP.mkdir ~perm: 0o755 EP.(fs / name)
    with
      | _ ->
        Reporter.emitf Initialization_warning "Directory `%s` already exists" name
  in
  let default_config_str =
    (* More convenient to just write this string instead of constructing it with the toml library*)
    {|[forest]
trees = ["trees" ]                   # The directories in which your trees are stored
assets = ["assets"]                  # The directories in which your assets are stored
theme = "theme"                      # The directory in which your theme is stored
let default_config_str =
  {|
[forest]
trees = ["trees" ]  # The directories in which your trees are stored
assets = ["assets"] # The directories in which your assets are stored
theme = "theme"     # The directory in which your theme is stored
|}
  in
  let index_tree_str =
    {|

let index_tree_str =
  {|
\title{Hello, World!}
\p{
  Welcome to your first tree! This tree is the root of your forest.
@@ -83,17 +72,26 @@ theme = "theme"                      # The directory in which your theme is stor
  }
}
|}

let init ~env dir =
  let default_theme_url = "https://git.sr.ht/~jonsterling/forester-base-theme" in
  let theme_version = "4.3.0" in
  let cwd =
    match dir with
    | None -> Eio.Stdenv.cwd env
    | Some d -> 
      begin
        try
          EP.mkdir ~perm: 0o755 EP.(Eio.Stdenv.cwd env / d)
        with
          | _ ->
            Reporter.emitf Initialization_warning "Directory `%s` already exists" d
      end;
      EP.((Eio.Stdenv.cwd env) / d)
  in
  begin
    if EP.is_file EP.(Eio.Stdenv.fs env / "forest.toml") then
      Reporter.emitf Initialization_warning "forest.toml already exists"
    else
      EP.(save ~create: (`Exclusive 0o644) (fs / "forest.toml") default_config_str)
  end;
  EP.(save ~create: (`Exclusive 0o644) (fs / ".gitignore") {|output/|});
  begin
    try
      let shut_up = Eio_util.null_sink () in
      let proc_mgr = Eio.Stdenv.process_mgr env in
      let@ cmd =
        List.iter @~
          [
@@ -103,30 +101,28 @@ theme = "theme"                      # The directory in which your theme is stor
            ["git"; "-C"; "theme"; "checkout"; theme_version];
          ]
      in
      Eio.Process.run (Eio.Stdenv.process_mgr env) ~stdout: shut_up ~stderr: shut_up cmd
      Eio.Process.run ~cwd proc_mgr cmd
    with
      | _ ->
      | exn ->
        Reporter.fatalf
          Configuration_error
          {|Failed to set up theme. To perform this step manually, run the commands
          {|
Failed to set up theme: %a. To perform this step manually, run the commands

   git init
   git submodule add %s
   git -C theme checkout %s|}
git init
git submodule add %s
git -C theme checkout %s
        |}
          Eio.Exn.pp
          exn
          default_theme_url
          theme_version
  end;
  ["trees"; "assets"] |> List.iter try_create_dir;
  begin
    try
      EP.(save ~create: (`Exclusive 0o644) (fs / "trees" / "index.tree") index_tree_str)
    with
      | _ ->
        let@ () = Reporter.with_backtrace Emp in
        Reporter.emitf Initialization_warning "`index.tree` already exists"
  end;
  build ~env "forest.toml" true None false false;
  Format.printf "%s" "Initialized forest, try editing `trees/index.tree` and running `forester build`. Afterwards, you can open `output/index.xml` in your browser to view your forest.\n"
  ["trees"; "assets"] |> List.iter (Eio_util.try_create_dir ~cwd);
  Eio_util.try_create_file ~cwd ~content: default_config_str "forest.toml";
  Eio_util.try_create_file ~cwd ~content: "output/" ".gitignore";
  Eio_util.try_create_file ~cwd ~content: index_tree_str "trees/index.tree";
  Reporter.emitf Log "%s" "Initialized forest, try editing `trees/index.tree` and running `forester build`. Afterwards, you can open `output/index.xml` in your browser to view your forest."

let arg_config =
  let doc = "A TOML file like $(i,forest.toml)" in
@@ -226,6 +222,10 @@ let query_cmd ~env =
  Cmd.group info [query_all_cmd ~env]

let init_cmd ~env =
  let arg_dir =
    let doc = "The directory in which to initialize the forest" in
    Arg.value @@ Arg.opt (Arg.some Arg.string) None @@ Arg.info ["dir"] ~docv: "DIR" ~doc
  in
  let doc = "Initialize a new forest" in
  let man =
    [
@@ -234,7 +234,7 @@ let init_cmd ~env =
    ]
  in
  let info = Cmd.info "init" ~version ~doc ~man in
  Cmd.v info Term.(const (init ~env) $ const ())
  Cmd.v info Term.(const (init ~env) $ arg_dir)

let cmd ~env =
  let doc = "a tool for tending mathematical forests" in
diff --git a/lib/frontend/Eio_util.ml b/lib/frontend/Eio_util.ml
index 4d40588..ed6bdc5 100644
--- a/lib/frontend/Eio_util.ml
+++ b/lib/frontend/Eio_util.ml
@@ -1,5 +1,6 @@
open Forester_prelude
open Eio
let ( / ) = Eio.Path.( / )

module NullSink: Flow.Pi.SINK with type t = unit = struct
  type t = unit
@@ -55,6 +56,26 @@ let file_exists path =
  with
    | Eio.Io (Eio.Fs.E (Eio.Fs.Not_found _), _) -> false

let try_create_dir ~cwd dname =
  if Eio.Path.is_directory (cwd / dname) then
    Forester_core.Reporter.emitf Initialization_warning "`%s` already exists" dname
  else
    try
      Eio.Path.mkdir ~perm: 0o755 (cwd / dname)
    with
      | exn ->
        Forester_core.Reporter.emitf Initialization_warning "Failed to create directory `%s`: %a" dname Eio.Exn.pp exn

let try_create_file ~cwd ?(content = "") fname =
  if Eio.Path.is_file (cwd / fname) then
    Forester_core.Reporter.emitf Initialization_warning "`%s` already exists" fname
  else
    try
      Eio.Path.save ~create: (`Exclusive 0o644) (cwd / fname) content
    with
      | exn ->
        Forester_core.Reporter.emitf Initialization_warning "Failed to create file `%s`: %a" fname Eio.Exn.pp exn

(* TODO: make this portable *)
let copy_to_dir ~env ~cwd ~source ~dest_dir =
  run_process ~quiet: true ~env ~cwd ["cp"; "-R"; source; dest_dir ^ "/"]
diff --git a/lib/frontend/dune b/lib/frontend/dune
index 7f3eeb9..0e3d7b9 100644
--- a/lib/frontend/dune
+++ b/lib/frontend/dune
@@ -15,6 +15,7 @@
  eio
  eio.core
  eio.unix
  fmt
  yojson
  asai
  algaeff
-- 
2.46.0