Skip to content

Commit f20ca62

Browse files
committed
Auto merge of #2547 - alexcrichton:more-locking, r=brson
Add file locks in a few more locations One was discovered by making `target_dir` return a `Filesystem`, the other was discovered by failing tests on the nightly OSX bots.
2 parents 12f76a5 + 6f6d7c8 commit f20ca62

18 files changed

+184
-112
lines changed

src/cargo/ops/cargo_clean.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,24 @@ pub fn clean(manifest_path: &Path, opts: &CleanOptions) -> CargoResult<()> {
2121

2222
// If we have a spec, then we need to delete some packages, otherwise, just
2323
// remove the whole target directory and be done with it!
24+
//
25+
// Note that we don't bother grabbing a lock here as we're just going to
26+
// blow it all away anyway.
2427
if opts.spec.is_empty() {
28+
let target_dir = target_dir.into_path_unlocked();
2529
return rm_rf(&target_dir);
2630
}
2731

2832
let (resolve, packages) = try!(ops::fetch(manifest_path, opts.config));
2933

3034
let dest = if opts.release {"release"} else {"debug"};
31-
let host_layout = Layout::new(opts.config, &root, None, dest);
32-
let target_layout = opts.target.map(|target| {
33-
Layout::new(opts.config, &root, Some(target), dest)
34-
});
35+
let host_layout = try!(Layout::new(opts.config, &root, None, dest));
36+
let target_layout = match opts.target {
37+
Some(target) => {
38+
Some(try!(Layout::new(opts.config, &root, Some(target), dest)))
39+
}
40+
None => None,
41+
};
3542

3643
let cx = try!(Context::new(&resolve, &packages, opts.config,
3744
host_layout, target_layout,

src/cargo/ops/cargo_doc.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,12 @@ pub fn doc(manifest_path: &Path,
5050
}
5151
};
5252

53+
// Don't bother locking here as if this is getting deleted there's
54+
// nothing we can do about it and otherwise if it's getting overwritten
55+
// then that's also ok!
5356
let target_dir = options.compile_opts.config.target_dir(&package);
5457
let path = target_dir.join("doc").join(&name).join("index.html");
58+
let path = path.into_path_unlocked();
5559
if fs::metadata(&path).is_ok() {
5660
let mut shell = options.compile_opts.config.shell();
5761
match open_docs(&path) {

src/cargo/ops/cargo_generate_lockfile.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub fn generate_lockfile(manifest_path: &Path, config: &Config)
2323
let resolve = try!(ops::resolve_with_previous(&mut registry, &package,
2424
Method::Everything,
2525
None, None));
26-
try!(ops::write_pkg_lockfile(&package, &resolve));
26+
try!(ops::write_pkg_lockfile(&package, &resolve, config));
2727
Ok(())
2828
}
2929

@@ -106,7 +106,7 @@ pub fn update_lockfile(manifest_path: &Path,
106106
}
107107
}
108108

109-
try!(ops::write_pkg_lockfile(&package, &resolve));
109+
try!(ops::write_pkg_lockfile(&package, &resolve, opts.config));
110110
return Ok(());
111111

112112
fn fill_with_deps<'a>(resolve: &'a Resolve, dep: &'a PackageId,

src/cargo/ops/cargo_install.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ pub fn install(root: Option<&str>,
8282
let target_dir = if source_id.is_path() {
8383
config.target_dir(&pkg)
8484
} else {
85-
config.cwd().join("target-install")
85+
Filesystem::new(config.cwd().join("target-install"))
8686
};
87-
config.set_target_dir(&target_dir);
87+
config.set_target_dir(target_dir.clone());
8888
let compile = try!(ops::compile_pkg(&pkg, Some(source), opts).chain_error(|| {
8989
human(format!("failed to compile `{}`, intermediate artifacts can be \
9090
found at `{}`", pkg, target_dir.display()))
@@ -108,6 +108,9 @@ pub fn install(root: Option<&str>,
108108
}
109109

110110
if !source_id.is_path() {
111+
// Don't bother grabbing a lock as we're going to blow it all away
112+
// anyway.
113+
let target_dir = target_dir.into_path_unlocked();
111114
try!(fs::remove_dir_all(&target_dir));
112115
}
113116

src/cargo/ops/cargo_package.rs

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
use std::io::prelude::*;
21
use std::fs::{self, File};
3-
use std::path::{self, Path, PathBuf};
2+
use std::io::SeekFrom;
3+
use std::io::prelude::*;
4+
use std::path::{self, Path};
45

56
use tar::{Archive, Builder, Header};
67
use flate2::{GzBuilder, Compression};
78
use flate2::read::GzDecoder;
89

910
use core::{SourceId, Package, PackageId};
1011
use sources::PathSource;
11-
use util::{self, CargoResult, human, internal, ChainError, Config};
12+
use util::{self, CargoResult, human, internal, ChainError, Config, FileLock};
1213
use ops;
1314

1415
pub fn package(manifest_path: &Path,
1516
config: &Config,
1617
verify: bool,
1718
list: bool,
18-
metadata: bool) -> CargoResult<Option<PathBuf>> {
19+
metadata: bool) -> CargoResult<Option<FileLock>> {
1920
let path = manifest_path.parent().unwrap();
2021
let id = try!(SourceId::for_path(path));
2122
let mut src = PathSource::new(path, &id, config);
@@ -39,29 +40,37 @@ pub fn package(manifest_path: &Path,
3940

4041
let filename = format!("{}-{}.crate", pkg.name(), pkg.version());
4142
let dir = config.target_dir(&pkg).join("package");
42-
let dst = dir.join(&filename);
43-
if fs::metadata(&dst).is_ok() {
44-
return Ok(Some(dst))
45-
}
43+
let mut dst = match dir.open_ro(&filename, config, "packaged crate") {
44+
Ok(f) => return Ok(Some(f)),
45+
Err(..) => {
46+
let tmp = format!(".{}", filename);
47+
try!(dir.open_rw(&tmp, config, "package scratch space"))
48+
}
49+
};
4650

4751
// Package up and test a temporary tarball and only move it to the final
4852
// location if it actually passes all our tests. Any previously existing
4953
// tarball can be assumed as corrupt or invalid, so we just blow it away if
5054
// it exists.
5155
try!(config.shell().status("Packaging", pkg.package_id().to_string()));
52-
let tmp_dst = dir.join(format!(".{}", filename));
53-
let _ = fs::remove_file(&tmp_dst);
54-
try!(tar(&pkg, &src, config, &tmp_dst, &filename).chain_error(|| {
56+
try!(dst.file().set_len(0));
57+
try!(tar(&pkg, &src, config, dst.file(), &filename).chain_error(|| {
5558
human("failed to prepare local package for uploading")
5659
}));
5760
if verify {
58-
try!(run_verify(config, &pkg, &tmp_dst).chain_error(|| {
61+
try!(dst.seek(SeekFrom::Start(0)));
62+
try!(run_verify(config, &pkg, dst.file()).chain_error(|| {
5963
human("failed to verify package tarball")
6064
}))
6165
}
62-
try!(fs::rename(&tmp_dst, &dst).chain_error(|| {
63-
human("failed to move temporary tarball into final location")
64-
}));
66+
try!(dst.seek(SeekFrom::Start(0)));
67+
{
68+
let src_path = dst.path();
69+
let dst_path = dst.parent().join(&filename);
70+
try!(fs::rename(&src_path, &dst_path).chain_error(|| {
71+
human("failed to move temporary tarball into final location")
72+
}));
73+
}
6574
Ok(Some(dst))
6675
}
6776

@@ -103,26 +112,17 @@ fn check_metadata(pkg: &Package, config: &Config) -> CargoResult<()> {
103112
fn tar(pkg: &Package,
104113
src: &PathSource,
105114
config: &Config,
106-
dst: &Path,
115+
dst: &File,
107116
filename: &str) -> CargoResult<()> {
108-
if fs::metadata(&dst).is_ok() {
109-
bail!("destination already exists: {}", dst.display())
110-
}
111-
112-
try!(fs::create_dir_all(dst.parent().unwrap()));
113-
114-
let tmpfile = try!(File::create(dst));
115-
116117
// Prepare the encoder and its header
117118
let filename = Path::new(filename);
118119
let encoder = GzBuilder::new().filename(try!(util::path2bytes(filename)))
119-
.write(tmpfile, Compression::Best);
120+
.write(dst, Compression::Best);
120121

121122
// Put all package files into a compressed archive
122123
let mut ar = Builder::new(encoder);
123124
let root = pkg.root();
124125
for file in try!(src.list_files(pkg)).iter() {
125-
if &**file == dst { continue }
126126
let relative = util::without_prefix(&file, &root).unwrap();
127127
try!(check_filename(relative));
128128
let relative = try!(relative.to_str().chain_error(|| {
@@ -173,11 +173,13 @@ fn tar(pkg: &Package,
173173
Ok(())
174174
}
175175

176-
fn run_verify(config: &Config, pkg: &Package, tar: &Path)
176+
fn run_verify(config: &Config,
177+
pkg: &Package,
178+
tar: &File)
177179
-> CargoResult<()> {
178180
try!(config.shell().status("Verifying", pkg));
179181

180-
let f = try!(GzDecoder::new(try!(File::open(tar))));
182+
let f = try!(GzDecoder::new(tar));
181183
let dst = pkg.root().join(&format!("target/package/{}-{}",
182184
pkg.name(), pkg.version()));
183185
if fs::metadata(&dst).is_ok() {

src/cargo/ops/cargo_pkgid.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ pub fn pkgid(manifest_path: &Path,
88
spec: Option<&str>,
99
config: &Config) -> CargoResult<PackageIdSpec> {
1010
let package = try!(Package::for_path(manifest_path, config));
11-
12-
let lockfile = package.root().join("Cargo.lock");
13-
let resolve = match try!(ops::load_lockfile(&lockfile, &package, config)) {
11+
let resolve = match try!(ops::load_pkg_lockfile(&package, config)) {
1412
Some(resolve) => resolve,
1513
None => bail!("a Cargo.lock must exist for this command"),
1614
};

src/cargo/ops/cargo_rustc/layout.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ use std::io;
5050
use std::path::{PathBuf, Path};
5151

5252
use core::{Package, Target};
53-
use util::Config;
53+
use util::{Config, FileLock, CargoResult, Filesystem};
5454
use util::hex::short_hash;
5555

5656
pub struct Layout {
@@ -60,6 +60,7 @@ pub struct Layout {
6060
build: PathBuf,
6161
fingerprint: PathBuf,
6262
examples: PathBuf,
63+
_lock: FileLock,
6364
}
6465

6566
pub struct LayoutProxy<'a> {
@@ -68,8 +69,10 @@ pub struct LayoutProxy<'a> {
6869
}
6970

7071
impl Layout {
71-
pub fn new(config: &Config, pkg: &Package, triple: Option<&str>,
72-
dest: &str) -> Layout {
72+
pub fn new(config: &Config,
73+
pkg: &Package,
74+
triple: Option<&str>,
75+
dest: &str) -> CargoResult<Layout> {
7376
let mut path = config.target_dir(pkg);
7477
// Flexible target specifications often point at filenames, so interpret
7578
// the target triple as a Path and then just use the file stem as the
@@ -78,18 +81,25 @@ impl Layout {
7881
path.push(Path::new(triple).file_stem().unwrap());
7982
}
8083
path.push(dest);
81-
Layout::at(path)
84+
Layout::at(config, path)
8285
}
8386

84-
pub fn at(root: PathBuf) -> Layout {
85-
Layout {
87+
pub fn at(config: &Config, root: Filesystem) -> CargoResult<Layout> {
88+
// For now we don't do any more finer-grained locking on the artifact
89+
// directory, so just lock the entire thing for the duration of this
90+
// compile.
91+
let lock = try!(root.open_rw(".cargo-lock", config, "build directory"));
92+
let root = root.into_path_unlocked();
93+
94+
Ok(Layout {
8695
deps: root.join("deps"),
8796
native: root.join("native"),
8897
build: root.join("build"),
8998
fingerprint: root.join(".fingerprint"),
9099
examples: root.join("examples"),
91100
root: root,
92-
}
101+
_lock: lock,
102+
})
93103
}
94104

95105
pub fn prepare(&mut self) -> io::Result<()> {

src/cargo/ops/cargo_rustc/mod.rs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ use std::env;
33
use std::ffi::{OsStr, OsString};
44
use std::fs;
55
use std::io::prelude::*;
6-
use std::path::{self, PathBuf, Path};
6+
use std::path::{self, PathBuf};
77
use std::sync::Arc;
88

99
use core::{Package, PackageId, PackageSet, Target, Resolve};
1010
use core::{Profile, Profiles};
11-
use util::{self, CargoResult, human, Filesystem};
11+
use util::{self, CargoResult, human};
1212
use util::{Config, internal, ChainError, profile, join_paths};
1313

1414
use self::job::{Job, Work};
@@ -80,17 +80,13 @@ pub fn compile_targets<'a, 'cfg: 'a>(pkg_targets: &'a PackagesToBuild<'a>,
8080

8181
let dest = if build_config.release {"release"} else {"debug"};
8282
let root = try!(packages.get(resolve.root()));
83-
let host_layout = Layout::new(config, root, None, &dest);
84-
let target_layout = build_config.requested_target.as_ref().map(|target| {
85-
layout::Layout::new(config, root, Some(&target), &dest)
86-
});
87-
88-
// For now we don't do any more finer-grained locking on the artifact
89-
// directory, so just lock the entire thing for the duration of this
90-
// compile.
91-
let fs = Filesystem::new(host_layout.root().to_path_buf());
92-
let path = Path::new(".cargo-lock");
93-
let _lock = try!(fs.open_rw(path, config, "build directory"));
83+
let host_layout = try!(Layout::new(config, root, None, &dest));
84+
let target_layout = match build_config.requested_target.as_ref() {
85+
Some(target) => {
86+
Some(try!(layout::Layout::new(config, root, Some(&target), &dest)))
87+
}
88+
None => None,
89+
};
9490

9591
let mut cx = try!(Context::new(resolve, packages, config,
9692
host_layout, target_layout,

0 commit comments

Comments
 (0)