@@ -404,14 +404,38 @@ module Crawl = struct
404
404
in
405
405
Some (Descr.Item. Library lib_descr)
406
406
407
+ (* * [source_path_is_in_dirs dirs p] tests whether the source path [p] is a
408
+ descendant of some of the provided directory [dirs]. If [dirs = None],
409
+ then it always succeeds. If [dirs = Some l], then a matching directory is
410
+ search in the list [l]. *)
411
+ let source_path_is_in_dirs dirs (p : Path.Source.t ) =
412
+ match dirs with
413
+ | None -> true
414
+ | Some dirs ->
415
+ List. exists ~f: (fun dir -> Path.Source. is_descendant p ~of_: dir) dirs
416
+
417
+ (* * Tests whether a dune file is located in a path that is a descendant of
418
+ some directory *)
419
+ let dune_file_is_in_dirs dirs (dune_file : Dune_file.t ) =
420
+ source_path_is_in_dirs dirs dune_file.dir
421
+
422
+ (* * Tests whether a library is located in a path that is a descendant of some
423
+ directory *)
424
+ let lib_is_in_dirs dirs (lib : Lib.t ) =
425
+ source_path_is_in_dirs dirs
426
+ (Path. drop_build_context_exn @@ Lib_info. best_src_dir @@ Lib. info lib)
427
+
407
428
(* * Builds a workspace description for the provided dune setup and context *)
408
- let workspace options
429
+ let workspace options dirs
409
430
({ Dune_rules.Main. conf; contexts = _ ; scontexts } :
410
431
Dune_rules.Main.build_system ) (context : Context.t ) :
411
432
Descr.Workspace. t Memo. t =
412
433
let sctx = Context_name.Map. find_exn scontexts context.name in
413
434
let open Memo.O in
414
- let * dune_files = Dune_load.Dune_files. eval conf.dune_files ~context in
435
+ let * dune_files =
436
+ Dune_load.Dune_files. eval conf.dune_files ~context
437
+ >> | List. filter ~f: (dune_file_is_in_dirs dirs)
438
+ in
415
439
let * exes, exe_libs =
416
440
(* the list of workspace items that describe executables, and the list of
417
441
their direct library dependencies *)
@@ -438,7 +462,9 @@ module Crawl = struct
438
462
let * scope = Scope.DB. find_by_project ctx project in
439
463
Scope. libs scope |> Lib.DB. all)
440
464
>> | Lib.Set. union_all
465
+ >> | Lib.Set. filter ~f: (lib_is_in_dirs dirs)
441
466
in
467
+
442
468
let + libs =
443
469
(* the executables' libraries, and the project's libraries *)
444
470
Lib.Set. union exe_libs project_libs
@@ -610,29 +636,40 @@ end
610
636
without hassle. *)
611
637
module What = struct
612
638
type t =
613
- | Workspace
639
+ | Workspace of { dirs : string list option }
614
640
| Opam_files
615
641
| Pp of string
616
642
617
- let default = Workspace
643
+ (* * By default, describe the whole workspace *)
644
+ let default = Workspace { dirs = None }
618
645
619
646
(* The list of command names, their args, their documentation, and their
620
647
parser *)
621
648
let parsers_with_docs :
622
649
(string * string list * string * t Dune_lang.Decoder. t ) list =
623
650
let open Dune_lang.Decoder in
624
651
[ ( " workspace"
625
- , []
626
- , " prints a description of the workspace's structure"
627
- , return Workspace )
652
+ , [ " DIRS" ]
653
+ , " prints a description of the workspace's structure. If some \
654
+ directories DIRS are provided, then only those directories of the \
655
+ workspace are considered."
656
+ , let + dirs = repeat relative_file in
657
+ (* [None] means that all directories should be accepted,
658
+ whereas [Some l] means that only the directories in the
659
+ list [l] should be accepted. The checks on whether the
660
+ paths exist and whether they are directories are performed
661
+ later in the [describe] function. *)
662
+ let dirs = if List. is_empty dirs then None else Some dirs in
663
+ Workspace { dirs } )
628
664
; ( " opam-files"
629
665
, []
630
666
, " prints information about the Opam files that have been discovered"
631
667
, return Opam_files )
632
668
; ( " pp"
633
669
, [ " FILE" ]
634
670
, " builds a given FILE and prints the preprocessed output"
635
- , filename >> | fun s -> Pp s )
671
+ , let + s = filename in
672
+ Pp s )
636
673
]
637
674
638
675
(* The list of documentation strings (one for each command) *)
@@ -666,14 +703,37 @@ module What = struct
666
703
in
667
704
Dune_lang.Decoder. parse parse Univ_map. empty ast
668
705
669
- let describe t options setup super_context =
706
+ let describe t options ( common : Common.t ) setup super_context =
670
707
let some = Memo. map ~f: (fun x -> Some x) in
671
708
match t with
672
709
| Opam_files -> Opam_files. get () |> some
673
- | Workspace ->
710
+ | Workspace { dirs } ->
674
711
let context = Super_context. context super_context in
675
712
let open Memo.O in
676
- Crawl. workspace options setup context
713
+ let * dirs =
714
+ (* prefix directories with the workspace root, so that the
715
+ command also works correctly when it is run from a
716
+ subdirectory *)
717
+ Memo.Option. map dirs
718
+ ~f:
719
+ (Memo.List. map ~f: (fun dir ->
720
+ let p =
721
+ Path.Source. (relative root) (Common. prefix_target common dir)
722
+ in
723
+ let s = Path. source p in
724
+ if not @@ Path. exists s then
725
+ User_error. raise
726
+ [ Pp. textf " No such file or directory: %s"
727
+ (Path. to_string s)
728
+ ];
729
+ if not @@ Path. is_directory s then
730
+ User_error. raise
731
+ [ Pp. textf " File exists, but is not a directory: %s"
732
+ (Path. to_string s)
733
+ ];
734
+ Memo. return p))
735
+ in
736
+ Crawl. workspace options dirs setup context
677
737
>> | Sanitize_for_tests.Workspace. sanitize context
678
738
>> | Descr.Workspace. to_dyn options
679
739
|> some
@@ -799,12 +859,12 @@ let term : unit Term.t =
799
859
Import.Main. find_scontext_exn setup ~name: context_name
800
860
in
801
861
let + res =
802
- Build_system. run (fun () ->
803
- What. describe what options setup super_context)
862
+ Build_system. run_exn (fun () ->
863
+ What. describe what options common setup super_context)
804
864
in
805
865
match res with
806
- | Error `Already_reported | Ok None -> ()
807
- | Ok ( Some res ) -> (
866
+ | None -> ()
867
+ | Some res -> (
808
868
match format with
809
869
| Csexp -> Csexp. to_channel stdout (Sexp. of_dyn res)
810
870
| Sexp -> print_as_sexp res))
0 commit comments