123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174(*********************************************************************************)(* Dunolint - A tool to lint and help manage files in dune projects *)(* Copyright (C) 2024-2025 Mathieu Barbin <mathieu.barbin@gmail.com> *)(* *)(* This file is part of Dunolint. *)(* *)(* Dunolint is free software; you can redistribute it and/or modify it *)(* under the terms of the GNU Lesser General Public License as published by *)(* the Free Software Foundation either version 3 of the License, or any later *)(* version, with the LGPL-3.0 Linking Exception. *)(* *)(* Dunolint is distributed in the hope that it will be useful, but WITHOUT *)(* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *)(* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *)(* and the file `NOTICE.md` at the root of this repository for more details. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* and the LGPL-3.0 Linking Exception along with this library. If not, see *)(* <http://www.gnu.org/licenses/> and <https://spdx.org>, respectively. *)(*********************************************************************************)(* This module is derived from the dune code base file
* [./bin/workspace_root.mli] which is released under MIT:
*
* Copyright (c) 2016 Jane Street Group, LLC <opensource@janestreet.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Changes:
*
* - Remove explicit dependency to [Stdune] - use [Base] instead.
* - Inline source file names (e.g. "dune-workspace").
* - Use [Err] instead of [User_message].
* - Rename [create_exn] as [find_exn].
* - Use polymorphic variant and subtypes for [Kind].
* - Remove [reach_from_root_prefix].
*)moduleSource_filename=structletdune_project="dune-project"letdune_workspace="dune-workspace"endtypet=Absolute_path.tletpatht=tmoduleCandidate_kind=structtypet=[`Dune_workspace|`Dune_project]letpriority=function|`Dune_workspace->1|`Dune_project->2;;letlowest_priority=Int.max_valueletof_dir_contentsfiles=ifSet.memfilesSource_filename.dune_workspacethenSome`Dune_workspaceelseifSet.memfilesSource_filename.dune_projectthenSome`Dune_projectelseNone;;endmoduleCandidate=structtypet={dir:string;to_cwd:stringlist;kind:Candidate_kind.t}endletfind()=letcwd=Unix.getcwd()inletrecloopcounter~candidate~to_cwddir=(* This special case prevents actual enclosing repo dir to be mistaken as
workspace root in the context of running tests with dune. *)ifString.equal(Stdlib.Filename.basenamedir)"_build"thencandidateelseloop_internalcounter~candidate~to_cwddirandloop_internalcounter~(candidate:Candidate.toption)~to_cwddir:Candidate.toption=matchStdlib.Sys.readdirdirwith|exceptionSys_errormsg->(Err.warning[Pp.textf"Unable to read directory %s. Will not look for root in parent directories."dir;Pp.textf"Reason: %s"msg;Pp.text"To remove this warning, set your root explicitly using --root."];candidate)[@coverageoff]|files->letfiles=Set.of_list(moduleString)(Array.to_listfiles)inletcandidate=letcandidate_priority=matchcandidatewith|Somec->Candidate_kind.priorityc.kind|None->Candidate_kind.lowest_priorityinmatchCandidate_kind.of_dir_contentsfileswith|SomekindwhenCandidate_kind.prioritykind<=candidate_priority->Some{Candidate.kind;dir;to_cwd}|_->candidateincontcounter~candidatedir~to_cwdandcontcounter~candidate~to_cwddir=ifcounter>String.lengthcwdthencandidate[@coverageoff]else(letparent=Stdlib.Filename.dirnamedirinifString.equalparentdirthencandidateelse(letbase=Stdlib.Filename.basenamedirinloop(counter+1)parent~candidate~to_cwd:(base::to_cwd)))inloop0~candidate:None~to_cwd:[]cwd;;letfind_exn~default_is_cwd~specified_by_user=matchspecified_by_userwith|Somepath->path|None->(matchfind()with|Some{dir;to_cwd=_;kind=_}->Absolute_path.vdir|None->ifdefault_is_cwdthenUnix.getcwd()|>Absolute_path.velseErr.raise[Pp.text"I cannot find the root of the current dune workspace/project.";Pp.text"If you would like to create a new dune project, you can type:";Pp.nop;Pp.verbatim" dune init project NAME";Pp.nop;Pp.text"Otherwise, please make sure to run dune inside an existing project or \
workspace. For more information about how dune identifies the root of \
the current workspace/project, please refer to \
https://dune.readthedocs.io/en/stable/usage.html#finding-the-root"]);;letchdirt~level=letcwd=Unix.getcwd()|>Absolute_path.vinif(not(Absolute_path.equaltcwd))&&Err.log_enables~levelthenprerr_endline(Printf.sprintf"Entering directory '%s'"(Absolute_path.to_stringt));Unix.chdir(Absolute_path.to_stringt);;