-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Basic functionality (and initial
repro
crate)
Adds extremely basic functionality for invoking `cargo build --locked` as `cargo repro build`. Though this may seem fairly pointless in and of itself, the goal of a followup commit would be to collect environmental information during this step (OS/release, rustc/cargo version, CWD, environment variables, git commit, C/C++ compiler versions if applicable) and use that during the verification process to detect and highlight mismatches. This commit attempts to split the CLI app (i.e. `cargo-repro`) from a library-level crate containing the core functionality (ala `cargo-audit` and the `rustsec` crate), in case there is interest in driving these sorts of builds from external tooling.
- Loading branch information
Showing
12 changed files
with
275 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
[package] | ||
name = "repro" | ||
description = """ | ||
Support crate for cargo-repro, a tool for building and verifying | ||
Rust packages that are reproducible byte-for-byte using a | ||
Cargo-driven workflow. | ||
""" | ||
version = "0.0.0" | ||
authors = ["Rust Secure Code WG <[email protected]>"] | ||
edition = "2018" | ||
license = "Apache-2.0 OR MIT" | ||
readme = "README.md" | ||
repository = "https://github.com/rust-secure-code/cargo-repro" | ||
categories = ["command-line-utilities", "development-tools", "rust-patterns"] | ||
keywords = ["cargo", "deterministic", "reproducible", "security", "verifiable"] | ||
|
||
[badges] | ||
maintenance = { status = "experimental" } | ||
|
||
[dependencies] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
//! Rust project builder - wrapper for invoking Cargo | ||
use std::{ | ||
ffi::OsString, | ||
process::{Child, Command, ExitStatus}, | ||
}; | ||
|
||
/// Name of the `cargo` executable | ||
const CARGO_EXE: &str = "cargo"; | ||
|
||
/// Rust project builder | ||
#[derive(Clone, Debug)] | ||
pub struct Builder { | ||
program: OsString, | ||
args: Vec<OsString>, | ||
} | ||
|
||
impl Default for Builder { | ||
fn default() -> Self { | ||
Self::new(CARGO_EXE) | ||
} | ||
} | ||
|
||
impl Builder { | ||
/// Create `Builder` that invokes the given command with the given arguments | ||
pub fn new<S>(program: S) -> Self | ||
where | ||
S: Into<OsString>, | ||
{ | ||
Self { | ||
program: program.into(), | ||
args: vec![], | ||
} | ||
} | ||
|
||
/// Append an argument to the set of arguments to run | ||
pub fn arg<S>(&mut self, arg: S) -> &mut Self | ||
where | ||
S: Into<OsString>, | ||
{ | ||
self.args.push(arg.into()); | ||
self | ||
} | ||
|
||
/// Append multiple arguments to the set of arguments to run | ||
pub fn args<I, S>(&mut self, args: I) -> &mut Self | ||
where | ||
I: IntoIterator<Item = S>, | ||
S: Into<OsString>, | ||
{ | ||
self.args.extend(args.into_iter().map(|a| a.into())); | ||
self | ||
} | ||
|
||
/// Run the given subcommand | ||
pub fn run(&self) -> Process { | ||
let child = Command::new(&self.program) | ||
.args(&self.args) | ||
.spawn() | ||
.unwrap_or_else(|e| { | ||
panic!("error running command: {}", e); | ||
}); | ||
|
||
Process(child) | ||
} | ||
} | ||
|
||
/// Wrapper for the builder subprocess | ||
pub struct Process(Child); | ||
|
||
impl Process { | ||
/// Wait for the child to finish | ||
pub fn wait(mut self) -> ExitStatus { | ||
self.0 | ||
.wait() | ||
.unwrap_or_else(|e| panic!("couldn't get child's exit status: {}", e)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
//! `repro` crate: perform and verify reproducible builds of Rust code | ||
#![forbid(unsafe_code)] | ||
#![deny(warnings, missing_docs, trivial_casts, unused_qualifications)] | ||
#![doc( | ||
html_logo_url = "https://avatars3.githubusercontent.com/u/44121472", | ||
html_root_url = "https://docs.rs/repro/0.0.0" | ||
)] | ||
|
||
pub mod builder; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
//! `cargo repro` subcommands | ||
pub mod build; | ||
pub mod verify; | ||
|
||
use self::{build::BuildCommand, verify::VerifyCommand}; | ||
|
||
/// `cargo repro` subcommands | ||
pub enum Command { | ||
/// `cargo repro build` subcommand | ||
Build(BuildCommand), | ||
|
||
/// `cargo repro verify` subcommand | ||
Verify(VerifyCommand), | ||
} | ||
|
||
impl Command { | ||
/// Parse command to execute from CLI args | ||
pub fn from_args(mut args: impl Iterator<Item = String>) -> Option<Self> { | ||
// ARGV[0] is always the name of the executed binary | ||
args.next().unwrap(); | ||
|
||
// Cargo passes `repro` as the first argument when invoking `cargo repro` | ||
if args.next().as_ref().map(String::as_str) != Some("repro") { | ||
return None; | ||
} | ||
|
||
let command = match args.next().as_ref().map(String::as_str) { | ||
Some("build") => Command::Build(BuildCommand::from_args(args)), | ||
Some("verify") => Command::Verify(VerifyCommand::from_args(args)), | ||
_ => return None, | ||
}; | ||
|
||
Some(command) | ||
} | ||
|
||
/// Run the parsed command | ||
pub fn run(&self) { | ||
match self { | ||
Command::Build(build) => build.run(), | ||
Command::Verify(verify) => verify.run(), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
//! `cargo repro build` subcommand | ||
use repro::builder::Builder; | ||
|
||
/// Cargo argument for a locked build. This is needed to ensure the build | ||
/// is reproducible. | ||
pub const LOCKED_ARG: &str = "--locked"; | ||
|
||
/// `cargo repro build` subcommand | ||
pub struct BuildCommand { | ||
/// Arguments passed to `cargo repro build` (to be passed to Cargo) | ||
pub args: Vec<String>, | ||
} | ||
|
||
impl BuildCommand { | ||
/// Initialize this command from the given arguments, which should *NOT* | ||
/// include `["cargo", "repro", "build"]` | ||
pub fn from_args(args: impl Iterator<Item = String>) -> Self { | ||
Self { | ||
args: args.collect(), | ||
} | ||
} | ||
|
||
/// Run this subcommand | ||
// TODO(tarcieri): factor more of this logic into the `repro` crate? | ||
pub fn run(&self) { | ||
let mut builder = Builder::default(); | ||
builder.arg("build"); | ||
|
||
// Add the `--locked` argument unless it's been specified explicitly | ||
if !self.args.iter().any(|arg| arg.as_str() == LOCKED_ARG) { | ||
builder.arg(LOCKED_ARG); | ||
} | ||
|
||
builder.args(&self.args); | ||
let exit_status = builder.run().wait(); | ||
|
||
if !exit_status.success() { | ||
panic!( | ||
"cargo exited with non-zero status: {}", | ||
exit_status | ||
.code() | ||
.map(|code| code.to_string()) | ||
.unwrap_or_else(|| "unknown".to_owned()) | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
//! `cargo repro verify` subcommand | ||
/// `cargo repro verify` subcommand | ||
pub struct VerifyCommand { | ||
/// Arguments passed to `cargo repro verify` (to be passed to Cargo) | ||
pub args: Vec<String>, | ||
} | ||
|
||
impl VerifyCommand { | ||
/// Initialize this command from the given arguments, which should *NOT* | ||
/// include `["cargo", "repro", "verify"]` | ||
pub fn from_args(args: impl Iterator<Item = String>) -> Self { | ||
Self { | ||
args: args.collect(), | ||
} | ||
} | ||
|
||
/// Run this subcommand | ||
pub fn run(&self) { | ||
println!("cargo repro: build and verify byte-for-byte reproducible Rust packages"); | ||
println!(); | ||
println!("WORK IN PROGRESS: The 'verify' functionality of this tool is unimplemented."); | ||
println!("If you are interested in contributing, please see the GitHub issues:"); | ||
println!(); | ||
println!(" https://github.com/rust-secure-code/cargo-repro/issues"); | ||
println!(); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
//! cargo-repro: perform and verify reproducible builds of Rust code with Cargo | ||
#![deny(warnings, missing_docs, trivial_casts, unused_qualifications)] | ||
#![forbid(unsafe_code)] | ||
|
||
pub mod commands; | ||
|
||
use commands::Command; | ||
use std::{env, process}; | ||
|
||
fn main() { | ||
let command = Command::from_args(env::args()).unwrap_or_else(|| usage()); | ||
command.run(); | ||
} | ||
|
||
fn usage() -> ! { | ||
println!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); | ||
println!( | ||
"{}\n", | ||
env!("CARGO_PKG_DESCRIPTION") | ||
.split_whitespace() | ||
.collect::<Vec<_>>() | ||
.join(" ") | ||
); | ||
|
||
println!("SUBCOMMANDS:"); | ||
println!(" build\tPerform a reproducible build of a Cargo project"); | ||
println!(" verify\t(UNIMPLEMENTED) Verify a reproducible build"); | ||
|
||
process::exit(1); | ||
} |