@@ -68,13 +68,18 @@ pub struct BuildQueue {
68
68
queued : Arc < Mutex < ( Build , Build ) > > ,
69
69
}
70
70
71
+ /// Used when tracking modified files across different builds.
72
+ type FileVersion = u64 ;
73
+
71
74
// Information needed to run and configure builds.
72
75
struct Internals {
73
76
// Arguments and environment with which we call rustc.
74
77
// This can be further expanded for multi-crate target configuration.
75
78
// This lock should only be held transiently.
76
79
compilation_cx : Arc < Mutex < CompilationContext > > ,
77
80
env_lock : Arc < EnvironmentLock > ,
81
+ /// Set of files that were modified since last build.
82
+ dirty_files : Arc < Mutex < HashMap < PathBuf , FileVersion > > > ,
78
83
vfs : Arc < Vfs > ,
79
84
// This lock should only be held transiently.
80
85
config : Arc < Mutex < Config > > ,
@@ -146,7 +151,8 @@ enum Build {
146
151
struct PendingBuild {
147
152
build_dir : PathBuf ,
148
153
priority : BuildPriority ,
149
- // Closure to execture once the build is complete.
154
+ built_files : HashMap < PathBuf , FileVersion > ,
155
+ // Closure to execute once the build is complete.
150
156
and_then : Box < FnBox ( BuildResult ) + Send + ' static > ,
151
157
}
152
158
@@ -228,6 +234,7 @@ impl BuildQueue {
228
234
229
235
let build = PendingBuild {
230
236
build_dir : new_build_dir. to_owned ( ) ,
237
+ built_files : self . internals . dirty_files . lock ( ) . unwrap ( ) . clone ( ) ,
231
238
priority,
232
239
and_then : Box :: new ( and_then) ,
233
240
} ;
@@ -324,7 +331,8 @@ impl BuildQueue {
324
331
}
325
332
326
333
// Run the build.
327
- let result = internals. run_build ( & build. build_dir , build. priority ) ;
334
+ let result = internals. run_build ( & build. build_dir , build. priority ,
335
+ & build. built_files ) ;
328
336
// Assert that the build was not squashed.
329
337
if let BuildResult :: Squashed = result {
330
338
unreachable ! ( ) ;
@@ -340,6 +348,14 @@ impl BuildQueue {
340
348
}
341
349
}
342
350
}
351
+
352
+ /// Marks a given versioned file as dirty since last build. The dirty flag
353
+ /// will be cleared by a successful build that builds this or a more recent
354
+ /// version of this file.
355
+ pub fn mark_file_dirty ( & self , file : PathBuf , version : FileVersion ) {
356
+ trace ! ( "Marking file as dirty: {:?} ({})" , file, version) ;
357
+ self . internals . dirty_files . lock ( ) . unwrap ( ) . insert ( file, version) ;
358
+ }
343
359
}
344
360
345
361
impl Internals {
@@ -348,6 +364,7 @@ impl Internals {
348
364
compilation_cx : Arc :: new ( Mutex :: new ( CompilationContext :: new ( ) ) ) ,
349
365
vfs,
350
366
config,
367
+ dirty_files : Arc :: new ( Mutex :: new ( HashMap :: new ( ) ) ) ,
351
368
// Since environment is global mutable state and we can run multiple server
352
369
// instances, be sure to use a global lock to ensure env var consistency
353
370
env_lock : EnvironmentLock :: get ( ) ,
@@ -356,7 +373,12 @@ impl Internals {
356
373
}
357
374
358
375
// Entry point method for building.
359
- fn run_build ( & self , new_build_dir : & Path , priority : BuildPriority ) -> BuildResult {
376
+ fn run_build (
377
+ & self ,
378
+ new_build_dir : & Path ,
379
+ priority : BuildPriority ,
380
+ built_files : & HashMap < PathBuf , FileVersion > ,
381
+ ) -> BuildResult {
360
382
trace ! ( "run_build, {:?} {:?}" , new_build_dir, priority) ;
361
383
362
384
// Check if the build directory changed and update it.
@@ -375,7 +397,23 @@ impl Internals {
375
397
}
376
398
}
377
399
378
- self . build ( )
400
+ let result = self . build ( ) ;
401
+ // On a successful build, clear dirty files that were successfuly built
402
+ // now. It's possible that a build was scheduled with given files, but
403
+ // user later changed them. These should still be left as dirty (not built).
404
+ match * & result {
405
+ BuildResult :: Success ( _, _) | BuildResult :: Failure ( _, _) => {
406
+ let mut dirty_files = self . dirty_files . lock ( ) . unwrap ( ) ;
407
+ dirty_files. retain ( |file, dirty_version| {
408
+ built_files. get ( file)
409
+ . map ( |built_version| built_version < dirty_version)
410
+ . unwrap_or ( false )
411
+ } ) ;
412
+ trace ! ( "Files still dirty after the build: {:?}" , * dirty_files) ;
413
+ } ,
414
+ _ => { }
415
+ } ;
416
+ result
379
417
}
380
418
381
419
// Build the project.
@@ -405,9 +443,9 @@ impl Internals {
405
443
// If the build plan has already been cached, use it, unless Cargo
406
444
// has to be specifically rerun (e.g. when build scripts changed)
407
445
let work = {
446
+ let modified: Vec < _ > = self . dirty_files . lock ( ) . unwrap ( )
447
+ . keys ( ) . cloned ( ) . collect ( ) ;
408
448
let cx = self . compilation_cx . lock ( ) . unwrap ( ) ;
409
- let modified: Vec < _ > = self . vfs . get_changes ( ) . keys ( ) . cloned ( ) . collect ( ) ;
410
-
411
449
cx. build_plan . prepare_work ( & modified)
412
450
} ;
413
451
return match work {
0 commit comments