From 2e26ecc2b2990245903a97897d414729517760e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ulysse=20G=C3=A9rard?= <thevoodoos@gmail.com>
Date: Mon, 22 Nov 2021 10:47:27 +0100
Subject: [PATCH 1/4] Restore workspace finding behavior
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Ulysse Gérard <thevoodoos@gmail.com>
---
 bin/workspace_root.ml | 58 ++++++++++++++++++++++++++++---------------
 1 file changed, 38 insertions(+), 20 deletions(-)

diff --git a/bin/workspace_root.ml b/bin/workspace_root.ml
index 4169e84c227..f029e687d1d 100644
--- a/bin/workspace_root.ml
+++ b/bin/workspace_root.ml
@@ -8,6 +8,20 @@ module Kind = struct
     | Dune_workspace
     | Dune_project
     | Cwd
+
+  let priority = function
+    | Explicit -> 0
+    | Dune_workspace -> 1
+    | Dune_project -> 2
+    | Cwd -> 3
+
+  let of_dir_contents files =
+    if String.Set.mem files Workspace.filename then
+      Some Dune_workspace
+    else if String.Set.mem files Dune_project.filename then
+      Some Dune_project
+    else
+      None
 end
 
 type t =
@@ -17,17 +31,11 @@ type t =
   ; kind : Kind.t
   }
 
-module Candidate = struct
-  type t =
-    { dir : string
-    ; to_cwd : string list
-    ; kind : Kind.t
-    }
-end
+let make kind dir = { kind; dir; to_cwd = []; reach_from_root_prefix = "" }
 
 let find () =
   let cwd = Sys.getcwd () in
-  let rec loop counter ~candidate ~to_cwd dir : Candidate.t option =
+  let rec loop counter ~candidate ~to_cwd dir =
     match Sys.readdir dir with
     | exception Sys_error msg ->
       User_warning.emit
@@ -42,13 +50,24 @@ let find () =
       candidate
     | files ->
       let files = String.Set.of_list (Array.to_list files) in
-      if String.Set.mem files Workspace.filename then
-        Some { kind = Dune_workspace; dir; to_cwd }
-      else if String.Set.mem files Dune_project.filename then
-        let candidate = Some { Candidate.kind = Dune_project; dir; to_cwd } in
-        cont counter ~candidate dir ~to_cwd
-      else
-        cont counter ~candidate dir ~to_cwd
+      let candidate =
+        let candidate_priority =
+          match candidate with
+          | Some c -> Kind.priority c.kind
+          | None -> 10
+        in
+        match Kind.of_dir_contents files with
+        | Some kind when Kind.priority kind <= candidate_priority ->
+          Some
+            { kind
+            ; dir
+            ; to_cwd
+            ; (* This field is computed at the end *) reach_from_root_prefix =
+                ""
+            }
+        | _ -> candidate
+      in
+      cont counter ~candidate dir ~to_cwd
   and cont counter ~candidate ~to_cwd dir =
     if counter > String.length cwd then
       candidate
@@ -65,21 +84,20 @@ let find () =
 let create ~default_is_cwd ~specified_by_user =
   match
     match specified_by_user with
-    | Some dn -> Some { Candidate.kind = Explicit; dir = dn; to_cwd = [] }
+    | Some dn -> Some (make Explicit dn)
     | None -> (
-      let cwd = { Candidate.kind = Cwd; dir = "."; to_cwd = [] } in
       if Dune_util.Config.inside_dune then
-        Some cwd
+        Some (make Cwd ".")
       else
         match find () with
         | Some s -> Some s
         | None ->
           if default_is_cwd then
-            Some cwd
+            Some (make Cwd ".")
           else
             None)
   with
-  | Some { Candidate.dir; to_cwd; kind } ->
+  | Some { dir; to_cwd; kind; _ } ->
     { kind
     ; dir
     ; to_cwd

From 0177eafa31a4004e5aa0535d3ca48fb38a0b8331 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ulysse=20G=C3=A9rard?= <thevoodoos@gmail.com>
Date: Mon, 22 Nov 2021 13:48:53 +0100
Subject: [PATCH 2/4] Update docs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Ulysse Gérard <thevoodoos@gmail.com>
---
 doc/usage.rst | 46 ++++++++++++++++++++++------------------------
 1 file changed, 22 insertions(+), 24 deletions(-)

diff --git a/doc/usage.rst b/doc/usage.rst
index 4ec22fbff3d..67b3ce20c6b 100644
--- a/doc/usage.rst
+++ b/doc/usage.rst
@@ -85,11 +85,10 @@ Finding the Root
 ================
 
 The root of the current workspace is determined by looking up a
-``dune-workspace`` or ``dune-project`` file in the current directory
-and its parent directories.
+``dune-workspace`` or ``dune-project`` file in the current directory and its
+parent directories. Dune requires at least one of these two files to operate.
 
-If it isn't in the current
-directory, Dune prints out the root when starting:
+If it isn't in the current directory, Dune prints out the root when starting:
 
 .. code:: bash
 
@@ -100,17 +99,16 @@ directory, Dune prints out the root when starting:
 This message can be suppressed with the ``--no-print-directory``
 command line option (as in GNU make).
 
-Dune requires at least one ``dune-workspace`` file or ``dune-project``
-file to operate. This file may appear in the current or a parent
-directory. It's used to mark the root of the current workspace;
-however, ``dune-workspace`` and ``dune-project`` files are treated
-slightly differently. Since there can be only a single workspace
-active at a given time, Dune stops its search for the root at the
-first ``dune-workspace`` file it encounters. On the other hand, Dune
-projects are composable, and there can be multiple projects in a
-single workspace. For this reason, when Dune finds a ``dune-project``
-file it will continue searching in parent directories, in case this
-project is part of a bigger workspace.
+More precisely, Dune will choose the outermost ancestor directory containing a
+``dune-workspace`` file which is used to mark the root of the current workspace.
+If no ``dune-workspace`` file is present the same strategy applies with
+``dune-project`` files.
+
+In case of a mix of `dune-workspace` and `dune-project` files, workspace files
+take precedence over project files in the sense that if a ``dune-workspace``
+file is found only parent ``dune-workspace`` files will be considered when
+looking for the root, while if a `dune-project` file is found both parent
+``dune-workspace`` and ``dune-project`` files will be considered.
 
 A ``dune-workspace`` file is also a configuration file. Dune will read
 it unless the ``--workspace`` command line option is used.  See the
@@ -302,7 +300,7 @@ See :ref:`variables-for-artifacts` for more information.
 Finding External Libraries
 ==========================
 
-When a library isn't available in the workspace, Dune search for it 
+When a library isn't available in the workspace, Dune search for it
 in the installed world and expect it to be already compiled.
 
 It looks up external libraries using a specific list of search paths,
@@ -411,7 +409,7 @@ dune subst
 ==========
 
 One of the features ``dune-release`` provides is watermarking; it replaces
-various strings of the form ``%%ID%%`` in all your project files 
+various strings of the form ``%%ID%%`` in all your project files
 before creating a release tarball or when the Opam user pins the package.
 
 This is especially interesting for the ``VERSION`` watermark, which gets
@@ -453,7 +451,7 @@ file in the directory where ``dune subst`` is called. The
 ``dune-project`` file must exist and contain a valid ``(name ...)``
 field.
 
-Note that ``dune subst`` is meant to be called from the Opam file and 
+Note that ``dune subst`` is meant to be called from the Opam file and
 behaves a bit different to other Dune commands. In
 particular it doesn't try to detect the root of the workspace and must
 be called from the root of the project.
@@ -523,13 +521,13 @@ OCaml projects to find them, and this location might be different from
 Historically, the location where to store OCaml library files was
 configured through `findlib
 <http://projects.camlcity.org/projects/findlib.html>`__, and the
-``ocamlfind`` command-line tool was used to both install 
-and locate these files. Many Linux distributions (or other packaging systems) 
+``ocamlfind`` command-line tool was used to both install
+and locate these files. Many Linux distributions (or other packaging systems)
 use this mechanism to setup where OCaml library files should be
 copied.
 
 As a result, if neither ``--libdir`` or ``--prefix`` is passed to ``dune
-install``, and ``ocamlfind`` is present in the ``PATH``, then Dune copies library files 
+install``, and ``ocamlfind`` is present in the ``PATH``, then Dune copies library files
 to the directory reported by ``ocamlfind printconf destdir``. This
 ensures that ``dune install`` can be used without Opam. When using opam,
 ``ocamlfind`` is configured to point to the Opam directory, so this rule makes
@@ -562,7 +560,7 @@ Querying Merlin Configuration
 Since Version 2.8, Dune no longer promotes ``.merlin`` files to the source
 directories. Instead, Dune stores these configurations in the `_build`
 folder, and Merlin communicates directly with Dune to obtain its configuration
-via the `ocaml-merlin` subcommand. The Merlin configuration is now stanza-specific, 
+via the `ocaml-merlin` subcommand. The Merlin configuration is now stanza-specific,
 allowing finer control. The following commands aren't needed for
 normal Dune and Merlin use, but they can provide insightful information when
 debugging or configuring non-standard projects.
@@ -592,8 +590,8 @@ Merlin configuration syntax by running the following command:
 
     $ dune ocaml dump-dot-merlin > .merlin
 
-In that case, Dune prints only one configuration: the result of the configuration's 
-coarse merge in the current folder's various modules. 
+In that case, Dune prints only one configuration: the result of the configuration's
+coarse merge in the current folder's various modules.
 This folder must be in a Dune workspace, and the project must be already
 built. Preprocessing directives and other flags will be commented out and must
 be un-commented afterward. This feature doesn't aim at writing exact or correct

From 8aa12dbc292a6324794b2c21f3ddcf04e0363da9 Mon Sep 17 00:00:00 2001
From: Jeremie Dimino <jeremie@dimino.org>
Date: Mon, 22 Nov 2021 11:27:44 +0000
Subject: [PATCH 3/4] tweaks
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Jeremie Dimino <jeremie@dimino.org>
Signed-off-by: Ulysse Gérard <thevoodoos@gmail.com>
---
 bin/workspace_root.ml | 32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/bin/workspace_root.ml b/bin/workspace_root.ml
index f029e687d1d..d1ccb15fde9 100644
--- a/bin/workspace_root.ml
+++ b/bin/workspace_root.ml
@@ -15,6 +15,8 @@ module Kind = struct
     | Dune_project -> 2
     | Cwd -> 3
 
+  let lowest_priority = max_int
+
   let of_dir_contents files =
     if String.Set.mem files Workspace.filename then
       Some Dune_workspace
@@ -31,11 +33,18 @@ type t =
   ; kind : Kind.t
   }
 
-let make kind dir = { kind; dir; to_cwd = []; reach_from_root_prefix = "" }
+module Candidate = struct
+  type t =
+    { dir : string
+    ; to_cwd : string list
+    ; kind : Kind.t
+    }
+end
 
 let find () =
   let cwd = Sys.getcwd () in
-  let rec loop counter ~candidate ~to_cwd dir =
+  let rec loop counter ~(candidate : Candidate.t option) ~to_cwd dir :
+      Candidate.t option =
     match Sys.readdir dir with
     | exception Sys_error msg ->
       User_warning.emit
@@ -54,17 +63,11 @@ let find () =
         let candidate_priority =
           match candidate with
           | Some c -> Kind.priority c.kind
-          | None -> 10
+          | None -> Kind.lowest_priority
         in
         match Kind.of_dir_contents files with
         | Some kind when Kind.priority kind <= candidate_priority ->
-          Some
-            { kind
-            ; dir
-            ; to_cwd
-            ; (* This field is computed at the end *) reach_from_root_prefix =
-                ""
-            }
+          Some { Candidate.kind; dir; to_cwd }
         | _ -> candidate
       in
       cont counter ~candidate dir ~to_cwd
@@ -84,20 +87,21 @@ let find () =
 let create ~default_is_cwd ~specified_by_user =
   match
     match specified_by_user with
-    | Some dn -> Some (make Explicit dn)
+    | Some dn -> Some { Candidate.kind = Explicit; dir = dn; to_cwd = [] }
     | None -> (
+      let cwd = { Candidate.kind = Cwd; dir = "."; to_cwd = [] } in
       if Dune_util.Config.inside_dune then
-        Some (make Cwd ".")
+        Some cwd
       else
         match find () with
         | Some s -> Some s
         | None ->
           if default_is_cwd then
-            Some (make Cwd ".")
+            Some cwd
           else
             None)
   with
-  | Some { dir; to_cwd; kind; _ } ->
+  | Some { Candidate.dir; to_cwd; kind } ->
     { kind
     ; dir
     ; to_cwd

From 44ed978121ed52ec7d6e4622cf75e10072e69f97 Mon Sep 17 00:00:00 2001
From: Ulysse <5031221+voodoos@users.noreply.github.com>
Date: Mon, 22 Nov 2021 21:30:52 +0100
Subject: [PATCH 4/4] Grammar tweaks in doc/usage.rst
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Christine Rose <christinerose@users.noreply.github.com>
Signed-off-by: Ulysse Gérard <thevoodoos@gmail.com>
---
 doc/usage.rst | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/doc/usage.rst b/doc/usage.rst
index 67b3ce20c6b..864acd68d75 100644
--- a/doc/usage.rst
+++ b/doc/usage.rst
@@ -100,14 +100,14 @@ This message can be suppressed with the ``--no-print-directory``
 command line option (as in GNU make).
 
 More precisely, Dune will choose the outermost ancestor directory containing a
-``dune-workspace`` file which is used to mark the root of the current workspace.
-If no ``dune-workspace`` file is present the same strategy applies with
+``dune-workspace`` file, which is used to mark the root of the current workspace.
+If no ``dune-workspace`` file is present, the same strategy applies with
 ``dune-project`` files.
 
 In case of a mix of `dune-workspace` and `dune-project` files, workspace files
 take precedence over project files in the sense that if a ``dune-workspace``
-file is found only parent ``dune-workspace`` files will be considered when
-looking for the root, while if a `dune-project` file is found both parent
+file is found, only parent ``dune-workspace`` files will be considered when
+looking for the root; however, if a `dune-project` file is found both parent
 ``dune-workspace`` and ``dune-project`` files will be considered.
 
 A ``dune-workspace`` file is also a configuration file. Dune will read
@@ -300,7 +300,7 @@ See :ref:`variables-for-artifacts` for more information.
 Finding External Libraries
 ==========================
 
-When a library isn't available in the workspace, Dune search for it
+When a library isn't available in the workspace, Dune will search for it
 in the installed world and expect it to be already compiled.
 
 It looks up external libraries using a specific list of search paths,