diff --git a/src/com/google/javascript/jscomp/PersistentInputStore.java b/src/com/google/javascript/jscomp/PersistentInputStore.java index 6e775da5918..229177c724c 100644 --- a/src/com/google/javascript/jscomp/PersistentInputStore.java +++ b/src/com/google/javascript/jscomp/PersistentInputStore.java @@ -15,6 +15,8 @@ */ package com.google.javascript.jscomp; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; import java.util.HashMap; import java.util.Map; @@ -44,6 +46,29 @@ private static class CacheEntry { CacheEntry(String digest) { this.digest = digest; } + + private Map zipEntries = ImmutableMap.of(); + + CompilerInput getCachedZipEntry(SourceFile zipEntry) { + String originalPath = zipEntry.getOriginalPath(); + // Avoid allocating a HashMap instance for arbitrary CompilerInputs. + if (zipEntries.isEmpty()) { + zipEntries = new HashMap<>(); + } + if (!zipEntries.containsKey(originalPath)) { + zipEntries.put(originalPath, CompilerInput.makePersistentInput(zipEntry)); + } + return zipEntries.get(originalPath); + } + + void updateDigest(String newDigest) { + if (!newDigest.equals(digest)) { + this.input = null; + this.digest = newDigest; + + zipEntries = ImmutableMap.of(); + } + } } /** @@ -53,11 +78,7 @@ private static class CacheEntry { public void addInput(String path, String digest) { if (store.containsKey(path)) { CacheEntry dep = store.get(path); - if (!dep.digest.equals(digest)) { - // Invalidate cache since digest has changed. - dep.digest = digest; - dep.input = null; - } + dep.updateDigest(digest); } else { store.put(path, new CacheEntry(digest)); } @@ -70,8 +91,17 @@ public void addInput(String path, String digest) { *

If a matching blaze input cannot be found, just create a new compiler input for scratch. */ public CompilerInput getCachedCompilerInput(SourceFile source) { - if (store.containsKey(source.getOriginalPath())) { - CacheEntry cacheEntry = store.get(source.getOriginalPath()); + String originalPath = source.getOriginalPath(); + // For zip files. + if (originalPath.contains(".js.zip!/")) { + int indexOf = originalPath.indexOf(".js.zip!/"); + String zipPath = originalPath.substring(0, indexOf + ".js.zip".length()); + Preconditions.checkState(store.containsKey(zipPath)); + return store.get(zipPath).getCachedZipEntry(source); + } + // For regular files. + if (store.containsKey(originalPath)) { + CacheEntry cacheEntry = store.get(originalPath); if (cacheEntry.input == null) { cacheEntry.input = CompilerInput.makePersistentInput(source); } diff --git a/test/com/google/javascript/jscomp/PersistentInputStoreTest.java b/test/com/google/javascript/jscomp/PersistentInputStoreTest.java index 7ee4364dd58..a93ee6ac0f5 100644 --- a/test/com/google/javascript/jscomp/PersistentInputStoreTest.java +++ b/test/com/google/javascript/jscomp/PersistentInputStoreTest.java @@ -52,4 +52,33 @@ public void testPopulateDependencyInfoDigestChanged() { // Stored CompilerInput was revoked from cache. assertThat(testStore.getCachedCompilerInput(file)).isNotSameAs(input); } + + public void testCacheZipFiles() { + PersistentInputStore store = new PersistentInputStore(); + store.addInput("path/to/a/zipfile.js.zip", "aaa"); + + SourceFile zipEntryA = SourceFile.fromFile("path/to/a/zipfile.js.zip!/relative/a.js"); + SourceFile zipEntryB = SourceFile.fromFile("path/to/a/zipfile.js.zip!/relative/b.js"); + + CompilerInput inputA = store.getCachedCompilerInput(zipEntryA); + CompilerInput inputB = store.getCachedCompilerInput(zipEntryB); + + // Returns same compiler input. Reused from last compile. + assertThat(inputA).isSameAs(store.getCachedCompilerInput(zipEntryA)); + assertThat(inputB).isSameAs(store.getCachedCompilerInput(zipEntryB)); + + // New compile. Digest did not change. + store.addInput("path/to/a/zipfile.js.zip", "aaa"); + + // Returns same compiler input. Reused from last compile. + assertThat(inputA).isSameAs(store.getCachedCompilerInput(zipEntryA)); + assertThat(inputB).isSameAs(store.getCachedCompilerInput(zipEntryB)); + + // New Compile. Digest CHANGES! + store.addInput("path/to/a/zipfile.js.zip", "bbb"); + + // All inputs from the zip are recomputed. + assertThat(inputA).isNotSameAs(store.getCachedCompilerInput(zipEntryA)); + assertThat(inputB).isNotSameAs(store.getCachedCompilerInput(zipEntryB)); + } }