summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit')
-rw-r--r--org.eclipse.jgit/.settings/.api_filters14
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNodeProvider.java81
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java57
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java37
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java63
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GlobalAttributesNode.java87
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java80
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java11
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java270
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java88
15 files changed, 722 insertions, 77 deletions
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index ed330b1517..c7a96a2f25 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -14,6 +14,20 @@
</message_arguments>
</filter>
</resource>
+ <resource path="src/org/eclipse/jgit/lib/Repository.java" type="org.eclipse.jgit.lib.Repository">
+ <filter comment="Only implementors of Repository are affected. That should be allowed" id="336695337">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.lib.Repository"/>
+ <message_argument value="createAttributesNodeProvider()"/>
+ </message_arguments>
+ </filter>
+ <filter id="336695337">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.lib.Repository"/>
+ <message_argument value="newAttributesNodeProvider()"/>
+ </message_arguments>
+ </filter>
+ </resource>
<resource path="src/org/eclipse/jgit/transport/PushCertificate.java" type="org.eclipse.jgit.transport.PushCertificate">
<filter comment="PushCertificate wasn't really usable in 4.0" id="338722907">
<message_arguments>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
index de6c32a808..ae297a6438 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
@@ -63,6 +63,7 @@ import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
import org.eclipse.jgit.treewalk.WorkingTreeIterator;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
@@ -139,6 +140,7 @@ public class AddCommand extends GitCommand<DirCache> {
try (ObjectInserter inserter = repo.newObjectInserter();
final TreeWalk tw = new TreeWalk(repo)) {
+ tw.setOperationType(OperationType.CHECKIN_OP);
dc = repo.lockDirCache();
DirCacheIterator c;
@@ -146,6 +148,7 @@ public class AddCommand extends GitCommand<DirCache> {
tw.addTree(new DirCacheBuildIterator(builder));
if (workingTreeIterator == null)
workingTreeIterator = new FileTreeIterator(repo);
+ workingTreeIterator.setDirCacheIterator(tw, 0);
tw.addTree(workingTreeIterator);
tw.setRecursive(true);
if (!addAll)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
index 6174d48d3a..53e18df479 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -86,6 +86,7 @@ import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
import org.eclipse.jgit.util.ChangeIdUtil;
/**
@@ -328,6 +329,7 @@ public class CommitCommand extends GitCommand<RevCommit> {
boolean emptyCommit = true;
try (TreeWalk treeWalk = new TreeWalk(repo)) {
+ treeWalk.setOperationType(OperationType.CHECKIN_OP);
int dcIdx = treeWalk
.addTree(new DirCacheBuildIterator(existingBuilder));
int fIdx = treeWalk.addTree(new FileTreeIterator(repo));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNodeProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNodeProvider.java
new file mode 100644
index 0000000000..6f2ebad677
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNodeProvider.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014, Arthur Daussy <arthur.daussy@obeo.fr>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.attributes;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.lib.CoreConfig;
+
+/**
+ * An interface used to retrieve the global and info {@link AttributesNode}s.
+ *
+ * @since 4.2
+ *
+ */
+public interface AttributesNodeProvider {
+
+ /**
+ * Retrieve the {@link AttributesNode} that holds the information located
+ * in $GIT_DIR/info/attributes file.
+ *
+ * @return the {@link AttributesNode} that holds the information located in
+ * $GIT_DIR/info/attributes file.
+ * @throws IOException
+ * if an error is raised while parsing the attributes file
+ */
+ public AttributesNode getInfoAttributesNode() throws IOException;
+
+ /**
+ * Retrieve the {@link AttributesNode} that holds the information located
+ * in the global gitattributes file.
+ *
+ * @return the {@link AttributesNode} that holds the information located in
+ * the global gitattributes file.
+ * @throws IOException
+ * IOException if an error is raised while parsing the
+ * attributes file
+ * @see CoreConfig#getAttributesFile()
+ */
+ public AttributesNode getGlobalAttributesNode() throws IOException;
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java
new file mode 100644
index 0000000000..8f23a83f78
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.attributes;
+
+import java.util.Map;
+
+/**
+ * Interface for classes which provide git attributes
+ *
+ * @since 4.2
+ */
+public interface AttributesProvider {
+ /**
+ * @return the currently active attributes by attribute key
+ */
+ public Map<String, Attribute> getAttributes();
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
index 6d9a32db92..92cdf391c1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
@@ -76,6 +76,7 @@ import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.IO;
@@ -963,6 +964,7 @@ public class DirCache {
private void updateSmudgedEntries() throws IOException {
List<String> paths = new ArrayList<String>(128);
try (TreeWalk walk = new TreeWalk(repository)) {
+ walk.setOperationType(OperationType.CHECKIN_OP);
for (int i = 0; i < entryCnt; i++)
if (sortedEntries[i].isSmudged())
paths.add(sortedEntries[i].getPathString());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java
index 122f6d3d19..0d5fd0f859 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java
@@ -44,8 +44,13 @@
package org.eclipse.jgit.internal.storage.dfs;
import java.io.IOException;
+import java.io.InputStream;
import java.text.MessageFormat;
+import java.util.Collections;
+import org.eclipse.jgit.attributes.AttributesNode;
+import org.eclipse.jgit.attributes.AttributesNodeProvider;
+import org.eclipse.jgit.attributes.AttributesRule;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.RefUpdate;
@@ -126,4 +131,36 @@ public abstract class DfsRepository extends Repository {
public ReflogReader getReflogReader(String refName) throws IOException {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public AttributesNodeProvider createAttributesNodeProvider() {
+ // TODO Check if the implementation used in FileRepository can be used
+ // for this kind of repository
+ return new EmptyAttributesNodeProvider();
+ }
+
+ private static class EmptyAttributesNodeProvider implements
+ AttributesNodeProvider {
+ private EmptyAttributesNode emptyAttributesNode = new EmptyAttributesNode();
+
+ public AttributesNode getInfoAttributesNode() throws IOException {
+ return emptyAttributesNode;
+ }
+
+ public AttributesNode getGlobalAttributesNode() throws IOException {
+ return emptyAttributesNode;
+ }
+
+ private static class EmptyAttributesNode extends AttributesNode {
+
+ public EmptyAttributesNode() {
+ super(Collections.<AttributesRule> emptyList());
+ }
+
+ @Override
+ public void parse(InputStream in) throws IOException {
+ // Do nothing
+ }
+ }
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
index 995621ee3e..490cbcaa81 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
@@ -49,11 +49,15 @@ package org.eclipse.jgit.internal.storage.file;
import static org.eclipse.jgit.lib.RefDatabase.ALL;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Set;
+import org.eclipse.jgit.attributes.AttributesNode;
+import org.eclipse.jgit.attributes.AttributesNodeProvider;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.events.ConfigChangedEvent;
import org.eclipse.jgit.events.ConfigChangedListener;
@@ -479,4 +483,63 @@ public class FileRepository extends Repository {
return new ReflogReaderImpl(this, ref.getName());
return null;
}
+
+ @Override
+ public AttributesNodeProvider createAttributesNodeProvider() {
+ return new AttributesNodeProviderImpl(this);
+ }
+
+ /**
+ * Implementation a {@link AttributesNodeProvider} for a
+ * {@link FileRepository}.
+ *
+ * @author <a href="mailto:arthur.daussy@obeo.fr">Arthur Daussy</a>
+ *
+ */
+ static class AttributesNodeProviderImpl implements
+ AttributesNodeProvider {
+
+ private AttributesNode infoAttributesNode;
+
+ private AttributesNode globalAttributesNode;
+
+ /**
+ * Constructor.
+ *
+ * @param repo
+ * {@link Repository} that will provide the attribute nodes.
+ */
+ protected AttributesNodeProviderImpl(Repository repo) {
+ infoAttributesNode = new InfoAttributesNode(repo);
+ globalAttributesNode = new GlobalAttributesNode(repo);
+ }
+
+ public AttributesNode getInfoAttributesNode() throws IOException {
+ if (infoAttributesNode instanceof InfoAttributesNode)
+ infoAttributesNode = ((InfoAttributesNode) infoAttributesNode)
+ .load();
+ return infoAttributesNode;
+ }
+
+ public AttributesNode getGlobalAttributesNode() throws IOException {
+ if (globalAttributesNode instanceof GlobalAttributesNode)
+ globalAttributesNode = ((GlobalAttributesNode) globalAttributesNode)
+ .load();
+ return globalAttributesNode;
+ }
+
+ static void loadRulesFromFile(AttributesNode r, File attrs)
+ throws FileNotFoundException, IOException {
+ if (attrs.exists()) {
+ FileInputStream in = new FileInputStream(attrs);
+ try {
+ r.parse(in);
+ } finally {
+ in.close();
+ }
+ }
+ }
+
+ }
+
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GlobalAttributesNode.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GlobalAttributesNode.java
new file mode 100644
index 0000000000..454d3bff69
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GlobalAttributesNode.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014, Arthur Daussy <arthur.daussy@obeo.fr>
+ * Copyright (C) 2015, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.internal.storage.file;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.jgit.attributes.AttributesNode;
+import org.eclipse.jgit.lib.CoreConfig;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.FS;
+
+/** Attribute node loaded from global system-wide file. */
+public class GlobalAttributesNode extends AttributesNode {
+ final Repository repository;
+
+ /**
+ * @param repository
+ */
+ public GlobalAttributesNode(Repository repository) {
+ this.repository = repository;
+ }
+
+ /**
+ * @return the attributes node
+ * @throws IOException
+ */
+ public AttributesNode load() throws IOException {
+ AttributesNode r = new AttributesNode();
+
+ FS fs = repository.getFS();
+ String path = repository.getConfig().get(CoreConfig.KEY)
+ .getAttributesFile();
+ if (path != null) {
+ File attributesFile;
+ if (path.startsWith("~/")) { //$NON-NLS-1$
+ attributesFile = fs.resolve(fs.userHome(),
+ path.substring(2));
+ } else {
+ attributesFile = fs.resolve(null, path);
+ }
+ FileRepository.AttributesNodeProviderImpl.loadRulesFromFile(r, attributesFile);
+ }
+ return r.getRules().isEmpty() ? null : r;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java
new file mode 100644
index 0000000000..eb53434b74
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014, Arthur Daussy <arthur.daussy@obeo.fr>
+ * Copyright (C) 2015, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.internal.storage.file;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.jgit.attributes.AttributesNode;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.FS;
+
+/** Attribute node loaded from the $GIT_DIR/info/attributes file. */
+public class InfoAttributesNode extends AttributesNode {
+ final Repository repository;
+
+ /**
+ * @param repository
+ */
+ public InfoAttributesNode(Repository repository) {
+ this.repository = repository;
+ }
+
+ /**
+ * @return the attributes node
+ * @throws IOException
+ */
+ public AttributesNode load() throws IOException {
+ AttributesNode r = new AttributesNode();
+
+ FS fs = repository.getFS();
+
+ File attributes = fs.resolve(repository.getDirectory(),
+ "info/attributes"); //$NON-NLS-1$
+ FileRepository.AttributesNodeProviderImpl.loadRulesFromFile(r, attributes);
+
+ return r.getRules().isEmpty() ? null : r;
+ }
+
+} \ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
index 3fde2f919b..281cde8750 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
@@ -74,6 +74,7 @@ import org.eclipse.jgit.treewalk.EmptyTreeIterator;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.WorkingTreeIterator;
+import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
import org.eclipse.jgit.treewalk.filter.IndexDiffFilter;
import org.eclipse.jgit.treewalk.filter.SkipWorkTreeFilter;
@@ -403,6 +404,7 @@ public class IndexDiff {
dirCache = repository.readDirCache();
try (TreeWalk treeWalk = new TreeWalk(repository)) {
+ treeWalk.setOperationType(OperationType.CHECKIN_OP);
treeWalk.setRecursive(true);
// add the trees (tree, dirchache, workdir)
if (tree != null)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
index d4c72cb9cb..eda02dea4e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -64,6 +64,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+import org.eclipse.jgit.attributes.AttributesNodeProvider;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.errors.AmbiguousObjectException;
import org.eclipse.jgit.errors.CorruptObjectException;
@@ -210,6 +211,16 @@ public abstract class Repository implements AutoCloseable {
public abstract StoredConfig getConfig();
/**
+ * @return a new {@link AttributesNodeProvider}. This
+ * {@link AttributesNodeProvider} is lazy loaded only once. It means
+ * that it will not be updated after loading. Prefer creating new
+ * instance for each use.
+ * @since 4.2
+ */
+ public abstract AttributesNodeProvider createAttributesNodeProvider();
+
+
+ /**
* @return the used file system abstraction
*/
public FS getFS() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
index 2d6acbddf0..350f563964 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
@@ -96,7 +96,7 @@ public class NameConflictTreeWalk extends TreeWalk {
* the repository the walker will obtain data from.
*/
public NameConflictTreeWalk(final Repository repo) {
- this(repo.newObjectReader());
+ super(repo);
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
index 06e828419d..7f7a5c3938 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
@@ -45,7 +45,17 @@
package org.eclipse.jgit.treewalk;
import java.io.IOException;
-
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.attributes.Attribute;
+import org.eclipse.jgit.attributes.AttributesNode;
+import org.eclipse.jgit.attributes.AttributesNodeProvider;
+import org.eclipse.jgit.attributes.AttributesProvider;
+import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
@@ -82,10 +92,39 @@ import org.eclipse.jgit.util.RawParseUtils;
* Multiple simultaneous TreeWalk instances per {@link Repository} are
* permitted, even from concurrent threads.
*/
-public class TreeWalk implements AutoCloseable {
+public class TreeWalk implements AutoCloseable, AttributesProvider {
private static final AbstractTreeIterator[] NO_TREES = {};
/**
+ * @since 4.2
+ */
+ public static enum OperationType {
+ /**
+ * Represents a checkout operation (for example a checkout or reset
+ * operation).
+ */
+ CHECKOUT_OP,
+
+ /**
+ * Represents a checkin operation (for example an add operation)
+ */
+ CHECKIN_OP
+ }
+
+ /**
+ * Type of operation you want to retrieve the git attributes for.
+ */
+ private OperationType operationType = OperationType.CHECKOUT_OP;
+
+ /**
+ * @param operationType
+ * @since 4.2
+ */
+ public void setOperationType(OperationType operationType) {
+ this.operationType = operationType;
+ }
+
+ /**
* Open a tree walk and filter to exactly one path.
* <p>
* The returned tree walk is already positioned on the requested path, so
@@ -213,8 +252,13 @@ public class TreeWalk implements AutoCloseable {
private boolean postChildren;
+ private AttributesNodeProvider attributesNodeProvider;
+
AbstractTreeIterator currentHead;
+ /** Cached attribute for the current entry */
+ private Map<String, Attribute> attrs = null;
+
/**
* Create a new tree walker for a given repository.
*
@@ -225,6 +269,7 @@ public class TreeWalk implements AutoCloseable {
*/
public TreeWalk(final Repository repo) {
this(repo.newObjectReader(), true);
+ attributesNodeProvider = repo.createAttributesNodeProvider();
}
/**
@@ -356,8 +401,29 @@ public class TreeWalk implements AutoCloseable {
postOrderTraversal = b;
}
+ /**
+ * Sets the {@link AttributesNodeProvider} for this {@link TreeWalk}.
+ * <p>
+ * This is a requirement for a correct computation of the git attributes.
+ * If this {@link TreeWalk} has been built using
+ * {@link #TreeWalk(Repository)} constructor, the
+ * {@link AttributesNodeProvider} has already been set. Indeed,the
+ * {@link Repository} can provide an {@link AttributesNodeProvider} using
+ * {@link Repository#createAttributesNodeProvider()} method. Otherwise you
+ * should provide one.
+ * </p>
+ *
+ * @see Repository#createAttributesNodeProvider()
+ * @param provider
+ * @since 4.2
+ */
+ public void setAttributesNodeProvider(AttributesNodeProvider provider) {
+ attributesNodeProvider = provider;
+ }
+
/** Reset this walker so new tree iterators can be added to it. */
public void reset() {
+ attrs = null;
trees = NO_TREES;
advance = false;
depth = 0;
@@ -401,6 +467,7 @@ public class TreeWalk implements AutoCloseable {
advance = false;
depth = 0;
+ attrs = null;
}
/**
@@ -450,6 +517,7 @@ public class TreeWalk implements AutoCloseable {
trees = r;
advance = false;
depth = 0;
+ attrs = null;
}
/**
@@ -546,6 +614,7 @@ public class TreeWalk implements AutoCloseable {
public boolean next() throws MissingObjectException,
IncorrectObjectTypeException, CorruptObjectException, IOException {
try {
+ attrs = null;
if (advance) {
advance = false;
postChildren = false;
@@ -915,6 +984,7 @@ public class TreeWalk implements AutoCloseable {
*/
public void enterSubtree() throws MissingObjectException,
IncorrectObjectTypeException, CorruptObjectException, IOException {
+ attrs = null;
final AbstractTreeIterator ch = currentHead;
final AbstractTreeIterator[] tmp = new AbstractTreeIterator[trees.length];
for (int i = 0; i < trees.length; i++) {
@@ -1008,4 +1078,200 @@ public class TreeWalk implements AutoCloseable {
static String pathOf(final byte[] buf, int pos, int end) {
return RawParseUtils.decode(Constants.CHARSET, buf, pos, end);
}
+
+ /**
+ * Retrieve the git attributes for the current entry.
+ *
+ * <h4>Git attribute computation</h4>
+ *
+ * <ul>
+ * <li>Get the attributes matching the current path entry from the info file
+ * (see {@link AttributesNodeProvider#getInfoAttributesNode()}).</li>
+ * <li>Completes the list of attributes using the .gitattributes files
+ * located on the current path (the further the directory that contains
+ * .gitattributes is from the path in question, the lower its precedence).
+ * For a checkin operation, it will look first on the working tree (if any).
+ * If there is no attributes file, it will fallback on the index. For a
+ * checkout operation, it will first use the index entry and then fallback
+ * on the working tree if none.</li>
+ * <li>In the end, completes the list of matching attributes using the
+ * global attribute file define in the configuration (see
+ * {@link AttributesNodeProvider#getGlobalAttributesNode()})</li>
+ *
+ * </ul>
+ *
+ *
+ * <h4>Iterator constraints</h4>
+ *
+ * <p>
+ * In order to have a correct list of attributes for the current entry, this
+ * {@link TreeWalk} requires to have at least one
+ * {@link AttributesNodeProvider} and a {@link DirCacheIterator} set up. An
+ * {@link AttributesNodeProvider} is used to retrieve the attributes from
+ * the info attributes file and the global attributes file. The
+ * {@link DirCacheIterator} is used to retrieve the .gitattributes files
+ * stored in the index. A {@link WorkingTreeIterator} can also be provided
+ * to access the local version of the .gitattributes files. If none is
+ * provided it will fallback on the {@link DirCacheIterator}.
+ * </p>
+ *
+ * @return a {@link Set} of {@link Attribute}s that match the current entry.
+ * @since 4.2
+ */
+ public Map<String, Attribute> getAttributes() {
+ if (attrs != null)
+ return attrs;
+
+ if (attributesNodeProvider == null) {
+ // The work tree should have a AttributesNodeProvider to be able to
+ // retrieve the info and global attributes node
+ throw new IllegalStateException(
+ "The tree walk should have one AttributesNodeProvider set in order to compute the git attributes."); //$NON-NLS-1$
+ }
+
+ WorkingTreeIterator workingTreeIterator = getTree(WorkingTreeIterator.class);
+ DirCacheIterator dirCacheIterator = getTree(DirCacheIterator.class);
+
+ if (workingTreeIterator == null && dirCacheIterator == null) {
+ // Can not retrieve the attributes without at least one of the above
+ // iterators.
+ return Collections.<String, Attribute> emptyMap();
+ }
+
+ String path = currentHead.getEntryPathString();
+ final boolean isDir = FileMode.TREE.equals(currentHead.mode);
+ Map<String, Attribute> attributes = new LinkedHashMap<String, Attribute>();
+ try {
+ // Gets the info attributes
+ AttributesNode infoNodeAttr = attributesNodeProvider
+ .getInfoAttributesNode();
+ if (infoNodeAttr != null) {
+ infoNodeAttr.getAttributes(path, isDir, attributes);
+ }
+
+
+ // Gets the attributes located on the current entry path
+ getPerDirectoryEntryAttributes(path, isDir, operationType,
+ workingTreeIterator, dirCacheIterator,
+ attributes);
+
+ // Gets the attributes located in the global attribute file
+ AttributesNode globalNodeAttr = attributesNodeProvider
+ .getGlobalAttributesNode();
+ if (globalNodeAttr != null) {
+ globalNodeAttr.getAttributes(path, isDir, attributes);
+ }
+ } catch (IOException e) {
+ throw new JGitInternalException("Error while parsing attributes", e); //$NON-NLS-1$
+ }
+ return attributes;
+ }
+
+ /**
+ * Get the attributes located on the current entry path.
+ *
+ * @param path
+ * current entry path
+ * @param isDir
+ * holds true if the current entry is a directory
+ * @param opType
+ * type of operation
+ * @param workingTreeIterator
+ * a {@link WorkingTreeIterator} matching the current entry
+ * @param dirCacheIterator
+ * a {@link DirCacheIterator} matching the current entry
+ * @param attributes
+ * Non null map holding the existing attributes. This map will be
+ * augmented with new entry. None entry will be overrided.
+ * @throws IOException
+ * It raises an {@link IOException} if a problem appears while
+ * parsing one on the attributes file.
+ */
+ private void getPerDirectoryEntryAttributes(String path, boolean isDir,
+ OperationType opType, WorkingTreeIterator workingTreeIterator,
+ DirCacheIterator dirCacheIterator, Map<String, Attribute> attributes)
+ throws IOException {
+ // Prevents infinite recurrence
+ if (workingTreeIterator != null || dirCacheIterator != null) {
+ AttributesNode currentAttributesNode = getCurrentAttributesNode(
+ opType, workingTreeIterator, dirCacheIterator);
+ if (currentAttributesNode != null) {
+ currentAttributesNode.getAttributes(path, isDir, attributes);
+ }
+ getPerDirectoryEntryAttributes(path, isDir, opType,
+ getParent(workingTreeIterator, WorkingTreeIterator.class),
+ getParent(dirCacheIterator, DirCacheIterator.class),
+ attributes);
+ }
+ }
+
+ private <T extends AbstractTreeIterator> T getParent(T current,
+ Class<T> type) {
+ if (current != null) {
+ AbstractTreeIterator parent = current.parent;
+ if (type.isInstance(parent)) {
+ return type.cast(parent);
+ }
+ }
+ return null;
+ }
+
+ private <T> T getTree(Class<T> type) {
+ for (int i = 0; i < trees.length; i++) {
+ AbstractTreeIterator tree = trees[i];
+ if (type.isInstance(tree)) {
+ return type.cast(tree);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the {@link AttributesNode} for the current entry.
+ * <p>
+ * This method implements the fallback mechanism between the index and the
+ * working tree depending on the operation type
+ * </p>
+ *
+ * @param opType
+ * @param workingTreeIterator
+ * @param dirCacheIterator
+ * @return a {@link AttributesNode} of the current entry,
+ * {@link NullPointerException} otherwise.
+ * @throws IOException
+ * It raises an {@link IOException} if a problem appears while
+ * parsing one on the attributes file.
+ */
+ private AttributesNode getCurrentAttributesNode(OperationType opType,
+ WorkingTreeIterator workingTreeIterator,
+ DirCacheIterator dirCacheIterator) throws IOException {
+ AttributesNode attributesNode = null;
+ switch (opType) {
+ case CHECKIN_OP:
+ if (workingTreeIterator != null) {
+ attributesNode = workingTreeIterator.getEntryAttributesNode();
+ }
+ if (attributesNode == null && dirCacheIterator != null) {
+ attributesNode = dirCacheIterator
+ .getEntryAttributesNode(getObjectReader());
+ }
+ break;
+ case CHECKOUT_OP:
+ if (dirCacheIterator != null) {
+ attributesNode = dirCacheIterator
+ .getEntryAttributesNode(getObjectReader());
+ }
+ if (attributesNode == null && workingTreeIterator != null) {
+ attributesNode = workingTreeIterator.getEntryAttributesNode();
+ }
+ break;
+ default:
+ throw new IllegalStateException(
+ "The only supported operation types are:" //$NON-NLS-1$
+ + OperationType.CHECKIN_OP + "," //$NON-NLS-1$
+ + OperationType.CHECKOUT_OP);
+ }
+
+ return attributesNode;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
index 73ab04f9cb..e36ce0faf5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -74,6 +74,8 @@ import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.ignore.FastIgnoreRule;
import org.eclipse.jgit.ignore.IgnoreNode;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.file.GlobalAttributesNode;
+import org.eclipse.jgit.internal.storage.file.InfoAttributesNode;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.CoreConfig;
import org.eclipse.jgit.lib.CoreConfig.CheckStat;
@@ -150,14 +152,14 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
* Holds the {@link AttributesNode} that is stored in
* $GIT_DIR/info/attributes file.
*/
- private AttributesNode infoAttributeNode;
+ private AttributesNode infoAttributesNode;
/**
* Holds the {@link AttributesNode} that is stored in global attribute file.
*
* @see CoreConfig#getAttributesFile()
*/
- private AttributesNode globalAttributeNode;
+ private AttributesNode globalAttributesNode;
/**
* Create a new iterator with no parent.
@@ -202,8 +204,8 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
protected WorkingTreeIterator(final WorkingTreeIterator p) {
super(p);
state = p.state;
- infoAttributeNode = p.infoAttributeNode;
- globalAttributeNode = p.globalAttributeNode;
+ infoAttributesNode = p.infoAttributesNode;
+ globalAttributesNode = p.globalAttributesNode;
}
/**
@@ -224,9 +226,9 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
entry = null;
ignoreNode = new RootIgnoreNode(entry, repo);
- infoAttributeNode = new InfoAttributesNode(repo);
+ infoAttributesNode = new InfoAttributesNode(repo);
- globalAttributeNode = new GlobalAttributesNode(repo);
+ globalAttributesNode = new GlobalAttributesNode(repo);
}
/**
@@ -678,9 +680,9 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
* @since 3.7
*/
public AttributesNode getInfoAttributesNode() throws IOException {
- if (infoAttributeNode instanceof InfoAttributesNode)
- infoAttributeNode = ((InfoAttributesNode) infoAttributeNode).load();
- return infoAttributeNode;
+ if (infoAttributesNode instanceof InfoAttributesNode)
+ infoAttributesNode = ((InfoAttributesNode) infoAttributesNode).load();
+ return infoAttributesNode;
}
/**
@@ -696,10 +698,10 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
* @since 3.7
*/
public AttributesNode getGlobalAttributesNode() throws IOException {
- if (globalAttributeNode instanceof GlobalAttributesNode)
- globalAttributeNode = ((GlobalAttributesNode) globalAttributeNode)
+ if (globalAttributesNode instanceof GlobalAttributesNode)
+ globalAttributesNode = ((GlobalAttributesNode) globalAttributesNode)
.load();
- return globalAttributeNode;
+ return globalAttributesNode;
}
private static final Comparator<Entry> ENTRY_CMP = new Comparator<Entry>() {
@@ -1296,68 +1298,6 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
}
}
- /**
- * Attributes node loaded from global system-wide file.
- */
- private static class GlobalAttributesNode extends AttributesNode {
- final Repository repository;
-
- GlobalAttributesNode(Repository repository) {
- this.repository = repository;
- }
-
- AttributesNode load() throws IOException {
- AttributesNode r = new AttributesNode();
-
- FS fs = repository.getFS();
- String path = repository.getConfig().get(CoreConfig.KEY)
- .getAttributesFile();
- if (path != null) {
- File attributesFile;
- if (path.startsWith("~/")) //$NON-NLS-1$
- attributesFile = fs.resolve(fs.userHome(),
- path.substring(2));
- else
- attributesFile = fs.resolve(null, path);
- loadRulesFromFile(r, attributesFile);
- }
- return r.getRules().isEmpty() ? null : r;
- }
- }
-
- /** Magic type indicating there may be rules for the top level. */
- private static class InfoAttributesNode extends AttributesNode {
- final Repository repository;
-
- InfoAttributesNode(Repository repository) {
- this.repository = repository;
- }
-
- AttributesNode load() throws IOException {
- AttributesNode r = new AttributesNode();
-
- FS fs = repository.getFS();
-
- File attributes = fs.resolve(repository.getDirectory(),
- "info/attributes"); //$NON-NLS-1$
- loadRulesFromFile(r, attributes);
-
- return r.getRules().isEmpty() ? null : r;
- }
-
- }
-
- private static void loadRulesFromFile(AttributesNode r, File attrs)
- throws FileNotFoundException, IOException {
- if (attrs.exists()) {
- FileInputStream in = new FileInputStream(attrs);
- try {
- r.parse(in);
- } finally {
- in.close();
- }
- }
- }
private static final class IteratorState {
/** Options used to process the working tree. */