From: Ferry Huberts <ferry.huberts@pelagic.nl>
To: git@vger.kernel.org
Cc: "Shawn O. Pearce" <spearce@spearce.org>,
Robin Rosenberg <robin.rosenberg@dewire.com>,
Ferry Huberts <ferry.huberts@pelagic.nl>
Subject: [EGIT] [PATCH RFC v1 5/5] Use the ignore patterns cache to determine ignores
Date: Thu, 26 Mar 2009 22:34:27 +0100 [thread overview]
Message-ID: <55baa61ac6caea86a364ddc0421d9422d96f2825.1238102327.git.ferry.huberts@pelagic.nl> (raw)
In-Reply-To: <6b4495184b92d42059a12af17c54f1951337338a.1238102327.git.ferry.huberts@pelagic.nl>
In-Reply-To: <cover.1238102327.git.ferry.huberts@pelagic.nl>
Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
---
.../src/org/spearce/egit/core/ignores/DType.java | 44 ++++++
.../src/org/spearce/egit/core/ignores/Exclude.java | 143 ++++++++++++++++----
.../spearce/egit/core/ignores/GitIgnoreData.java | 43 ++++++-
.../egit/core/ignores/IgnoreProjectCache.java | 44 ++++++
.../egit/core/ignores/IgnoreRepositoryCache.java | 68 ++++++++--
.../spearce/egit/core/project/GitProjectData.java | 3 +
org.spearce.jgit/META-INF/MANIFEST.MF | 1 +
7 files changed, 307 insertions(+), 39 deletions(-)
create mode 100644 org.spearce.egit.core/src/org/spearce/egit/core/ignores/DType.java
diff --git a/org.spearce.egit.core/src/org/spearce/egit/core/ignores/DType.java b/org.spearce.egit.core/src/org/spearce/egit/core/ignores/DType.java
new file mode 100644
index 0000000..5661dca
--- /dev/null
+++ b/org.spearce.egit.core/src/org/spearce/egit/core/ignores/DType.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (C) 2009, Ferry Huberts <ferry.huberts@pelagic.nl>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * See LICENSE for the full license text, also available.
+ *******************************************************************************/
+package org.spearce.egit.core.ignores;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+
+/**
+ * This class describes a file type in the same way as git does.
+ *
+ * The git definition can be found in the source file cache.h. The code can be
+ * found in the source file dir.c:get_dtype
+ */
+enum DType {
+ DT_UNKNOWN, DT_DIR, DT_REG, DT_LINK;
+
+ /*
+ * Interface Methods
+ */
+
+ static DType get(final IResource resource) {
+ if (resource == null) {
+ return DT_UNKNOWN;
+ }
+ if (resource instanceof IFile) {
+ return DT_REG;
+ }
+ if ((resource instanceof IFolder) || (resource instanceof IProject)) {
+ return DT_DIR;
+ }
+ if (resource.isLinked()) {
+ return DT_LINK;
+ }
+
+ return DT_UNKNOWN;
+ }
+}
\ No newline at end of file
diff --git a/org.spearce.egit.core/src/org/spearce/egit/core/ignores/Exclude.java b/org.spearce.egit.core/src/org/spearce/egit/core/ignores/Exclude.java
index c4c48e9..eaddd17 100644
--- a/org.spearce.egit.core/src/org/spearce/egit/core/ignores/Exclude.java
+++ b/org.spearce.egit.core/src/org/spearce/egit/core/ignores/Exclude.java
@@ -9,6 +9,9 @@
import java.util.regex.Pattern;
+import org.spearce.jgit.errors.InvalidPatternException;
+import org.spearce.jgit.fnmatch.FileNameMatcher;
+
/**
* This class describes an ignore pattern in the same way as git does, with some
* extra information to support Eclipse specific functionality.
@@ -105,6 +108,110 @@ Exclude(final String pattern, final String base,
}
/*
+ * Interface Methods
+ */
+
+ /**
+ * Tries to match a given resource to the Exclude
+ *
+ * @param pathName
+ * the full path of the resource, relative to the checkout
+ * directory
+ * @param baseName
+ * the baseName of the resource
+ * @param resourceType
+ * the type of the resource
+ * @return true when the resource matches this Exclude, false otherwise
+ *
+ */
+ boolean isMatch(final String pathName, final String baseName,
+ final DType resourceType) {
+ /* this is needed to make the exact same match as git does */
+ String xbase = pathName;
+ final int pos = xbase.lastIndexOf('/');
+ if (pos < 0) {
+ xbase = "";
+ } else {
+ xbase = xbase.substring(0, pos + 1);
+ }
+
+ if (mustBeDir && (resourceType != DType.DT_DIR)) {
+ return false;
+ }
+
+ if (noDir) {
+ /* pattern does not contain directories. dir.c: match basename */
+ if (noWildcard) {
+ /* pattern does not contain directories and has no wildcards */
+ if (baseName.equals(pattern)) {
+ return to_exclude;
+ }
+ } else if (endsWith) {
+ /*
+ * pattern does not contain directories and resource must end
+ * with pattern.substring(1)
+ */
+ if (baseName.endsWith(pattern.substring(1))) {
+ return to_exclude;
+ }
+ } else {
+ /*
+ * pattern does not contain directories, has wildcards, and does
+ * not end with pattern.substring(1)
+ */
+ try {
+ final FileNameMatcher matcher = new FileNameMatcher(
+ pattern, null);
+ matcher.append(baseName);
+ if (matcher.isMatch()) {
+ return to_exclude;
+ }
+ } catch (final InvalidPatternException e) {
+ return false;
+ }
+ }
+ } else {
+ /*
+ * pattern contains directories. dir.c: match with FNM_PATHNAME:
+ * exclude (e.g. 'this.pattern') has base (baselen long) implicitly
+ * in front of it.
+ */
+ final int baselen = base.length();
+ String matchPattern = this.pattern;
+ if (matchPattern.startsWith("/")) {
+ matchPattern = matchPattern.substring(1);
+ }
+
+ if ((pathName.length() < baselen)
+ || ((baselen > 0) && (pathName.charAt(baselen - 1) != '/'))
+ || !pathName.substring(0, baselen).equals(xbase)) {
+ return false;
+ }
+
+ final String remainingResourceName = pathName.substring(baselen);
+ if (noWildcard) {
+ /* pattern contains directories and has no wildcards */
+ if (remainingResourceName.equals(matchPattern)) {
+ return to_exclude;
+ }
+ } else {
+ /* pattern contains directories and has wildcards */
+ try {
+ final FileNameMatcher matcher = new FileNameMatcher(
+ matchPattern, Character.valueOf('/'));
+ matcher.append(remainingResourceName);
+ if (matcher.isMatch()) {
+ return to_exclude;
+ }
+ } catch (final InvalidPatternException e) {
+ return false;
+ }
+ }
+ }
+ return false;
+ }
+
+ /*
* Private Methods
*/
@@ -119,40 +226,18 @@ private boolean no_wildcard(final String string) {
/*
* Getters / Setters
*/
-
- public String getIgnoreFileAbsolutePath() {
- return ignoreFileAbsolutePath;
- }
-
- public int getLineNumber() {
- return lineNumber;
- }
-
- /**
- * @return the base
- */
- public String getBase() {
- return base;
- }
-
- /**
- * @return the noDir
- */
- public boolean isNoDir() {
- return noDir;
- }
-
+
/**
- * @return the endsWith
+ * @return the ignoreFileAbsolutePath
*/
- public boolean isEndsWith() {
- return endsWith;
+ public String getIgnoreFileAbsolutePath() {
+ return ignoreFileAbsolutePath;
}
/**
- * @return the noWildcard
+ * @return the lineNumber
*/
- public boolean isNoWildcard() {
- return noWildcard;
+ public int getLineNumber() {
+ return lineNumber;
}
}
\ No newline at end of file
diff --git a/org.spearce.egit.core/src/org/spearce/egit/core/ignores/GitIgnoreData.java b/org.spearce.egit.core/src/org/spearce/egit/core/ignores/GitIgnoreData.java
index 401a378..48cf454 100644
--- a/org.spearce.egit.core/src/org/spearce/egit/core/ignores/GitIgnoreData.java
+++ b/org.spearce.egit.core/src/org/spearce/egit/core/ignores/GitIgnoreData.java
@@ -14,6 +14,7 @@
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.team.core.Team;
import org.spearce.egit.core.project.RepositoryMapping;
import org.spearce.jgit.lib.Repository;
@@ -128,7 +129,7 @@ public synchronized static void importWorkspaceIgnores() {
* FIXME: also do the file `git config --global --get
* core.excludesfile`, is this already covered? RepositoryConfig
* globalConfig = new RepositoryConfig(null, new File(FS.userHome(),
- * ".gitconfig"));
+ * ".gitconfig")); RepositoryConfig.openUserConfig
*/
/*
@@ -136,4 +137,44 @@ public synchronized static void importWorkspaceIgnores() {
* repositories.toString());
*/
}
+
+ /**
+ * @param resource
+ * the resource to check
+ * @return null when not matched, the matching Exclude otherwise the
+ * resource
+ */
+ synchronized static Exclude isResourceExcluded(final IResource resource) {
+ if (resource == null) {
+ return null;
+ }
+
+ final RepositoryMapping mapping = RepositoryMapping
+ .getMapping(resource);
+ if (mapping == null) {
+ return null;
+ }
+
+ final IgnoreRepositoryCache cache = repositories.get(mapping
+ .getRepository());
+ if (cache == null) {
+ return null;
+ }
+
+ /* FIXME: also check global core.excludesfile, is this already covered? */
+
+ return cache.isIgnored(resource, mapping);
+ }
+
+ /**
+ * @param resource
+ * @return true when the resource is ignored
+ */
+ public synchronized static boolean isIgnored(final IResource resource) {
+ if (isResourceExcluded(resource) != null) {
+ return true;
+ }
+
+ return Team.isIgnoredHint(resource);
+ }
}
diff --git a/org.spearce.egit.core/src/org/spearce/egit/core/ignores/IgnoreProjectCache.java b/org.spearce.egit.core/src/org/spearce/egit/core/ignores/IgnoreProjectCache.java
index fe2f529..7f35240 100644
--- a/org.spearce.egit.core/src/org/spearce/egit/core/ignores/IgnoreProjectCache.java
+++ b/org.spearce.egit.core/src/org/spearce/egit/core/ignores/IgnoreProjectCache.java
@@ -15,6 +15,7 @@
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
/**
* This class implements a cache of ignore patterns for an Eclipse project: it
@@ -198,4 +199,47 @@ synchronized void processIgnoreFile(final IFile ignoreFile,
// break;
// }
}
+
+ synchronized Exclude isIgnored(final String pathName,
+ final String baseName, final DType dType,
+ final IPath deepestDirectory) {
+ IPath searchDir = deepestDirectory;
+ String lookupKey = (searchDir.isEmpty() ? searchDir.toString()
+ : searchDir.toString() + "/");
+ final boolean result = false;
+ searcher: while (!result) {
+ /* look for the first ignore file up in the tree */
+ while (!ignoreFilesIndex.containsKey(lookupKey)) {
+ searchDir = searchDir.removeLastSegments(1);
+ if (searchDir.isEmpty()) {
+ break searcher;
+ }
+ lookupKey = (searchDir.isEmpty() ? searchDir.toString()
+ : searchDir.toString() + "/");
+ }
+ final IFile ignoreFile = ignoreFilesIndex.get(lookupKey);
+
+ /* when found then try to match the resource to those patterns */
+ if (ignoreFile != null) {
+ final LinkedList<Exclude> excludeList = ignoreFiles
+ .get(ignoreFile);
+ for (int i = excludeList.size() - 1; i >= 0; i--) {
+ final Exclude x = excludeList.get(i);
+ if (x.isMatch(pathName, baseName, dType)) {
+ return x;
+ }
+ }
+ }
+
+ if (searchDir.isEmpty()) {
+ break searcher;
+ }
+ searchDir = searchDir.removeLastSegments(1);
+ lookupKey = (searchDir.isEmpty() ? searchDir.toString() : searchDir
+ .toString()
+ + "/");
+ }
+
+ return null;
+ }
}
\ No newline at end of file
diff --git a/org.spearce.egit.core/src/org/spearce/egit/core/ignores/IgnoreRepositoryCache.java b/org.spearce.egit.core/src/org/spearce/egit/core/ignores/IgnoreRepositoryCache.java
index 4b6bf61..9bfb197 100644
--- a/org.spearce.egit.core/src/org/spearce/egit/core/ignores/IgnoreRepositoryCache.java
+++ b/org.spearce.egit.core/src/org/spearce/egit/core/ignores/IgnoreRepositoryCache.java
@@ -35,7 +35,7 @@
/** the repository */
private Repository repository = null;
- /** the checkout directory for the repository */
+ /** the checkout directory for the repository, full path, platform specific */
private String checkoutDir = null;
/** the cache that holds ignore data on a per-project basis */
@@ -59,6 +59,9 @@
/** the core.excludesfile setting */
private String coreExcludesSetting = null;
+ /** the exclude for the repository itself */
+ private Exclude repositoryExclude = null;
+
/**
* Retrieve a project mapping from the projects cache. When the project is
* not yet in the cache then create a new mapping for it and store it in the
@@ -95,6 +98,8 @@ IgnoreRepositoryCache(final Repository repository) {
}
this.repository = repository;
this.checkoutDir = repository.getWorkDir().getAbsolutePath();
+ this.repositoryExclude = new Exclude("/.git/", "", checkoutDir
+ + "/.git/config", 1);
}
/*
@@ -295,14 +300,59 @@ private boolean readRepositoryCoreExcludesSetting() {
return changes;
}
- /*
- * Getters / Setters
- */
+ synchronized Exclude isIgnored(final IResource resource,
+ final RepositoryMapping mapping) {
+ final String pathName = mapping.getRepoRelativePath(resource);
+ IPath deepestDirectory = new Path(pathName).removeLastSegments(1);
+ final String baseName = resource.getName();
+ final DType dType = DType.get(resource);
+
+ /* the repository directory is always ignored */
+ if (this.repositoryExclude.isMatch(pathName, resource.getName(), DType
+ .get(resource))) {
+ return this.repositoryExclude;
+ }
- /**
- * @return the checkoutDir
- */
- public String getCheckoutDir() {
- return checkoutDir;
+ Exclude exclude = null;
+
+ /* check project excludes */
+ final IProject project = resource.getProject();
+ if (project != null) {
+ final IgnoreProjectCache cache = projects.get(project);
+ if (cache != null) {
+ exclude = cache.isIgnored(pathName, baseName, dType,
+ deepestDirectory);
+ if (exclude != null) {
+ return exclude;
+ }
+ }
+ deepestDirectory = new Path(mapping.getRepoRelativePath(project))
+ .removeLastSegments(1);
+ } else {
+ deepestDirectory = new Path("");
+ }
+
+ /* check excludes outside projects */
+ exclude = outside
+ .isIgnored(pathName, baseName, dType, deepestDirectory);
+ if (exclude != null) {
+ return exclude;
+ }
+
+ /* also check info/exclude file per repo */
+ exclude = infoExclude.isIgnored(baseName, baseName, dType,
+ deepestDirectory);
+ if (exclude != null) {
+ return exclude;
+ }
+
+ /* also check core.excludesfile per repo */
+ exclude = coreExcludes.isIgnored(baseName, baseName, dType,
+ deepestDirectory);
+ if (exclude != null) {
+ return exclude;
+ }
+
+ return null;
}
}
\ No newline at end of file
diff --git a/org.spearce.egit.core/src/org/spearce/egit/core/project/GitProjectData.java b/org.spearce.egit.core/src/org/spearce/egit/core/project/GitProjectData.java
index 414bd83..09766b6 100644
--- a/org.spearce.egit.core/src/org/spearce/egit/core/project/GitProjectData.java
+++ b/org.spearce.egit.core/src/org/spearce/egit/core/project/GitProjectData.java
@@ -63,6 +63,9 @@
@SuppressWarnings("synthetic-access")
public void resourceChanged(final IResourceChangeEvent event) {
switch (event.getType()) {
+ case IResourceChangeEvent.POST_CHANGE:
+ // GitIgnoreData.processChangesForIgnores(event);
+ break;
case IResourceChangeEvent.PRE_CLOSE:
uncache((IProject) event.getResource());
GitIgnoreData.uncacheProject(event.getResource());
diff --git a/org.spearce.jgit/META-INF/MANIFEST.MF b/org.spearce.jgit/META-INF/MANIFEST.MF
index 3344c3c..e5f6478 100644
--- a/org.spearce.jgit/META-INF/MANIFEST.MF
+++ b/org.spearce.jgit/META-INF/MANIFEST.MF
@@ -7,6 +7,7 @@ Bundle-Localization: plugin
Bundle-Vendor: %provider_name
Export-Package: org.spearce.jgit.dircache,
org.spearce.jgit.errors;uses:="org.spearce.jgit.lib",
+ org.spearce.jgit.fnmatch,
org.spearce.jgit.lib,
org.spearce.jgit.revplot,
org.spearce.jgit.revwalk,
--
1.6.0.6
next prev parent reply other threads:[~2009-03-26 21:36 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-03-26 21:34 [EGIT] [PATCH RFC v1 0/5] Add (static) ignore functionality to EGit Ferry Huberts
2009-03-26 21:34 ` [EGIT] [PATCH RFC v1 1/5] Build up the ignore patterns cache upon workspace startup Ferry Huberts
2009-03-26 21:34 ` [EGIT] [PATCH RFC v1 2/5] Enable the ignore handling of the plugin Ferry Huberts
2009-03-26 21:34 ` [EGIT] [PATCH RFC v1 3/5] Optimise ignore evaluation Ferry Huberts
2009-03-26 21:34 ` [EGIT] [PATCH RFC v1 4/5] Do not set .git as a Team ignore pattern Ferry Huberts
2009-03-26 21:34 ` Ferry Huberts [this message]
2009-03-29 9:23 ` [EGIT] [PATCH RFC v1 0/5] Add (static) ignore functionality to EGit Robin Rosenberg
2009-03-29 10:43 ` Ferry Huberts (Pelagic)
2009-03-30 4:27 ` Shawn O. Pearce
2009-03-30 0:40 ` Jonathan Gossage
2009-03-30 6:18 ` Robin Rosenberg
2009-04-05 21:02 ` Shawn O. Pearce
2009-04-06 16:46 ` Ferry Huberts (Pelagic)
2009-04-06 16:51 ` Ferry Huberts (Pelagic)
2009-04-06 17:03 ` Shawn O. Pearce
2009-04-06 17:38 ` Sverre Rabbelier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=55baa61ac6caea86a364ddc0421d9422d96f2825.1238102327.git.ferry.huberts@pelagic.nl \
--to=ferry.huberts@pelagic.nl \
--cc=git@vger.kernel.org \
--cc=robin.rosenberg@dewire.com \
--cc=spearce@spearce.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).