1
use crate::domain::commands::arguments::{Argument, Arguments};
2
use crate::domain::flyweight_data::FlyweightData;
3
use crate::domain::target::{Target, TargetIdentifier};
4
use crate::domain::translation_unit::{TranslationUnit, TranslationUnitStatus};
5
use crate::project_model::compiler::CppCompiler;
6
use crate::utils::constants::error_messages;
7
use crate::utils::fs;
8
use color_eyre::eyre::Context;
9
use color_eyre::Result;
10
use indexmap::IndexMap;
11
use serde::{Deserialize, Serialize};
12
use std::fmt::Debug;
13
use std::path::{Path, PathBuf};
14

            
15
/// Holds the generated command line arguments for a concrete compiler
16
14
#[derive(Serialize, Deserialize, Default, Debug)]
17
pub struct Commands<'a> {
18
6
    pub flyweight_data: Option<FlyweightData<'a>>,
19
6
    pub modules: ModulesCommands<'a>,
20
6
    pub targets: IndexMap<TargetIdentifier<'a>, Target<'a>>,
21
}
22

            
23
impl<'a> Commands<'a> {
24
    /// Attempts to remove from the fs all the compilation products of any tracked
25
    /// [`SourceCommandLine`] of the user declared modules and then,
26
    /// removes its data from the cache
27
    pub fn clean_user_modules(&mut self) -> Result<()> {
28
        self.modules.clear()
29
    }
30

            
31
    /// Attempts to remove from the fs all the compilation products of any tracked
32
    /// [`SourceCommandLine`] for all the user declared [`Target`](s) and then,
33
    /// removes its data from the cache
34
    pub fn clean_targets(&mut self) -> Result<()> {
35
        self.targets
36
            .values_mut()
37
            .try_for_each(|target| {
38
                target
39
                    .sources
40
                    .iter()
41
                    .try_for_each(|scl| fs::delete_file(Path::new(&scl.byproduct)))
42
            })
43
            .with_context(|| error_messages::FAILURE_CLEANING_TARGETS)?;
44
        self.targets.clear();
45
        Ok(())
46
    }
47
}
48

            
49
14
#[derive(Serialize, Deserialize, Default, Debug)]
50
pub struct ModulesCommands<'a> {
51
6
    pub cpp_stdlib: Option<SourceCommandLine<'a>>,
52
6
    pub c_compat_stdlib: Option<SourceCommandLine<'a>>,
53
6
    pub system_modules: Vec<SourceCommandLine<'a>>,
54
6
    pub interfaces: Vec<SourceCommandLine<'a>>,
55
6
    pub implementations: Vec<SourceCommandLine<'a>>,
56
}
57

            
58
impl<'a> ModulesCommands<'a> {
59
    /// Deletes from the fs and then the [`SourceCommandLine`] from the [`ZorkCache`] all
60
    /// the user [`ModuleInteface`] (and its variants) and [`ModuleImplementation`]
61
    pub fn clear(&mut self) -> Result<()> {
62
        self.interfaces
63
            .iter()
64
            .try_for_each(|mod_cmd| fs::delete_file(Path::new(&mod_cmd.byproduct)))
65
            .with_context(|| error_messages::FAILURE_CLEANING_MODULE_INTERFACES)?;
66
        self.interfaces.clear();
67

            
68
        self.implementations
69
            .iter()
70
            .try_for_each(|mod_cmd| fs::delete_file(Path::new(&mod_cmd.byproduct)))
71
            .with_context(|| error_messages::FAILURE_CLEANING_MODULE_IMPLEMENTATIONS)?;
72
        self.implementations.clear();
73

            
74
        Ok(())
75
    }
76
}
77

            
78
/// Type for representing the command line that will be sent to the target compiler, and
79
/// store its different components
80
///
81
/// * directory*: the path where the translation unit lives
82
/// * filename*: the translation unit declared name on the fs with the extension
83
/// * args*: member that holds all the cmd arguments that will be passed to the compiler driver
84
/// * status*: A [`TranslationUnitStatus`] that represents all the different phases that a source command
85
///     line can have among all the different iterations of the program, changing according to the modifications
86
///     over the translation unit in the fs and the result of the build execution
87
///
88
/// *byproduct*: A [`PathBuf`] like [`Argument`] which hold the physical address on the filesystem
89
///     where the compiled object file will be dumped after building it
90
11
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
91
pub struct SourceCommandLine<'a> {
92
    pub directory: PathBuf,
93
    pub filename: String,
94
    pub args: Arguments<'a>,
95
    pub status: TranslationUnitStatus,
96
    pub byproduct: Argument<'a>,
97
}
98

            
99
impl<'a> SourceCommandLine<'a> {
100
10
    pub fn new<T: TranslationUnit<'a>, B: Into<Argument<'a>>>(
101
        tu: &T,
102
        args: Arguments<'a>,
103
        byproduct: B,
104
    ) -> Self {
105
10
        Self {
106
10
            directory: PathBuf::from(tu.parent()),
107
10
            filename: tu.filename(),
108
            args,
109
10
            status: TranslationUnitStatus::PendingToBuild,
110
10
            byproduct: byproduct.into(),
111
        }
112
10
    }
113

            
114
2
    pub fn path(&self) -> PathBuf {
115
2
        self.directory.join(Path::new(&self.filename))
116
2
    }
117

            
118
    pub fn filename(&self) -> &String {
119
        &self.filename
120
    }
121
}
122

            
123
28
#[derive(Debug, Default, Serialize, Deserialize, Clone, Eq, PartialEq)]
124
pub struct LinkerCommandLine<'a> {
125
12
    pub target: Argument<'a>,
126
12
    pub args: Arguments<'a>,
127
12
    pub extra_args: Arguments<'a>,
128
12
    pub execution_result: TranslationUnitStatus,
129
}
130

            
131
impl<'a> LinkerCommandLine<'a> {
132
4
    pub fn get_target_output_for(&self, compiler: CppCompiler) -> Vec<Argument> {
133
4
        match compiler {
134
            CppCompiler::CLANG | CppCompiler::GCC => {
135
4
                vec![Argument::from("-o"), self.target.clone()]
136
            }
137
            CppCompiler::MSVC => vec![self.target.clone()],
138
        }
139
4
    }
140
}
141

            
142
impl<'a> Commands<'a> {
143
    /// Returns a [std::iter::Chain] (behind the opaque impl clause return type signature)
144
    /// which points to all the generated commands for the two variants of the compilers vendors C++ modular
145
    /// standard libraries implementations (see: [crate::project_model::compiler::StdLibMode])
146
    /// joined to all the commands generated for every [TranslationUnit] declared by the user for
147
    /// its project
148
    pub fn get_all_modules_command_lines(
149
        &mut self,
150
    ) -> impl Iterator<Item = &mut SourceCommandLine<'a>> + Debug {
151
        self.modules
152
            .cpp_stdlib
153
            .as_mut_slice()
154
            .iter_mut()
155
            .chain(self.modules.c_compat_stdlib.as_mut_slice().iter_mut())
156
            .chain(self.modules.system_modules.as_mut_slice().iter_mut())
157
            .chain(self.modules.interfaces.as_mut_slice().iter_mut())
158
            .chain(self.modules.implementations.as_mut_slice().iter_mut())
159
    }
160
}