Next step would be to ensure Turbo cache is updated.
Signed-off-by: Imran M Yousuf <imyo...@smartitengineering.com>
---
src/org/nbgit/util/exclude/Excludes.java | 79 +++++++++++++++++++++++++++---
1 files changed, 72 insertions(+), 7 deletions(-)
diff --git a/src/org/nbgit/util/exclude/Excludes.java
b/src/org/nbgit/util/exclude/Excludes.java
index 9b7cba3..9aa8d12 100644
--- a/src/org/nbgit/util/exclude/Excludes.java
+++ b/src/org/nbgit/util/exclude/Excludes.java
@@ -45,14 +45,24 @@
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
-import java.util.HashMap;
+import java.util.Collections;
+import java.util.Date;
import java.util.HashSet;
+import java.util.Hashtable;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
import java.util.Vector;
import org.nbgit.Git;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.api.queries.SharabilityQuery;
+import org.openide.filesystems.FileAttributeEvent;
+import org.openide.filesystems.FileChangeAdapter;
+import org.openide.filesystems.FileEvent;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileRenameEvent;
import org.openide.filesystems.FileUtil;
import org.spearce.jgit.lib.Repository;
@@ -65,21 +75,46 @@
private Excludes() {
}
-
private static final String FILENAME_GITIGNORE = ".gitignore"; // NOI18N
- private static HashMap<String, List<PathPattern>> ignorePatterns;
+ private final static Map<String, List<PathPattern>>
ignorePatterns = new Hashtable<String, List<PathPattern>>();
+ private final static Timer timer = new Timer();
+ private final static TimerTask externalChangeTrackerTask;
+ private final static int DELAY = 5000;
+
+ static {
+ externalChangeTrackerTask = new TimerTask() {
+
+ private final Date lastChecked = new Date();
+
+ @Override
+ public void run() {
+ final Set<String> absPathSet = ignorePatterns.keySet();
+ for (String absPath : absPathSet) {
+ final File file = new File(absPath);
+ FileObject fileObject = FileUtil.toFileObject(file);
+ if (file.exists() &&
fileObject.lastModified().after(lastChecked)) {
+ fileObject.refresh();
+ }
+ }
+ lastChecked.setTime(System.currentTimeMillis());
+ }
+ };
+ timer.schedule(externalChangeTrackerTask, DELAY, DELAY);
+ }
private static List<PathPattern> getIgnorePatterns(File file) {
- if (ignorePatterns == null) {
- ignorePatterns = new HashMap<String, List<PathPattern>>();
- }
String key = file.getAbsolutePath();
List<PathPattern> patterns = ignorePatterns.get(key);
- if (patterns == null) {
+ if (patterns == null && file.exists() && !file.isDirectory()) {
patterns = readIgnorePatterns(file);
+ if (!ignorePatterns.keySet().contains(key)) {
+ monitorFileChange(key);
+ }
if (!patterns.isEmpty()) {
ignorePatterns.put(key, patterns);
}
+ } else if (patterns == null) {
+ patterns = Collections.emptyList();
}
return patterns;
}
@@ -162,6 +197,36 @@ public static boolean isIgnored(File file,
boolean checkSharability) {
return false;
}
+ private static void monitorFileChange(final String key) {
+ final FileObject fileObject = FileUtil.toFileObject(new File(key));
+ fileObject.addFileChangeListener(new FileChangeAdapter() {
+
+ private void evictPatterns() {
+ ignorePatterns.remove(key);
+ }
+
+ @Override
+ public void fileChanged(FileEvent fe) {
+ evictPatterns();
+ }
+
+ @Override
+ public void fileAttributeChanged(FileAttributeEvent fe) {
+ evictPatterns();
+ }
+
+ @Override
+ public void fileDeleted(FileEvent fe) {
+ evictPatterns();
+ }
+
+ @Override
+ public void fileRenamed(FileRenameEvent fe) {
+ evictPatterns();
+ }
+ });
+ }
+
private static String stripWorkDir(File wd, File f) {
int skip = f.getPath().length() > wd.getPath().length() ? 1 : 0;
String relName = f.getPath().substring(wd.getPath().length() + skip);
--
1.6.2.1
Signed-off-by: Imran M Yousuf <imyo...@smartitengineering.com>
[jf: updated and refactored to move the main logic into the a utility class
to make the code reusable. Also, guard the code against race conditions.]
Signed-off-by: Jonas Fonseca <fon...@diku.dk>
---
On Sun, Aug 16, 2009 at 22:07, Imran M Yousuf<imyo...@gmail.com> wrote:
>
> Thanks for the update. I forgot to mention earlier that I remembered
> why I used a separate set for keeping the collection of files being
> monitored, its because, "ignorePatterns" patterns will have entries
> flushed from map while the files should still be monitored. So I would
> like to re-do the patch with a separate collection for maintaining the
> list of files being monitored; please let me know when I should start
> with it and I would like to help you by porting the code so you can
> simply pull from my github fork.
I still do not see why this is even needed. If a file is removed the
current code will simply reload it if/when it is later recreated.
This patch is my current version of the updated patch, which should
hopefully make it possible to use the code for monitoring other things.
Please review/repost so we can get the tracking code into the tree.
src/org/nbgit/util/exclude/ExcludeCache.java | 10 +-
src/org/nbgit/util/exclude/MonitoredFileMap.java | 162 ++++++++++++++++++++++
2 files changed, 165 insertions(+), 7 deletions(-)
create mode 100644 src/org/nbgit/util/exclude/MonitoredFileMap.java
diff --git a/src/org/nbgit/util/exclude/ExcludeCache.java b/src/org/nbgit/util/exclude/ExcludeCache.java
index 62f4f8e..c05add2 100644
--- a/src/org/nbgit/util/exclude/ExcludeCache.java
+++ b/src/org/nbgit/util/exclude/ExcludeCache.java
@@ -36,15 +36,12 @@
package org.nbgit.util.exclude;
import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Vector;
import org.spearce.jgit.lib.Repository;
class ExcludeCache {
- private final Map<String, PathPatternList> map = new HashMap<String, PathPatternList>();
+ private final MonitoredFileMap<PathPatternList> map = MonitoredFileMap.create();
private final Repository repo;
public static ExcludeCache create(Repository repository) {
@@ -143,12 +140,12 @@ private PathPatternList getUserPatternList() {
}
private PathPatternList getPatternList(File file, String basePath) {
- PathPatternList list = map.get(file.getPath());
+ PathPatternList list = map.get(file);
if (list == null) {
list = ExcludeUtils.readExcludeFile(file, basePath);
if (list == null)
return null;
- map.put(file.getPath(), list);
+ map.put(file, list);
}
return list;
}
@@ -163,5 +160,4 @@ public String toString() {
builder.append("]");
return builder.toString();
}
-
}
diff --git a/src/org/nbgit/util/exclude/MonitoredFileMap.java b/src/org/nbgit/util/exclude/MonitoredFileMap.java
new file mode 100644
index 0000000..7151c9c
--- /dev/null
+++ b/src/org/nbgit/util/exclude/MonitoredFileMap.java
@@ -0,0 +1,162 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2009 Imran M Yousuf <imyo...@smartitengineering.com>
+ * Copyright 2009 Jonas Fonseca <fon...@diku.dk>
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file.
+ *
+ * This particular file is subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.nbgit.util.exclude;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import org.openide.filesystems.FileAttributeEvent;
+import org.openide.filesystems.FileChangeAdapter;
+import org.openide.filesystems.FileEvent;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileRenameEvent;
+import org.openide.filesystems.FileUtil;
+
+class MonitoredFileMap<T> {
+
+ private final Map<String, T> map = Collections.synchronizedMap(new HashMap<String, T>());
+ private FileMonitorTask monitorTask;
+
+ private MonitoredFileMap() {
+ }
+
+ public static <T> MonitoredFileMap<T> create() {
+ return new MonitoredFileMap<T>();
+ }
+
+ public T get(File file) {
+ synchronized (map) {
+ return map.get(file.getPath());
+ }
+ }
+
+ public void put(File file, T list) {
+ final String key = file.getPath();
+ synchronized (map) {
+ map.put(key, list);
+ }
+ setupFileMonitoring(key);
+ }
+
+ private void setupFileMonitoring(final String key) {
+ if (monitorTask == null)
+ monitorTask = new FileMonitorTask();
+
+ FileObject fileObject = FileUtil.toFileObject(new File(key));
+ fileObject.addFileChangeListener(new FileChangeAdapter() {
+
+ private void evictFile() {
+ FileMonitorTask task;
+ synchronized (map) {
+ map.remove(key);
+ task = map.isEmpty() ? monitorTask : null;
+ if (task != monitorTask)
+ monitorTask = null;
+ }
+ if (task != null) {
+ task.stop();
+ }
+ }
+
+ @Override
+ public void fileChanged(FileEvent fe) {
+ evictFile();
+ }
+
+ @Override
+ public void fileAttributeChanged(FileAttributeEvent fe) {
+ evictFile();
+ }
+
+ @Override
+ public void fileDeleted(FileEvent fe) {
+ evictFile();
+ }
+
+ @Override
+ public void fileRenamed(FileRenameEvent fe) {
+ evictFile();
+ }
+ });
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("size=" + map.size());
+ return builder.toString();
+ }
+
+ private class FileMonitorTask extends TimerTask {
+
+ private final static int DELAY = 10000;
+ private final Timer timer = new Timer();
+ private long lastModified;
+
+ private FileMonitorTask() {
+ timer.schedule(this, DELAY, DELAY);
+ }
+
+ private void stop() {
+ timer.cancel();
+ }
+
+ @Override
+ public void run() {
+ Set<File> filesToRefresh = new HashSet<File>();
+ Set<String> paths = map.keySet();
+
+ synchronized (map) {
+ for (String path : paths) {
+ final File file = new File(path);
+ if (!file.exists() || file.lastModified() < lastModified) {
+ filesToRefresh.add(file);
+ }
+ }
+ }
+ for (File file : filesToRefresh) {
+ FileUtil.toFileObject(file).refresh(true);
+ }
+ lastModified = System.currentTimeMillis();
+ }
+ }
+}
--
1.6.4.rc3.195.g2b05f