1 use std
::collections
::HashSet
;
2 use std
::io
::{Write, BufWriter, ErrorKind}
;
3 use std
::fs
::{self, File}
;
4 use std
::path
::{Path, PathBuf}
;
6 use ops
::{Context, Unit}
;
7 use util
::{CargoResult, internal}
;
8 use ops
::cargo_rustc
::fingerprint
;
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
{
14 Some(base
) => match path
.strip_prefix(base
) {
15 Ok(relpath
) => relpath
,
19 relpath
.to_str().ok_or_else(|| internal("path not utf-8")).map(|f
| f
.replace(" ", "\\ "))
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
<()>
25 if !visited
.insert(*unit
) {
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
)?
{
36 debug
!("can't find dep_info for {:?} {:?}",
37 unit
.pkg
.package_id(), unit
.profile
);
38 return Err(internal("dep_info missing"));
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());
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
)?
;
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");
68 let mut outfile
= BufWriter
::new(File
::create(output_path
)?
);
69 let target_fn
= render_filename(link_dst
, basedir
)?
;
70 write
!(outfile
, "{}:", target_fn
)?
;
72 write
!(outfile
, " {}", render_filename(dep
, basedir
)?
)?
;
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
79 if err
.kind() != ErrorKind
::NotFound
{
80 return Err(err
.into());