1
- use std:: io:: Read ;
2
- use std:: env;
3
- use std:: fs:: { self , File } ;
4
- use std:: path:: { Path , PathBuf } ;
1
+ use std:: collections:: HashMap ;
5
2
6
- use toml:: { self , Table , Value } ;
3
+ use toml:: Value ;
7
4
8
5
use dep:: { Dep , DepKind } ;
9
6
use graph:: DepGraph ;
10
7
use error:: { CliErrorKind , CliResult } ;
11
8
use config:: Config ;
9
+ use util;
10
+
11
+ macro_rules! propagate_kind {
12
+ ( $me: ident, $kind: expr) => ( {
13
+ let mut changes = false ;
14
+ loop {
15
+ for ( dep, children) in & $me. dep_tree {
16
+ if $me. styles. get( dep) . unwrap( ) == & $kind {
17
+ for child in children {
18
+ if $me. styles. get( child) . unwrap( ) != & $kind {
19
+ * $me. styles. get_mut( child) . unwrap( ) = $kind;
20
+ changes = true ;
21
+ }
22
+ }
23
+ }
24
+ }
25
+ if !changes { break ; }
26
+ changes = false ;
27
+ }
28
+ } ) ;
29
+ }
12
30
13
31
pub struct Project < ' c , ' o >
14
32
where ' o : ' c
15
33
{
16
- pwd : PathBuf ,
17
34
cfg : & ' c Config < ' o > ,
35
+ styles : HashMap < String , DepKind > ,
36
+ dep_tree : HashMap < String , Vec < String > > ,
37
+ blacklist : Vec < String >
18
38
}
19
39
20
40
impl < ' c , ' o > Project < ' c , ' o > {
21
- pub fn from_config ( cfg : & ' c Config < ' o > ) -> CliResult < Self > {
22
- let pwd = try!( env:: current_dir ( ) ) ;
23
-
41
+ pub fn with_config ( cfg : & ' c Config < ' o > ) -> CliResult < Self > {
24
42
Ok ( Project {
25
- pwd : pwd,
26
43
cfg : cfg,
44
+ styles : HashMap :: new ( ) ,
45
+ dep_tree : HashMap :: new ( ) ,
46
+ blacklist : vec ! [ ]
27
47
} )
28
48
}
29
49
30
- fn find_project_file ( & self , file : & str ) -> CliResult < PathBuf > {
31
- let mut pwd = self . pwd . as_path ( ) ;
50
+ pub fn graph ( mut self ) -> CliResult < DepGraph < ' c , ' o > > {
51
+ let mut dg = try! ( self . parse_root_deps ( ) ) ;
32
52
33
- loop {
34
- let manifest = pwd. join ( file) ;
35
- if let Ok ( metadata) = fs:: metadata ( & manifest) {
36
- if metadata. is_file ( ) {
37
- return Ok ( manifest) ;
38
- }
39
- }
53
+ try!( self . parse_lock_file ( & mut dg) ) ;
40
54
41
- match pwd. parent ( ) {
42
- Some ( p) => pwd = p,
43
- None => break ,
44
- }
45
- }
55
+ self . update_styles ( & mut dg) ;
46
56
47
- Err ( From :: from ( CliErrorKind :: Generic ( format ! ( "Could not find `{}` in `{}` or any \
48
- parent directory, or it isn't a valid \
49
- lock-file",
50
- file,
51
- pwd. display( ) ) ) ) )
57
+ Ok ( dg)
52
58
}
53
59
54
- fn toml_from_file < P : AsRef < Path > > ( p : P ) -> CliResult < Box < Table > > {
55
- debugln ! ( "executing; from_file; file={:?}" , p. as_ref( ) ) ;
56
- let mut f = try!( File :: open ( p. as_ref ( ) ) ) ;
57
-
58
- let mut s = String :: new ( ) ;
59
- try!( f. read_to_string ( & mut s) ) ;
60
-
61
- let mut parser = toml:: Parser :: new ( & s) ;
62
- match parser. parse ( ) {
63
- Some ( toml) => return Ok ( Box :: new ( toml) ) ,
64
- None => { }
65
- }
66
-
67
- // On err
68
- let mut error_str = format ! ( "could not parse input as TOML\n " ) ;
69
- for error in parser. errors . iter ( ) {
70
- let ( loline, locol) = parser. to_linecol ( error. lo ) ;
71
- let ( hiline, hicol) = parser. to_linecol ( error. hi ) ;
72
- error_str. push_str ( & format ! ( "{:?}:{}:{}{} {}\n " ,
73
- f,
74
- loline + 1 ,
75
- locol + 1 ,
76
- if loline != hiline || locol != hicol {
77
- format!( "-{}:{}" , hiline + 1 , hicol + 1 )
78
- } else {
79
- "" . to_owned( )
80
- } ,
81
- error. desc) ) ;
60
+ fn update_styles ( & mut self , dg : & mut DepGraph < ' c , ' o > ) {
61
+ propagate_kind ! ( self , DepKind :: Dev ) ;
62
+ propagate_kind ! ( self , DepKind :: Optional ) ;
63
+ propagate_kind ! ( self , DepKind :: Build ) ;
64
+ for ( name, kind) in & self . styles {
65
+ if ( * kind == DepKind :: Dev && !self . cfg . dev_deps ) ||
66
+ ( * kind == DepKind :: Optional && !self . cfg . optional_deps ) ||
67
+ ( * kind == DepKind :: Build && !self . cfg . build_deps ) {
68
+ dg. remove ( & * name) ;
69
+ } else {
70
+ dg. update_style ( & * name, * kind) ;
71
+ }
82
72
}
83
- Err ( From :: from ( CliErrorKind :: Generic ( error_str ) ) )
73
+ dg . remove_orphans ( ) ;
84
74
}
85
75
86
- pub fn graph ( mut self ) -> CliResult < DepGraph < ' c , ' o > > {
87
- let dg = try!( self . parse_root_deps ( ) ) ;
88
-
89
- self . parse_lock_file ( dg)
90
- }
91
-
92
- fn parse_lock_file ( & self , mut dg : DepGraph < ' c , ' o > ) -> CliResult < DepGraph < ' c , ' o > > {
93
- let lock_path = try!( self . find_project_file ( self . cfg . lock_file ) ) ;
94
- let lock_toml = try!( Project :: toml_from_file ( lock_path) ) ;
76
+ fn parse_lock_file ( & mut self , dg : & mut DepGraph < ' c , ' o > ) -> CliResult < ( ) > {
77
+ let lock_path = try!( util:: find_manifest_file ( self . cfg . lock_file ) ) ;
78
+ let lock_toml = try!( util:: toml_from_file ( lock_path) ) ;
95
79
96
80
if let Some ( & Value :: Array ( ref packages) ) = lock_toml. get ( "package" ) {
97
81
for pkg in packages {
82
+ let mut children = vec ! [ ] ;
98
83
let name = pkg. lookup ( "name" )
99
84
. expect ( "no 'name' field in Cargo.lock [package] table" )
100
85
. as_str ( )
101
86
. expect ( "'name' field of [package] table in Cargo.lock was not a \
102
- valid string") ;
103
- let id = dg. find_or_add ( name, DepKind :: Build ) ;
87
+ valid string") . to_owned ( ) ;
88
+ let kind = match self . styles . get ( & name) {
89
+ Some ( k) => k. clone ( ) ,
90
+ None => DepKind :: Build
91
+ } ;
92
+ let id = dg. find_or_add ( & * name, kind) ;
104
93
105
94
if let Some ( & Value :: Array ( ref deps) ) = pkg. lookup ( "dependencies" ) {
106
95
for dep in deps {
107
96
let dep_string =
108
97
dep. as_str ( ) . unwrap_or ( "" ) . split ( " " ) . collect :: < Vec < _ > > ( ) [ 0 ] ;
109
98
110
- dg. add_child ( id, dep_string, None ) ;
99
+ children. push ( dep_string. to_owned ( ) ) ;
100
+ self . styles . insert ( dep_string. to_owned ( ) , kind) ;
101
+ dg. add_child ( id, dep_string, Some ( kind) ) ;
111
102
}
103
+ self . dep_tree . insert ( name. to_owned ( ) , children) ;
104
+ } else {
105
+ self . dep_tree . insert ( name. to_owned ( ) , vec ! [ ] ) ;
112
106
}
107
+ self . styles . insert ( name. to_owned ( ) , kind) ;
113
108
}
114
109
}
115
110
116
111
debugln ! ( "all lock deps: {:#?}" , dg) ;
117
- Ok ( dg )
112
+ Ok ( ( ) )
118
113
}
119
114
120
115
pub fn parse_root_deps ( & mut self ) -> CliResult < DepGraph < ' c , ' o > > {
121
116
debugln ! ( "executing; parse_root_deps;" ) ;
122
- let manifest_path = try!( self . find_project_file ( self . cfg . manifest_file ) ) ;
123
- let manifest_toml = try!( Project :: toml_from_file ( manifest_path) ) ;
117
+ let manifest_path = try!( util :: find_manifest_file ( self . cfg . manifest_file ) ) ;
118
+ let manifest_toml = try!( util :: toml_from_file ( manifest_path) ) ;
124
119
let root_table = match manifest_toml. get ( "package" ) {
125
120
Some ( table) => table,
126
121
None => return Err ( From :: from ( CliErrorKind :: TomlTableRoot ) ) ,
@@ -140,30 +135,34 @@ impl<'c, 'o> Project<'c, 'o> {
140
135
141
136
if let Some ( table) = manifest_toml. get ( "dependencies" ) {
142
137
if let Some ( table) = table. as_table ( ) {
143
- for ( name, dep_table) in table. iter ( ) {
138
+ for ( name, dep_table) in table. into_iter ( ) {
144
139
if let Some ( & Value :: Boolean ( opt) ) = dep_table. lookup ( "optional" ) {
145
- if self . cfg . optional_deps && opt {
146
- dg. add_child ( root_id, name, Some ( DepKind :: Optional ) ) ;
140
+ self . styles . insert ( name. clone ( ) , DepKind :: Optional ) ;
141
+ dg. add_child ( root_id, name, Some ( DepKind :: Optional ) ) ;
142
+ if !self . cfg . optional_deps && opt {
143
+ self . blacklist . push ( name. clone ( ) ) ;
147
144
}
148
145
} else {
146
+ self . styles . insert ( name. clone ( ) , DepKind :: Build ) ;
149
147
dg. add_child ( root_id, name, None ) ;
150
148
}
151
149
}
152
150
}
153
151
}
154
152
155
- if self . cfg . dev_deps {
156
- if let Some ( table) = manifest_toml. get ( "dev-dependencies" ) {
157
- if let Some ( table) = table. as_table ( ) {
158
- for ( name, _) in table. iter ( ) {
159
- dg. add_child ( root_id, name, Some ( DepKind :: Dev ) ) ;
153
+ if let Some ( table) = manifest_toml. get ( "dev-dependencies" ) {
154
+ if let Some ( table) = table. as_table ( ) {
155
+ for ( name, _) in table. into_iter ( ) {
156
+ self . styles . insert ( name. clone ( ) , DepKind :: Dev ) ;
157
+ dg. add_child ( root_id, name, Some ( DepKind :: Dev ) ) ;
158
+ if !self . cfg . dev_deps {
159
+ self . blacklist . push ( name. clone ( ) ) ;
160
160
}
161
161
}
162
162
}
163
163
}
164
164
165
165
debugln ! ( "root deps: {:#?}" , dg) ;
166
-
167
166
Ok ( dg)
168
167
}
169
168
}
0 commit comments