Lines 68-84
Link Here
|
68 |
|
68 |
|
69 |
import javax.swing.event.ChangeEvent; |
69 |
import javax.swing.event.ChangeEvent; |
70 |
import javax.swing.event.ChangeListener; |
70 |
import javax.swing.event.ChangeListener; |
|
|
71 |
import org.netbeans.api.annotations.common.NonNull; |
72 |
import org.netbeans.api.annotations.common.NullAllowed; |
71 |
|
73 |
|
72 |
import org.netbeans.api.java.classpath.ClassPath; |
74 |
import org.netbeans.api.java.classpath.ClassPath; |
73 |
import org.netbeans.api.java.queries.AnnotationProcessingQuery; |
75 |
import org.netbeans.api.java.queries.AnnotationProcessingQuery; |
74 |
import org.netbeans.api.java.queries.BinaryForSourceQuery; |
|
|
75 |
import org.netbeans.api.java.queries.BinaryForSourceQuery.Result; |
76 |
import org.netbeans.api.java.queries.SourceForBinaryQuery; |
76 |
import org.netbeans.api.java.queries.SourceForBinaryQuery; |
77 |
import org.netbeans.api.java.source.BuildArtifactMapper.ArtifactsUpdated; |
77 |
import org.netbeans.api.java.source.BuildArtifactMapper.ArtifactsUpdated; |
78 |
import org.netbeans.api.java.source.SourceUtils; |
78 |
import org.netbeans.api.java.source.SourceUtils; |
79 |
import org.netbeans.api.queries.FileBuiltQuery; |
79 |
import org.netbeans.api.queries.FileBuiltQuery; |
80 |
import org.netbeans.api.queries.FileBuiltQuery.Status; |
80 |
import org.netbeans.api.queries.FileBuiltQuery.Status; |
81 |
import org.netbeans.api.queries.VisibilityQuery; |
81 |
import org.netbeans.api.queries.VisibilityQuery; |
|
|
82 |
import org.netbeans.modules.java.preprocessorbridge.api.CompileOnSaveActionQuery; |
83 |
import org.netbeans.modules.java.preprocessorbridge.spi.CompileOnSaveAction; |
82 |
import org.netbeans.modules.java.source.indexing.COSSynchronizingIndexer; |
84 |
import org.netbeans.modules.java.source.indexing.COSSynchronizingIndexer; |
83 |
import org.netbeans.modules.java.source.indexing.JavaIndex; |
85 |
import org.netbeans.modules.java.source.indexing.JavaIndex; |
84 |
import org.netbeans.modules.java.source.parsing.FileObjects; |
86 |
import org.netbeans.modules.java.source.parsing.FileObjects; |
Lines 90-96
Link Here
|
90 |
import org.netbeans.modules.parsing.spi.indexing.ErrorsCache; |
92 |
import org.netbeans.modules.parsing.spi.indexing.ErrorsCache; |
91 |
import org.netbeans.spi.queries.FileBuiltQueryImplementation; |
93 |
import org.netbeans.spi.queries.FileBuiltQueryImplementation; |
92 |
import org.openide.filesystems.FileObject; |
94 |
import org.openide.filesystems.FileObject; |
93 |
import org.openide.filesystems.FileStateInvalidException; |
|
|
94 |
import org.openide.filesystems.FileUtil; |
95 |
import org.openide.filesystems.FileUtil; |
95 |
import org.openide.util.ChangeSupport; |
96 |
import org.openide.util.ChangeSupport; |
96 |
import org.openide.util.Exceptions; |
97 |
import org.openide.util.Exceptions; |
Lines 98-104
Link Here
|
98 |
import org.openide.util.RequestProcessor; |
99 |
import org.openide.util.RequestProcessor; |
99 |
import org.openide.util.BaseUtilities; |
100 |
import org.openide.util.BaseUtilities; |
100 |
import org.openide.util.Lookup; |
101 |
import org.openide.util.Lookup; |
|
|
102 |
import org.openide.util.WeakListeners; |
101 |
import org.openide.util.WeakSet; |
103 |
import org.openide.util.WeakSet; |
|
|
104 |
import org.openide.util.lookup.ServiceProvider; |
102 |
|
105 |
|
103 |
/** |
106 |
/** |
104 |
* |
107 |
* |
Lines 175-403
Link Here
|
175 |
} |
178 |
} |
176 |
} |
179 |
} |
177 |
|
180 |
|
178 |
private static File getTarget(URL source) { |
|
|
179 |
Result binaryRoots = BinaryForSourceQuery.findBinaryRoots(source); |
180 |
|
181 |
File result = null; |
182 |
|
183 |
for (URL u : binaryRoots.getRoots()) { |
184 |
assert u != null : "Null in BinaryForSourceQuery.Result.roots: " + binaryRoots; //NOI18N |
185 |
if (u == null) { |
186 |
continue; |
187 |
} |
188 |
File f = FileUtil.archiveOrDirForURL(u); |
189 |
|
190 |
try { |
191 |
if (FileUtil.isArchiveFile(BaseUtilities.toURI(f).toURL())) { |
192 |
continue; |
193 |
} |
194 |
|
195 |
if (f != null && result != null) { |
196 |
Logger.getLogger(BuildArtifactMapperImpl.class.getName()).log(Level.WARNING, "More than one binary directory for root: {0}", source.toExternalForm()); |
197 |
return null; |
198 |
} |
199 |
|
200 |
result = f; |
201 |
} catch (MalformedURLException ex) { |
202 |
Exceptions.printStackTrace(ex); |
203 |
} |
204 |
} |
205 |
|
206 |
return result; |
207 |
} |
208 |
|
209 |
@SuppressWarnings("deprecation") |
181 |
@SuppressWarnings("deprecation") |
210 |
public static Boolean ensureBuilt(URL sourceRoot, Object context, boolean copyResources, boolean keepResourceUpToDate) throws IOException { |
182 |
public static Boolean ensureBuilt(URL sourceRoot, Object context, boolean copyResources, boolean keepResourceUpToDate) throws IOException { |
211 |
File targetFolder = getTarget(sourceRoot); |
183 |
final CompileOnSaveAction a = CompileOnSaveActionQuery.getAction(sourceRoot); |
212 |
|
184 |
if (a != null) { |
213 |
if (targetFolder == null) { |
185 |
final CompileOnSaveAction.Context ctx = CompileOnSaveAction.Context.sync( |
214 |
return null; |
186 |
sourceRoot, |
|
|
187 |
copyResources, |
188 |
keepResourceUpToDate, |
189 |
context); |
190 |
return a.performAction(ctx); |
215 |
} |
191 |
} |
216 |
|
192 |
return null; |
217 |
try { |
|
|
218 |
SourceUtils.waitScanFinished(); |
219 |
} catch (InterruptedException e) { |
220 |
//Not Important |
221 |
LOG.log(Level.FINE, null, e); |
222 |
return null; |
223 |
} |
224 |
|
225 |
if (JavaIndex.ensureAttributeValue(sourceRoot, DIRTY_ROOT, null)) { |
226 |
IndexingManager.getDefault().refreshIndexAndWait(sourceRoot, null); |
227 |
} |
228 |
|
229 |
if (JavaIndex.getAttribute(sourceRoot, DIRTY_ROOT, null) != null) { |
230 |
return false; |
231 |
} |
232 |
|
233 |
FileObject[][] sources = new FileObject[1][]; |
234 |
|
235 |
if (!protectAgainstErrors(targetFolder, sources, context)) { |
236 |
return false; |
237 |
} |
238 |
|
239 |
File tagFile = new File(targetFolder, TAG_FILE_NAME); |
240 |
File tagUpdateResourcesFile = new File(targetFolder, TAG_UPDATE_RESOURCES); |
241 |
final boolean forceResourceCopy = copyResources && keepResourceUpToDate && !tagUpdateResourcesFile.exists(); |
242 |
final boolean cosActive = tagFile.exists(); |
243 |
if (cosActive && !forceResourceCopy) { |
244 |
return true; |
245 |
} |
246 |
|
247 |
if (!cosActive) { |
248 |
delete(targetFolder, false/*#161085: cleanCompletely*/); |
249 |
} |
250 |
|
251 |
if (!targetFolder.exists() && !targetFolder.mkdirs()) { |
252 |
throw new IOException("Cannot create destination folder: " + targetFolder.getAbsolutePath()); |
253 |
} |
254 |
|
255 |
sources(targetFolder, sources); |
256 |
|
257 |
for (int i = sources[0].length - 1; i>=0; i--) { |
258 |
final FileObject sr = sources[0][i]; |
259 |
if (!cosActive) { |
260 |
URL srURL = sr.toURL(); |
261 |
File index = JavaIndex.getClassFolder(srURL, true); |
262 |
|
263 |
if (index == null) { |
264 |
//#181992: (not nice) ignore the annotation processing target directory: |
265 |
if (srURL.equals(AnnotationProcessingQuery.getAnnotationProcessingOptions(sr).sourceOutputDirectory())) { |
266 |
continue; |
267 |
} |
268 |
|
269 |
return null; |
270 |
} |
271 |
|
272 |
copyRecursively(index, targetFolder); |
273 |
} |
274 |
|
275 |
if (copyResources) { |
276 |
Set<String> javaMimeTypes = COSSynchronizingIndexer.gatherJavaMimeTypes(); |
277 |
String[] javaMimeTypesArr = javaMimeTypes.toArray(new String[0]); |
278 |
|
279 |
copyRecursively(sr, targetFolder, javaMimeTypes, javaMimeTypesArr); |
280 |
} |
281 |
} |
282 |
|
283 |
if (!cosActive) { |
284 |
new FileOutputStream(tagFile).close(); |
285 |
} |
286 |
|
287 |
if (keepResourceUpToDate) |
288 |
new FileOutputStream(tagUpdateResourcesFile).close(); |
289 |
|
290 |
return true; |
291 |
} |
193 |
} |
292 |
|
194 |
|
293 |
@SuppressWarnings("deprecation") |
195 |
@SuppressWarnings("deprecation") |
294 |
public static Boolean clean(URL sourceRoot) throws IOException { |
196 |
public static Boolean clean(URL sourceRoot) throws IOException { |
295 |
File targetFolder = getTarget(sourceRoot); |
197 |
final CompileOnSaveAction a = CompileOnSaveActionQuery.getAction(sourceRoot); |
296 |
|
198 |
if (a != null) { |
297 |
if (targetFolder == null) { |
199 |
final CompileOnSaveAction.Context ctx = CompileOnSaveAction.Context.clean(sourceRoot); |
298 |
return null; |
200 |
return a.performAction(ctx); |
299 |
} |
201 |
} |
300 |
|
|
|
301 |
File tagFile = new File(targetFolder, TAG_FILE_NAME); |
302 |
|
303 |
if (!tagFile.exists()) { |
304 |
return null; |
305 |
} |
306 |
|
307 |
try { |
308 |
SourceUtils.waitScanFinished(); |
309 |
} catch (InterruptedException e) { |
310 |
//Not Important |
311 |
LOG.log(Level.FINE, null, e); |
312 |
return false; |
313 |
} |
314 |
|
315 |
delete(targetFolder, false); |
316 |
delete(tagFile, true); |
317 |
|
318 |
return null; |
202 |
return null; |
319 |
} |
203 |
} |
320 |
|
204 |
|
321 |
public static File getTargetFolder(URL sourceRoot) { |
205 |
public static boolean isUpdateClasses(URL sourceRoot) { |
322 |
File targetFolder = getTarget(sourceRoot); |
206 |
final CompileOnSaveAction a = CompileOnSaveActionQuery.getAction(sourceRoot); |
323 |
|
207 |
return a != null ? |
324 |
if (targetFolder == null) { |
208 |
a.isUpdateClasses(): |
325 |
return null; |
209 |
false; |
326 |
} |
|
|
327 |
|
328 |
if (!new File(targetFolder, TAG_FILE_NAME).exists()) { |
329 |
return null; |
330 |
} |
331 |
|
332 |
return targetFolder; |
333 |
} |
210 |
} |
334 |
|
211 |
|
335 |
public static boolean isUpdateResources(File targetFolder) { |
212 |
public static boolean isUpdateResources(URL srcRoot) { |
336 |
return targetFolder != null && new File(targetFolder, TAG_UPDATE_RESOURCES).exists(); |
213 |
final CompileOnSaveAction a = CompileOnSaveActionQuery.getAction(srcRoot); |
|
|
214 |
return a != null ? |
215 |
a.isUpdateResources(): |
216 |
false; |
337 |
} |
217 |
} |
338 |
|
218 |
|
339 |
public static void classCacheUpdated(URL sourceRoot, File cacheRoot, Iterable<File> deleted, Iterable<File> updated, boolean resource) { |
219 |
public static void classCacheUpdated(URL sourceRoot, File cacheRoot, Iterable<File> deleted, Iterable<File> updated, boolean resource) { |
340 |
if (!deleted.iterator().hasNext() && !updated.iterator().hasNext()) { |
220 |
final CompileOnSaveAction a = CompileOnSaveActionQuery.getAction(sourceRoot); |
341 |
return ; |
221 |
if (a != null) { |
342 |
} |
|
|
343 |
|
344 |
File targetFolder = getTargetFolder(sourceRoot); |
345 |
|
346 |
if (targetFolder == null) { |
347 |
return ; |
348 |
} |
349 |
|
350 |
if (resource && !isUpdateResources(targetFolder)) { |
351 |
return ; |
352 |
} |
353 |
|
354 |
List<File> updatedFiles = new LinkedList<File>(); |
355 |
|
356 |
for (File deletedFile : deleted) { |
357 |
final String relPath = relativizeFile(cacheRoot, deletedFile); |
358 |
if (relPath == null) { |
359 |
throw new IllegalArgumentException (String.format( |
360 |
"Deleted file: %s is not under cache root: %s, (normalized file: %s).", //NOI18N |
361 |
deletedFile.getAbsolutePath(), |
362 |
cacheRoot.getAbsolutePath(), |
363 |
FileUtil.normalizeFile(deletedFile).getAbsolutePath())); |
364 |
} |
365 |
File toDelete = resolveFile(targetFolder, relPath); |
366 |
|
367 |
toDelete.delete(); |
368 |
updatedFiles.add(toDelete); |
369 |
} |
370 |
|
371 |
for (File updatedFile : updated) { |
372 |
final String relPath = relativizeFile(cacheRoot, updatedFile); |
373 |
if (relPath == null) { |
374 |
throw new IllegalArgumentException (String.format( |
375 |
"Updated file: %s is not under cache root: %s, (normalized file: %s).", //NOI18N |
376 |
updatedFile.getAbsolutePath(), |
377 |
cacheRoot.getAbsolutePath(), |
378 |
FileUtil.normalizeFile(updatedFile).getAbsolutePath())); |
379 |
} |
380 |
File target = resolveFile(targetFolder, relPath); |
381 |
|
382 |
try { |
222 |
try { |
383 |
copyFile(updatedFile, target); |
223 |
final CompileOnSaveAction.Context ctx = CompileOnSaveAction.Context.update( |
384 |
updatedFiles.add(target); |
224 |
sourceRoot, |
|
|
225 |
resource, |
226 |
cacheRoot, |
227 |
updated, |
228 |
deleted, |
229 |
(updatedFiles) -> fire(sourceRoot, updatedFiles)); |
230 |
a.performAction(ctx); |
385 |
} catch (IOException ex) { |
231 |
} catch (IOException ex) { |
386 |
Exceptions.printStackTrace(ex); |
232 |
Exceptions.printStackTrace(ex); |
387 |
} |
233 |
} |
388 |
} |
234 |
} |
389 |
|
235 |
} |
390 |
if (updatedFiles.size() > 0) { |
236 |
|
|
|
237 |
private static void fire( |
238 |
@NonNull final URL sourceRoot, |
239 |
@NonNull final Iterable<File> updatedFiles) { |
240 |
if (updatedFiles.iterator().hasNext()) { |
391 |
Set<ArtifactsUpdated> listeners; |
241 |
Set<ArtifactsUpdated> listeners; |
392 |
|
|
|
393 |
synchronized (BuildArtifactMapperImpl.class) { |
242 |
synchronized (BuildArtifactMapperImpl.class) { |
394 |
listeners = source2Listener.get(sourceRoot); |
243 |
listeners = source2Listener.get(sourceRoot); |
395 |
|
|
|
396 |
if (listeners != null) { |
244 |
if (listeners != null) { |
397 |
listeners = new HashSet<ArtifactsUpdated>(listeners); |
245 |
listeners = new HashSet<>(listeners); |
398 |
} |
246 |
} |
399 |
} |
247 |
} |
400 |
|
|
|
401 |
if (listeners != null) { |
248 |
if (listeners != null) { |
402 |
for (ArtifactsUpdated listener : listeners) { |
249 |
for (ArtifactsUpdated listener : listeners) { |
403 |
listener.artifactsUpdated(updatedFiles); |
250 |
listener.artifactsUpdated(updatedFiles); |
Lines 405-411
Link Here
|
405 |
} |
252 |
} |
406 |
} |
253 |
} |
407 |
} |
254 |
} |
408 |
|
255 |
|
409 |
private static void copyFile(File updatedFile, File target) throws IOException { |
256 |
private static void copyFile(File updatedFile, File target) throws IOException { |
410 |
final File parent = target.getParentFile(); |
257 |
final File parent = target.getParentFile(); |
411 |
if (parent != null && !parent.exists()) { |
258 |
if (parent != null && !parent.exists()) { |
Lines 692-750
Link Here
|
692 |
return delegate; |
539 |
return delegate; |
693 |
} |
540 |
} |
694 |
|
541 |
|
695 |
File target = getTarget(owner.getURL()); |
542 |
final CompileOnSaveAction action = CompileOnSaveActionQuery.getAction(owner.toURL()); |
696 |
File tagFile = FileUtil.normalizeFile(new File(target, TAG_FILE_NAME)); |
543 |
if (action == null) { |
|
|
544 |
return delegate; |
545 |
} |
697 |
|
546 |
|
698 |
synchronized(this) { |
547 |
synchronized(this) { |
699 |
Reference<FileChangeListenerImpl> ref = file2Listener.get(tagFile); |
|
|
700 |
FileChangeListenerImpl l = ref != null ? ref.get() : null; |
701 |
|
702 |
if (l == null) { |
703 |
file2Listener.put(tagFile, new WeakReference<FileChangeListenerImpl>(l = new FileChangeListenerImpl())); |
704 |
listener2File.put(l, tagFile); |
705 |
FileChangeSupport.DEFAULT.addListener(l, tagFile); |
706 |
} |
707 |
|
708 |
Reference<Status> prevRef = file2Status.get(file); |
548 |
Reference<Status> prevRef = file2Status.get(file); |
709 |
result = prevRef != null ? prevRef.get() : null; |
549 |
result = prevRef != null ? prevRef.get() : null; |
710 |
|
550 |
|
711 |
if (result == null) { |
551 |
if (result == null) { |
712 |
file2Status.put(file, new WeakReference<Status>(result = new FileBuiltQueryStatusImpl(delegate, tagFile, l))); |
552 |
file2Status.put(file, new WeakReference<Status>(result = new FileBuiltQueryStatusImpl(delegate, action))); |
713 |
} |
553 |
} |
714 |
|
554 |
|
715 |
return result; |
555 |
return result; |
716 |
} |
556 |
} |
717 |
} catch (FileStateInvalidException ex) { |
|
|
718 |
Exceptions.printStackTrace(ex); |
719 |
return null; |
720 |
} finally { |
557 |
} finally { |
721 |
recursive.remove(); |
558 |
recursive.remove(); |
722 |
} |
559 |
} |
723 |
} |
560 |
} |
724 |
|
561 |
|
725 |
} |
562 |
} |
726 |
|
|
|
727 |
private static Map<File, Reference<FileChangeListenerImpl>> file2Listener = new WeakHashMap<File, Reference<FileChangeListenerImpl>>(); |
728 |
private static Map<FileChangeListenerImpl, File> listener2File = new WeakHashMap<FileChangeListenerImpl, File>(); |
729 |
|
563 |
|
730 |
private static final class FileBuiltQueryStatusImpl implements FileBuiltQuery.Status, ChangeListener { |
564 |
private static final class FileBuiltQueryStatusImpl implements FileBuiltQuery.Status, ChangeListener { |
731 |
|
565 |
|
732 |
private final FileBuiltQuery.Status delegate; |
566 |
private final FileBuiltQuery.Status delegate; |
733 |
private final File tag; |
567 |
private final CompileOnSaveAction action; |
734 |
private final FileChangeListenerImpl fileListener; |
|
|
735 |
private final ChangeSupport cs = new ChangeSupport(this); |
568 |
private final ChangeSupport cs = new ChangeSupport(this); |
736 |
|
569 |
|
737 |
public FileBuiltQueryStatusImpl(Status delegate, File tag, FileChangeListenerImpl fileListener) { |
570 |
public FileBuiltQueryStatusImpl(Status delegate, CompileOnSaveAction action) { |
738 |
this.delegate = delegate; |
571 |
this.delegate = delegate; |
739 |
this.tag = tag; |
572 |
this.action = action; |
740 |
this.fileListener = fileListener; |
|
|
741 |
|
573 |
|
742 |
delegate.addChangeListener(this); |
574 |
delegate.addChangeListener(this); |
743 |
fileListener.addListener(this); |
575 |
action.addChangeListener(WeakListeners.change(this, action)); |
744 |
} |
576 |
} |
745 |
|
577 |
|
746 |
public boolean isBuilt() { |
578 |
public boolean isBuilt() { |
747 |
return delegate.isBuilt() || tag.canRead(); |
579 |
return delegate.isBuilt() || action.isUpdateClasses(); |
748 |
} |
580 |
} |
749 |
|
581 |
|
750 |
public void addChangeListener(ChangeListener l) { |
582 |
public void addChangeListener(ChangeListener l) { |
Lines 794-798
Link Here
|
794 |
} |
626 |
} |
795 |
}); |
627 |
}); |
796 |
} |
628 |
} |
|
|
629 |
} |
630 |
|
631 |
private static final class DefaultCompileOnSaveAction implements CompileOnSaveAction, ChangeListener { |
632 |
//@GuardedBy("file2Listener") |
633 |
private static Map<File, Reference<FileChangeListenerImpl>> file2Listener = new WeakHashMap<>(); |
634 |
//@GuardedBy("file2Listener") |
635 |
private static Map<FileChangeListenerImpl, File> listener2File = new WeakHashMap<>(); |
636 |
|
637 |
private final URL root; |
638 |
private final ChangeSupport cs; |
639 |
//@GuardedBy("file2Listener") |
640 |
private FileChangeListenerImpl listenerDelegate; |
641 |
|
642 |
DefaultCompileOnSaveAction(@NonNull final URL root) { |
643 |
this.root = root; |
644 |
this.cs = new ChangeSupport(this); |
645 |
} |
646 |
|
647 |
public boolean isEnabled() { |
648 |
return true; |
649 |
} |
650 |
|
651 |
@Override |
652 |
public boolean isUpdateClasses() { |
653 |
return isUpdateClasses(CompileOnSaveAction.Context.getTarget(root)); |
654 |
} |
655 |
|
656 |
@Override |
657 |
public boolean isUpdateResources() { |
658 |
return isUpdateResources(CompileOnSaveAction.Context.getTarget(root)); |
659 |
} |
660 |
|
661 |
@Override |
662 |
public Boolean performAction(@NonNull final Context ctx) throws IOException { |
663 |
assert root.equals(ctx.getSourceRoot()); |
664 |
switch (ctx.getOperation()) { |
665 |
case CLEAN: |
666 |
return performClean(ctx); |
667 |
case SYNC: |
668 |
return performSync(ctx); |
669 |
case UPDATE: |
670 |
return performUpdate(ctx); |
671 |
default: |
672 |
} throw new IllegalArgumentException(String.valueOf(ctx.getOperation())); |
673 |
} |
674 |
|
675 |
@Override |
676 |
public void addChangeListener(@NonNull final ChangeListener listener) { |
677 |
final File target = CompileOnSaveAction.Context.getTarget(root); |
678 |
final File tagFile = FileUtil.normalizeFile(new File(target, TAG_FILE_NAME)); |
679 |
synchronized (file2Listener) { |
680 |
if (listenerDelegate == null) { |
681 |
final Reference<FileChangeListenerImpl> ref = file2Listener.get(tagFile); |
682 |
FileChangeListenerImpl l = ref != null ? ref.get() : null; |
683 |
if (l == null) { |
684 |
file2Listener.put(tagFile, new WeakReference<FileChangeListenerImpl>(l = new FileChangeListenerImpl())); |
685 |
listener2File.put(l, tagFile); |
686 |
FileChangeSupport.DEFAULT.addListener(l, tagFile); |
687 |
//Need to hold l |
688 |
} |
689 |
listenerDelegate = l; |
690 |
listenerDelegate.addListener(this); |
691 |
} |
692 |
} |
693 |
cs.addChangeListener(listener); |
694 |
} |
695 |
|
696 |
@Override |
697 |
public void removeChangeListner(@NonNull final ChangeListener listener) { |
698 |
cs.removeChangeListener(listener); |
699 |
} |
700 |
|
701 |
@Override |
702 |
public void stateChanged(@NonNull final ChangeEvent e) { |
703 |
cs.fireChange(); |
704 |
} |
705 |
|
706 |
private Boolean performClean(@NonNull final Context ctx) throws IOException { |
707 |
final File targetFolder = ctx.getTarget(); |
708 |
|
709 |
if (targetFolder == null) { |
710 |
return null; |
711 |
} |
712 |
|
713 |
File tagFile = new File(targetFolder, TAG_FILE_NAME); |
714 |
|
715 |
if (!tagFile.exists()) { |
716 |
return null; |
717 |
} |
718 |
|
719 |
try { |
720 |
SourceUtils.waitScanFinished(); |
721 |
} catch (InterruptedException e) { |
722 |
//Not Important |
723 |
LOG.log(Level.FINE, null, e); |
724 |
return false; |
725 |
} |
726 |
|
727 |
delete(targetFolder, false); |
728 |
delete(tagFile, true); |
729 |
|
730 |
return null; |
731 |
} |
732 |
|
733 |
private Boolean performSync(@NonNull final Context ctx) throws IOException { |
734 |
final URL sourceRoot = ctx.getSourceRoot(); |
735 |
final File targetFolder = ctx.getTarget(); |
736 |
final boolean copyResources = ctx.isCopyResources(); |
737 |
final boolean keepResourceUpToDate = ctx.isKeepResourcesUpToDate(); |
738 |
final Object context = ctx.getOwner(); |
739 |
|
740 |
if (targetFolder == null) { |
741 |
return null; |
742 |
} |
743 |
|
744 |
try { |
745 |
SourceUtils.waitScanFinished(); |
746 |
} catch (InterruptedException e) { |
747 |
//Not Important |
748 |
LOG.log(Level.FINE, null, e); |
749 |
return null; |
750 |
} |
751 |
|
752 |
if (JavaIndex.ensureAttributeValue(sourceRoot, DIRTY_ROOT, null)) { |
753 |
IndexingManager.getDefault().refreshIndexAndWait(sourceRoot, null); |
754 |
} |
755 |
|
756 |
if (JavaIndex.getAttribute(sourceRoot, DIRTY_ROOT, null) != null) { |
757 |
return false; |
758 |
} |
759 |
|
760 |
FileObject[][] sources = new FileObject[1][]; |
761 |
|
762 |
if (!protectAgainstErrors(targetFolder, sources, context)) { |
763 |
return false; |
764 |
} |
765 |
|
766 |
File tagFile = new File(targetFolder, TAG_FILE_NAME); |
767 |
File tagUpdateResourcesFile = new File(targetFolder, TAG_UPDATE_RESOURCES); |
768 |
final boolean forceResourceCopy = copyResources && keepResourceUpToDate && !tagUpdateResourcesFile.exists(); |
769 |
final boolean cosActive = tagFile.exists(); |
770 |
if (cosActive && !forceResourceCopy) { |
771 |
return true; |
772 |
} |
773 |
|
774 |
if (!cosActive) { |
775 |
delete(targetFolder, false/*#161085: cleanCompletely*/); |
776 |
} |
777 |
|
778 |
if (!targetFolder.exists() && !targetFolder.mkdirs()) { |
779 |
throw new IOException("Cannot create destination folder: " + targetFolder.getAbsolutePath()); |
780 |
} |
781 |
|
782 |
sources(targetFolder, sources); |
783 |
|
784 |
for (int i = sources[0].length - 1; i>=0; i--) { |
785 |
final FileObject sr = sources[0][i]; |
786 |
if (!cosActive) { |
787 |
URL srURL = sr.toURL(); |
788 |
File index = JavaIndex.getClassFolder(srURL, true); |
789 |
|
790 |
if (index == null) { |
791 |
//#181992: (not nice) ignore the annotation processing target directory: |
792 |
if (srURL.equals(AnnotationProcessingQuery.getAnnotationProcessingOptions(sr).sourceOutputDirectory())) { |
793 |
continue; |
794 |
} |
795 |
|
796 |
return null; |
797 |
} |
798 |
|
799 |
copyRecursively(index, targetFolder); |
800 |
} |
801 |
|
802 |
if (copyResources) { |
803 |
Set<String> javaMimeTypes = COSSynchronizingIndexer.gatherJavaMimeTypes(); |
804 |
String[] javaMimeTypesArr = javaMimeTypes.toArray(new String[0]); |
805 |
|
806 |
copyRecursively(sr, targetFolder, javaMimeTypes, javaMimeTypesArr); |
807 |
} |
808 |
} |
809 |
|
810 |
if (!cosActive) { |
811 |
new FileOutputStream(tagFile).close(); |
812 |
} |
813 |
|
814 |
if (keepResourceUpToDate) |
815 |
new FileOutputStream(tagUpdateResourcesFile).close(); |
816 |
|
817 |
return true; |
818 |
} |
819 |
|
820 |
private Boolean performUpdate(@NonNull final Context ctx) throws IOException { |
821 |
final Iterable<? extends File> deleted = ctx.getDeleted(); |
822 |
final Iterable<? extends File> updated = ctx.getUpdated(); |
823 |
final boolean resource = ctx.isCopyResources(); |
824 |
final File cacheRoot = ctx.getCacheRoot(); |
825 |
if (!deleted.iterator().hasNext() && !updated.iterator().hasNext()) { |
826 |
return null; |
827 |
} |
828 |
File targetFolder = ctx.getTarget(); |
829 |
if (targetFolder == null) { |
830 |
return null; |
831 |
} |
832 |
if (!isUpdateClasses(targetFolder)) { |
833 |
return null; |
834 |
} |
835 |
|
836 |
if (resource && !isUpdateResources(targetFolder)) { |
837 |
return null; |
838 |
} |
839 |
|
840 |
List<File> updatedFiles = new LinkedList<>(); |
841 |
|
842 |
for (File deletedFile : deleted) { |
843 |
final String relPath = relativizeFile(cacheRoot, deletedFile); |
844 |
if (relPath == null) { |
845 |
throw new IllegalArgumentException (String.format( |
846 |
"Deleted file: %s is not under cache root: %s, (normalized file: %s).", //NOI18N |
847 |
deletedFile.getAbsolutePath(), |
848 |
cacheRoot.getAbsolutePath(), |
849 |
FileUtil.normalizeFile(deletedFile).getAbsolutePath())); |
850 |
} |
851 |
File toDelete = resolveFile(targetFolder, relPath); |
852 |
|
853 |
toDelete.delete(); |
854 |
updatedFiles.add(toDelete); |
855 |
} |
856 |
|
857 |
for (File updatedFile : updated) { |
858 |
final String relPath = relativizeFile(cacheRoot, updatedFile); |
859 |
if (relPath == null) { |
860 |
throw new IllegalArgumentException (String.format( |
861 |
"Updated file: %s is not under cache root: %s, (normalized file: %s).", //NOI18N |
862 |
updatedFile.getAbsolutePath(), |
863 |
cacheRoot.getAbsolutePath(), |
864 |
FileUtil.normalizeFile(updatedFile).getAbsolutePath())); |
865 |
} |
866 |
File target = resolveFile(targetFolder, relPath); |
867 |
|
868 |
try { |
869 |
copyFile(updatedFile, target); |
870 |
updatedFiles.add(target); |
871 |
} catch (IOException ex) { |
872 |
Exceptions.printStackTrace(ex); |
873 |
} |
874 |
} |
875 |
ctx.filesUpdated(updatedFiles); |
876 |
return true; |
877 |
} |
878 |
|
879 |
private boolean isUpdateClasses(@NullAllowed final File targetFolder) { |
880 |
if (targetFolder == null) { |
881 |
return false; |
882 |
} |
883 |
return new File(targetFolder, TAG_FILE_NAME).exists(); |
884 |
} |
885 |
|
886 |
private boolean isUpdateResources(@NullAllowed final File targetFolder) { |
887 |
if (targetFolder == null) { |
888 |
return false; |
889 |
} |
890 |
return new File(targetFolder, TAG_UPDATE_RESOURCES).exists(); |
891 |
} |
892 |
} |
893 |
|
894 |
@ServiceProvider(service = CompileOnSaveAction.Provider.class, position = Integer.MAX_VALUE) |
895 |
public static final class Provider implements CompileOnSaveAction.Provider { |
896 |
//@GuardedBy("normCache") |
897 |
private final Map<URL,Reference<DefaultCompileOnSaveAction>> normCache |
898 |
= new WeakHashMap<>(); |
899 |
@Override |
900 |
public CompileOnSaveAction forRoot(@NonNull final URL root) { |
901 |
synchronized (normCache) { |
902 |
final Reference<DefaultCompileOnSaveAction> ref = normCache.get(root); |
903 |
DefaultCompileOnSaveAction res; |
904 |
if (ref == null || (res = ref.get()) == null) { |
905 |
res = new DefaultCompileOnSaveAction(root); |
906 |
normCache.put(root, new WeakReference<>(res)); |
907 |
} |
908 |
return res; |
909 |
} |
910 |
} |
797 |
} |
911 |
} |
798 |
} |
912 |
} |