cargo_modules/
command.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5use clap::Parser;
6
7use crate::{
8    analyzer::{LoadOptions, load_workspace},
9    options::{GeneralOptions, ProjectOptions},
10};
11
12use self::{
13    dependencies::command::Command as DependenciesCommand,
14    orphans::command::Command as OrphansCommand, structure::command::Command as StructureCommand,
15};
16
17pub mod dependencies;
18pub mod orphans;
19pub mod structure;
20
21#[derive(Parser, Clone, PartialEq, Eq, Debug)]
22#[command(
23    name = "cargo-modules",
24    bin_name = "cargo-modules",
25    about = "Visualize/analyze a crate's internal structure."
26)]
27pub enum Command {
28    #[command(
29        name = "structure",
30        about = "Prints a crate's hierarchical structure as a tree."
31    )]
32    Structure(StructureCommand),
33
34    #[command(
35        name = "dependencies",
36        about = "Prints a crate's internal dependencies as a graph.",
37        after_help = r#"
38        If you have xdot installed on your system, you can run this using:
39        `cargo modules dependencies | xdot -`
40        "#
41    )]
42    Dependencies(DependenciesCommand),
43
44    #[command(
45        name = "orphans",
46        about = "Detects unlinked source files within a crate's directory."
47    )]
48    Orphans(OrphansCommand),
49}
50
51impl Command {
52    pub(crate) fn sanitize(&mut self) {
53        match self {
54            Self::Structure(command) => command.sanitize(),
55            Self::Dependencies(command) => command.sanitize(),
56            Self::Orphans(command) => command.sanitize(),
57        }
58    }
59
60    pub fn run(self) -> Result<(), anyhow::Error> {
61        let general_options = self.general_options();
62        let project_options = self.project_options();
63        let load_options = self.load_options();
64
65        let (krate, host, vfs, edition) =
66            load_workspace(general_options, project_options, &load_options)?;
67        let db = host.raw_database();
68
69        match self {
70            #[allow(unused_variables)]
71            Self::Structure(command) => command.run(krate, db, edition),
72            #[allow(unused_variables)]
73            Self::Dependencies(command) => command.run(krate, db, edition),
74            #[allow(unused_variables)]
75            Self::Orphans(command) => command.run(krate, db, &vfs, edition),
76        }
77    }
78
79    fn general_options(&self) -> &GeneralOptions {
80        match self {
81            Self::Structure(command) => &command.options.general,
82            Self::Dependencies(command) => &command.options.general,
83            Self::Orphans(command) => &command.options.general,
84        }
85    }
86
87    #[allow(dead_code)]
88    fn project_options(&self) -> &ProjectOptions {
89        match self {
90            Self::Structure(command) => &command.options.project,
91            Self::Dependencies(command) => &command.options.project,
92            Self::Orphans(command) => &command.options.project,
93        }
94    }
95
96    #[allow(dead_code)]
97    fn load_options(&self) -> LoadOptions {
98        match self {
99            Self::Structure(command) => command.load_options(),
100            Self::Dependencies(command) => command.load_options(),
101            Self::Orphans(command) => command.load_options(),
102        }
103    }
104}