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
use crate::commands::{CommandExecutionOptions, execute_commands};
use crate::file_operations::{FileApplyOptions, apply_file_operations};
use crate::{ActionPlan, Reporter, Result};
/// Options that control action plan execution.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct ExecuteOptions {
/// Rejects strict-mode file-operation conflicts.
pub strict: bool,
/// Replaces existing file-operation targets where supported.
pub force: bool,
/// Prints planned work without changing files or running commands.
pub dry_run: bool,
/// Prints detailed file-operation actions instead of compact summaries.
pub verbose: bool,
/// Applies file operations only.
pub skip_commands: bool,
}
/// Result summary for action plan execution.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct ExecutionReport {
/// Number of file actions applied or reported.
pub file_action_count: usize,
}
/// Executes validated action plans.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Executor {
options: ExecuteOptions,
}
impl Executor {
/// Creates an executor from execution options.
#[must_use]
pub const fn new(options: ExecuteOptions) -> Self {
Self { options }
}
/// Applies the file-operation portion of a plan.
///
/// # Errors
///
/// Returns an error if file operation application or output reporting
/// fails.
pub fn execute_files(
&self,
plan: &ActionPlan,
reporter: &mut dyn Reporter,
) -> Result<ExecutionReport> {
let report = apply_file_operations(
plan,
FileApplyOptions {
strict: self.options.strict,
force: self.options.force,
dry_run: self.options.dry_run,
verbose: self.options.verbose,
},
reporter,
)?;
Ok(ExecutionReport {
file_action_count: report.action_count,
})
}
/// Executes the command portion of a plan.
///
/// # Errors
///
/// Returns an error if command execution or output reporting fails.
pub fn execute_commands(&self, plan: &ActionPlan, reporter: &mut dyn Reporter) -> Result<()> {
execute_commands(
plan,
CommandExecutionOptions {
dry_run: self.options.dry_run,
},
reporter,
)
}
/// Executes a complete action plan.
///
/// # Errors
///
/// Returns an error if file operation application, command execution, or
/// output reporting fails.
pub fn execute(
&self,
plan: &ActionPlan,
reporter: &mut dyn Reporter,
) -> Result<ExecutionReport> {
let report = self.execute_files(plan, reporter)?;
if !self.options.skip_commands {
self.execute_commands(plan, reporter)?;
}
Ok(report)
}
}