]> git.proxmox.com Git - cargo.git/blob - src/cargo/ops/cargo_rustc/output_depinfo.rs
More lint cleaning
[cargo.git] / src / cargo / ops / cargo_rustc / output_depinfo.rs
1 use std::collections::HashSet;
2 use std::io::{Write, BufWriter, ErrorKind};
3 use std::fs::{self, File};
4 use std::path::{Path, PathBuf};
5
6 use ops::{Context, Unit};
7 use util::{CargoResult, internal};
8 use ops::cargo_rustc::fingerprint;
9
10 fn render_filename<P: AsRef<Path>>(path: P, basedir: Option<&str>) -> CargoResult<String> {
11 let path = path.as_ref();
12 let relpath = match basedir {
13 None => path,
14 Some(base) => match path.strip_prefix(base) {
15 Ok(relpath) => relpath,
16 _ => path,
17 }
18 };
19 relpath.to_str().ok_or_else(|| internal("path not utf-8")).map(|f| f.replace(" ", "\\ "))
20 }
21
22 fn add_deps_for_unit<'a, 'b>(deps: &mut HashSet<PathBuf>, context: &mut Context<'a, 'b>,
23 unit: &Unit<'a>, visited: &mut HashSet<Unit<'a>>) -> CargoResult<()>
24 {
25 if !visited.insert(*unit) {
26 return Ok(());
27 }
28
29 // Add dependencies from rustc dep-info output (stored in fingerprint directory)
30 let dep_info_loc = fingerprint::dep_info_loc(context, unit);
31 if let Some(paths) = fingerprint::parse_dep_info(&dep_info_loc)? {
32 for path in paths {
33 deps.insert(path);
34 }
35 } else {
36 debug!("can't find dep_info for {:?} {:?}",
37 unit.pkg.package_id(), unit.profile);
38 return Err(internal("dep_info missing"));
39 }
40
41 // Add rerun-if-changed dependencies
42 let key = (unit.pkg.package_id().clone(), unit.kind);
43 if let Some(output) = context.build_state.outputs.lock().unwrap().get(&key) {
44 for path in &output.rerun_if_changed {
45 deps.insert(path.into());
46 }
47 }
48
49 // Recursively traverse all transitive dependencies
50 for dep_unit in &context.dep_targets(unit)? {
51 let source_id = dep_unit.pkg.package_id().source_id();
52 if source_id.is_path() {
53 add_deps_for_unit(deps, context, dep_unit, visited)?;
54 }
55 }
56 Ok(())
57 }
58
59 pub fn output_depinfo<'a, 'b>(context: &mut Context<'a, 'b>, unit: &Unit<'a>) -> CargoResult<()> {
60 let mut deps = HashSet::new();
61 let mut visited = HashSet::new();
62 let success = add_deps_for_unit(&mut deps, context, unit, &mut visited).is_ok();
63 let basedir = None; // TODO
64 for &(_, ref link_dst, _) in context.target_filenames(unit)?.iter() {
65 if let Some(ref link_dst) = *link_dst {
66 let output_path = link_dst.with_extension("d");
67 if success {
68 let mut outfile = BufWriter::new(File::create(output_path)?);
69 let target_fn = render_filename(link_dst, basedir)?;
70 write!(outfile, "{}:", target_fn)?;
71 for dep in &deps {
72 write!(outfile, " {}", render_filename(dep, basedir)?)?;
73 }
74 writeln!(outfile, "")?;
75 } else if let Err(err) = fs::remove_file(output_path) {
76 // dep-info generation failed, so delete output file. This will usually
77 // cause the build system to always rerun the build rule, which is correct
78 // if inefficient.
79 if err.kind() != ErrorKind::NotFound {
80 return Err(err.into());
81 }
82 }
83 }
84 }
85 Ok(())
86 }