in grails-core/src/main/groovy/grails/boot/GrailsApp.groovy [147:281]
protected void enableDevelopmentModeWatch(Environment environment, ConfigurableApplicationContext applicationContext, String... args) {
def location = environment.getReloadLocation()
if (location) {
directoryWatcher = new DirectoryWatcher()
Queue<File> changedFiles = new ConcurrentLinkedQueue<>()
Queue<File> newFiles = new ConcurrentLinkedQueue<>()
directoryWatcher.addListener(new FileExtensionFileChangeListener(['groovy', 'java']) {
@Override
void onChange(File file, List<String> extensions) {
changedFiles << file.canonicalFile
}
@Override
void onNew(File file, List<String> extensions) {
changedFiles << file.canonicalFile
// For some bizarre reason Windows fires onNew events even for files that have
// just been modified and not created
if (System.getProperty("os.name").toLowerCase().indexOf("windows") != -1) {
return
}
newFiles << file.canonicalFile
}
})
def pluginManager = applicationContext.getBean(GrailsPluginManager)
def pluginManagerListener = createPluginManagerListener(applicationContext)
directoryWatcher.addListener(pluginManagerListener)
File baseDir = new File(location).canonicalFile
String baseDirPath = baseDir.canonicalPath
List<File> watchBaseDirectories = [baseDir]
for (GrailsPlugin plugin in pluginManager.allPlugins) {
if (plugin instanceof BinaryGrailsPlugin) {
BinaryGrailsPlugin binaryGrailsPlugin = (BinaryGrailsPlugin) plugin
def pluginDirectory = binaryGrailsPlugin.projectDirectory
if (pluginDirectory != null) {
watchBaseDirectories << pluginDirectory
}
}
}
for (dir in watchBaseDirectories) {
configureDirectoryWatcher(directoryWatcher, dir.absolutePath)
}
for (GrailsPlugin plugin in pluginManager.allPlugins) {
def watchedResourcePatterns = plugin.getWatchedResourcePatterns()
if (watchedResourcePatterns != null) {
for (WatchPattern wp in new ArrayList<WatchPattern>(watchedResourcePatterns)) {
boolean first = true
for (watchBase in watchBaseDirectories) {
if (!first) {
if (wp.file != null) {
String relativePath = wp.file.canonicalPath - baseDirPath
File watchFile = new File(watchBase, relativePath)
// the base project will already been in the list of watch patterns, but we add any subprojects here
plugin.watchedResourcePatterns.add(new WatchPattern(file: watchFile, extension: wp.extension))
} else if (wp.directory != null) {
String relativePath = wp.directory.canonicalPath - baseDirPath
File watchDir = new File(watchBase, relativePath)
// the base project will already been in the list of watch patterns, but we add any subprojects here
plugin.watchedResourcePatterns.add(new WatchPattern(directory: watchDir, extension: wp.extension))
}
}
first = false
if (wp.file) {
String relativePath = wp.file.canonicalPath - baseDirPath
def resolvedPath = new File(watchBase, relativePath)
directoryWatcher.addWatchFile(resolvedPath)
} else if (wp.directory && wp.extension) {
String relativePath = wp.directory.canonicalPath - baseDirPath
def resolvedPath = new File(watchBase, relativePath)
directoryWatcher.addWatchDirectory(resolvedPath, wp.extension)
}
}
}
}
}
developmentModeActive = true
Thread.start {
CompilerConfiguration compilerConfig = new CompilerConfiguration()
compilerConfig.setTargetDirectory(new File(location, BuildSettings.BUILD_CLASSES_PATH))
while (isDevelopmentModeActive()) {
// Workaround for some IDE / OS combos - 2 events (new + update) for the same file
def uniqueChangedFiles = changedFiles as Set
def i = uniqueChangedFiles.size()
try {
if (i > 1) {
changedFiles.clear()
for (f in uniqueChangedFiles) {
recompile(f, compilerConfig, location)
if (newFiles.contains(f)) {
newFiles.remove(f)
}
pluginManager.informOfFileChange(f)
sleep 1000
}
} else if (i == 1) {
changedFiles.clear()
def changedFile = uniqueChangedFiles[0]
changedFile = changedFile.canonicalFile
// Groovy files within the 'conf' directory are not compiled
String confPath = "${File.separator}grails-app${File.separator}conf${File.separator}"
if (changedFile.path.contains(confPath)) {
pluginManager.informOfFileChange(changedFile)
} else {
recompile(changedFile, compilerConfig, location)
if (newFiles.contains(changedFile)) {
newFiles.remove(changedFile)
}
pluginManager.informOfFileChange(changedFile)
}
}
newFiles.clear()
} catch (CompilationFailedException cfe) {
log.error("Compilation Error: $cfe.message", cfe)
}
sleep(1000)
}
}
directoryWatcher.start()
}
}