Source file commandTree.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
(**************************************************************************)
(*                                                                        *)
(*    Copyright 2020 OCamlPro & Origin Labs                               *)
(*                                                                        *)
(*  All rights reserved. This file is distributed under the terms of the  *)
(*  GNU Lesser General Public License version 2.1, with the special       *)
(*  exception on linking described in the file LICENSE.                   *)
(*                                                                        *)
(**************************************************************************)

open Ezcmd.V2
open Types
open EzPrintTree

let cmd_name = "tree"

let string_of_version = function
  | Version -> "version"
  | Semantic (major, minor, fix) -> Printf.sprintf "%d.%d.%d" major minor fix
  | Lt version -> Printf.sprintf "< %s" version
  | Le version -> Printf.sprintf "<= %s" version
  | Eq version -> Printf.sprintf "= %s" version
  | Ge version -> Printf.sprintf ">= %s" version
  | Gt version -> Printf.sprintf "> %s" version
  | NoVersion -> ""

let action () =
  let p, _ = Project.get () in

  let h = Hashtbl.create 97 in
  List.iter
    (fun package -> Hashtbl.add h package.name (package, ref 0, ref false))
    p.packages;
  let add_dep (name, d) =
    try
      match d.depversions with
      | []
      | [ Version ] ->
          let _, counter, _ = Hashtbl.find h name in
          incr counter
      | _ -> ()
    with Not_found -> ()
  in
  List.iter
    (fun package ->
       List.iter add_dep package.p_dependencies;
       List.iter add_dep package.p_tools)
    p.packages;

  let rec tree_of_dep kind (name, d) =
    try
      match d.depversions with
      | []
      | [ Version ] ->
          let package, counter, printed = Hashtbl.find h name in
          if (not !printed) && !counter = 1 then (
            printed := true;
            tree_of_package package
          ) else
            raise Not_found
      | _ -> raise Not_found
    with Not_found ->
      let dep_descr =
        Printf.sprintf "%s%s %s" name kind
          (String.concat " " (List.map string_of_version d.depversions))
      in
      Branch (dep_descr, [])
  and tree_of_package package =
    let package_descr = Printf.sprintf "%s %s (/%s)"
        ( Misc.string_of_kind package.kind ) package.name package.dir in
    Branch
      ( package_descr,
        List.map (tree_of_dep "") package.p_dependencies
        @ List.map (tree_of_dep "(tool)") package.p_tools )
  in

  let branches = ref [] in
  let print p =
    let _package, counter, printed = Hashtbl.find h p.name in
    if (not !printed) && !counter <> 1 then (
      printed := true;
      branches := tree_of_package p :: !branches
    )
  in
  print p.package;
  List.iter
    (fun package -> if package != p.package then print package)
    p.packages;
  let print_deps kind list =
    branches :=
      (Branch
         (Printf.sprintf "[%s]" kind,
          List.map
            (fun (name, d) ->
               Branch (
                 Printf.sprintf "%s %s" name
                   (String.concat " " (List.map string_of_version d.depversions)), []) )
            list)) :: !branches;
  in
  print_deps "dependencies" p.dependencies;
  print_deps "tools" p.tools;
  print_tree "" (Branch ("File drom.toml", List.rev !branches));
  ()

let cmd = EZCMD.sub cmd_name action
    ~doc: "Display a tree of dependencies"
    ~man:[
      `S "DESCRIPTION";

      `Blocks [
        `P "Print the project as a tree of dependencies, i.e. dependencies are printed as branches of the package they are dependencies of. If a package is itself a dependency of another package, it will be printed there.";
      ];

      `S "EXAMPLE";
      `Pre {|
└──drom (/src/drom)
   └──drom_lib (/src/drom_lib)
      └──toml 5.0.0
      └──opam-file-format 2.1.1
      └──ez_subst >= 0.1
      └──ez_file 0.2.0
      └──ez_config 0.1.0
      └──ez_cmdliner 0.2.0
      └──directories >= 0.2
[tools]
└── ppx_inline_test
└── ppx_expect
└── odoc
└── ocamlformat
|};
    ]