Skip to content

Commit 51fc677

Browse files
committed
assets live compiler: process modified file (not entire set of files) fix #549
1 parent 6132a0f commit 51fc677

4 files changed

Lines changed: 61 additions & 34 deletions

File tree

jooby-assets-j2v8/src/main/java/org/jooby/assets/V8Context.java

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
import java.util.Collections;
2828
import java.util.List;
2929
import java.util.Map;
30+
import java.util.Optional;
3031
import java.util.function.Consumer;
32+
import java.util.function.Function;
3133

3234
import org.slf4j.Logger;
3335
import org.slf4j.LoggerFactory;
@@ -45,6 +47,8 @@
4547
import com.google.common.io.BaseEncoding;
4648
import com.google.common.io.ByteStreams;
4749

50+
import javaslang.control.Try;
51+
4852
public class V8Context {
4953

5054
public interface Callback {
@@ -129,24 +133,19 @@ private List<AssetProblem> problems(final V8Array array) {
129133
return result.build();
130134
}
131135

136+
private <T> Optional<T> get(final String name, final Function<String, T> provider) {
137+
return Try.of(() -> Optional.of(register(provider.apply(name)))).getOrElse(Optional.empty());
138+
}
139+
132140
private AssetProblem problem(final V8Object js) {
133-
int line = -1;
134-
if (js.contains("line")) {
135-
line = ((Number) js.get("line")).intValue();
136-
}
137-
int column = -1;
138-
if (js.contains("column")) {
139-
column = ((Number) js.get("column")).intValue();
140-
}
141-
String filename = "file.js";
142-
if (js.contains("filename")) {
143-
filename = js.getString("filename");
144-
}
145-
String evidence = null;
146-
if (js.contains("evidence")) {
147-
evidence = js.getString("evidence");
148-
}
149-
return new AssetProblem(filename, line, column, js.getString("message"), evidence);
141+
Optional<Integer> line = get("line", name -> ((Number) js.get(name)).intValue());
142+
Optional<Integer> column = get("column", name -> ((Number) js.get(name)).intValue());
143+
Optional<String> filename = get("filename", js::getString);
144+
Optional<String> evidence = get("evidence", js::getString);
145+
Optional<String> message = get("message", js::getString);
146+
147+
return new AssetProblem(filename.orElse("file.js"), line.orElse(-1), column.orElse(-1),
148+
message.orElse(""), evidence.orElse(null));
150149
}
151150

152151
private URL resolve(final String path) {

jooby-assets/src/main/java/org/jooby/assets/AssetCompiler.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,6 @@ private String compile(final List<AssetProcessor> pipeline, final Iterator<Strin
397397
StringBuilder buff = new StringBuilder();
398398
while (files.hasNext()) {
399399
String file = files.next();
400-
log.info(" {}", file);
401400
buff.append(compile(pipeline, file, type, readFile(loader, file, charset))).append(sep);
402401
}
403402
return buff.toString();
@@ -406,6 +405,7 @@ private String compile(final List<AssetProcessor> pipeline, final Iterator<Strin
406405
private String compile(final List<AssetProcessor> pipeline, final String filename,
407406
final MediaType type, final String input) throws Exception {
408407

408+
log.info(" {}", filename);
409409
Iterator<AssetProcessor> it = pipeline.iterator();
410410
String contents = input;
411411
while (it.hasNext()) {
@@ -414,11 +414,11 @@ private String compile(final List<AssetProcessor> pipeline, final String filenam
414414
String pname = processor.name();
415415
long start = System.currentTimeMillis();
416416
try {
417-
log.debug("executing: {}", pname);
417+
log.debug(" executing: {}", pname);
418418
contents = processor.process(filename, contents, conf);
419419
} finally {
420420
long end = System.currentTimeMillis();
421-
log.debug("{} took {}ms", pname, end - start);
421+
log.debug(" {} took {}ms", pname, end - start);
422422
}
423423
}
424424
}

jooby-assets/src/main/java/org/jooby/internal/assets/LiveCompiler.java

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,60 +22,86 @@
2222

2323
import java.io.File;
2424
import java.io.IOException;
25+
import java.nio.file.Files;
2526
import java.nio.file.Path;
2627
import java.nio.file.Paths;
28+
import java.nio.file.StandardWatchEventKinds;
2729
import java.nio.file.WatchEvent.Kind;
2830
import java.util.List;
31+
import java.util.Map;
32+
import java.util.concurrent.ConcurrentHashMap;
2933
import java.util.concurrent.atomic.AtomicBoolean;
30-
import java.util.concurrent.atomic.AtomicReference;
3134

35+
import org.jooby.MediaType;
3236
import org.jooby.Request;
3337
import org.jooby.Response;
3438
import org.jooby.Route;
3539
import org.jooby.assets.AssetCompiler;
3640
import org.jooby.assets.AssetException;
3741
import org.jooby.assets.AssetProblem;
42+
import org.jooby.internal.URLAsset;
3843

3944
import com.google.common.collect.Lists;
4045
import com.typesafe.config.Config;
4146

47+
import javaslang.control.Try;
48+
4249
public class LiveCompiler implements Route.Handler {
4350

4451
private final Config conf;
4552

4653
private final AssetCompiler compiler;
4754

48-
private final AtomicReference<AssetException> lastErr = new AtomicReference<AssetException>(null);
55+
private final Map<String, AssetException> errors = new ConcurrentHashMap<>();
4956

5057
private final Watcher watcher;
5158

5259
private final AtomicBoolean firstRun = new AtomicBoolean(true);
5360

61+
private Path basedir;
62+
5463
public LiveCompiler(final Config conf, final AssetCompiler compiler) throws IOException {
5564
this.conf = requireNonNull(conf, "Config is required.");
5665
this.compiler = requireNonNull(compiler, "Asset compiler is required.");
57-
this.watcher = new Watcher(this::onChange, Paths.get("public"));
66+
this.basedir = Paths.get("public");
67+
this.watcher = new Watcher(this::onChange, basedir);
68+
5869
}
5970

6071
private void onChange(final Kind<?> kind, final Path path) {
6172
File outputdir = new File(conf.getString("application.tmpdir"), "__public_");
6273
outputdir.mkdirs();
74+
String filename = Route.normalize(Try.of(() -> path.subpath(1, path.getNameCount()).toString())
75+
.getOrElse(path.toString()));
6376
try {
6477
boolean firstRun = this.firstRun.compareAndSet(true, false);
65-
if (!firstRun) {
78+
if (!firstRun && !path.equals(basedir)) {
6679
if (!compiler.contains(path.toString())) {
6780
return;
6881
}
6982
}
70-
compiler.build(conf.getString("application.env"), outputdir);
71-
lastErr.set(null);
83+
if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
84+
errors.remove(filename);
85+
} else {
86+
if (Files.isDirectory(path)) {
87+
errors.clear();
88+
compiler.build(conf.getString("application.env"), outputdir);
89+
} else {
90+
MediaType type = MediaType.byPath(path).orElse(MediaType.octetstream);
91+
compiler.build(new URLAsset(path.toUri().toURL(), filename, type));
92+
errors.remove(filename);
93+
}
94+
}
7295
} catch (AssetException ex) {
73-
lastErr.set(rewrite(ex));
96+
String localname = ex.getProblems().stream()
97+
.findFirst()
98+
.map(AssetProblem::getFilename)
99+
.orElse(filename);
100+
errors.put(localname, rewrite(ex));
74101
} catch (Exception ex) {
75-
ex.printStackTrace();
76102
AssetException assetEx = rewrite(new AssetException("compiler",
77-
new AssetProblem(path.toString(), -1, -1, ex.getMessage(), null), ex));
78-
lastErr.set(assetEx);
103+
new AssetProblem(filename, -1, -1, ex.getMessage(), null), ex));
104+
errors.put(filename, assetEx);
79105
}
80106
}
81107

@@ -97,9 +123,11 @@ private AssetException rewrite(final AssetException ex) {
97123

98124
@Override
99125
public void handle(final Request req, final Response rsp) throws Throwable {
100-
AssetException ex = lastErr.get();
101-
if (ex != null) {
102-
throw ex;
126+
if (req.param("assets.sync").isSet()) {
127+
onChange(StandardWatchEventKinds.ENTRY_MODIFY, basedir);
128+
}
129+
if (errors.size() > 0) {
130+
throw errors.values().iterator().next();
103131
}
104132
}
105133

jooby-assets/src/main/java/org/jooby/internal/assets/Watcher.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ private boolean processEvents() {
145145
Path child = dir.resolve(name);
146146
File file = child.toFile();
147147

148-
if (file.isFile()) {
148+
if (file.isFile() || kind == ENTRY_DELETE) {
149149
listener.accept(kind, dir.resolve(name));
150150
}
151151

0 commit comments

Comments
 (0)