Skip to content

Commit f0786a7

Browse files
committed
finish refactor, add docs and tests
1 parent 6328b5c commit f0786a7

File tree

6 files changed

+163
-50
lines changed

6 files changed

+163
-50
lines changed

src/build.rs

Lines changed: 73 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
use crate::cmd::{Command, MountKind, Runnable, SandboxBuilder};
22
use crate::prepare::Prepare;
3-
use crate::{Crate, Toolchain, Workspace, crates::CratePatch};
3+
use crate::{Crate, Toolchain, Workspace};
44
use failure::Error;
55
use remove_dir_all::remove_dir_all;
66
use std::path::PathBuf;
77
use std::vec::Vec;
88

9+
/// Holds info for a patch to be added to a crate's Cargo.toml
10+
#[derive(Clone)]
11+
pub struct CratePatch {
12+
/// Crate name to patch
13+
pub name: String,
14+
/// URL of the git repo
15+
pub uri: String,
16+
/// Branch of the git repo
17+
pub branch: String
18+
}
19+
920
/// Directory in the [`Workspace`](struct.Workspace.html) where builds can be executed.
1021
///
1122
/// The build directory contains the source code of the crate being built and the target directory
@@ -16,6 +27,7 @@ pub struct BuildDirectory {
1627
name: String,
1728
}
1829

30+
/// Builder for configuring builds in a [`BuildDirectory`](struct.BuildDirectory.html).
1931
pub struct Builder<'a> {
2032
build_dir: &'a mut BuildDirectory,
2133
toolchain: &'a Toolchain,
@@ -26,11 +38,56 @@ pub struct Builder<'a> {
2638

2739
impl<'a> Builder<'a> {
2840

41+
/// Add a patch to this build.
42+
/// Patches get added to the crate's Cargo.toml in the `patch.crates-io` table.
43+
/// # Example
44+
///
45+
/// ```no_run
46+
/// # use rustwide::{WorkspaceBuilder, Toolchain, Crate, CratePatch, cmd::SandboxBuilder};
47+
/// # use std::error::Error;
48+
/// # fn main() -> Result<(), Box<dyn Error>> {
49+
/// # let workspace = WorkspaceBuilder::new("".as_ref(), "").init()?;
50+
/// # let toolchain = Toolchain::Dist { name: "".into() };
51+
/// # let krate = Crate::local("".as_ref());
52+
/// # let sandbox = SandboxBuilder::new();
53+
/// let crate_patch = CratePatch { name: "bar".into(), uri: "https://github.com/foo/bar".into(), branch: "baz".into() };
54+
/// let mut build_dir = workspace.build_dir("foo");
55+
/// build_dir.build(&toolchain, &krate, sandbox)
56+
/// .patch(crate_patch)
57+
/// .run(|build| {
58+
/// build.cargo().args(&["test", "--all"]).run()?;
59+
/// Ok(())
60+
/// })?;
61+
/// # Ok(())
62+
/// # }
2963
pub fn patch(mut self, patch: CratePatch) -> Self {
3064
self.patches.push(patch);
3165
self
3266
}
3367

68+
/// Run a sandboxed build of the provided crate with the provided toolchain. The closure will
69+
/// be provided an instance of [`Build`](struct.Build.html) that allows spawning new processes
70+
/// inside the sandbox.
71+
///
72+
/// All the state will be kept on disk as long as the closure doesn't exit: after that things
73+
/// might be removed.
74+
/// # Example
75+
///
76+
/// ```no_run
77+
/// # use rustwide::{WorkspaceBuilder, Toolchain, Crate, cmd::SandboxBuilder};
78+
/// # use std::error::Error;
79+
/// # fn main() -> Result<(), Box<dyn Error>> {
80+
/// # let workspace = WorkspaceBuilder::new("".as_ref(), "").init()?;
81+
/// # let toolchain = Toolchain::Dist { name: "".into() };
82+
/// # let krate = Crate::local("".as_ref());
83+
/// # let sandbox = SandboxBuilder::new();
84+
/// let mut build_dir = workspace.build_dir("foo");
85+
/// build_dir.build(&toolchain, &krate, sandbox).run(|build| {
86+
/// build.cargo().args(&["test", "--all"]).run()?;
87+
/// Ok(())
88+
/// })?;
89+
/// # Ok(())
90+
/// # }
3491
pub fn run<R, F: FnOnce(&Build) -> Result<R, Error>>(self, f: F) -> Result<R, Error> {
3592
self.build_dir.run(self.toolchain, self.krate, self.sandbox, self.patches, f)
3693
}
@@ -44,22 +101,8 @@ impl BuildDirectory {
44101
}
45102
}
46103

47-
pub fn build<'a>(&'a mut self,
48-
toolchain: &'a Toolchain,
49-
krate: &'a Crate,
50-
sandbox: SandboxBuilder,
51-
) -> Builder {
52-
Builder {
53-
build_dir: self, toolchain, krate, sandbox, patches: Vec::new()
54-
}
55-
}
56-
57-
/// Run a sandboxed build of the provided crate with the provided toolchain. The closure will
58-
/// be provided an instance of [`Build`](struct.Build.html) that allows spawning new processes
59-
/// inside the sandbox.
60-
///
61-
/// All the state will be kept on disk as long as the closure doesn't exit: after that things
62-
/// might be removed.
104+
/// Create a build in this build directory. Returns a builder that can be used
105+
/// to configure the build and run it.
63106
///
64107
/// # Example
65108
///
@@ -72,13 +115,23 @@ impl BuildDirectory {
72115
/// # let krate = Crate::local("".as_ref());
73116
/// # let sandbox = SandboxBuilder::new();
74117
/// let mut build_dir = workspace.build_dir("foo");
75-
/// build_dir.build(&toolchain, &krate, sandbox, |build| {
118+
/// build_dir.build(&toolchain, &krate, sandbox).run(|build| {
76119
/// build.cargo().args(&["test", "--all"]).run()?;
77120
/// Ok(())
78121
/// })?;
79122
/// # Ok(())
80123
/// # }
81124
/// ```
125+
pub fn build<'a>(&'a mut self,
126+
toolchain: &'a Toolchain,
127+
krate: &'a Crate,
128+
sandbox: SandboxBuilder,
129+
) -> Builder {
130+
Builder {
131+
build_dir: self, toolchain, krate, sandbox, patches: Vec::new()
132+
}
133+
}
134+
82135
pub(crate) fn run<R, F: FnOnce(&Build) -> Result<R, Error>>(
83136
&mut self,
84137
toolchain: &Toolchain,
@@ -155,7 +208,7 @@ impl Build<'_> {
155208
/// # let krate = Crate::local("".as_ref());
156209
/// # let sandbox = SandboxBuilder::new();
157210
/// let mut build_dir = workspace.build_dir("foo");
158-
/// build_dir.build(&toolchain, &krate, sandbox, |build| {
211+
/// build_dir.build(&toolchain, &krate, sandbox).run(|build| {
159212
/// build.cmd("rustfmt").args(&["--check", "src/main.rs"]).run()?;
160213
/// Ok(())
161214
/// })?;
@@ -192,7 +245,7 @@ impl Build<'_> {
192245
/// # let krate = Crate::local("".as_ref());
193246
/// # let sandbox = SandboxBuilder::new();
194247
/// let mut build_dir = workspace.build_dir("foo");
195-
/// build_dir.build(&toolchain, &krate, sandbox, |build| {
248+
/// build_dir.build(&toolchain, &krate, sandbox).run(|build| {
196249
/// build.cargo().args(&["test", "--all"]).run()?;
197250
/// Ok(())
198251
/// })?;

src/crates/mod.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,6 @@ enum CrateType {
2020
Local(local::Local),
2121
}
2222

23-
#[derive(Clone)]
24-
pub struct CratePatch {
25-
pub name: String,
26-
pub uri: String,
27-
pub branch: String
28-
}
29-
3023
/// A Rust crate that can be used with rustwide.
3124
pub struct Crate(CrateType);
3225

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ mod tools;
2929
mod utils;
3030
mod workspace;
3131

32-
pub use crate::build::{Build, BuildDirectory};
32+
pub use crate::build::{Build, BuildDirectory, CratePatch};
3333
pub use crate::crates::Crate;
3434
pub use crate::prepare::PrepareError;
3535
pub use crate::toolchain::Toolchain;

src/prepare.rs

Lines changed: 87 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::cmd::Command;
2-
use crate::{Crate, crates::CratePatch, Toolchain, Workspace};
2+
use crate::{Crate, Toolchain, CratePatch, Workspace};
33
use failure::{Error, Fail, ResultExt};
44
use log::info;
55
use std::path::Path;
@@ -146,28 +146,28 @@ pub struct TomlTweaker<'a> {
146146
krate: &'a Crate,
147147
table: Table,
148148
dir: Option<&'a Path>,
149-
patches: &'a Vec<CratePatch>,
149+
patches: Vec<CratePatch>,
150150
}
151151

152152
impl<'a> TomlTweaker<'a> {
153-
pub fn new(krate: &'a Crate, cargo_toml: &'a Path, patches: &'a Vec<CratePatch>) -> Result<Self, Error> {
153+
pub fn new(krate: &'a Crate, cargo_toml: &'a Path, patches: &[CratePatch]) -> Result<Self, Error> {
154154
let toml_content = ::std::fs::read_to_string(cargo_toml)
155155
.with_context(|_| PrepareError::MissingCargoToml)?;
156156
let table: Table =
157157
toml::from_str(&toml_content).with_context(|_| PrepareError::InvalidCargoTomlSyntax)?;
158158

159159
let dir = cargo_toml.parent();
160160

161-
Ok(TomlTweaker { krate, table, dir, patches })
161+
Ok(TomlTweaker { krate, table, dir, patches: patches.to_vec() })
162162
}
163163

164164
#[cfg(test)]
165-
fn new_with_table(krate: &'a Crate, table: Table, patches: &'a Vec<CratePatch>) -> Self {
165+
fn new_with_table(krate: &'a Crate, table: Table, patches: &[CratePatch]) -> Self {
166166
TomlTweaker {
167167
krate,
168168
table,
169169
dir: None,
170-
patches,
170+
patches: patches.to_vec(),
171171
}
172172
}
173173

@@ -282,18 +282,30 @@ impl<'a> TomlTweaker<'a> {
282282
}
283283

284284
fn apply_patches(&mut self) {
285-
if self.patches.len() > 0 {
286-
if !self.table.contains_key("patch.crates-io") {
287-
self.table.insert("patch.crates-io".into(), Value::Table(Table::new()));
288-
}
289-
290-
if let Some(&mut Value::Table(ref mut patches)) = self.table.get_mut("patch.crates-io") {
291-
for patch in self.patches.iter().cloned() {
292-
let mut patch_table = Table::new();
293-
patch_table.insert("git".into(), Value::String(patch.uri));
294-
patch_table.insert("branch".into(), Value::String(patch.branch));
295-
patches.insert(patch.name, Value::Table(patch_table));
285+
if !self.patches.is_empty() {
286+
let mut patch_table = self.table.get_mut("patch");
287+
let patch_table = match patch_table {
288+
Some(ref mut pt) => pt,
289+
None => {
290+
self.table.insert("patch".to_string(), Value::Table(Table::new()));
291+
self.table.get_mut("patch").unwrap()
292+
},
293+
};
294+
295+
let mut cratesio_table = patch_table.get_mut("crates-io");
296+
let cratesio_table = match cratesio_table {
297+
Some(ref mut cio) => cio,
298+
None => {
299+
patch_table.as_table_mut().unwrap().insert("crates-io".to_string(), Value::Table(Table::new()));
300+
patch_table.get_mut("crates-io").unwrap()
296301
}
302+
};
303+
304+
for patch in self.patches.iter().cloned() {
305+
let mut table = Table::new();
306+
table.insert("git".into(), Value::String(patch.uri));
307+
table.insert("branch".into(), Value::String(patch.branch));
308+
cratesio_table.as_table_mut().unwrap().insert(patch.name, Value::Table(table));
297309
}
298310
}
299311
}
@@ -353,7 +365,7 @@ pub enum PrepareError {
353365
#[cfg(test)]
354366
mod tests {
355367
use super::TomlTweaker;
356-
use crate::crates::Crate;
368+
use crate::{CratePatch, crates::Crate};
357369
use toml::{self, Value};
358370

359371
#[test]
@@ -378,7 +390,8 @@ mod tests {
378390
let result = toml.clone();
379391

380392
let krate = Crate::local("/dev/null".as_ref());
381-
let mut tweaker = TomlTweaker::new_with_table(&krate, toml.as_table().unwrap().clone());
393+
let patches: Vec<CratePatch> = Vec::new();
394+
let mut tweaker = TomlTweaker::new_with_table(&krate, toml.as_table().unwrap().clone(), &patches);
382395
tweaker.tweak();
383396

384397
assert_eq!(Value::Table(tweaker.table), result);
@@ -427,7 +440,61 @@ mod tests {
427440
};
428441

429442
let krate = Crate::local("/dev/null".as_ref());
430-
let mut tweaker = TomlTweaker::new_with_table(&krate, toml.as_table().unwrap().clone());
443+
let patches: Vec<CratePatch> = Vec::new();
444+
let mut tweaker = TomlTweaker::new_with_table(&krate, toml.as_table().unwrap().clone(), &patches);
445+
tweaker.tweak();
446+
447+
assert_eq!(Value::Table(tweaker.table), result);
448+
}
449+
450+
#[test]
451+
fn test_tweak_table_patches() {
452+
let toml = toml! {
453+
cargo-features = ["foobar"]
454+
455+
[package]
456+
name = "foo"
457+
version = "1.0"
458+
459+
[dependencies]
460+
bar = "1.0"
461+
462+
[dev-dependencies]
463+
baz = "1.0"
464+
465+
[target."cfg(unix)".dependencies]
466+
quux = "1.0"
467+
};
468+
469+
let result = toml! {
470+
cargo-features = ["foobar"]
471+
472+
[package]
473+
name = "foo"
474+
version = "1.0"
475+
476+
[dependencies]
477+
bar = "1.0"
478+
479+
[dev-dependencies]
480+
baz = "1.0"
481+
482+
[target."cfg(unix)".dependencies]
483+
quux = "1.0"
484+
485+
[patch.crates-io]
486+
quux = { git = "https://git.example.com/quux", branch = "dev" }
487+
};
488+
489+
let krate = Crate::local("/dev/null".as_ref());
490+
let patches = vec![
491+
CratePatch {
492+
name: "quux".into(),
493+
uri: "https://git.example.com/quux".into(),
494+
branch: "dev".into(),
495+
}
496+
];
497+
let mut tweaker = TomlTweaker::new_with_table(&krate, toml.as_table().unwrap().clone(), &patches);
431498
tweaker.tweak();
432499

433500
assert_eq!(Value::Table(tweaker.table), result);

tests/buildtest/runner.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ impl Runner {
4343
) -> Result<T, Error> {
4444
let mut dir = self.workspace.build_dir(&self.crate_name);
4545
dir.purge()?;
46-
dir.build(self.toolchain, &self.krate, sandbox, f)
46+
dir.build(self.toolchain, &self.krate, sandbox).run(f)
4747
}
4848
}
4949

tests/integration/crates_git.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fn test_fetch() -> Result<(), Error> {
1919
let mut dir = workspace.build_dir("integration-crates_git-test_fetch");
2020
dir.purge()?;
2121
Ok(
22-
dir.build(&toolchain, &krate, SandboxBuilder::new(), |build| {
22+
dir.build(&toolchain, &krate, SandboxBuilder::new()).run(|build| {
2323
Ok(Command::new(&workspace, "git")
2424
.args(&["rev-parse", "HEAD"])
2525
.cd(build.host_source_dir())

0 commit comments

Comments
 (0)