Skip to main content

cargo_memex/
build.rs

1use crate::manifest::Manifest;
2use crate::meme::Meme;
3use anyhow::Context;
4use std::path::PathBuf;
5use std::process::Command;
6use structopt::StructOpt;
7
8/// Executes build of the memex executable meme which produces meme "binary".
9///
10/// It does so by invoking `cargo build` and then post processing the final binary.
11#[derive(Debug, StructOpt)]
12#[structopt(name = "build")]
13pub struct BuildCommand {
14    /// Path to the Cargo.toml of the cargo project
15    #[structopt(long, parse(from_os_str))]
16    manifest_path: Option<PathBuf>,
17
18    /// The targeted meme
19    meme: Option<String>,
20
21    /// Build the specified binary
22    #[structopt(long)]
23    bin: Option<String>,
24
25    /// Build the specified examples
26    #[structopt(long)]
27    example: Option<String>,
28
29    /// Build the meme in release mode, with optimizations
30    #[structopt(long)]
31    release: bool,
32
33    /// Fetch a random meme from this subreddit
34    #[structopt(long)]
35    subreddit: Option<String>,
36}
37
38impl BuildCommand {
39    /// execute the build command
40    pub fn run(&self) -> anyhow::Result<BuildOutput> {
41        let meme = if let Some(ref subreddit) = self.subreddit {
42            Meme::fetch_random_meme(subreddit)?
43                .context(format!("No jpeg meme found on subreddit {}", subreddit))?
44        } else {
45            if let Some(ref meme) = self.meme {
46                Meme::new(meme)?
47            } else {
48                if let Ok(Some(meme)) = Meme::fetch_random_meme("rustjerk") {
49                    meme
50                } else {
51                    if self.release {
52                        Meme::new("release")?
53                    } else {
54                        Meme::new("debug")?
55                    }
56                }
57            }
58        };
59
60        let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".to_string());
61        let mut cmd = Command::new(cargo);
62        cmd.arg("build");
63
64        let (manifest, mut bin_path) = if let Some(ref path) = self.manifest_path {
65            cmd.arg("--manifest-path").arg(path);
66            (
67                Manifest::new(path)?,
68                path.parent()
69                    .map(|p| p.to_path_buf())
70                    .unwrap_or_else(|| PathBuf::from(".")),
71            )
72        } else {
73            (Manifest::new("./Cargo.toml")?, PathBuf::from("."))
74        };
75        bin_path.push("target");
76
77        if self.release {
78            cmd.arg("--release");
79            bin_path.push("release");
80        } else {
81            bin_path.push("debug");
82        }
83
84        let bin_name = if let Some(ref bin) = self.bin {
85            cmd.arg("--bin").arg(bin);
86            bin.clone()
87        } else if let Some(ref example) = self.example {
88            cmd.arg("--example").arg(example);
89            bin_path.push("examples");
90            example.clone()
91        } else {
92            manifest.name()?.to_string()
93        };
94        bin_path.push(&bin_name);
95
96        log::debug!("Executing: `{:?}`", cmd);
97        let child = cmd.spawn()?;
98        let output = child
99            .wait_with_output()
100            .context(format!("Error executing `{:?}`", cmd))?;
101
102        if !output.status.success() {
103            anyhow::bail!(
104                "`{:?}` failed with exit code: {:?}",
105                cmd,
106                output.status.code()
107            );
108        }
109
110        let mut meme_path = bin_path.clone();
111        meme_path.set_extension("jpeg");
112        meme.write_with_bin_to(&bin_path, &meme_path)?;
113        Ok(BuildOutput {
114            meme_path,
115            bin_path,
116            bin_name,
117        })
118    }
119}
120
121pub struct BuildOutput {
122    pub meme_path: PathBuf,
123    /// Path to the cargo binary.
124    pub bin_path: PathBuf,
125    /// Name of the executable
126    pub bin_name: String,
127}