forge/cmd/
flatten.rs

1use clap::{Parser, ValueHint};
2use eyre::Result;
3use foundry_cli::{
4    opts::{BuildOpts, ProjectPathOpts},
5    utils::LoadConfig,
6};
7use foundry_common::{flatten, fs};
8use std::path::PathBuf;
9
10/// CLI arguments for `forge flatten`.
11#[derive(Clone, Debug, Parser)]
12pub struct FlattenArgs {
13    /// The path to the contract to flatten.
14    #[arg(value_hint = ValueHint::FilePath, value_name = "PATH")]
15    pub target_path: PathBuf,
16
17    /// The path to output the flattened contract.
18    ///
19    /// If not specified, the flattened contract will be output to stdout.
20    #[arg(
21        long,
22        short,
23        value_hint = ValueHint::FilePath,
24        value_name = "PATH",
25    )]
26    pub output: Option<PathBuf>,
27
28    #[command(flatten)]
29    project_paths: ProjectPathOpts,
30}
31
32impl FlattenArgs {
33    pub fn run(self) -> Result<()> {
34        let Self { target_path, output, project_paths } = self;
35
36        // flatten is a subset of `BuildArgs` so we can reuse that to get the config
37        let build = BuildOpts { project_paths, ..Default::default() };
38        let config = build.load_config()?;
39        let project = config.ephemeral_project()?;
40
41        let target_path = dunce::canonicalize(target_path)?;
42        let flattened = flatten(project, &target_path)?;
43
44        match output {
45            Some(output) => {
46                fs::create_dir_all(output.parent().unwrap())?;
47                fs::write(&output, flattened)?;
48                sh_println!("Flattened file written at {}", output.display())?;
49            }
50            None => sh_println!("{flattened}")?,
51        };
52
53        Ok(())
54    }
55}