@@ -236,31 +236,73 @@ void onDocAdded(const std::string& id)
236
236
if (docPath.extensionLowerCase () != " .rmd" )
237
237
return ;
238
238
239
- FilePath cachePath = chunkCacheFolder (path, id);
239
+ // find the cache (test for saved)
240
+ FilePath cachePath = chunkCacheFolder (path, id, notebookCtxId ());
241
+ if (!cachePath.exists ())
242
+ cachePath = chunkCacheFolder (path, id, kSavedCtx );
243
+
240
244
FilePath notebookPath = docPath.parent ().complete (docPath.stem () +
241
245
kNotebookExt );
242
246
243
- // clean up incompatible cache versions (as we're about to invalidate them
244
- // by mutating the document without updating them)
245
- if (cachePath.exists ())
246
- {
247
- std::vector<FilePath> versions;
248
- cachePath.children (&versions);
249
- BOOST_FOREACH (const FilePath& version, versions)
250
- {
251
- if (version.isDirectory () && version.filename () != kCacheVersion )
252
- {
253
- error = version.remove ();
254
- if (error)
255
- LOG_ERROR (error);
256
- }
257
- }
258
- }
259
-
260
247
// if the cache doesn't exist but we have a notebook file, hydrate from that
261
248
// file
262
249
if (!cachePath.exists () && notebookPath.exists ())
263
250
{
251
+ error = r::exec::RFunction (" .rs.hydrateCacheFromNotebook" ,
252
+ notebookPath.absolutePath ()).call ();
253
+ if (error)
254
+ LOG_ERROR (error);
255
+ return ;
256
+ }
257
+
258
+ // if both the local cache and the notebook cache exist, we need to decide
259
+ // which to load
260
+ if (cachePath.exists () && notebookPath.exists ())
261
+ {
262
+ // get the dates first--in no case will we use the notebook over the
263
+ // local cache if the local cache is newer (this will be the case most
264
+ // of the time). we want to check this first because it's cheap; further
265
+ // tests will require us to test the caches for compatibility, which is
266
+ // more expensive.
267
+
268
+ // find the chunk definition file
269
+ FilePath chunkDefs = cachePath.complete (kNotebookChunkDefFilename );
270
+ if (!chunkDefs.exists ())
271
+ return ;
272
+
273
+ std::time_t localCacheTime = chunkDefs.lastWriteTime ();
274
+ std::time_t nbCacheTime = notebookPath.lastWriteTime ();
275
+
276
+ if (localCacheTime >= nbCacheTime)
277
+ return ;
278
+
279
+ // if we got this far, it means that the notebook cache looks newer than
280
+ // our cache -- test to see whether it's compatible
281
+ bool matches = false ;
282
+ error = r::exec::RFunction (" .rs.testNotebookRmdMatches" ,
283
+ docPath.absolutePath (), notebookPath.absolutePath ()).call (&matches);
284
+ if (error)
285
+ {
286
+ LOG_ERROR (error);
287
+ return ;
288
+ }
289
+
290
+ if (!matches)
291
+ {
292
+ // the notebook cache looks newer but it isn't aligned with the .Rmd,
293
+ // so we can't use it
294
+ return ;
295
+ }
296
+
297
+ // if we got this far, we have matching newer notebook cache. blow away
298
+ // our stale local cache and rehydrate from the notebook cache.
299
+ error = cachePath.remove ();
300
+ if (error)
301
+ {
302
+ LOG_ERROR (error);
303
+ return ;
304
+ }
305
+
264
306
error = r::exec::RFunction (" .rs.hydrateCacheFromNotebook" ,
265
307
notebookPath.absolutePath ()).call ();
266
308
if (error)
0 commit comments