@@ -131,28 +131,44 @@ struct Context {
131131/// Builds the list of all packages required to build the first argument.
132132pub fn resolve ( summary : & Summary , method : Method ,
133133 registry : & mut Registry ) -> CargoResult < Resolve > {
134- log ! ( 5 , "resolve; summary={:?}" , summary) ;
134+ log ! ( 5 , "resolve; summary={}" , summary. get_package_id( ) ) ;
135+ let summary = Rc :: new ( summary. clone ( ) ) ;
135136
136- let mut cx = Box :: new ( Context {
137+ let cx = Box :: new ( Context {
137138 resolve : Resolve :: new ( summary. get_package_id ( ) . clone ( ) ) ,
138139 activations : HashMap :: new ( ) ,
139140 visited : Rc :: new ( RefCell :: new ( HashSet :: new ( ) ) ) ,
140141 } ) ;
141142 let _p = profile:: start ( format ! ( "resolving: {:?}" , summary) ) ;
142- cx . activations . insert ( ( summary. get_name ( ) . to_string ( ) ,
143- summary . get_source_id ( ) . clone ( ) ) ,
144- vec ! [ Rc :: new ( summary . clone ( ) ) ] ) ;
145- match try! ( activate ( cx , registry , summary , method ) ) {
146- Ok ( cx ) => Ok ( cx . resolve ) ,
143+ match try! ( activate ( cx , registry , & summary, method ) ) {
144+ Ok ( cx ) => {
145+ debug ! ( "resolved: {:?}" , cx . resolve ) ;
146+ Ok ( cx . resolve )
147+ }
147148 Err ( e) => Err ( e) ,
148149 }
149150}
150151
151152fn activate ( mut cx : Box < Context > ,
152153 registry : & mut Registry ,
153- parent : & Summary ,
154+ parent : & Rc < Summary > ,
154155 method : Method )
155156 -> CargoResult < CargoResult < Box < Context > > > {
157+ // Dependency graphs are required to be a DAG, so we keep a set of
158+ // packages we're visiting and bail if we hit a dupe.
159+ let id = parent. get_package_id ( ) ;
160+ if !cx. visited . borrow_mut ( ) . insert ( id. clone ( ) ) {
161+ return Err ( human ( format ! ( "cyclic package dependency: package `{}` \
162+ depends on itself", id) ) )
163+ }
164+
165+ // If we're already activated, then that was easy!
166+ if flag_activated ( & mut * cx, parent, & method) {
167+ cx. visited . borrow_mut ( ) . remove ( id) ;
168+ return Ok ( Ok ( cx) )
169+ }
170+ debug ! ( "activating {}" , parent. get_package_id( ) ) ;
171+
156172 // Extracting the platform request.
157173 let platform = match method {
158174 Method :: Required ( _, _, _, platform) => platform,
@@ -162,7 +178,7 @@ fn activate(mut cx: Box<Context>,
162178 // First, figure out our set of dependencies based on the requsted set of
163179 // features. This also calculates what features we're going to enable for
164180 // our own dependencies.
165- let deps = try!( resolve_features ( & mut * cx, parent, method) ) ;
181+ let deps = try!( resolve_features ( & mut * cx, & * * parent, method) ) ;
166182
167183 // Next, transform all dependencies into a list of possible candidates which
168184 // can satisfy that dependency.
@@ -185,7 +201,40 @@ fn activate(mut cx: Box<Context>,
185201 a. len ( ) . cmp ( & b. len ( ) )
186202 } ) ;
187203
188- activate_deps ( cx, registry, parent, platform, deps. as_slice ( ) , 0 )
204+ Ok ( match try!( activate_deps ( cx, registry, & * * parent, platform, & * deps, 0 ) ) {
205+ Ok ( cx) => {
206+ cx. visited . borrow_mut ( ) . remove ( parent. get_package_id ( ) ) ;
207+ Ok ( cx)
208+ }
209+ Err ( e) => Err ( e) ,
210+ } )
211+ }
212+
213+ // Activate this summary by inserting it into our list of known activations.
214+ //
215+ // Returns if this summary with the given method is already activated.
216+ fn flag_activated ( cx : & mut Context ,
217+ summary : & Rc < Summary > ,
218+ method : & Method ) -> bool {
219+ let id = summary. get_package_id ( ) ;
220+ let key = ( id. get_name ( ) . to_string ( ) , id. get_source_id ( ) . clone ( ) ) ;
221+ let prev = cx. activations . entry ( key) . get ( ) . unwrap_or_else ( |e| {
222+ e. insert ( Vec :: new ( ) )
223+ } ) ;
224+ if !prev. iter ( ) . any ( |c| c == summary) {
225+ cx. resolve . graph . add ( id. clone ( ) , & [ ] ) ;
226+ prev. push ( summary. clone ( ) ) ;
227+ return false
228+ }
229+ debug ! ( "checking if {} is already activated" , summary. get_package_id( ) ) ;
230+ let features = match * method {
231+ Method :: Required ( _, features, _, _) => features,
232+ Method :: Everything => return false ,
233+ } ;
234+ match cx. resolve . features ( id) {
235+ Some ( prev) => features. iter ( ) . all ( |f| prev. contains ( f) ) ,
236+ None => features. len ( ) == 0 ,
237+ }
189238}
190239
191240fn activate_deps < ' a > ( cx : Box < Context > ,
@@ -237,50 +286,20 @@ fn activate_deps<'a>(cx: Box<Context>,
237286 log ! ( 5 , "{}[{}]>{} trying {}" , parent. get_name( ) , cur, dep. get_name( ) ,
238287 candidate. get_version( ) ) ;
239288 let mut my_cx = cx. clone ( ) ;
240- let early_return = {
241- let my_cx = & mut * my_cx;
242- my_cx. resolve . graph . link ( parent. get_package_id ( ) . clone ( ) ,
243- candidate. get_package_id ( ) . clone ( ) ) ;
244- let prev = match my_cx. activations . entry ( key. clone ( ) ) {
245- Occupied ( e) => e. into_mut ( ) ,
246- Vacant ( e) => e. insert ( Vec :: new ( ) ) ,
247- } ;
248- if prev. iter ( ) . any ( |c| c == candidate) {
249- match cx. resolve . features ( candidate. get_package_id ( ) ) {
250- Some ( prev_features) => {
251- features. iter ( ) . all ( |f| prev_features. contains ( f) )
252- }
253- None => features. len ( ) == 0 ,
254- }
255- } else {
256- my_cx. resolve . graph . add ( candidate. get_package_id ( ) . clone ( ) , & [ ] ) ;
257- prev. push ( candidate. clone ( ) ) ;
258- false
259- }
260- } ;
289+ my_cx. resolve . graph . link ( parent. get_package_id ( ) . clone ( ) ,
290+ candidate. get_package_id ( ) . clone ( ) ) ;
261291
262- let my_cx = if early_return {
263- my_cx
264- } else {
265- // Dependency graphs are required to be a DAG. Non-transitive
266- // dependencies (dev-deps), however, can never introduce a cycle, so
267- // we skip them.
268- if dep. is_transitive ( ) &&
269- !cx. visited . borrow_mut ( ) . insert ( candidate. get_package_id ( ) . clone ( ) ) {
270- return Err ( human ( format ! ( "cyclic package dependency: package `{}` \
271- depends on itself",
272- candidate. get_package_id( ) ) ) )
273- }
274- let my_cx = try!( activate ( my_cx, registry, & * * candidate, method) ) ;
275- if dep. is_transitive ( ) {
276- cx. visited . borrow_mut ( ) . remove ( candidate. get_package_id ( ) ) ;
277- }
278- match my_cx {
279- Ok ( cx) => cx,
280- Err ( e) => { last_err = Some ( e) ; continue }
281- }
292+ // If we hit an intransitive dependency then clear out the visitation
293+ // list as we can't induce a cycle through transitive dependencies.
294+ if !dep. is_transitive ( ) {
295+ my_cx. visited . borrow_mut ( ) . clear ( ) ;
296+ }
297+ let my_cx = match try!( activate ( my_cx, registry, candidate, method) ) {
298+ Ok ( cx) => cx,
299+ Err ( e) => { last_err = Some ( e) ; continue }
282300 } ;
283- match try!( activate_deps ( my_cx, registry, parent, platform, deps, cur + 1 ) ) {
301+ match try!( activate_deps ( my_cx, registry, parent, platform, deps,
302+ cur + 1 ) ) {
284303 Ok ( cx) => return Ok ( Ok ( cx) ) ,
285304 Err ( e) => { last_err = Some ( e) ; }
286305 }
0 commit comments