From bbcbcab8d39dd4bdf194cdba02c97a9eb70b2379 Mon Sep 17 00:00:00 2001 From: Terry Parker Date: Mon, 9 Nov 2015 18:55:18 -0800 Subject: Remove PackWriter.Statistics and other deprecated classes These classes make improper use of internal classes in the public API and were replaced by corresponding classes in the JGit 4.1 release. Change-Id: I3d474210e49089aa788314b4e08f505f0d26619b Signed-off-by: Terry Parker --- .../jgit/internal/storage/pack/PackWriter.java | 286 --------------------- .../src/org/eclipse/jgit/transport/UploadPack.java | 40 --- .../eclipse/jgit/transport/UploadPackLogger.java | 75 ------ .../jgit/transport/UploadPackLoggerChain.java | 96 ------- 4 files changed, 497 deletions(-) delete mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java delete mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLoggerChain.java diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java index 19b6b080da..e31f2412c0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java @@ -2057,292 +2057,6 @@ public class PackWriter implements AutoCloseable { return true; } - /** - * Summary of how PackWriter created the pack. - * - * @deprecated Use {@link PackStatistics} instead. - */ - @Deprecated - public static class Statistics { - /** Statistics about a single class of object. */ - public static class ObjectType { - // All requests are forwarded to this object. - private PackStatistics.ObjectType objectType; - - /** - * Wraps an - * {@link org.eclipse.jgit.storage.pack.PackStatistics.ObjectType} - * instance to maintain backwards compatibility with existing API. - * - * @param type - * the wrapped instance - */ - public ObjectType(PackStatistics.ObjectType type) { - objectType = type; - } - - /** - * @return total number of objects output. This total includes the - * value of {@link #getDeltas()}. - */ - public long getObjects() { - return objectType.getObjects(); - } - - /** - * @return total number of deltas output. This may be lower than the - * actual number of deltas if a cached pack was reused. - */ - public long getDeltas() { - return objectType.getDeltas(); - } - - /** - * @return number of objects whose existing representation was - * reused in the output. This count includes - * {@link #getReusedDeltas()}. - */ - public long getReusedObjects() { - return objectType.getReusedObjects(); - } - - /** - * @return number of deltas whose existing representation was reused - * in the output, as their base object was also output or - * was assumed present for a thin pack. This may be lower - * than the actual number of reused deltas if a cached pack - * was reused. - */ - public long getReusedDeltas() { - return objectType.getReusedDeltas(); - } - - /** - * @return total number of bytes written. This size includes the - * object headers as well as the compressed data. This size - * also includes all of {@link #getDeltaBytes()}. - */ - public long getBytes() { - return objectType.getBytes(); - } - - /** - * @return number of delta bytes written. This size includes the - * object headers for the delta objects. - */ - public long getDeltaBytes() { - return objectType.getDeltaBytes(); - } - } - - // All requests are forwarded to this object. - private PackStatistics statistics; - - /** - * Wraps a {@link PackStatistics} object to maintain backwards - * compatibility with existing API. - * - * @param stats - * the wrapped PackStatitics object - */ - public Statistics(PackStatistics stats) { - statistics = stats; - } - - /** - * @return unmodifiable collection of objects to be included in the - * pack. May be null if the pack was hand-crafted in a unit - * test. - */ - public Set getInterestingObjects() { - return statistics.getInterestingObjects(); - } - - /** - * @return unmodifiable collection of objects that should be excluded - * from the pack, as the peer that will receive the pack already - * has these objects. - */ - public Set getUninterestingObjects() { - return statistics.getUninterestingObjects(); - } - - /** - * @return unmodifiable collection of the cached packs that were reused - * in the output, if any were selected for reuse. - */ - public Collection getReusedPacks() { - return statistics.getReusedPacks(); - } - - /** - * @return number of objects in the output pack that went through the - * delta search process in order to find a potential delta base. - */ - public int getDeltaSearchNonEdgeObjects() { - return statistics.getDeltaSearchNonEdgeObjects(); - } - - /** - * @return number of objects in the output pack that went through delta - * base search and found a suitable base. This is a subset of - * {@link #getDeltaSearchNonEdgeObjects()}. - */ - public int getDeltasFound() { - return statistics.getDeltasFound(); - } - - /** - * @return total number of objects output. This total includes the value - * of {@link #getTotalDeltas()}. - */ - public long getTotalObjects() { - return statistics.getTotalObjects(); - } - - /** - * @return the count of objects that needed to be discovered through an - * object walk because they were not found in bitmap indices. - * Returns -1 if no bitmap indices were found. - * - * @since 4.0 - */ - public long getBitmapIndexMisses() { - return statistics.getBitmapIndexMisses(); - } - - /** - * @return total number of deltas output. This may be lower than the - * actual number of deltas if a cached pack was reused. - */ - public long getTotalDeltas() { - return statistics.getTotalDeltas(); - } - - /** - * @return number of objects whose existing representation was reused in - * the output. This count includes {@link #getReusedDeltas()}. - */ - public long getReusedObjects() { - return statistics.getReusedObjects(); - } - - /** - * @return number of deltas whose existing representation was reused in - * the output, as their base object was also output or was - * assumed present for a thin pack. This may be lower than the - * actual number of reused deltas if a cached pack was reused. - */ - public long getReusedDeltas() { - return statistics.getReusedDeltas(); - } - - /** - * @return total number of bytes written. This size includes the pack - * header, trailer, thin pack, and reused cached pack(s). - */ - public long getTotalBytes() { - return statistics.getTotalBytes(); - } - - /** - * @return size of the thin pack in bytes, if a thin pack was generated. - * A thin pack is created when the client already has objects - * and some deltas are created against those objects, or if a - * cached pack is being used and some deltas will reference - * objects in the cached pack. This size does not include the - * pack header or trailer. - */ - public long getThinPackBytes() { - return statistics.getThinPackBytes(); - } - - /** - * @param typeCode - * object type code, e.g. OBJ_COMMIT or OBJ_TREE. - * @return information about this type of object in the pack. - */ - public ObjectType byObjectType(int typeCode) { - return new ObjectType(statistics.byObjectType(typeCode)); - } - - /** @return true if the resulting pack file was a shallow pack. */ - public boolean isShallow() { - return statistics.isShallow(); - } - - /** @return depth (in commits) the pack includes if shallow. */ - public int getDepth() { - return statistics.getDepth(); - } - - /** - * @return time in milliseconds spent enumerating the objects that need - * to be included in the output. This time includes any restarts - * that occur when a cached pack is selected for reuse. - */ - public long getTimeCounting() { - return statistics.getTimeCounting(); - } - - /** - * @return time in milliseconds spent matching existing representations - * against objects that will be transmitted, or that the client - * can be assumed to already have. - */ - public long getTimeSearchingForReuse() { - return statistics.getTimeSearchingForReuse(); - } - - /** - * @return time in milliseconds spent finding the sizes of all objects - * that will enter the delta compression search window. The - * sizes need to be known to better match similar objects - * together and improve delta compression ratios. - */ - public long getTimeSearchingForSizes() { - return statistics.getTimeSearchingForSizes(); - } - - /** - * @return time in milliseconds spent on delta compression. This is - * observed wall-clock time and does not accurately track CPU - * time used when multiple threads were used to perform the - * delta compression. - */ - public long getTimeCompressing() { - return statistics.getTimeCompressing(); - } - - /** - * @return time in milliseconds spent writing the pack output, from - * start of header until end of trailer. The transfer speed can - * be approximated by dividing {@link #getTotalBytes()} by this - * value. - */ - public long getTimeWriting() { - return statistics.getTimeWriting(); - } - - /** @return total time spent processing this pack. */ - public long getTimeTotal() { - return statistics.getTimeTotal(); - } - - /** - * @return get the average output speed in terms of bytes-per-second. - * {@code getTotalBytes() / (getTimeWriting() / 1000.0)}. - */ - public double getTransferRate() { - return statistics.getTransferRate(); - } - - /** @return formatted message string for display to clients. */ - public String getMessage() { - return statistics.getMessage(); - } - } - private class MutableState { /** Estimated size of a single ObjectToPack instance. */ // Assume 64-bit pointers, since this is just an estimate. diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java index 101057fb4f..f9ab56d950 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java @@ -312,8 +312,6 @@ public class UploadPack { private PackStatistics statistics; - private UploadPackLogger logger = UploadPackLogger.NULL; - /** * Create a new pack upload for an open repository. * @@ -585,28 +583,6 @@ public class UploadPack { } } - /** - * @return the configured logger. - * - * @deprecated Use {@link #getPreUploadHook()}. - */ - @Deprecated - public UploadPackLogger getLogger() { - return logger; - } - - /** - * Set the logger. - * - * @param logger - * the logger instance. If null, no logging occurs. - * @deprecated Use {@link #setPreUploadHook(PreUploadHook)}. - */ - @Deprecated - public void setLogger(UploadPackLogger logger) { - this.logger = logger; - } - /** * Check whether the client expects a side-band stream. * @@ -677,21 +653,6 @@ public class UploadPack { } } - /** - * Get the PackWriter's statistics if a pack was sent to the client. - * - * @return statistics about pack output, if a pack was sent. Null if no pack - * was sent, such as during the negotation phase of a smart HTTP - * connection, or if the client was already up-to-date. - * @since 3.0 - * @deprecated Use {@link #getStatistics()}. - */ - @Deprecated - public PackWriter.Statistics getPackStatistics() { - return statistics == null ? null - : new PackWriter.Statistics(statistics); - } - /** * Get the PackWriter's statistics if a pack was sent to the client. * @@ -1547,7 +1508,6 @@ public class UploadPack { statistics = pw.getStatistics(); if (statistics != null) { postUploadHook.onPostUpload(statistics); - logger.onPackStatistics(new PackWriter.Statistics(statistics)); } pw.close(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java deleted file mode 100644 index 85ebecc450..0000000000 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2011, Google Inc. - * 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.transport; - -import org.eclipse.jgit.internal.storage.pack.PackWriter; - -/** - * Logs activity that occurred within {@link UploadPack}. - *

- * Implementors of the interface are responsible for associating the current - * thread to a particular connection, if they need to also include connection - * information. One method is to use a {@link java.lang.ThreadLocal} to remember - * the connection information before invoking UploadPack. - * - * @deprecated use {@link PostUploadHook} instead - */ -@Deprecated -public interface UploadPackLogger { - /** A simple no-op logger. */ - public static final UploadPackLogger NULL = new UploadPackLogger() { - public void onPackStatistics(PackWriter.Statistics stats) { - // Do nothing. - } - }; - - /** - * Notice to the logger after a pack has been sent. - * - * @param stats - * the statistics after sending a pack to the client. - * @since 3.0 - */ - public void onPackStatistics(PackWriter.Statistics stats); -} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLoggerChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLoggerChain.java deleted file mode 100644 index 4ea0319d9c..0000000000 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLoggerChain.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2011, Google Inc. - * 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.transport; - -import java.util.List; - -import org.eclipse.jgit.internal.storage.pack.PackWriter; - -/** - * UploadPackLogger that delegates to a list of other loggers. - *

- * loggers are run in the order passed to the constructor. - * - * @deprecated Use {@link PostUploadHookChain} instead. - */ -@Deprecated -public class UploadPackLoggerChain implements UploadPackLogger { - private final UploadPackLogger[] loggers; - private final int count; - - /** - * Create a new logger chaining the given loggers together. - * - * @param loggers - * loggers to execute, in order. - * @return a new logger chain of the given loggers. - */ - public static UploadPackLogger newChain( - List loggers) { - UploadPackLogger[] newLoggers = new UploadPackLogger[loggers.size()]; - int i = 0; - for (UploadPackLogger logger : loggers) - if (logger != UploadPackLogger.NULL) - newLoggers[i++] = logger; - if (i == 0) - return UploadPackLogger.NULL; - else if (i == 1) - return newLoggers[0]; - else - return new UploadPackLoggerChain(newLoggers, i); - } - - /** - * @since 3.0 - */ - public void onPackStatistics(PackWriter.Statistics stats) { - for (int i = 0; i < count; i++) - loggers[i].onPackStatistics(stats); - } - - private UploadPackLoggerChain(UploadPackLogger[] loggers, int count) { - this.loggers = loggers; - this.count = count; - } -} -- cgit v1.2.3 From 1fa6f3a7509dc937551006e11dfd3bdaea921cd0 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Tue, 10 Nov 2015 20:14:01 -0500 Subject: Revert "Remove PackWriter.Statistics and other deprecated classes" This reverts commit bbcbcab8d39dd4bdf194cdba02c97a9eb70b2379. These classes were part of the public API and should not be removed until JGit 5.0. Change-Id: Ife4bee69f82151de6ef8ea1a4c6c146d91bbf0d5 --- .../jgit/internal/storage/pack/PackWriter.java | 286 +++++++++++++++++++++ .../src/org/eclipse/jgit/transport/UploadPack.java | 40 +++ .../eclipse/jgit/transport/UploadPackLogger.java | 75 ++++++ .../jgit/transport/UploadPackLoggerChain.java | 96 +++++++ 4 files changed, 497 insertions(+) create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLoggerChain.java diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java index e31f2412c0..19b6b080da 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java @@ -2057,6 +2057,292 @@ public class PackWriter implements AutoCloseable { return true; } + /** + * Summary of how PackWriter created the pack. + * + * @deprecated Use {@link PackStatistics} instead. + */ + @Deprecated + public static class Statistics { + /** Statistics about a single class of object. */ + public static class ObjectType { + // All requests are forwarded to this object. + private PackStatistics.ObjectType objectType; + + /** + * Wraps an + * {@link org.eclipse.jgit.storage.pack.PackStatistics.ObjectType} + * instance to maintain backwards compatibility with existing API. + * + * @param type + * the wrapped instance + */ + public ObjectType(PackStatistics.ObjectType type) { + objectType = type; + } + + /** + * @return total number of objects output. This total includes the + * value of {@link #getDeltas()}. + */ + public long getObjects() { + return objectType.getObjects(); + } + + /** + * @return total number of deltas output. This may be lower than the + * actual number of deltas if a cached pack was reused. + */ + public long getDeltas() { + return objectType.getDeltas(); + } + + /** + * @return number of objects whose existing representation was + * reused in the output. This count includes + * {@link #getReusedDeltas()}. + */ + public long getReusedObjects() { + return objectType.getReusedObjects(); + } + + /** + * @return number of deltas whose existing representation was reused + * in the output, as their base object was also output or + * was assumed present for a thin pack. This may be lower + * than the actual number of reused deltas if a cached pack + * was reused. + */ + public long getReusedDeltas() { + return objectType.getReusedDeltas(); + } + + /** + * @return total number of bytes written. This size includes the + * object headers as well as the compressed data. This size + * also includes all of {@link #getDeltaBytes()}. + */ + public long getBytes() { + return objectType.getBytes(); + } + + /** + * @return number of delta bytes written. This size includes the + * object headers for the delta objects. + */ + public long getDeltaBytes() { + return objectType.getDeltaBytes(); + } + } + + // All requests are forwarded to this object. + private PackStatistics statistics; + + /** + * Wraps a {@link PackStatistics} object to maintain backwards + * compatibility with existing API. + * + * @param stats + * the wrapped PackStatitics object + */ + public Statistics(PackStatistics stats) { + statistics = stats; + } + + /** + * @return unmodifiable collection of objects to be included in the + * pack. May be null if the pack was hand-crafted in a unit + * test. + */ + public Set getInterestingObjects() { + return statistics.getInterestingObjects(); + } + + /** + * @return unmodifiable collection of objects that should be excluded + * from the pack, as the peer that will receive the pack already + * has these objects. + */ + public Set getUninterestingObjects() { + return statistics.getUninterestingObjects(); + } + + /** + * @return unmodifiable collection of the cached packs that were reused + * in the output, if any were selected for reuse. + */ + public Collection getReusedPacks() { + return statistics.getReusedPacks(); + } + + /** + * @return number of objects in the output pack that went through the + * delta search process in order to find a potential delta base. + */ + public int getDeltaSearchNonEdgeObjects() { + return statistics.getDeltaSearchNonEdgeObjects(); + } + + /** + * @return number of objects in the output pack that went through delta + * base search and found a suitable base. This is a subset of + * {@link #getDeltaSearchNonEdgeObjects()}. + */ + public int getDeltasFound() { + return statistics.getDeltasFound(); + } + + /** + * @return total number of objects output. This total includes the value + * of {@link #getTotalDeltas()}. + */ + public long getTotalObjects() { + return statistics.getTotalObjects(); + } + + /** + * @return the count of objects that needed to be discovered through an + * object walk because they were not found in bitmap indices. + * Returns -1 if no bitmap indices were found. + * + * @since 4.0 + */ + public long getBitmapIndexMisses() { + return statistics.getBitmapIndexMisses(); + } + + /** + * @return total number of deltas output. This may be lower than the + * actual number of deltas if a cached pack was reused. + */ + public long getTotalDeltas() { + return statistics.getTotalDeltas(); + } + + /** + * @return number of objects whose existing representation was reused in + * the output. This count includes {@link #getReusedDeltas()}. + */ + public long getReusedObjects() { + return statistics.getReusedObjects(); + } + + /** + * @return number of deltas whose existing representation was reused in + * the output, as their base object was also output or was + * assumed present for a thin pack. This may be lower than the + * actual number of reused deltas if a cached pack was reused. + */ + public long getReusedDeltas() { + return statistics.getReusedDeltas(); + } + + /** + * @return total number of bytes written. This size includes the pack + * header, trailer, thin pack, and reused cached pack(s). + */ + public long getTotalBytes() { + return statistics.getTotalBytes(); + } + + /** + * @return size of the thin pack in bytes, if a thin pack was generated. + * A thin pack is created when the client already has objects + * and some deltas are created against those objects, or if a + * cached pack is being used and some deltas will reference + * objects in the cached pack. This size does not include the + * pack header or trailer. + */ + public long getThinPackBytes() { + return statistics.getThinPackBytes(); + } + + /** + * @param typeCode + * object type code, e.g. OBJ_COMMIT or OBJ_TREE. + * @return information about this type of object in the pack. + */ + public ObjectType byObjectType(int typeCode) { + return new ObjectType(statistics.byObjectType(typeCode)); + } + + /** @return true if the resulting pack file was a shallow pack. */ + public boolean isShallow() { + return statistics.isShallow(); + } + + /** @return depth (in commits) the pack includes if shallow. */ + public int getDepth() { + return statistics.getDepth(); + } + + /** + * @return time in milliseconds spent enumerating the objects that need + * to be included in the output. This time includes any restarts + * that occur when a cached pack is selected for reuse. + */ + public long getTimeCounting() { + return statistics.getTimeCounting(); + } + + /** + * @return time in milliseconds spent matching existing representations + * against objects that will be transmitted, or that the client + * can be assumed to already have. + */ + public long getTimeSearchingForReuse() { + return statistics.getTimeSearchingForReuse(); + } + + /** + * @return time in milliseconds spent finding the sizes of all objects + * that will enter the delta compression search window. The + * sizes need to be known to better match similar objects + * together and improve delta compression ratios. + */ + public long getTimeSearchingForSizes() { + return statistics.getTimeSearchingForSizes(); + } + + /** + * @return time in milliseconds spent on delta compression. This is + * observed wall-clock time and does not accurately track CPU + * time used when multiple threads were used to perform the + * delta compression. + */ + public long getTimeCompressing() { + return statistics.getTimeCompressing(); + } + + /** + * @return time in milliseconds spent writing the pack output, from + * start of header until end of trailer. The transfer speed can + * be approximated by dividing {@link #getTotalBytes()} by this + * value. + */ + public long getTimeWriting() { + return statistics.getTimeWriting(); + } + + /** @return total time spent processing this pack. */ + public long getTimeTotal() { + return statistics.getTimeTotal(); + } + + /** + * @return get the average output speed in terms of bytes-per-second. + * {@code getTotalBytes() / (getTimeWriting() / 1000.0)}. + */ + public double getTransferRate() { + return statistics.getTransferRate(); + } + + /** @return formatted message string for display to clients. */ + public String getMessage() { + return statistics.getMessage(); + } + } + private class MutableState { /** Estimated size of a single ObjectToPack instance. */ // Assume 64-bit pointers, since this is just an estimate. diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java index f9ab56d950..101057fb4f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java @@ -312,6 +312,8 @@ public class UploadPack { private PackStatistics statistics; + private UploadPackLogger logger = UploadPackLogger.NULL; + /** * Create a new pack upload for an open repository. * @@ -583,6 +585,28 @@ public class UploadPack { } } + /** + * @return the configured logger. + * + * @deprecated Use {@link #getPreUploadHook()}. + */ + @Deprecated + public UploadPackLogger getLogger() { + return logger; + } + + /** + * Set the logger. + * + * @param logger + * the logger instance. If null, no logging occurs. + * @deprecated Use {@link #setPreUploadHook(PreUploadHook)}. + */ + @Deprecated + public void setLogger(UploadPackLogger logger) { + this.logger = logger; + } + /** * Check whether the client expects a side-band stream. * @@ -653,6 +677,21 @@ public class UploadPack { } } + /** + * Get the PackWriter's statistics if a pack was sent to the client. + * + * @return statistics about pack output, if a pack was sent. Null if no pack + * was sent, such as during the negotation phase of a smart HTTP + * connection, or if the client was already up-to-date. + * @since 3.0 + * @deprecated Use {@link #getStatistics()}. + */ + @Deprecated + public PackWriter.Statistics getPackStatistics() { + return statistics == null ? null + : new PackWriter.Statistics(statistics); + } + /** * Get the PackWriter's statistics if a pack was sent to the client. * @@ -1508,6 +1547,7 @@ public class UploadPack { statistics = pw.getStatistics(); if (statistics != null) { postUploadHook.onPostUpload(statistics); + logger.onPackStatistics(new PackWriter.Statistics(statistics)); } pw.close(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java new file mode 100644 index 0000000000..85ebecc450 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011, Google Inc. + * 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.transport; + +import org.eclipse.jgit.internal.storage.pack.PackWriter; + +/** + * Logs activity that occurred within {@link UploadPack}. + *

+ * Implementors of the interface are responsible for associating the current + * thread to a particular connection, if they need to also include connection + * information. One method is to use a {@link java.lang.ThreadLocal} to remember + * the connection information before invoking UploadPack. + * + * @deprecated use {@link PostUploadHook} instead + */ +@Deprecated +public interface UploadPackLogger { + /** A simple no-op logger. */ + public static final UploadPackLogger NULL = new UploadPackLogger() { + public void onPackStatistics(PackWriter.Statistics stats) { + // Do nothing. + } + }; + + /** + * Notice to the logger after a pack has been sent. + * + * @param stats + * the statistics after sending a pack to the client. + * @since 3.0 + */ + public void onPackStatistics(PackWriter.Statistics stats); +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLoggerChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLoggerChain.java new file mode 100644 index 0000000000..4ea0319d9c --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLoggerChain.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2011, Google Inc. + * 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.transport; + +import java.util.List; + +import org.eclipse.jgit.internal.storage.pack.PackWriter; + +/** + * UploadPackLogger that delegates to a list of other loggers. + *

+ * loggers are run in the order passed to the constructor. + * + * @deprecated Use {@link PostUploadHookChain} instead. + */ +@Deprecated +public class UploadPackLoggerChain implements UploadPackLogger { + private final UploadPackLogger[] loggers; + private final int count; + + /** + * Create a new logger chaining the given loggers together. + * + * @param loggers + * loggers to execute, in order. + * @return a new logger chain of the given loggers. + */ + public static UploadPackLogger newChain( + List loggers) { + UploadPackLogger[] newLoggers = new UploadPackLogger[loggers.size()]; + int i = 0; + for (UploadPackLogger logger : loggers) + if (logger != UploadPackLogger.NULL) + newLoggers[i++] = logger; + if (i == 0) + return UploadPackLogger.NULL; + else if (i == 1) + return newLoggers[0]; + else + return new UploadPackLoggerChain(newLoggers, i); + } + + /** + * @since 3.0 + */ + public void onPackStatistics(PackWriter.Statistics stats) { + for (int i = 0; i < count; i++) + loggers[i].onPackStatistics(stats); + } + + private UploadPackLoggerChain(UploadPackLogger[] loggers, int count) { + this.loggers = loggers; + this.count = count; + } +} -- cgit v1.2.3 From 797f94d3319a6bea2cacce707a6a5ee67f00ea17 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Tue, 10 Nov 2015 15:11:04 -0800 Subject: RefDirectory.exactRef: Do not ignore symrefs to unborn branch When asked to read a symref pointing to a branch-yet-to-be-born (such as HEAD in a newly initialized repository), DfsRepository and FileRepository return different results. FileRepository: exactRef("HEAD") => null DfsRepository: exactRef("HEAD") => SymbolicRef[HEAD -> refs/heads/master=00000000] getRef("HEAD") returns the same as DfsRepository's exactRef in both backends. The intended behavior is the DfsRepository one: exactRef() is supposed to be like getRef(), but more exact because it doesn't need to traverse the search path. The discrepancy is because DfsRefDatabase implements exactRef() directly with the intended semantics, while RefDirectory uses a fallback implementation built on top of getRefs(). getRefs() skips symrefs to an unborn branch. Override the fallback implementation with a correct implementation that is similar to getRef() to avoid this. A followup change will fix the fallback. Change-Id: Ic138a5564a099ebf32248d86b93e2de9ab3c94ee Reported-by: David Pursehouse Improved-by: Christian Halstrick Bug: 478865 --- .../internal/storage/file/RefDirectoryTest.java | 19 +++++++++++++++++ .../jgit/internal/storage/file/RefDirectory.java | 24 ++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java index 0991598920..d66753da08 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java @@ -1024,6 +1024,25 @@ public class RefDirectoryTest extends LocalDiskRepositoryTestCase { assertNull(refdir.getRef("v1.0")); } + @Test + public void testExactRef_EmptyDatabase() throws IOException { + Ref r; + + r = refdir.exactRef(HEAD); + assertTrue(r.isSymbolic()); + assertSame(LOOSE, r.getStorage()); + assertEquals("refs/heads/master", r.getTarget().getName()); + assertSame(NEW, r.getTarget().getStorage()); + assertNull(r.getTarget().getObjectId()); + + assertNull(refdir.exactRef("refs/heads/master")); + assertNull(refdir.exactRef("refs/tags/v1.0")); + assertNull(refdir.exactRef("FETCH_HEAD")); + assertNull(refdir.exactRef("NOT.A.REF.NAME")); + assertNull(refdir.exactRef("master")); + assertNull(refdir.exactRef("v1.0")); + } + @Test public void testGetRef_FetchHead() throws IOException { // This is an odd special case where we need to make sure we read diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java index 6a04a538ef..bb5b044405 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java @@ -261,6 +261,30 @@ public class RefDirectory extends RefDatabase { return loose; } + @Override + public Ref exactRef(String name) throws IOException { + RefList packed = getPackedRefs(); + Ref ref; + try { + ref = readRef(name, packed); + if (ref != null) { + ref = resolve(ref, 0, null, null, packed); + } + } catch (IOException e) { + if (name.contains("/") //$NON-NLS-1$ + || !(e.getCause() instanceof InvalidObjectIdException)) { + throw e; + } + + // While looking for a ref outside of refs/ (e.g., 'config'), we + // found a non-ref file (e.g., a config file) instead. Treat this + // as a ref-not-found condition. + ref = null; + } + fireRefsChanged(); + return ref; + } + @Override public Ref getRef(final String needle) throws IOException { final RefList packed = getPackedRefs(); -- cgit v1.2.3 From e18444de30f1f019b5f7f0a463da42a884cb6a9a Mon Sep 17 00:00:00 2001 From: RĂ¼diger Herrmann Date: Thu, 12 Nov 2015 15:54:13 +0100 Subject: Fix MissingObjectException in RenameDetector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When attempting to determine the size of a blob that does not exist, the RenameDetector throws a MissingObjectException. The fix is to return a size of zero if the size is requested for a blob id that doesn't exist. Bug: 481577 Change-Id: I4e86276039c630617610cc51d0eefa56d7d3952f Signed-off-by: RĂ¼diger Herrmann --- .../org/eclipse/jgit/diff/RenameDetectorTest.java | 31 ++++++++++++++++++++++ .../src/org/eclipse/jgit/diff/ContentSource.java | 6 ++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java index e83ef772ff..4315be9e49 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java @@ -48,6 +48,7 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.util.Arrays; import java.util.List; import org.eclipse.jgit.diff.DiffEntry.ChangeType; @@ -226,6 +227,19 @@ public class RenameDetectorTest extends RepositoryTestCase { assertCopy(d, b, 100, entries.get(2)); } + @Test + public void testExactRename_UnstagedFile() throws Exception { + ObjectId aId = blob("foo"); + DiffEntry a = DiffEntry.delete(PATH_A, aId); + DiffEntry b = DiffEntry.add(PATH_B, aId); + + rd.addAll(Arrays.asList(a, b)); + List entries = rd.compute(); + + assertEquals(1, entries.size()); + assertRename(a, b, 100, entries.get(0)); + } + @Test public void testInexactRename_OnePair() throws Exception { ObjectId aId = blob("foo\nbar\nbaz\nblarg\n"); @@ -429,6 +443,23 @@ public class RenameDetectorTest extends RepositoryTestCase { assertSame(b, entries.get(1)); } + @Test + public void testNoRenames_UntrackedFile() throws Exception { + ObjectId aId = blob("foo"); + ObjectId bId = ObjectId + .fromString("3049eb6eee7e1318f4e78e799bf33f1e54af9cbf"); + + DiffEntry a = DiffEntry.delete(PATH_A, aId); + DiffEntry b = DiffEntry.add(PATH_B, bId); + + rd.addAll(Arrays.asList(a, b)); + List entries = rd.compute(); + + assertEquals(2, entries.size()); + assertSame(a, entries.get(0)); + assertSame(b, entries.get(1)); + } + @Test public void testBreakModify_BreakAll() throws Exception { ObjectId aId = blob("foo"); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java index 0dc4b05787..444ab1cb83 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java @@ -132,7 +132,11 @@ public abstract class ContentSource { @Override public long size(String path, ObjectId id) throws IOException { - return reader.getObjectSize(id, Constants.OBJ_BLOB); + try { + return reader.getObjectSize(id, Constants.OBJ_BLOB); + } catch (MissingObjectException ignore) { + return 0; + } } @Override -- cgit v1.2.3 From 7dcb50a04a03a96e7514a8598eaf9bb052af867e Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Wed, 11 Nov 2015 10:42:46 -0800 Subject: Fallback exactRef: Do not ignore symrefs to unborn branch When asked to read a symref pointing to a branch-yet-to-be-born (such as HEAD in a newly initialized repository), getRef and getRefs provide different results. getRef: SymbolicRef[HEAD -> refs/heads/master=00000000] getRefs and getAdditionalRefs: nothing exactRef should match the getRef behavior: it is meant to be a simpler, faster version of getRef that lets you search for a ref without resolving it using the search path without other semantic changes. But the fallback implementation of exactRef relies on getRefs and produces null for this case. Luckily the in-tree RefDatabase implementations override exactRef and get the correct behavior. But any out-of-tree storage backend that doesn't inherit from DfsRefDatabase or RefDirectory would still return null when it shouldn't. Let the fallback implementation use getRef instead to avoid this. This means that exactRef would waste some effort traversing the ref search path when the named ref is not found --- but subclasses tend to override exactRef for performance already, so in the default implementation correctness is more important. Bug: 478865 Change-Id: I60f04e3ce3bf4731640ffd2433d329e621330029 --- .../src/org/eclipse/jgit/lib/RefDatabase.java | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java index ef22fb90fe..b62033cbd2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java @@ -239,20 +239,11 @@ public abstract class RefDatabase { * @since 4.1 */ public Ref exactRef(String name) throws IOException { - int slash = name.lastIndexOf('/'); - String prefix = name.substring(0, slash + 1); - String rest = name.substring(slash + 1); - Ref result = getRefs(prefix).get(rest); - if (result != null || slash != -1) { - return result; + Ref ref = getRef(name); + if (ref == null || !name.equals(ref.getName())) { + return null; } - - for (Ref ref : getAdditionalRefs()) { - if (name.equals(ref.getName())) { - return ref; - } - } - return null; + return ref; } /** -- cgit v1.2.3 From 3cb5f113982f4ba75f6720cf7428f82b61cd3a32 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Sat, 14 Nov 2015 00:09:54 +0100 Subject: JGit v4.1.1.201511131810-r Change-Id: If0246daab39fa279c30874549b198e7aa917bc62 Signed-off-by: Matthias Sohn --- org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF | 2 +- org.eclipse.jgit.ant.test/pom.xml | 2 +- org.eclipse.jgit.ant/META-INF/MANIFEST.MF | 2 +- org.eclipse.jgit.ant/pom.xml | 2 +- org.eclipse.jgit.archive/META-INF/MANIFEST.MF | 2 +- org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF | 4 ++-- org.eclipse.jgit.archive/pom.xml | 2 +- org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF | 2 +- org.eclipse.jgit.http.apache/pom.xml | 2 +- org.eclipse.jgit.http.server/META-INF/MANIFEST.MF | 2 +- org.eclipse.jgit.http.server/pom.xml | 2 +- org.eclipse.jgit.http.test/META-INF/MANIFEST.MF | 2 +- org.eclipse.jgit.http.test/pom.xml | 2 +- org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF | 2 +- org.eclipse.jgit.junit.http/pom.xml | 2 +- org.eclipse.jgit.junit/META-INF/MANIFEST.MF | 2 +- org.eclipse.jgit.junit/pom.xml | 2 +- org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml | 2 +- org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml | 2 +- .../org.eclipse.jgit.http.apache.feature/feature.xml | 2 +- .../org.eclipse.jgit.http.apache.feature/pom.xml | 2 +- org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml | 2 +- org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml | 2 +- org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml | 2 +- org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml | 2 +- .../org.eclipse.jgit.pgm.source.feature/feature.xml | 2 +- .../org.eclipse.jgit.pgm.source.feature/pom.xml | 2 +- org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml | 2 +- .../org.eclipse.jgit.source.feature/feature.xml | 2 +- org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml | 2 +- .../org.eclipse.jgit.target/META-INF/MANIFEST.MF | 2 +- org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml | 2 +- org.eclipse.jgit.packaging/pom.xml | 2 +- org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF | 2 +- org.eclipse.jgit.pgm.test/pom.xml | 2 +- org.eclipse.jgit.pgm/META-INF/MANIFEST.MF | 2 +- org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF | 4 ++-- org.eclipse.jgit.pgm/pom.xml | 2 +- org.eclipse.jgit.test/META-INF/MANIFEST.MF | 2 +- org.eclipse.jgit.test/pom.xml | 2 +- org.eclipse.jgit.ui/META-INF/MANIFEST.MF | 2 +- org.eclipse.jgit.ui/pom.xml | 2 +- org.eclipse.jgit/META-INF/MANIFEST.MF | 2 +- org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF | 4 ++-- org.eclipse.jgit/pom.xml | 2 +- pom.xml | 2 +- 46 files changed, 49 insertions(+), 49 deletions(-) diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF index 1ce2ec27f7..e216612e3c 100644 --- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.ant.test -Bundle-Version: 4.1.1.qualifier +Bundle-Version: 4.1.1.201511131810-r Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Import-Package: org.apache.tools.ant, diff --git a/org.eclipse.jgit.ant.test/pom.xml b/org.eclipse.jgit.ant.test/pom.xml index ff1ec8335c..9e6c7d67a1 100644 --- a/org.eclipse.jgit.ant.test/pom.xml +++ b/org.eclipse.jgit.ant.test/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.ant.test diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF index d9fbd76142..0e9ede4f11 100644 --- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: org.eclipse.jgit.ant -Bundle-Version: 4.1.1.qualifier +Bundle-Version: 4.1.1.201511131810-r Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Import-Package: org.apache.tools.ant, org.eclipse.jgit.storage.file;version="[4.1.1,4.2.0)" diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml index 00351b9019..2b03847c54 100644 --- a/org.eclipse.jgit.ant/pom.xml +++ b/org.eclipse.jgit.ant/pom.xml @@ -48,7 +48,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.ant diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF index 0d073188c8..c3f51e9804 100644 --- a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.archive -Bundle-Version: 4.1.1.qualifier +Bundle-Version: 4.1.1.201511131810-r Bundle-Vendor: %provider_name Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-1.7 diff --git a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF index 743fe11f0d..dbb6473661 100644 --- a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.archive - Sources Bundle-SymbolicName: org.eclipse.jgit.archive.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 4.1.1.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.1.1.qualifier";roots="." +Bundle-Version: 4.1.1.201511131810-r +Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.1.1.201511131810-r";roots="." diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml index 65e87aa681..1a4dcabeaa 100644 --- a/org.eclipse.jgit.archive/pom.xml +++ b/org.eclipse.jgit.archive/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.archive diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF index 107dc84496..6036cafbd8 100644 --- a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: org.eclipse.jgit.http.apache -Bundle-Version: 4.1.1.qualifier +Bundle-Version: 4.1.1.201511131810-r Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Bundle-Localization: plugin Bundle-Vendor: %Provider-Name diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml index f8b29ed4e7..0bf73b7962 100644 --- a/org.eclipse.jgit.http.apache/pom.xml +++ b/org.eclipse.jgit.http.apache/pom.xml @@ -48,7 +48,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.http.apache diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF index 90c15fc599..e19980b57f 100644 --- a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.http.server -Bundle-Version: 4.1.1.qualifier +Bundle-Version: 4.1.1.201511131810-r Bundle-Localization: plugin Bundle-Vendor: %provider_name Export-Package: org.eclipse.jgit.http.server;version="4.1.1", diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml index a487bd3523..17ce3da128 100644 --- a/org.eclipse.jgit.http.server/pom.xml +++ b/org.eclipse.jgit.http.server/pom.xml @@ -52,7 +52,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.http.server diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF index 8aaeeb0324..d167da39f5 100644 --- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.http.test -Bundle-Version: 4.1.1.qualifier +Bundle-Version: 4.1.1.201511131810-r Bundle-Vendor: %provider_name Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-1.7 diff --git a/org.eclipse.jgit.http.test/pom.xml b/org.eclipse.jgit.http.test/pom.xml index 33a0f6d677..237f2267b6 100644 --- a/org.eclipse.jgit.http.test/pom.xml +++ b/org.eclipse.jgit.http.test/pom.xml @@ -51,7 +51,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.http.test diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF index 5f25bf1946..f669a1790a 100644 --- a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.junit.http -Bundle-Version: 4.1.1.qualifier +Bundle-Version: 4.1.1.201511131810-r Bundle-Localization: plugin Bundle-Vendor: %provider_name Bundle-ActivationPolicy: lazy diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml index 524afd6642..d1e09c32ab 100644 --- a/org.eclipse.jgit.junit.http/pom.xml +++ b/org.eclipse.jgit.junit.http/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.junit.http diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF index 48b8b12fe3..31c2304b72 100644 --- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.junit -Bundle-Version: 4.1.1.qualifier +Bundle-Version: 4.1.1.201511131810-r Bundle-Localization: plugin Bundle-Vendor: %provider_name Bundle-ActivationPolicy: lazy diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml index d231bc1a2f..b4d4d27f4a 100644 --- a/org.eclipse.jgit.junit/pom.xml +++ b/org.eclipse.jgit.junit/pom.xml @@ -52,7 +52,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.junit diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml index bfd343b0c1..7cf81353f8 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml index 5bd71f7345..849f7bbfa8 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.feature diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml index bb766ac238..8544d1a2bb 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml index 8dc47d0f9d..060ad0e6fb 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.feature diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml index e28eac537b..752f0444e0 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml index 99dd9bcb87..3ed76d3840 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.feature diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml index f66c089341..a6f0a4c047 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml index f078da6ec2..438173beaa 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.feature diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml index 7a511cbfa5..61070bff19 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml index a1d785d06f..3754fd6c91 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.feature diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml index 5e1ff48496..72da41c7e3 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.repository diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml index bfc552c3e9..09ee4c4782 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml index dcc51618b0..50816beaa9 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.feature diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF index 68b25b83d0..1d3c436e9f 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF @@ -2,4 +2,4 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: JGit Target Platform Bundle Bundle-SymbolicName: org.eclipse.jgit.target -Bundle-Version: 4.1.1.qualifier +Bundle-Version: 4.1.1.201511131810-r diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml index 11ae4e9a24..e95377f947 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml @@ -49,7 +49,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.target diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml index 1744cf2470..64750ec375 100644 --- a/org.eclipse.jgit.packaging/pom.xml +++ b/org.eclipse.jgit.packaging/pom.xml @@ -53,7 +53,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r pom JGit Tycho Parent diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF index 01ebb45639..5b9a115343 100644 --- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.pgm.test -Bundle-Version: 4.1.1.qualifier +Bundle-Version: 4.1.1.201511131810-r Bundle-Vendor: %provider_name Bundle-Localization: plugin Bundle-ActivationPolicy: lazy diff --git a/org.eclipse.jgit.pgm.test/pom.xml b/org.eclipse.jgit.pgm.test/pom.xml index 873bcde976..acfe6009f1 100644 --- a/org.eclipse.jgit.pgm.test/pom.xml +++ b/org.eclipse.jgit.pgm.test/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.pgm.test diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF index 62fcb68a68..30db7a84fa 100644 --- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.pgm -Bundle-Version: 4.1.1.qualifier +Bundle-Version: 4.1.1.201511131810-r Bundle-Vendor: %provider_name Bundle-ActivationPolicy: lazy Bundle-Localization: plugin diff --git a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF index 7f815943a6..dfc5ab9a97 100644 --- a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.pgm - Sources Bundle-SymbolicName: org.eclipse.jgit.pgm.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 4.1.1.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.1.1.qualifier";roots="." +Bundle-Version: 4.1.1.201511131810-r +Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.1.1.201511131810-r";roots="." diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml index 0007d0417c..2c2e55de6d 100644 --- a/org.eclipse.jgit.pgm/pom.xml +++ b/org.eclipse.jgit.pgm/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.pgm diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF index 3b67921b78..9d25fca29b 100644 --- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.test -Bundle-Version: 4.1.1.qualifier +Bundle-Version: 4.1.1.201511131810-r Bundle-Localization: plugin Bundle-Vendor: %provider_name Bundle-ActivationPolicy: lazy diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml index d1a5a46b3c..2385d27f9c 100644 --- a/org.eclipse.jgit.test/pom.xml +++ b/org.eclipse.jgit.test/pom.xml @@ -52,7 +52,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.test diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF index b7f44277fe..a9cedc091f 100644 --- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.ui -Bundle-Version: 4.1.1.qualifier +Bundle-Version: 4.1.1.201511131810-r Bundle-Vendor: %provider_name Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Export-Package: org.eclipse.jgit.awtui;version="4.1.1" diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml index a7a1992aba..d64de32437 100644 --- a/org.eclipse.jgit.ui/pom.xml +++ b/org.eclipse.jgit.ui/pom.xml @@ -52,7 +52,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit.ui diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF index 43be20db19..a10e6d6ee0 100644 --- a/org.eclipse.jgit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit -Bundle-Version: 4.1.1.qualifier +Bundle-Version: 4.1.1.201511131810-r Bundle-Localization: plugin Bundle-Vendor: %provider_name Bundle-ActivationPolicy: lazy diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF index 07480e3c27..83b239cadc 100644 --- a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit - Sources Bundle-SymbolicName: org.eclipse.jgit.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 4.1.1.qualifier -Eclipse-SourceBundle: org.eclipse.jgit;version="4.1.1.qualifier";roots="." +Bundle-Version: 4.1.1.201511131810-r +Eclipse-SourceBundle: org.eclipse.jgit;version="4.1.1.201511131810-r";roots="." diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml index 52c702faaf..8757940621 100644 --- a/org.eclipse.jgit/pom.xml +++ b/org.eclipse.jgit/pom.xml @@ -53,7 +53,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r org.eclipse.jgit diff --git a/pom.xml b/pom.xml index 5f911c6ba4..a899784773 100644 --- a/pom.xml +++ b/pom.xml @@ -51,7 +51,7 @@ org.eclipse.jgit org.eclipse.jgit-parent pom - 4.1.1-SNAPSHOT + 4.1.1.201511131810-r JGit - Parent ${jgit-url} -- cgit v1.2.3 From 3e2aff196e4f20183c13fd0c219101b6604477e8 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Sat, 14 Nov 2015 00:53:45 +0100 Subject: Prepare 4.1.2-SNAPSHOT builds Change-Id: I1d1c4d918f2260c866c4392c1abea1e40a1de962 Signed-off-by: Matthias Sohn --- org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF | 12 ++-- org.eclipse.jgit.ant.test/pom.xml | 2 +- org.eclipse.jgit.ant/META-INF/MANIFEST.MF | 6 +- org.eclipse.jgit.ant/pom.xml | 2 +- org.eclipse.jgit.archive/META-INF/MANIFEST.MF | 12 ++-- .../META-INF/SOURCE-MANIFEST.MF | 4 +- org.eclipse.jgit.archive/pom.xml | 2 +- org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF | 10 +-- org.eclipse.jgit.http.apache/pom.xml | 2 +- org.eclipse.jgit.http.server/META-INF/MANIFEST.MF | 26 +++---- org.eclipse.jgit.http.server/pom.xml | 2 +- org.eclipse.jgit.http.test/META-INF/MANIFEST.MF | 36 +++++----- org.eclipse.jgit.http.test/pom.xml | 2 +- org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF | 20 +++--- org.eclipse.jgit.junit.http/pom.xml | 2 +- org.eclipse.jgit.junit/META-INF/MANIFEST.MF | 32 ++++----- org.eclipse.jgit.junit/pom.xml | 2 +- .../org.eclipse.jgit.feature/feature.xml | 2 +- .../org.eclipse.jgit.feature/pom.xml | 2 +- .../feature.xml | 2 +- .../org.eclipse.jgit.http.apache.feature/pom.xml | 2 +- .../org.eclipse.jgit.junit.feature/feature.xml | 2 +- .../org.eclipse.jgit.junit.feature/pom.xml | 2 +- .../org.eclipse.jgit.pgm.feature/feature.xml | 2 +- .../org.eclipse.jgit.pgm.feature/pom.xml | 2 +- .../feature.xml | 2 +- .../org.eclipse.jgit.pgm.source.feature/pom.xml | 2 +- .../org.eclipse.jgit.repository/pom.xml | 2 +- .../org.eclipse.jgit.source.feature/feature.xml | 2 +- .../org.eclipse.jgit.source.feature/pom.xml | 2 +- .../org.eclipse.jgit.target/META-INF/MANIFEST.MF | 2 +- .../org.eclipse.jgit.target/pom.xml | 2 +- org.eclipse.jgit.packaging/pom.xml | 2 +- org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF | 34 ++++----- org.eclipse.jgit.pgm.test/pom.xml | 2 +- org.eclipse.jgit.pgm/META-INF/MANIFEST.MF | 64 ++++++++--------- org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF | 4 +- org.eclipse.jgit.pgm/pom.xml | 2 +- org.eclipse.jgit.test/META-INF/MANIFEST.MF | 80 +++++++++++----------- org.eclipse.jgit.test/pom.xml | 2 +- org.eclipse.jgit.ui/META-INF/MANIFEST.MF | 18 ++--- org.eclipse.jgit.ui/pom.xml | 2 +- org.eclipse.jgit/META-INF/MANIFEST.MF | 74 ++++++++++---------- org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF | 4 +- org.eclipse.jgit/pom.xml | 2 +- pom.xml | 2 +- 46 files changed, 248 insertions(+), 248 deletions(-) diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF index e216612e3c..8f5d0b90d3 100644 --- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF @@ -3,14 +3,14 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.ant.test -Bundle-Version: 4.1.1.201511131810-r +Bundle-Version: 4.1.2.qualifier Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Import-Package: org.apache.tools.ant, - org.eclipse.jgit.ant.tasks;version="[4.1.1,4.2.0)", - org.eclipse.jgit.internal.storage.file;version="[4.1.1,4.2.0)", - org.eclipse.jgit.junit;version="[4.1.1,4.2.0)", - org.eclipse.jgit.lib;version="[4.1.1,4.2.0)", - org.eclipse.jgit.util;version="[4.1.1,4.2.0)", + org.eclipse.jgit.ant.tasks;version="[4.1.2,4.2.0)", + org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)", + org.eclipse.jgit.junit;version="[4.1.2,4.2.0)", + org.eclipse.jgit.lib;version="[4.1.2,4.2.0)", + org.eclipse.jgit.util;version="[4.1.2,4.2.0)", org.hamcrest;version="[1.1.0,2.0.0)", org.junit;version="[4.0.0,5.0.0)" diff --git a/org.eclipse.jgit.ant.test/pom.xml b/org.eclipse.jgit.ant.test/pom.xml index 9e6c7d67a1..a514e3dbc5 100644 --- a/org.eclipse.jgit.ant.test/pom.xml +++ b/org.eclipse.jgit.ant.test/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.ant.test diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF index 0e9ede4f11..4986f0fbb0 100644 --- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF @@ -2,11 +2,11 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: org.eclipse.jgit.ant -Bundle-Version: 4.1.1.201511131810-r +Bundle-Version: 4.1.2.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Import-Package: org.apache.tools.ant, - org.eclipse.jgit.storage.file;version="[4.1.1,4.2.0)" + org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)" Bundle-Localization: plugin Bundle-Vendor: %Provider-Name -Export-Package: org.eclipse.jgit.ant.tasks;version="4.1.1"; +Export-Package: org.eclipse.jgit.ant.tasks;version="4.1.2"; uses:="org.apache.tools.ant.types,org.apache.tools.ant" diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml index 2b03847c54..cb0fcb0a17 100644 --- a/org.eclipse.jgit.ant/pom.xml +++ b/org.eclipse.jgit.ant/pom.xml @@ -48,7 +48,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.ant diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF index c3f51e9804..4b1e81d40d 100644 --- a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.archive -Bundle-Version: 4.1.1.201511131810-r +Bundle-Version: 4.1.2.qualifier Bundle-Vendor: %provider_name Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-1.7 @@ -12,14 +12,14 @@ Import-Package: org.apache.commons.compress.archivers;version="[1.4,2.0)", org.apache.commons.compress.compressors.bzip2;version="[1.4,2.0)", org.apache.commons.compress.compressors.gzip;version="[1.4,2.0)", org.apache.commons.compress.compressors.xz;version="[1.4,2.0)", - org.eclipse.jgit.api;version="[4.1.1,4.2.0)", - org.eclipse.jgit.lib;version="[4.1.1,4.2.0)", - org.eclipse.jgit.nls;version="[4.1.1,4.2.0)", - org.eclipse.jgit.util;version="[4.1.1,4.2.0)", + org.eclipse.jgit.api;version="[4.1.2,4.2.0)", + org.eclipse.jgit.lib;version="[4.1.2,4.2.0)", + org.eclipse.jgit.nls;version="[4.1.2,4.2.0)", + org.eclipse.jgit.util;version="[4.1.2,4.2.0)", org.osgi.framework;version="[1.3.0,2.0.0)" Bundle-ActivationPolicy: lazy Bundle-Activator: org.eclipse.jgit.archive.FormatActivator -Export-Package: org.eclipse.jgit.archive;version="4.1.1"; +Export-Package: org.eclipse.jgit.archive;version="4.1.2"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.api, org.apache.commons.compress.archivers, diff --git a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF index dbb6473661..cc3181962d 100644 --- a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.archive - Sources Bundle-SymbolicName: org.eclipse.jgit.archive.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 4.1.1.201511131810-r -Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.1.1.201511131810-r";roots="." +Bundle-Version: 4.1.2.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.1.2.qualifier";roots="." diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml index 1a4dcabeaa..1127a773fb 100644 --- a/org.eclipse.jgit.archive/pom.xml +++ b/org.eclipse.jgit.archive/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.archive diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF index 6036cafbd8..700badbca4 100644 --- a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: org.eclipse.jgit.http.apache -Bundle-Version: 4.1.1.201511131810-r +Bundle-Version: 4.1.2.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Bundle-Localization: plugin Bundle-Vendor: %Provider-Name @@ -19,10 +19,10 @@ Import-Package: org.apache.http;version="[4.1.0,5.0.0)", org.apache.http.impl.client;version="[4.1.0,5.0.0)", org.apache.http.impl.client.cache;version="[4.1.0,5.0.0)", org.apache.http.params;version="[4.1.0,5.0.0)", - org.eclipse.jgit.nls;version="[4.1.1,4.2.0)", - org.eclipse.jgit.transport.http;version="[4.1.1,4.2.0)", - org.eclipse.jgit.util;version="[4.1.1,4.2.0)" -Export-Package: org.eclipse.jgit.transport.http.apache;version="4.1.1"; + org.eclipse.jgit.nls;version="[4.1.2,4.2.0)", + org.eclipse.jgit.transport.http;version="[4.1.2,4.2.0)", + org.eclipse.jgit.util;version="[4.1.2,4.2.0)" +Export-Package: org.eclipse.jgit.transport.http.apache;version="4.1.2"; uses:="org.eclipse.jgit.transport.http, javax.net.ssl, org.apache.http.client, diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml index 0bf73b7962..dee349cd80 100644 --- a/org.eclipse.jgit.http.apache/pom.xml +++ b/org.eclipse.jgit.http.apache/pom.xml @@ -48,7 +48,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.http.apache diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF index e19980b57f..85e1dd7d42 100644 --- a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF @@ -2,13 +2,13 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.http.server -Bundle-Version: 4.1.1.201511131810-r +Bundle-Version: 4.1.2.qualifier Bundle-Localization: plugin Bundle-Vendor: %provider_name -Export-Package: org.eclipse.jgit.http.server;version="4.1.1", - org.eclipse.jgit.http.server.glue;version="4.1.1"; +Export-Package: org.eclipse.jgit.http.server;version="4.1.2", + org.eclipse.jgit.http.server.glue;version="4.1.2"; uses:="javax.servlet,javax.servlet.http", - org.eclipse.jgit.http.server.resolver;version="4.1.1"; + org.eclipse.jgit.http.server.resolver;version="4.1.2"; uses:="org.eclipse.jgit.transport.resolver, org.eclipse.jgit.lib, org.eclipse.jgit.transport, @@ -17,12 +17,12 @@ Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Import-Package: javax.servlet;version="[2.5.0,3.2.0)", javax.servlet.http;version="[2.5.0,3.2.0)", - org.eclipse.jgit.errors;version="[4.1.1,4.2.0)", - org.eclipse.jgit.internal.storage.dfs;version="[4.1.1,4.2.0)", - org.eclipse.jgit.internal.storage.file;version="[4.1.1,4.2.0)", - org.eclipse.jgit.lib;version="[4.1.1,4.2.0)", - org.eclipse.jgit.nls;version="[4.1.1,4.2.0)", - org.eclipse.jgit.revwalk;version="[4.1.1,4.2.0)", - org.eclipse.jgit.transport;version="[4.1.1,4.2.0)", - org.eclipse.jgit.transport.resolver;version="[4.1.1,4.2.0)", - org.eclipse.jgit.util;version="[4.1.1,4.2.0)" + org.eclipse.jgit.errors;version="[4.1.2,4.2.0)", + org.eclipse.jgit.internal.storage.dfs;version="[4.1.2,4.2.0)", + org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)", + org.eclipse.jgit.lib;version="[4.1.2,4.2.0)", + org.eclipse.jgit.nls;version="[4.1.2,4.2.0)", + org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)", + org.eclipse.jgit.transport;version="[4.1.2,4.2.0)", + org.eclipse.jgit.transport.resolver;version="[4.1.2,4.2.0)", + org.eclipse.jgit.util;version="[4.1.2,4.2.0)" diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml index 17ce3da128..8707e01534 100644 --- a/org.eclipse.jgit.http.server/pom.xml +++ b/org.eclipse.jgit.http.server/pom.xml @@ -52,7 +52,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.http.server diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF index d167da39f5..cff5d24fa2 100644 --- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.http.test -Bundle-Version: 4.1.1.201511131810-r +Bundle-Version: 4.1.2.qualifier Bundle-Vendor: %provider_name Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-1.7 @@ -22,23 +22,23 @@ Import-Package: javax.servlet;version="[2.5.0,3.2.0)", org.eclipse.jetty.util.log;version="[9.0.0,10.0.0)", org.eclipse.jetty.util.security;version="[9.0.0,10.0.0)", org.eclipse.jetty.util.thread;version="[9.0.0,10.0.0)", - org.eclipse.jgit.errors;version="[4.1.1,4.2.0)", - org.eclipse.jgit.http.server;version="[4.1.1,4.2.0)", - org.eclipse.jgit.http.server.glue;version="[4.1.1,4.2.0)", - org.eclipse.jgit.http.server.resolver;version="[4.1.1,4.2.0)", - org.eclipse.jgit.internal;version="[4.1.1,4.2.0)", - org.eclipse.jgit.internal.storage.file;version="[4.1.1,4.2.0)", - org.eclipse.jgit.junit;version="[4.1.1,4.2.0)", - org.eclipse.jgit.junit.http;version="[4.1.1,4.2.0)", - org.eclipse.jgit.lib;version="[4.1.1,4.2.0)", - org.eclipse.jgit.nls;version="[4.1.1,4.2.0)", - org.eclipse.jgit.revwalk;version="[4.1.1,4.2.0)", - org.eclipse.jgit.storage.file;version="[4.1.1,4.2.0)", - org.eclipse.jgit.transport;version="[4.1.1,4.2.0)", - org.eclipse.jgit.transport.http;version="[4.1.1,4.2.0)", - org.eclipse.jgit.transport.http.apache;version="[4.1.1,4.2.0)", - org.eclipse.jgit.transport.resolver;version="[4.1.1,4.2.0)", - org.eclipse.jgit.util;version="[4.1.1,4.2.0)", + org.eclipse.jgit.errors;version="[4.1.2,4.2.0)", + org.eclipse.jgit.http.server;version="[4.1.2,4.2.0)", + org.eclipse.jgit.http.server.glue;version="[4.1.2,4.2.0)", + org.eclipse.jgit.http.server.resolver;version="[4.1.2,4.2.0)", + org.eclipse.jgit.internal;version="[4.1.2,4.2.0)", + org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)", + org.eclipse.jgit.junit;version="[4.1.2,4.2.0)", + org.eclipse.jgit.junit.http;version="[4.1.2,4.2.0)", + org.eclipse.jgit.lib;version="[4.1.2,4.2.0)", + org.eclipse.jgit.nls;version="[4.1.2,4.2.0)", + org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)", + org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)", + org.eclipse.jgit.transport;version="[4.1.2,4.2.0)", + org.eclipse.jgit.transport.http;version="[4.1.2,4.2.0)", + org.eclipse.jgit.transport.http.apache;version="[4.1.2,4.2.0)", + org.eclipse.jgit.transport.resolver;version="[4.1.2,4.2.0)", + org.eclipse.jgit.util;version="[4.1.2,4.2.0)", org.hamcrest.core;version="[1.1.0,2.0.0)", org.junit;version="[4.0.0,5.0.0)", org.junit.runner;version="[4.0.0,5.0.0)", diff --git a/org.eclipse.jgit.http.test/pom.xml b/org.eclipse.jgit.http.test/pom.xml index 237f2267b6..8f7cd03fd7 100644 --- a/org.eclipse.jgit.http.test/pom.xml +++ b/org.eclipse.jgit.http.test/pom.xml @@ -51,7 +51,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.http.test diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF index f669a1790a..aa1dc8b2f8 100644 --- a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.junit.http -Bundle-Version: 4.1.1.201511131810-r +Bundle-Version: 4.1.2.qualifier Bundle-Localization: plugin Bundle-Vendor: %provider_name Bundle-ActivationPolicy: lazy @@ -20,16 +20,16 @@ Import-Package: javax.servlet;version="[2.5.0,3.2.0)", org.eclipse.jetty.util.component;version="[9.0.0,10.0.0)", org.eclipse.jetty.util.log;version="[9.0.0,10.0.0)", org.eclipse.jetty.util.security;version="[9.0.0,10.0.0)", - org.eclipse.jgit.errors;version="[4.1.1,4.2.0)", - org.eclipse.jgit.http.server;version="[4.1.1,4.2.0)", - org.eclipse.jgit.internal.storage.file;version="[4.1.1,4.2.0)", - org.eclipse.jgit.junit;version="[4.1.1,4.2.0)", - org.eclipse.jgit.lib;version="[4.1.1,4.2.0)", - org.eclipse.jgit.revwalk;version="[4.1.1,4.2.0)", - org.eclipse.jgit.transport;version="[4.1.1,4.2.0)", - org.eclipse.jgit.transport.resolver;version="[4.1.1,4.2.0)", + org.eclipse.jgit.errors;version="[4.1.2,4.2.0)", + org.eclipse.jgit.http.server;version="[4.1.2,4.2.0)", + org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)", + org.eclipse.jgit.junit;version="[4.1.2,4.2.0)", + org.eclipse.jgit.lib;version="[4.1.2,4.2.0)", + org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)", + org.eclipse.jgit.transport;version="[4.1.2,4.2.0)", + org.eclipse.jgit.transport.resolver;version="[4.1.2,4.2.0)", org.junit;version="[4.0.0,5.0.0)" -Export-Package: org.eclipse.jgit.junit.http;version="4.1.1"; +Export-Package: org.eclipse.jgit.junit.http;version="4.1.2"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.junit, javax.servlet.http, diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml index d1e09c32ab..40cdca158d 100644 --- a/org.eclipse.jgit.junit.http/pom.xml +++ b/org.eclipse.jgit.junit.http/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.junit.http diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF index 31c2304b72..048f65d8f2 100644 --- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF @@ -2,27 +2,27 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.junit -Bundle-Version: 4.1.1.201511131810-r +Bundle-Version: 4.1.2.qualifier Bundle-Localization: plugin Bundle-Vendor: %provider_name Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.7 -Import-Package: org.eclipse.jgit.api;version="[4.1.1,4.2.0)", - org.eclipse.jgit.api.errors;version="[4.1.1,4.2.0)", - org.eclipse.jgit.dircache;version="[4.1.1,4.2.0)", - org.eclipse.jgit.errors;version="[4.1.1,4.2.0)", - org.eclipse.jgit.internal.storage.file;version="[4.1.1,4.2.0)", - org.eclipse.jgit.internal.storage.pack;version="[4.1.1,4.2.0)", - org.eclipse.jgit.lib;version="[4.1.1,4.2.0)", - org.eclipse.jgit.merge;version="[4.1.1,4.2.0)", - org.eclipse.jgit.revwalk;version="[4.1.1,4.2.0)", - org.eclipse.jgit.storage.file;version="[4.1.1,4.2.0)", - org.eclipse.jgit.treewalk;version="[4.1.1,4.2.0)", - org.eclipse.jgit.treewalk.filter;version="[4.1.1,4.2.0)", - org.eclipse.jgit.util;version="[4.1.1,4.2.0)", - org.eclipse.jgit.util.io;version="[4.1.1,4.2.0)", +Import-Package: org.eclipse.jgit.api;version="[4.1.2,4.2.0)", + org.eclipse.jgit.api.errors;version="[4.1.2,4.2.0)", + org.eclipse.jgit.dircache;version="[4.1.2,4.2.0)", + org.eclipse.jgit.errors;version="[4.1.2,4.2.0)", + org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)", + org.eclipse.jgit.internal.storage.pack;version="[4.1.2,4.2.0)", + org.eclipse.jgit.lib;version="[4.1.2,4.2.0)", + org.eclipse.jgit.merge;version="[4.1.2,4.2.0)", + org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)", + org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)", + org.eclipse.jgit.treewalk;version="[4.1.2,4.2.0)", + org.eclipse.jgit.treewalk.filter;version="[4.1.2,4.2.0)", + org.eclipse.jgit.util;version="[4.1.2,4.2.0)", + org.eclipse.jgit.util.io;version="[4.1.2,4.2.0)", org.junit;version="[4.0.0,5.0.0)" -Export-Package: org.eclipse.jgit.junit;version="4.1.1"; +Export-Package: org.eclipse.jgit.junit;version="4.1.2"; uses:="org.eclipse.jgit.dircache, org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml index b4d4d27f4a..53f1bdcc85 100644 --- a/org.eclipse.jgit.junit/pom.xml +++ b/org.eclipse.jgit.junit/pom.xml @@ -52,7 +52,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.junit diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml index 7cf81353f8..43575f525a 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml index 849f7bbfa8..f7ef5ee250 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.feature diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml index 8544d1a2bb..f54ec78c50 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml index 060ad0e6fb..8be8b18b92 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.feature diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml index 752f0444e0..8dbf9f8a3c 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml index 3ed76d3840..aa1d85cdc4 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.feature diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml index a6f0a4c047..084c49f16c 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml index 438173beaa..6010467d6e 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.feature diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml index 61070bff19..8e13dc9396 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml index 3754fd6c91..b72f82f451 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.feature diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml index 72da41c7e3..d7c1f6ad78 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.repository diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml index 09ee4c4782..9a7e6e0ba8 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml index 50816beaa9..d710643114 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.feature diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF index 1d3c436e9f..60492325ca 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF @@ -2,4 +2,4 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: JGit Target Platform Bundle Bundle-SymbolicName: org.eclipse.jgit.target -Bundle-Version: 4.1.1.201511131810-r +Bundle-Version: 4.1.2.qualifier diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml index e95377f947..e8e036ed44 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml @@ -49,7 +49,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.target diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml index 64750ec375..e1f71cbd71 100644 --- a/org.eclipse.jgit.packaging/pom.xml +++ b/org.eclipse.jgit.packaging/pom.xml @@ -53,7 +53,7 @@ org.eclipse.jgit jgit.tycho.parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT pom JGit Tycho Parent diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF index 5b9a115343..08a08a828e 100644 --- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF @@ -2,27 +2,27 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.pgm.test -Bundle-Version: 4.1.1.201511131810-r +Bundle-Version: 4.1.2.qualifier Bundle-Vendor: %provider_name Bundle-Localization: plugin Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.7 -Import-Package: org.eclipse.jgit.api;version="[4.1.1,4.2.0)", - org.eclipse.jgit.api.errors;version="[4.1.1,4.2.0)", - org.eclipse.jgit.diff;version="[4.1.1,4.2.0)", - org.eclipse.jgit.dircache;version="[4.1.1,4.2.0)", - org.eclipse.jgit.junit;version="[4.1.1,4.2.0)", - org.eclipse.jgit.lib;version="[4.1.1,4.2.0)", - org.eclipse.jgit.merge;version="[4.1.1,4.2.0)", - org.eclipse.jgit.pgm;version="[4.1.1,4.2.0)", - org.eclipse.jgit.pgm.internal;version="[4.1.1,4.2.0)", - org.eclipse.jgit.pgm.opt;version="[4.1.1,4.2.0)", - org.eclipse.jgit.revwalk;version="[4.1.1,4.2.0)", - org.eclipse.jgit.storage.file;version="[4.1.1,4.2.0)", - org.eclipse.jgit.transport;version="[4.1.1,4.2.0)", - org.eclipse.jgit.treewalk;version="[4.1.1,4.2.0)", - org.eclipse.jgit.util;version="[4.1.1,4.2.0)", - org.eclipse.jgit.util.io;version="[4.1.1,4.2.0)", +Import-Package: org.eclipse.jgit.api;version="[4.1.2,4.2.0)", + org.eclipse.jgit.api.errors;version="[4.1.2,4.2.0)", + org.eclipse.jgit.diff;version="[4.1.2,4.2.0)", + org.eclipse.jgit.dircache;version="[4.1.2,4.2.0)", + org.eclipse.jgit.junit;version="[4.1.2,4.2.0)", + org.eclipse.jgit.lib;version="[4.1.2,4.2.0)", + org.eclipse.jgit.merge;version="[4.1.2,4.2.0)", + org.eclipse.jgit.pgm;version="[4.1.2,4.2.0)", + org.eclipse.jgit.pgm.internal;version="[4.1.2,4.2.0)", + org.eclipse.jgit.pgm.opt;version="[4.1.2,4.2.0)", + org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)", + org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)", + org.eclipse.jgit.transport;version="[4.1.2,4.2.0)", + org.eclipse.jgit.treewalk;version="[4.1.2,4.2.0)", + org.eclipse.jgit.util;version="[4.1.2,4.2.0)", + org.eclipse.jgit.util.io;version="[4.1.2,4.2.0)", org.hamcrest.core;bundle-version="[1.1.0,2.0.0)", org.junit;version="[4.4.0,5.0.0)", org.kohsuke.args4j;version="[2.0.12,2.1.0)" diff --git a/org.eclipse.jgit.pgm.test/pom.xml b/org.eclipse.jgit.pgm.test/pom.xml index acfe6009f1..132645b97c 100644 --- a/org.eclipse.jgit.pgm.test/pom.xml +++ b/org.eclipse.jgit.pgm.test/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.pgm.test diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF index 30db7a84fa..3a78d94df0 100644 --- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.pgm -Bundle-Version: 4.1.1.201511131810-r +Bundle-Version: 4.1.2.qualifier Bundle-Vendor: %provider_name Bundle-ActivationPolicy: lazy Bundle-Localization: plugin @@ -10,38 +10,38 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Import-Package: org.apache.commons.compress.archivers;version="[1.3,2.0)", org.apache.commons.compress.archivers.tar;version="[1.3,2.0)", org.apache.commons.compress.archivers.zip;version="[1.3,2.0)", - org.eclipse.jgit.api;version="[4.1.1,4.2.0)", - org.eclipse.jgit.api.errors;version="[4.1.1,4.2.0)", - org.eclipse.jgit.archive;version="[4.1.1,4.2.0)", - org.eclipse.jgit.awtui;version="[4.1.1,4.2.0)", - org.eclipse.jgit.blame;version="[4.1.1,4.2.0)", - org.eclipse.jgit.diff;version="[4.1.1,4.2.0)", - org.eclipse.jgit.dircache;version="[4.1.1,4.2.0)", - org.eclipse.jgit.errors;version="[4.1.1,4.2.0)", - org.eclipse.jgit.gitrepo;version="[4.1.1,4.2.0)", - org.eclipse.jgit.internal.storage.file;version="[4.1.1,4.2.0)", - org.eclipse.jgit.internal.storage.pack;version="[4.1.1,4.2.0)", - org.eclipse.jgit.lib;version="[4.1.1,4.2.0)", - org.eclipse.jgit.merge;version="4.1.1", - org.eclipse.jgit.nls;version="[4.1.1,4.2.0)", - org.eclipse.jgit.notes;version="[4.1.1,4.2.0)", - org.eclipse.jgit.revplot;version="[4.1.1,4.2.0)", - org.eclipse.jgit.revwalk;version="[4.1.1,4.2.0)", - org.eclipse.jgit.revwalk.filter;version="[4.1.1,4.2.0)", - org.eclipse.jgit.storage.file;version="[4.1.1,4.2.0)", - org.eclipse.jgit.storage.pack;version="[4.1.1,4.2.0)", - org.eclipse.jgit.transport;version="[4.1.1,4.2.0)", - org.eclipse.jgit.transport.resolver;version="[4.1.1,4.2.0)", - org.eclipse.jgit.treewalk;version="[4.1.1,4.2.0)", - org.eclipse.jgit.treewalk.filter;version="[4.1.1,4.2.0)", - org.eclipse.jgit.util;version="[4.1.1,4.2.0)", - org.eclipse.jgit.util.io;version="[4.1.1,4.2.0)", + org.eclipse.jgit.api;version="[4.1.2,4.2.0)", + org.eclipse.jgit.api.errors;version="[4.1.2,4.2.0)", + org.eclipse.jgit.archive;version="[4.1.2,4.2.0)", + org.eclipse.jgit.awtui;version="[4.1.2,4.2.0)", + org.eclipse.jgit.blame;version="[4.1.2,4.2.0)", + org.eclipse.jgit.diff;version="[4.1.2,4.2.0)", + org.eclipse.jgit.dircache;version="[4.1.2,4.2.0)", + org.eclipse.jgit.errors;version="[4.1.2,4.2.0)", + org.eclipse.jgit.gitrepo;version="[4.1.2,4.2.0)", + org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)", + org.eclipse.jgit.internal.storage.pack;version="[4.1.2,4.2.0)", + org.eclipse.jgit.lib;version="[4.1.2,4.2.0)", + org.eclipse.jgit.merge;version="4.1.2", + org.eclipse.jgit.nls;version="[4.1.2,4.2.0)", + org.eclipse.jgit.notes;version="[4.1.2,4.2.0)", + org.eclipse.jgit.revplot;version="[4.1.2,4.2.0)", + org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)", + org.eclipse.jgit.revwalk.filter;version="[4.1.2,4.2.0)", + org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)", + org.eclipse.jgit.storage.pack;version="[4.1.2,4.2.0)", + org.eclipse.jgit.transport;version="[4.1.2,4.2.0)", + org.eclipse.jgit.transport.resolver;version="[4.1.2,4.2.0)", + org.eclipse.jgit.treewalk;version="[4.1.2,4.2.0)", + org.eclipse.jgit.treewalk.filter;version="[4.1.2,4.2.0)", + org.eclipse.jgit.util;version="[4.1.2,4.2.0)", + org.eclipse.jgit.util.io;version="[4.1.2,4.2.0)", org.kohsuke.args4j;version="[2.0.12,2.1.0)", org.kohsuke.args4j.spi;version="[2.0.15,2.1.0)" -Export-Package: org.eclipse.jgit.console;version="4.1.1"; +Export-Package: org.eclipse.jgit.console;version="4.1.2"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.util", - org.eclipse.jgit.pgm;version="4.1.1"; + org.eclipse.jgit.pgm;version="4.1.2"; uses:="org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.pgm.opt, @@ -52,11 +52,11 @@ Export-Package: org.eclipse.jgit.console;version="4.1.1"; org.eclipse.jgit.treewalk, javax.swing, org.eclipse.jgit.transport", - org.eclipse.jgit.pgm.debug;version="4.1.1"; + org.eclipse.jgit.pgm.debug;version="4.1.2"; uses:="org.eclipse.jgit.util.io, org.eclipse.jgit.pgm", - org.eclipse.jgit.pgm.internal;version="4.1.1";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test", - org.eclipse.jgit.pgm.opt;version="4.1.1"; + org.eclipse.jgit.pgm.internal;version="4.1.2";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test", + org.eclipse.jgit.pgm.opt;version="4.1.2"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.kohsuke.args4j.spi, diff --git a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF index dfc5ab9a97..303ebf44f7 100644 --- a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.pgm - Sources Bundle-SymbolicName: org.eclipse.jgit.pgm.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 4.1.1.201511131810-r -Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.1.1.201511131810-r";roots="." +Bundle-Version: 4.1.2.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.1.2.qualifier";roots="." diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml index 2c2e55de6d..42fde6fe9a 100644 --- a/org.eclipse.jgit.pgm/pom.xml +++ b/org.eclipse.jgit.pgm/pom.xml @@ -50,7 +50,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.pgm diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF index 9d25fca29b..8f2f4284f0 100644 --- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF @@ -2,51 +2,51 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.test -Bundle-Version: 4.1.1.201511131810-r +Bundle-Version: 4.1.2.qualifier Bundle-Localization: plugin Bundle-Vendor: %provider_name Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Import-Package: com.googlecode.javaewah;version="[0.7.9,0.8.0)", - org.eclipse.jgit.api;version="[4.1.1,4.2.0)", - org.eclipse.jgit.api.errors;version="[4.1.1,4.2.0)", - org.eclipse.jgit.attributes;version="[4.1.1,4.2.0)", - org.eclipse.jgit.awtui;version="[4.1.1,4.2.0)", - org.eclipse.jgit.blame;version="[4.1.1,4.2.0)", - org.eclipse.jgit.diff;version="[4.1.1,4.2.0)", - org.eclipse.jgit.dircache;version="[4.1.1,4.2.0)", - org.eclipse.jgit.errors;version="[4.1.1,4.2.0)", - org.eclipse.jgit.events;version="[4.1.1,4.2.0)", - org.eclipse.jgit.fnmatch;version="[4.1.1,4.2.0)", - org.eclipse.jgit.gitrepo;version="[4.1.1,4.2.0)", - org.eclipse.jgit.hooks;version="[4.1.1,4.2.0)", - org.eclipse.jgit.ignore;version="[4.1.1,4.2.0)", - org.eclipse.jgit.ignore.internal;version="[4.1.1,4.2.0)", - org.eclipse.jgit.internal;version="[4.1.1,4.2.0)", - org.eclipse.jgit.internal.storage.dfs;version="[4.1.1,4.2.0)", - org.eclipse.jgit.internal.storage.file;version="[4.1.1,4.2.0)", - org.eclipse.jgit.internal.storage.pack;version="[4.1.1,4.2.0)", - org.eclipse.jgit.junit;version="[4.1.1,4.2.0)", - org.eclipse.jgit.lib;version="[4.1.1,4.2.0)", - org.eclipse.jgit.merge;version="[4.1.1,4.2.0)", - org.eclipse.jgit.nls;version="[4.1.1,4.2.0)", - org.eclipse.jgit.notes;version="[4.1.1,4.2.0)", - org.eclipse.jgit.patch;version="[4.1.1,4.2.0)", - org.eclipse.jgit.pgm;version="[4.1.1,4.2.0)", - org.eclipse.jgit.pgm.internal;version="[4.1.1,4.2.0)", - org.eclipse.jgit.revplot;version="[4.1.1,4.2.0)", - org.eclipse.jgit.revwalk;version="[4.1.1,4.2.0)", - org.eclipse.jgit.revwalk.filter;version="[4.1.1,4.2.0)", - org.eclipse.jgit.storage.file;version="[4.1.1,4.2.0)", - org.eclipse.jgit.storage.pack;version="[4.1.1,4.2.0)", - org.eclipse.jgit.submodule;version="[4.1.1,4.2.0)", - org.eclipse.jgit.transport;version="[4.1.1,4.2.0)", - org.eclipse.jgit.transport.http;version="[4.1.1,4.2.0)", - org.eclipse.jgit.transport.resolver;version="[4.1.1,4.2.0)", - org.eclipse.jgit.treewalk;version="[4.1.1,4.2.0)", - org.eclipse.jgit.treewalk.filter;version="[4.1.1,4.2.0)", - org.eclipse.jgit.util;version="[4.1.1,4.2.0)", - org.eclipse.jgit.util.io;version="[4.1.1,4.2.0)", + org.eclipse.jgit.api;version="[4.1.2,4.2.0)", + org.eclipse.jgit.api.errors;version="[4.1.2,4.2.0)", + org.eclipse.jgit.attributes;version="[4.1.2,4.2.0)", + org.eclipse.jgit.awtui;version="[4.1.2,4.2.0)", + org.eclipse.jgit.blame;version="[4.1.2,4.2.0)", + org.eclipse.jgit.diff;version="[4.1.2,4.2.0)", + org.eclipse.jgit.dircache;version="[4.1.2,4.2.0)", + org.eclipse.jgit.errors;version="[4.1.2,4.2.0)", + org.eclipse.jgit.events;version="[4.1.2,4.2.0)", + org.eclipse.jgit.fnmatch;version="[4.1.2,4.2.0)", + org.eclipse.jgit.gitrepo;version="[4.1.2,4.2.0)", + org.eclipse.jgit.hooks;version="[4.1.2,4.2.0)", + org.eclipse.jgit.ignore;version="[4.1.2,4.2.0)", + org.eclipse.jgit.ignore.internal;version="[4.1.2,4.2.0)", + org.eclipse.jgit.internal;version="[4.1.2,4.2.0)", + org.eclipse.jgit.internal.storage.dfs;version="[4.1.2,4.2.0)", + org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)", + org.eclipse.jgit.internal.storage.pack;version="[4.1.2,4.2.0)", + org.eclipse.jgit.junit;version="[4.1.2,4.2.0)", + org.eclipse.jgit.lib;version="[4.1.2,4.2.0)", + org.eclipse.jgit.merge;version="[4.1.2,4.2.0)", + org.eclipse.jgit.nls;version="[4.1.2,4.2.0)", + org.eclipse.jgit.notes;version="[4.1.2,4.2.0)", + org.eclipse.jgit.patch;version="[4.1.2,4.2.0)", + org.eclipse.jgit.pgm;version="[4.1.2,4.2.0)", + org.eclipse.jgit.pgm.internal;version="[4.1.2,4.2.0)", + org.eclipse.jgit.revplot;version="[4.1.2,4.2.0)", + org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)", + org.eclipse.jgit.revwalk.filter;version="[4.1.2,4.2.0)", + org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)", + org.eclipse.jgit.storage.pack;version="[4.1.2,4.2.0)", + org.eclipse.jgit.submodule;version="[4.1.2,4.2.0)", + org.eclipse.jgit.transport;version="[4.1.2,4.2.0)", + org.eclipse.jgit.transport.http;version="[4.1.2,4.2.0)", + org.eclipse.jgit.transport.resolver;version="[4.1.2,4.2.0)", + org.eclipse.jgit.treewalk;version="[4.1.2,4.2.0)", + org.eclipse.jgit.treewalk.filter;version="[4.1.2,4.2.0)", + org.eclipse.jgit.util;version="[4.1.2,4.2.0)", + org.eclipse.jgit.util.io;version="[4.1.2,4.2.0)", org.hamcrest;version="[1.1.0,2.0.0)", org.junit;version="[4.4.0,5.0.0)", org.junit.experimental.theories;version="[4.4.0,5.0.0)", diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml index 2385d27f9c..c174ba270b 100644 --- a/org.eclipse.jgit.test/pom.xml +++ b/org.eclipse.jgit.test/pom.xml @@ -52,7 +52,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.test diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF index a9cedc091f..3df4347016 100644 --- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF @@ -3,14 +3,14 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit.ui -Bundle-Version: 4.1.1.201511131810-r +Bundle-Version: 4.1.2.qualifier Bundle-Vendor: %provider_name Bundle-RequiredExecutionEnvironment: JavaSE-1.7 -Export-Package: org.eclipse.jgit.awtui;version="4.1.1" -Import-Package: org.eclipse.jgit.errors;version="[4.1.1,4.2.0)", - org.eclipse.jgit.lib;version="[4.1.1,4.2.0)", - org.eclipse.jgit.nls;version="[4.1.1,4.2.0)", - org.eclipse.jgit.revplot;version="[4.1.1,4.2.0)", - org.eclipse.jgit.revwalk;version="[4.1.1,4.2.0)", - org.eclipse.jgit.transport;version="[4.1.1,4.2.0)", - org.eclipse.jgit.util;version="[4.1.1,4.2.0)" +Export-Package: org.eclipse.jgit.awtui;version="4.1.2" +Import-Package: org.eclipse.jgit.errors;version="[4.1.2,4.2.0)", + org.eclipse.jgit.lib;version="[4.1.2,4.2.0)", + org.eclipse.jgit.nls;version="[4.1.2,4.2.0)", + org.eclipse.jgit.revplot;version="[4.1.2,4.2.0)", + org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)", + org.eclipse.jgit.transport;version="[4.1.2,4.2.0)", + org.eclipse.jgit.util;version="[4.1.2,4.2.0)" diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml index d64de32437..79c30f0ac9 100644 --- a/org.eclipse.jgit.ui/pom.xml +++ b/org.eclipse.jgit.ui/pom.xml @@ -52,7 +52,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit.ui diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF index a10e6d6ee0..24798be02a 100644 --- a/org.eclipse.jgit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/MANIFEST.MF @@ -2,11 +2,11 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit -Bundle-Version: 4.1.1.201511131810-r +Bundle-Version: 4.1.2.qualifier Bundle-Localization: plugin Bundle-Vendor: %provider_name Bundle-ActivationPolicy: lazy -Export-Package: org.eclipse.jgit.api;version="4.1.1"; +Export-Package: org.eclipse.jgit.api;version="4.1.2"; uses:="org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.diff, @@ -20,60 +20,60 @@ Export-Package: org.eclipse.jgit.api;version="4.1.1"; org.eclipse.jgit.submodule, org.eclipse.jgit.transport, org.eclipse.jgit.merge", - org.eclipse.jgit.api.errors;version="4.1.1"; + org.eclipse.jgit.api.errors;version="4.1.2"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.errors", - org.eclipse.jgit.attributes;version="4.1.1", - org.eclipse.jgit.blame;version="4.1.1"; + org.eclipse.jgit.attributes;version="4.1.2", + org.eclipse.jgit.blame;version="4.1.2"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.diff", - org.eclipse.jgit.diff;version="4.1.1"; + org.eclipse.jgit.diff;version="4.1.2"; uses:="org.eclipse.jgit.patch, org.eclipse.jgit.lib, org.eclipse.jgit.treewalk, org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.util", - org.eclipse.jgit.dircache;version="4.1.1"; + org.eclipse.jgit.dircache;version="4.1.2"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk, org.eclipse.jgit.util, org.eclipse.jgit.events, org.eclipse.jgit.attributes", - org.eclipse.jgit.errors;version="4.1.1"; + org.eclipse.jgit.errors;version="4.1.2"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.internal.storage.pack, org.eclipse.jgit.transport, org.eclipse.jgit.dircache", - org.eclipse.jgit.events;version="4.1.1"; + org.eclipse.jgit.events;version="4.1.2"; uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.fnmatch;version="4.1.1", - org.eclipse.jgit.gitrepo;version="4.1.1"; + org.eclipse.jgit.fnmatch;version="4.1.2", + org.eclipse.jgit.gitrepo;version="4.1.2"; uses:="org.eclipse.jgit.api, org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.xml.sax.helpers, org.xml.sax", - org.eclipse.jgit.gitrepo.internal;version="4.1.1";x-internal:=true, - org.eclipse.jgit.hooks;version="4.1.1"; + org.eclipse.jgit.gitrepo.internal;version="4.1.2";x-internal:=true, + org.eclipse.jgit.hooks;version="4.1.2"; uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.ignore;version="4.1.1", - org.eclipse.jgit.ignore.internal;version="4.1.1";x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal;version="4.1.1";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test", - org.eclipse.jgit.internal.storage.dfs;version="4.1.1"; + org.eclipse.jgit.ignore;version="4.1.2", + org.eclipse.jgit.ignore.internal;version="4.1.2";x-friends:="org.eclipse.jgit.test", + org.eclipse.jgit.internal;version="4.1.2";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test", + org.eclipse.jgit.internal.storage.dfs;version="4.1.2"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.http.server", - org.eclipse.jgit.internal.storage.file;version="4.1.1"; + org.eclipse.jgit.internal.storage.file;version="4.1.2"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.junit, org.eclipse.jgit.junit.http, org.eclipse.jgit.http.server, org.eclipse.jgit.java7.test, org.eclipse.jgit.pgm", - org.eclipse.jgit.internal.storage.pack;version="4.1.1";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", - org.eclipse.jgit.lib;version="4.1.1"; + org.eclipse.jgit.internal.storage.pack;version="4.1.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", + org.eclipse.jgit.lib;version="4.1.2"; uses:="org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.util, @@ -83,45 +83,45 @@ Export-Package: org.eclipse.jgit.api;version="4.1.1"; org.eclipse.jgit.treewalk, org.eclipse.jgit.transport, org.eclipse.jgit.submodule", - org.eclipse.jgit.merge;version="4.1.1"; + org.eclipse.jgit.merge;version="4.1.2"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk, org.eclipse.jgit.revwalk, org.eclipse.jgit.diff, org.eclipse.jgit.dircache, org.eclipse.jgit.api", - org.eclipse.jgit.nls;version="4.1.1", - org.eclipse.jgit.notes;version="4.1.1"; + org.eclipse.jgit.nls;version="4.1.2", + org.eclipse.jgit.notes;version="4.1.2"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk, org.eclipse.jgit.revwalk, org.eclipse.jgit.merge", - org.eclipse.jgit.patch;version="4.1.1"; + org.eclipse.jgit.patch;version="4.1.2"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.diff", - org.eclipse.jgit.revplot;version="4.1.1"; + org.eclipse.jgit.revplot;version="4.1.2"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk", - org.eclipse.jgit.revwalk;version="4.1.1"; + org.eclipse.jgit.revwalk;version="4.1.2"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.diff, org.eclipse.jgit.revwalk.filter", - org.eclipse.jgit.revwalk.filter;version="4.1.1"; + org.eclipse.jgit.revwalk.filter;version="4.1.2"; uses:="org.eclipse.jgit.revwalk, org.eclipse.jgit.lib, org.eclipse.jgit.util", - org.eclipse.jgit.storage.file;version="4.1.1"; + org.eclipse.jgit.storage.file;version="4.1.2"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.util", - org.eclipse.jgit.storage.pack;version="4.1.1"; + org.eclipse.jgit.storage.pack;version="4.1.2"; uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.submodule;version="4.1.1"; + org.eclipse.jgit.submodule;version="4.1.2"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.treewalk", - org.eclipse.jgit.transport;version="4.1.1"; + org.eclipse.jgit.transport;version="4.1.2"; uses:="org.eclipse.jgit.transport.resolver, org.eclipse.jgit.revwalk, org.eclipse.jgit.internal.storage.pack, @@ -133,26 +133,26 @@ Export-Package: org.eclipse.jgit.api;version="4.1.1"; org.eclipse.jgit.transport.http, org.eclipse.jgit.errors, org.eclipse.jgit.storage.pack", - org.eclipse.jgit.transport.http;version="4.1.1"; + org.eclipse.jgit.transport.http;version="4.1.2"; uses:="javax.net.ssl", - org.eclipse.jgit.transport.resolver;version="4.1.1"; + org.eclipse.jgit.transport.resolver;version="4.1.2"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.transport", - org.eclipse.jgit.treewalk;version="4.1.1"; + org.eclipse.jgit.treewalk;version="4.1.2"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.eclipse.jgit.attributes, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.util, org.eclipse.jgit.dircache", - org.eclipse.jgit.treewalk.filter;version="4.1.1"; + org.eclipse.jgit.treewalk.filter;version="4.1.2"; uses:="org.eclipse.jgit.treewalk", - org.eclipse.jgit.util;version="4.1.1"; + org.eclipse.jgit.util;version="4.1.2"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.transport.http, org.eclipse.jgit.storage.file, org.ietf.jgss", - org.eclipse.jgit.util.io;version="4.1.1" + org.eclipse.jgit.util.io;version="4.1.2" Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Require-Bundle: com.jcraft.jsch;bundle-version="[0.1.37,0.2.0)", org.eclipse.jdt.annotation;bundle-version="[1.1.0,2.0.0)";resolution:=optional diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF index 83b239cadc..c5476a85cf 100644 --- a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit - Sources Bundle-SymbolicName: org.eclipse.jgit.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 4.1.1.201511131810-r -Eclipse-SourceBundle: org.eclipse.jgit;version="4.1.1.201511131810-r";roots="." +Bundle-Version: 4.1.2.qualifier +Eclipse-SourceBundle: org.eclipse.jgit;version="4.1.2.qualifier";roots="." diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml index 8757940621..8791389dac 100644 --- a/org.eclipse.jgit/pom.xml +++ b/org.eclipse.jgit/pom.xml @@ -53,7 +53,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT org.eclipse.jgit diff --git a/pom.xml b/pom.xml index a899784773..760d66fdbd 100644 --- a/pom.xml +++ b/pom.xml @@ -51,7 +51,7 @@ org.eclipse.jgit org.eclipse.jgit-parent pom - 4.1.1.201511131810-r + 4.1.2-SNAPSHOT JGit - Parent ${jgit-url} -- cgit v1.2.3 From 4acff5a59e38eb13d4c7c17117526b5272c6e74f Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Sun, 15 Nov 2015 22:56:55 +0100 Subject: Handle InternalError during symlink support detection on Windows When JGit tries to detect symlink support the attempt to create a symlink may fail with a java.lang.InternalError. This was reported for a case where the application using JGit runs in Windows XP compatibility mode using Oracle JDK 1.8. Handle this by assuming symlinks are not supported in this case. Bug: 471027 Change-Id: I978288754dea0c6fffd3457fad7d4d971e27c6c2 Signed-off-by: Matthias Sohn --- org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java index f0a2e721a6..defe14f0ed 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java @@ -171,7 +171,8 @@ public class FS_Win32 extends FS { createSymLink(linkName, tempFile.getPath()); supportSymlinks = Boolean.TRUE; linkName.delete(); - } catch (IOException | UnsupportedOperationException e) { + } catch (IOException | UnsupportedOperationException + | InternalError e) { supportSymlinks = Boolean.FALSE; } finally { if (tempFile != null) -- cgit v1.2.3 From f1405a337a399a91a10497100a80e841b8ef7aea Mon Sep 17 00:00:00 2001 From: Andrey Loskutov Date: Sun, 15 Nov 2015 22:55:58 +0100 Subject: Added jgit own NonNull annotation type The annotation is required for example in Repository case (patch follows), where almost all non-void return methods return Nullable except few returning NonNull. I definitely do not favor this style, but it is a nightmare to clients to guess if the null check is needed or not. Change-Id: Ib2a778a246c6d84b7c32565f54df2385b59f6498 Signed-off-by: Andrey Loskutov --- .../src/org/eclipse/jgit/annotations/NonNull.java | 67 ++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java new file mode 100644 index 0000000000..a74654fb5b --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2015, Andrey Loskutov + * 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.annotations; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.LOCAL_VARIABLE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * JGit's replacement for the {@code javax.annotation.Nonnull}. + *

+ * Denotes that a local variable, parameter, field, method return value expected + * to be non {@code null}. + */ +@Documented +@Retention(RetentionPolicy.CLASS) +@Target({ FIELD, METHOD, PARAMETER, LOCAL_VARIABLE }) +public @interface NonNull { + // marker annotation with no members +} -- cgit v1.2.3 From 864d3899ad5decc6b2184fc8272b7caf3ce3bff4 Mon Sep 17 00:00:00 2001 From: Andrey Loskutov Date: Sun, 15 Nov 2015 22:59:14 +0100 Subject: Fixed typo in preferences: NonByDefault -> NonNullByDefault Change-Id: I6ef5fbdb57e7cba010ad23cb3f6af02891e7fe78 Signed-off-by: Andrey Loskutov --- org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs index 195987db64..45d6d2c4c0 100644 --- a/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs @@ -2,7 +2,7 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jgit.annotations.NonNull -org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jgit.annotations.NonByDefault +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jgit.annotations.NonNullByDefault org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jgit.annotations.Nullable org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -- cgit v1.2.3 From 2f6959d9f31faadcc50b5b0ded25f5e5a11befa4 Mon Sep 17 00:00:00 2001 From: Andrey Loskutov Date: Mon, 16 Nov 2015 23:41:38 +0100 Subject: Make jgit annotations accessible to other plugins Other plugins which want to use JGit nullness annotations in their code cannot do this if the annotations aren't part of the published API. Unfortunately it looks like although Eclipse JDT allows to use custom nullness annotation types per project, it does not understand if those annotations are used mixed with other nullness annotations in other projects. E.g. EGit can either configure JGit annotations for NPE analysis and so "understand" nullness from JGit API but so it loses the ability to use any other nullness annotations to annotate its own code. Change-Id: Ieeeb578c2fe35223a7561d668dce8e767dc89ef0 Signed-off-by: Andrey Loskutov --- org.eclipse.jgit/META-INF/MANIFEST.MF | 52 +++++++--------------- .../src/org/eclipse/jgit/annotations/NonNull.java | 2 + .../src/org/eclipse/jgit/annotations/Nullable.java | 2 + 3 files changed, 19 insertions(+), 37 deletions(-) diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF index b6899b2801..2a953b559d 100644 --- a/org.eclipse.jgit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/MANIFEST.MF @@ -6,7 +6,8 @@ Bundle-Version: 4.2.0.qualifier Bundle-Localization: plugin Bundle-Vendor: %provider_name Bundle-ActivationPolicy: lazy -Export-Package: org.eclipse.jgit.api;version="4.2.0"; +Export-Package: org.eclipse.jgit.annotations;version="4.2.0", + org.eclipse.jgit.api;version="4.2.0"; uses:="org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.diff, @@ -20,9 +21,7 @@ Export-Package: org.eclipse.jgit.api;version="4.2.0"; org.eclipse.jgit.submodule, org.eclipse.jgit.transport, org.eclipse.jgit.merge", - org.eclipse.jgit.api.errors;version="4.2.0"; - uses:="org.eclipse.jgit.lib, - org.eclipse.jgit.errors", + org.eclipse.jgit.api.errors;version="4.2.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors", org.eclipse.jgit.attributes;version="4.2.0", org.eclipse.jgit.blame;version="4.2.0"; uses:="org.eclipse.jgit.lib, @@ -47,8 +46,7 @@ Export-Package: org.eclipse.jgit.api;version="4.2.0"; org.eclipse.jgit.internal.storage.pack, org.eclipse.jgit.transport, org.eclipse.jgit.dircache", - org.eclipse.jgit.events;version="4.2.0"; - uses:="org.eclipse.jgit.lib", + org.eclipse.jgit.events;version="4.2.0";uses:="org.eclipse.jgit.lib", org.eclipse.jgit.fnmatch;version="4.2.0", org.eclipse.jgit.gitrepo;version="4.2.0"; uses:="org.eclipse.jgit.api, @@ -57,14 +55,11 @@ Export-Package: org.eclipse.jgit.api;version="4.2.0"; org.xml.sax.helpers, org.xml.sax", org.eclipse.jgit.gitrepo.internal;version="4.2.0";x-internal:=true, - org.eclipse.jgit.hooks;version="4.2.0"; - uses:="org.eclipse.jgit.lib", + org.eclipse.jgit.hooks;version="4.2.0";uses:="org.eclipse.jgit.lib", org.eclipse.jgit.ignore;version="4.2.0", org.eclipse.jgit.ignore.internal;version="4.2.0";x-friends:="org.eclipse.jgit.test", org.eclipse.jgit.internal;version="4.2.0";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test", - org.eclipse.jgit.internal.storage.dfs;version="4.2.0"; - x-friends:="org.eclipse.jgit.test, - org.eclipse.jgit.http.server", + org.eclipse.jgit.internal.storage.dfs;version="4.2.0";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.server", org.eclipse.jgit.internal.storage.file;version="4.2.0"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.junit, @@ -96,31 +91,18 @@ Export-Package: org.eclipse.jgit.api;version="4.2.0"; org.eclipse.jgit.treewalk, org.eclipse.jgit.revwalk, org.eclipse.jgit.merge", - org.eclipse.jgit.patch;version="4.2.0"; - uses:="org.eclipse.jgit.lib, - org.eclipse.jgit.diff", - org.eclipse.jgit.revplot;version="4.2.0"; - uses:="org.eclipse.jgit.lib, - org.eclipse.jgit.revwalk", + org.eclipse.jgit.patch;version="4.2.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff", + org.eclipse.jgit.revplot;version="4.2.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk", org.eclipse.jgit.revwalk;version="4.2.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.diff, org.eclipse.jgit.revwalk.filter", - org.eclipse.jgit.revwalk.filter;version="4.2.0"; - uses:="org.eclipse.jgit.revwalk, - org.eclipse.jgit.lib, - org.eclipse.jgit.util", - org.eclipse.jgit.storage.file;version="4.2.0"; - uses:="org.eclipse.jgit.lib, - org.eclipse.jgit.util", - org.eclipse.jgit.storage.pack;version="4.2.0"; - uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.submodule;version="4.2.0"; - uses:="org.eclipse.jgit.lib, - org.eclipse.jgit.treewalk.filter, - org.eclipse.jgit.treewalk", + org.eclipse.jgit.revwalk.filter;version="4.2.0";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util", + org.eclipse.jgit.storage.file;version="4.2.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util", + org.eclipse.jgit.storage.pack;version="4.2.0";uses:="org.eclipse.jgit.lib", + org.eclipse.jgit.submodule;version="4.2.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk", org.eclipse.jgit.transport;version="4.2.0"; uses:="org.eclipse.jgit.transport.resolver, org.eclipse.jgit.revwalk, @@ -133,11 +115,8 @@ Export-Package: org.eclipse.jgit.api;version="4.2.0"; org.eclipse.jgit.transport.http, org.eclipse.jgit.errors, org.eclipse.jgit.storage.pack", - org.eclipse.jgit.transport.http;version="4.2.0"; - uses:="javax.net.ssl", - org.eclipse.jgit.transport.resolver;version="4.2.0"; - uses:="org.eclipse.jgit.lib, - org.eclipse.jgit.transport", + org.eclipse.jgit.transport.http;version="4.2.0";uses:="javax.net.ssl", + org.eclipse.jgit.transport.resolver;version="4.2.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport", org.eclipse.jgit.treewalk;version="4.2.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, @@ -145,8 +124,7 @@ Export-Package: org.eclipse.jgit.api;version="4.2.0"; org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.util, org.eclipse.jgit.dircache", - org.eclipse.jgit.treewalk.filter;version="4.2.0"; - uses:="org.eclipse.jgit.treewalk", + org.eclipse.jgit.treewalk.filter;version="4.2.0";uses:="org.eclipse.jgit.treewalk", org.eclipse.jgit.util;version="4.2.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.transport.http, diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java index a74654fb5b..08f81cb9f8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java @@ -58,6 +58,8 @@ import java.lang.annotation.Target; *

* Denotes that a local variable, parameter, field, method return value expected * to be non {@code null}. + * + * @since 4.2 */ @Documented @Retention(RetentionPolicy.CLASS) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java index 254920e7a3..4275dc4fad 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java @@ -58,6 +58,8 @@ import java.lang.annotation.Target; *

* Denotes that a local variable, parameter, field, method return value can be * {@code null}. + * + * @since 4.2 */ @Documented @Retention(RetentionPolicy.CLASS) -- cgit v1.2.3 From 12280c02dbb8e4ac10893fbbd415be757afab4c1 Mon Sep 17 00:00:00 2001 From: Arthur Daussy Date: Fri, 31 Oct 2014 17:46:36 +0100 Subject: Adds the git attributes computation on the treewalk Adds the getAttributes feature to the tree walk. The computation of attributes needs to be done by the TreeWalk since it needs both a WorkingTreeIterator and a DirCacheIterator. Bug: 342372 CQ: 9120 Change-Id: I5e33257fd8c9895869a128bad3fd1e720409d361 Signed-off-by: Arthur Daussy Signed-off-by: Christian Halstrick --- .../eclipse/jgit/attributes/AttributeNodeTest.java | 182 ----- .../AttributesNodeDirCacheIteratorTest.java | 12 +- .../jgit/attributes/AttributesNodeTest.java | 182 +++++ .../AttributesNodeWorkingTreeIteratorTest.java | 47 +- .../jgit/attributes/TreeWalkAttributeTest.java | 865 +++++++++++++++++++++ org.eclipse.jgit/.settings/.api_filters | 14 + .../src/org/eclipse/jgit/api/AddCommand.java | 3 + .../src/org/eclipse/jgit/api/CommitCommand.java | 2 + .../jgit/attributes/AttributesNodeProvider.java | 81 ++ .../jgit/attributes/AttributesProvider.java | 57 ++ .../src/org/eclipse/jgit/dircache/DirCache.java | 2 + .../jgit/internal/storage/dfs/DfsRepository.java | 37 + .../jgit/internal/storage/file/FileRepository.java | 63 ++ .../storage/file/GlobalAttributesNode.java | 87 +++ .../internal/storage/file/InfoAttributesNode.java | 80 ++ .../src/org/eclipse/jgit/lib/IndexDiff.java | 2 + .../src/org/eclipse/jgit/lib/Repository.java | 11 + .../jgit/treewalk/NameConflictTreeWalk.java | 2 +- .../src/org/eclipse/jgit/treewalk/TreeWalk.java | 270 ++++++- .../eclipse/jgit/treewalk/WorkingTreeIterator.java | 88 +-- 20 files changed, 1790 insertions(+), 297 deletions(-) delete mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributeNodeTest.java create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNodeProvider.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GlobalAttributesNode.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributeNodeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributeNodeTest.java deleted file mode 100644 index ea250369a0..0000000000 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributeNodeTest.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2014, Obeo. - * 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 static org.eclipse.jgit.attributes.Attribute.State.SET; -import static org.eclipse.jgit.attributes.Attribute.State.UNSET; -import static org.junit.Assert.assertEquals; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; - -import org.junit.After; -import org.junit.Test; - -/** - * Test {@link AttributesNode} - */ -public class AttributeNodeTest { - - private static final Attribute A_SET_ATTR = new Attribute("A", SET); - - private static final Attribute A_UNSET_ATTR = new Attribute("A", UNSET); - - private static final Attribute B_SET_ATTR = new Attribute("B", SET); - - private static final Attribute B_UNSET_ATTR = new Attribute("B", UNSET); - - private static final Attribute C_VALUE_ATTR = new Attribute("C", "value"); - - private static final Attribute C_VALUE2_ATTR = new Attribute("C", "value2"); - - private InputStream is; - - @After - public void after() throws IOException { - if (is != null) - is.close(); - } - - @Test - public void testBasic() throws IOException { - String attributeFileContent = "*.type1 A -B C=value\n" - + "*.type2 -A B C=value2"; - - is = new ByteArrayInputStream(attributeFileContent.getBytes()); - AttributesNode node = new AttributesNode(); - node.parse(is); - assertAttribute("file.type1", node, - asSet(A_SET_ATTR, B_UNSET_ATTR, C_VALUE_ATTR)); - assertAttribute("file.type2", node, - asSet(A_UNSET_ATTR, B_SET_ATTR, C_VALUE2_ATTR)); - } - - @Test - public void testNegativePattern() throws IOException { - String attributeFileContent = "!*.type1 A -B C=value\n" - + "!*.type2 -A B C=value2"; - - is = new ByteArrayInputStream(attributeFileContent.getBytes()); - AttributesNode node = new AttributesNode(); - node.parse(is); - assertAttribute("file.type1", node, Collections. emptySet()); - assertAttribute("file.type2", node, Collections. emptySet()); - } - - @Test - public void testEmptyNegativeAttributeKey() throws IOException { - String attributeFileContent = "*.type1 - \n" // - + "*.type2 - -A"; - is = new ByteArrayInputStream(attributeFileContent.getBytes()); - AttributesNode node = new AttributesNode(); - node.parse(is); - assertAttribute("file.type1", node, Collections. emptySet()); - assertAttribute("file.type2", node, asSet(A_UNSET_ATTR)); - } - - @Test - public void testEmptyValueKey() throws IOException { - String attributeFileContent = "*.type1 = \n" // - + "*.type2 =value\n"// - + "*.type3 attr=\n"; - is = new ByteArrayInputStream(attributeFileContent.getBytes()); - AttributesNode node = new AttributesNode(); - node.parse(is); - assertAttribute("file.type1", node, Collections. emptySet()); - assertAttribute("file.type2", node, Collections. emptySet()); - assertAttribute("file.type3", node, asSet(new Attribute("attr", ""))); - } - - @Test - public void testEmptyLine() throws IOException { - String attributeFileContent = "*.type1 A -B C=value\n" // - + "\n" // - + " \n" // - + "*.type2 -A B C=value2"; - - is = new ByteArrayInputStream(attributeFileContent.getBytes()); - AttributesNode node = new AttributesNode(); - node.parse(is); - assertAttribute("file.type1", node, - asSet(A_SET_ATTR, B_UNSET_ATTR, C_VALUE_ATTR)); - assertAttribute("file.type2", node, - asSet(A_UNSET_ATTR, B_SET_ATTR, C_VALUE2_ATTR)); - } - - @Test - public void testTabSeparator() throws IOException { - String attributeFileContent = "*.type1 \tA -B\tC=value\n" - + "*.type2\t -A\tB C=value2\n" // - + "*.type3 \t\t B\n" // - + "*.type3\t-A";// - - is = new ByteArrayInputStream(attributeFileContent.getBytes()); - AttributesNode node = new AttributesNode(); - node.parse(is); - assertAttribute("file.type1", node, - asSet(A_SET_ATTR, B_UNSET_ATTR, C_VALUE_ATTR)); - assertAttribute("file.type2", node, - asSet(A_UNSET_ATTR, B_SET_ATTR, C_VALUE2_ATTR)); - assertAttribute("file.type3", node, asSet(A_UNSET_ATTR, B_SET_ATTR)); - } - - private void assertAttribute(String path, AttributesNode node, - Set attrs) { - HashMap attributes = new HashMap(); - node.getAttributes(path, false, attributes); - assertEquals(attrs, new HashSet(attributes.values())); - } - - static Set asSet(Attribute... attrs) { - Set result = new HashSet(); - for (Attribute attr : attrs) - result.add(attr); - return result; - } - -} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java index 49279e6e5a..3e6ca62202 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java @@ -243,23 +243,23 @@ public class AttributesNodeDirCacheIteratorTest extends RepositoryTestCase { DirCacheIterator itr = walk.getTree(0, DirCacheIterator.class); assertNotNull("has tree", itr); - AttributesNode attributeNode = itr.getEntryAttributesNode(db + AttributesNode attributesNode = itr.getEntryAttributesNode(db .newObjectReader()); - assertAttributeNode(pathName, attributeNode, nodeAttrs); + assertAttributesNode(pathName, attributesNode, nodeAttrs); if (D.equals(type)) walk.enterSubtree(); } - private void assertAttributeNode(String pathName, - AttributesNode attributeNode, List nodeAttrs) { - if (attributeNode == null) + private void assertAttributesNode(String pathName, + AttributesNode attributesNode, List nodeAttrs) { + if (attributesNode == null) assertTrue(nodeAttrs == null || nodeAttrs.isEmpty()); else { Map entryAttributes = new LinkedHashMap(); - attributeNode.getAttributes(pathName, false, entryAttributes); + attributesNode.getAttributes(pathName, false, entryAttributes); if (nodeAttrs != null && !nodeAttrs.isEmpty()) { for (Attribute attribute : nodeAttrs) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java new file mode 100644 index 0000000000..d82baaa36e --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2014, Obeo. + * 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 static org.eclipse.jgit.attributes.Attribute.State.SET; +import static org.eclipse.jgit.attributes.Attribute.State.UNSET; +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import org.junit.After; +import org.junit.Test; + +/** + * Test {@link AttributesNode} + */ +public class AttributesNodeTest { + + private static final Attribute A_SET_ATTR = new Attribute("A", SET); + + private static final Attribute A_UNSET_ATTR = new Attribute("A", UNSET); + + private static final Attribute B_SET_ATTR = new Attribute("B", SET); + + private static final Attribute B_UNSET_ATTR = new Attribute("B", UNSET); + + private static final Attribute C_VALUE_ATTR = new Attribute("C", "value"); + + private static final Attribute C_VALUE2_ATTR = new Attribute("C", "value2"); + + private InputStream is; + + @After + public void after() throws IOException { + if (is != null) + is.close(); + } + + @Test + public void testBasic() throws IOException { + String attributeFileContent = "*.type1 A -B C=value\n" + + "*.type2 -A B C=value2"; + + is = new ByteArrayInputStream(attributeFileContent.getBytes()); + AttributesNode node = new AttributesNode(); + node.parse(is); + assertAttribute("file.type1", node, + asSet(A_SET_ATTR, B_UNSET_ATTR, C_VALUE_ATTR)); + assertAttribute("file.type2", node, + asSet(A_UNSET_ATTR, B_SET_ATTR, C_VALUE2_ATTR)); + } + + @Test + public void testNegativePattern() throws IOException { + String attributeFileContent = "!*.type1 A -B C=value\n" + + "!*.type2 -A B C=value2"; + + is = new ByteArrayInputStream(attributeFileContent.getBytes()); + AttributesNode node = new AttributesNode(); + node.parse(is); + assertAttribute("file.type1", node, Collections. emptySet()); + assertAttribute("file.type2", node, Collections. emptySet()); + } + + @Test + public void testEmptyNegativeAttributeKey() throws IOException { + String attributeFileContent = "*.type1 - \n" // + + "*.type2 - -A"; + is = new ByteArrayInputStream(attributeFileContent.getBytes()); + AttributesNode node = new AttributesNode(); + node.parse(is); + assertAttribute("file.type1", node, Collections. emptySet()); + assertAttribute("file.type2", node, asSet(A_UNSET_ATTR)); + } + + @Test + public void testEmptyValueKey() throws IOException { + String attributeFileContent = "*.type1 = \n" // + + "*.type2 =value\n"// + + "*.type3 attr=\n"; + is = new ByteArrayInputStream(attributeFileContent.getBytes()); + AttributesNode node = new AttributesNode(); + node.parse(is); + assertAttribute("file.type1", node, Collections. emptySet()); + assertAttribute("file.type2", node, Collections. emptySet()); + assertAttribute("file.type3", node, asSet(new Attribute("attr", ""))); + } + + @Test + public void testEmptyLine() throws IOException { + String attributeFileContent = "*.type1 A -B C=value\n" // + + "\n" // + + " \n" // + + "*.type2 -A B C=value2"; + + is = new ByteArrayInputStream(attributeFileContent.getBytes()); + AttributesNode node = new AttributesNode(); + node.parse(is); + assertAttribute("file.type1", node, + asSet(A_SET_ATTR, B_UNSET_ATTR, C_VALUE_ATTR)); + assertAttribute("file.type2", node, + asSet(A_UNSET_ATTR, B_SET_ATTR, C_VALUE2_ATTR)); + } + + @Test + public void testTabSeparator() throws IOException { + String attributeFileContent = "*.type1 \tA -B\tC=value\n" + + "*.type2\t -A\tB C=value2\n" // + + "*.type3 \t\t B\n" // + + "*.type3\t-A";// + + is = new ByteArrayInputStream(attributeFileContent.getBytes()); + AttributesNode node = new AttributesNode(); + node.parse(is); + assertAttribute("file.type1", node, + asSet(A_SET_ATTR, B_UNSET_ATTR, C_VALUE_ATTR)); + assertAttribute("file.type2", node, + asSet(A_UNSET_ATTR, B_SET_ATTR, C_VALUE2_ATTR)); + assertAttribute("file.type3", node, asSet(A_UNSET_ATTR, B_SET_ATTR)); + } + + private void assertAttribute(String path, AttributesNode node, + Set attrs) { + HashMap attributes = new HashMap(); + node.getAttributes(path, false, attributes); + assertEquals(attrs, new HashSet(attributes.values())); + } + + static Set asSet(Attribute... attrs) { + Set result = new HashSet(); + for (Attribute attr : attrs) + result.add(attr); + return result; + } + +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java index 64b0535d6a..bcf17174b8 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java @@ -76,14 +76,10 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase { private static final FileMode F = FileMode.REGULAR_FILE; - private static Attribute EOL_CRLF = new Attribute("eol", "crlf"); - private static Attribute EOL_LF = new Attribute("eol", "lf"); private static Attribute DELTA_UNSET = new Attribute("delta", State.UNSET); - private static Attribute CUSTOM_VALUE = new Attribute("custom", "value"); - private TreeWalk walk; @Test @@ -112,25 +108,19 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase { walk = beginWalk(); assertIteration(F, ".gitattributes"); - assertIteration(F, "global.txt", asList(EOL_LF), null, - asList(CUSTOM_VALUE)); - assertIteration(F, "readme.txt", asList(EOL_LF), null, - asList(CUSTOM_VALUE)); + assertIteration(F, "global.txt", asList(EOL_LF)); + assertIteration(F, "readme.txt", asList(EOL_LF)); assertIteration(D, "src"); assertIteration(D, "src/config"); assertIteration(F, "src/config/.gitattributes"); - assertIteration(F, "src/config/readme.txt", asList(DELTA_UNSET), null, - asList(CUSTOM_VALUE)); - assertIteration(F, "src/config/windows.file", null, asList(EOL_CRLF), - null); - assertIteration(F, "src/config/windows.txt", asList(DELTA_UNSET), - asList(EOL_CRLF), asList(CUSTOM_VALUE)); + assertIteration(F, "src/config/readme.txt", asList(DELTA_UNSET)); + assertIteration(F, "src/config/windows.file", null); + assertIteration(F, "src/config/windows.txt", asList(DELTA_UNSET)); - assertIteration(F, "windows.file", null, asList(EOL_CRLF), null); - assertIteration(F, "windows.txt", asList(EOL_LF), asList(EOL_CRLF), - asList(CUSTOM_VALUE)); + assertIteration(F, "windows.file", null); + assertIteration(F, "windows.txt", asList(EOL_LF)); endWalk(); } @@ -212,14 +202,11 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase { private void assertIteration(FileMode type, String pathName) throws IOException { - assertIteration(type, pathName, Collections. emptyList(), - Collections. emptyList(), - Collections. emptyList()); + assertIteration(type, pathName, Collections. emptyList()); } private void assertIteration(FileMode type, String pathName, - List nodeAttrs, List infoAttrs, - List globalAttrs) + List nodeAttrs) throws IOException { assertTrue("walk has entry", walk.next()); assertEquals(pathName, walk.getPathString()); @@ -227,25 +214,21 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase { WorkingTreeIterator itr = walk.getTree(0, WorkingTreeIterator.class); assertNotNull("has tree", itr); - AttributesNode attributeNode = itr.getEntryAttributesNode(); - assertAttributeNode(pathName, attributeNode, nodeAttrs); - AttributesNode infoAttributeNode = itr.getInfoAttributesNode(); - assertAttributeNode(pathName, infoAttributeNode, infoAttrs); - AttributesNode globalAttributeNode = itr.getGlobalAttributesNode(); - assertAttributeNode(pathName, globalAttributeNode, globalAttrs); + AttributesNode attributesNode = itr.getEntryAttributesNode(); + assertAttributesNode(pathName, attributesNode, nodeAttrs); if (D.equals(type)) walk.enterSubtree(); } - private void assertAttributeNode(String pathName, - AttributesNode attributeNode, List nodeAttrs) { - if (attributeNode == null) + private void assertAttributesNode(String pathName, + AttributesNode attributesNode, List nodeAttrs) { + if (attributesNode == null) assertTrue(nodeAttrs == null || nodeAttrs.isEmpty()); else { Map entryAttributes = new LinkedHashMap(); - attributeNode.getAttributes(pathName, false, entryAttributes); + attributesNode.getAttributes(pathName, false, entryAttributes); if (nodeAttrs != null && !nodeAttrs.isEmpty()) { for (Attribute attribute : nodeAttrs) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java new file mode 100644 index 0000000000..c3d5e8752c --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java @@ -0,0 +1,865 @@ +/* + * Copyright (C) 2014, Obeo. + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.api.errors.NoFilepatternException; +import org.eclipse.jgit.attributes.Attribute.State; +import org.eclipse.jgit.dircache.DirCacheIterator; +import org.eclipse.jgit.errors.NoWorkTreeException; +import org.eclipse.jgit.junit.JGitTestUtil; +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.FileMode; +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.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests the attributes are correctly computed in a {@link TreeWalk}. + * + * @see TreeWalk#getAttributes() + */ +public class TreeWalkAttributeTest extends RepositoryTestCase { + + private static final FileMode M = FileMode.MISSING; + + private static final FileMode D = FileMode.TREE; + + private static final FileMode F = FileMode.REGULAR_FILE; + + private static Attribute EOL_CRLF = new Attribute("eol", "crlf"); + + private static Attribute EOL_LF = new Attribute("eol", "lf"); + + private static Attribute TEXT_SET = new Attribute("text", State.SET); + + private static Attribute TEXT_UNSET = new Attribute("text", State.UNSET); + + private static Attribute DELTA_UNSET = new Attribute("delta", State.UNSET); + + private static Attribute DELTA_SET = new Attribute("delta", State.SET); + + private static Attribute CUSTOM_GLOBAL = new Attribute("custom", "global"); + + private static Attribute CUSTOM_INFO = new Attribute("custom", "info"); + + private static Attribute CUSTOM_ROOT = new Attribute("custom", "root"); + + private static Attribute CUSTOM_PARENT = new Attribute("custom", "parent"); + + private static Attribute CUSTOM_CURRENT = new Attribute("custom", "current"); + + private static Attribute CUSTOM2_UNSET = new Attribute("custom2", + State.UNSET); + + private static Attribute CUSTOM2_SET = new Attribute("custom2", State.SET); + + private TreeWalk walk; + + private TreeWalk ci_walk; + + private Git git; + + private File customAttributeFile; + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + git = new Git(db); + } + + @Override + @After + public void tearDown() throws Exception { + super.tearDown(); + if (customAttributeFile != null) + customAttributeFile.delete(); + } + + /** + * Checks that the attributes are computed correctly depending on the + * operation type. + *

+ * In this test we changed the content of the attribute files in the working + * tree compared to the one in the index. + *

+ * + * @throws IOException + * @throws NoFilepatternException + * @throws GitAPIException + */ + @Test + public void testCheckinCheckoutDifferences() throws IOException, + NoFilepatternException, GitAPIException { + + writeGlobalAttributeFile("globalAttributesFile", "*.txt -custom2"); + writeAttributesFile(".git/info/attributes", "*.txt eol=crlf"); + writeAttributesFile(".gitattributes", "*.txt custom=root"); + writeAttributesFile("level1/.gitattributes", "*.txt text"); + writeAttributesFile("level1/level2/.gitattributes", "*.txt -delta"); + + writeTrashFile("l0.txt", ""); + + writeTrashFile("level1/l1.txt", ""); + + writeTrashFile("level1/level2/l2.txt", ""); + + git.add().addFilepattern(".").call(); + + beginWalk(); + + // Modify all attributes + writeGlobalAttributeFile("globalAttributesFile", "*.txt custom2"); + writeAttributesFile(".git/info/attributes", "*.txt eol=lf"); + writeAttributesFile(".gitattributes", "*.txt custom=info"); + writeAttributesFile("level1/.gitattributes", "*.txt -text"); + writeAttributesFile("level1/level2/.gitattributes", "*.txt delta"); + + assertEntry(F, ".gitattributes"); + assertEntry(F, "l0.txt", asSet(EOL_LF, CUSTOM_INFO, CUSTOM2_SET), + asSet(EOL_LF, CUSTOM_ROOT, CUSTOM2_SET)); + + assertEntry(D, "level1"); + assertEntry(F, "level1/.gitattributes"); + assertEntry(F, "level1/l1.txt", + asSet(EOL_LF, CUSTOM_INFO, CUSTOM2_SET, TEXT_UNSET), + asSet(EOL_LF, CUSTOM_ROOT, CUSTOM2_SET, TEXT_SET)); + + assertEntry(D, "level1/level2"); + assertEntry(F, "level1/level2/.gitattributes"); + assertEntry(F, "level1/level2/l2.txt", + asSet(EOL_LF, CUSTOM_INFO, CUSTOM2_SET, TEXT_UNSET, DELTA_SET), + asSet(EOL_LF, CUSTOM_ROOT, CUSTOM2_SET, TEXT_SET, DELTA_UNSET)); + + endWalk(); + } + + /** + * Checks that the index is used as fallback when the git attributes file + * are missing in the working tree. + * + * @throws IOException + * @throws NoFilepatternException + * @throws GitAPIException + */ + @Test + public void testIndexOnly() throws IOException, NoFilepatternException, + GitAPIException { + List attrFiles = new ArrayList(); + attrFiles.add(writeGlobalAttributeFile("globalAttributesFile", + "*.txt -custom2")); + attrFiles.add(writeAttributesFile(".git/info/attributes", + "*.txt eol=crlf")); + attrFiles + .add(writeAttributesFile(".gitattributes", "*.txt custom=root")); + attrFiles + .add(writeAttributesFile("level1/.gitattributes", "*.txt text")); + attrFiles.add(writeAttributesFile("level1/level2/.gitattributes", + "*.txt -delta")); + + writeTrashFile("l0.txt", ""); + + writeTrashFile("level1/l1.txt", ""); + + writeTrashFile("level1/level2/l2.txt", ""); + + git.add().addFilepattern(".").call(); + + // Modify all attributes + for (File attrFile : attrFiles) + attrFile.delete(); + + beginWalk(); + + assertEntry(M, ".gitattributes"); + assertEntry(F, "l0.txt", asSet(CUSTOM_ROOT)); + + assertEntry(D, "level1"); + assertEntry(M, "level1/.gitattributes"); + assertEntry(F, "level1/l1.txt", + + asSet(CUSTOM_ROOT, TEXT_SET)); + + assertEntry(D, "level1/level2"); + assertEntry(M, "level1/level2/.gitattributes"); + assertEntry(F, "level1/level2/l2.txt", + + asSet(CUSTOM_ROOT, TEXT_SET, DELTA_UNSET)); + + endWalk(); + } + + /** + * Check that we search in the working tree for attributes although the file + * we are currently inspecting does not exist anymore in the working tree. + * + * @throws IOException + * @throws NoFilepatternException + * @throws GitAPIException + */ + @Test + public void testIndexOnly2() + throws IOException, NoFilepatternException, GitAPIException { + File l2 = writeTrashFile("level1/level2/l2.txt", ""); + writeTrashFile("level1/level2/l1.txt", ""); + + git.add().addFilepattern(".").call(); + + writeAttributesFile(".gitattributes", "*.txt custom=root"); + assertTrue(l2.delete()); + + beginWalk(); + + assertEntry(F, ".gitattributes"); + assertEntry(D, "level1"); + assertEntry(D, "level1/level2"); + assertEntry(F, "level1/level2/l1.txt", asSet(CUSTOM_ROOT)); + assertEntry(M, "level1/level2/l2.txt", asSet(CUSTOM_ROOT)); + + endWalk(); + } + + /** + * Basic test for git attributes. + *

+ * In this use case files are present in both the working tree and the index + *

+ * + * @throws IOException + * @throws NoFilepatternException + * @throws GitAPIException + */ + @Test + public void testRules() throws IOException, NoFilepatternException, + GitAPIException { + writeAttributesFile(".git/info/attributes", "windows* eol=crlf"); + + writeAttributesFile(".gitattributes", "*.txt eol=lf"); + writeTrashFile("windows.file", ""); + writeTrashFile("windows.txt", ""); + writeTrashFile("readme.txt", ""); + + writeAttributesFile("src/config/.gitattributes", "*.txt -delta"); + writeTrashFile("src/config/readme.txt", ""); + writeTrashFile("src/config/windows.file", ""); + writeTrashFile("src/config/windows.txt", ""); + + beginWalk(); + + git.add().addFilepattern(".").call(); + + assertEntry(F, ".gitattributes"); + assertEntry(F, "readme.txt", asSet(EOL_LF)); + + assertEntry(D, "src"); + assertEntry(D, "src/config"); + assertEntry(F, "src/config/.gitattributes"); + assertEntry(F, "src/config/readme.txt", asSet(DELTA_UNSET, EOL_LF)); + assertEntry(F, "src/config/windows.file", asSet(EOL_CRLF)); + assertEntry(F, "src/config/windows.txt", asSet(DELTA_UNSET, EOL_CRLF)); + + assertEntry(F, "windows.file", asSet(EOL_CRLF)); + assertEntry(F, "windows.txt", asSet(EOL_CRLF)); + + endWalk(); + } + + /** + * Checks that if there is no .gitattributes file in the repository + * everything still work fine. + * + * @throws IOException + */ + @Test + public void testNoAttributes() throws IOException { + writeTrashFile("l0.txt", ""); + writeTrashFile("level1/l1.txt", ""); + writeTrashFile("level1/level2/l2.txt", ""); + + beginWalk(); + + assertEntry(F, "l0.txt"); + + assertEntry(D, "level1"); + assertEntry(F, "level1/l1.txt"); + + assertEntry(D, "level1/level2"); + assertEntry(F, "level1/level2/l2.txt"); + + endWalk(); + } + + /** + * Checks that an empty .gitattribute file does not return incorrect value. + * + * @throws IOException + */ + @Test + public void testEmptyGitAttributeFile() throws IOException { + writeAttributesFile(".git/info/attributes", ""); + writeTrashFile("l0.txt", ""); + writeAttributesFile(".gitattributes", ""); + writeTrashFile("level1/l1.txt", ""); + writeTrashFile("level1/level2/l2.txt", ""); + + beginWalk(); + + assertEntry(F, ".gitattributes"); + assertEntry(F, "l0.txt"); + + assertEntry(D, "level1"); + assertEntry(F, "level1/l1.txt"); + + assertEntry(D, "level1/level2"); + assertEntry(F, "level1/level2/l2.txt"); + + endWalk(); + } + + @Test + public void testNoMatchingAttributes() throws IOException { + writeAttributesFile(".git/info/attributes", "*.java delta"); + writeAttributesFile(".gitattributes", "*.java -delta"); + writeAttributesFile("levelA/.gitattributes", "*.java eol=lf"); + writeAttributesFile("levelB/.gitattributes", "*.txt eol=lf"); + + writeTrashFile("levelA/lA.txt", ""); + + beginWalk(); + + assertEntry(F, ".gitattributes"); + + assertEntry(D, "levelA"); + assertEntry(F, "levelA/.gitattributes"); + assertEntry(F, "levelA/lA.txt"); + + assertEntry(D, "levelB"); + assertEntry(F, "levelB/.gitattributes"); + + endWalk(); + } + + /** + * Checks that $GIT_DIR/info/attributes file has the highest precedence. + * + * @throws IOException + */ + @Test + public void testPrecedenceInfo() throws IOException { + writeGlobalAttributeFile("globalAttributesFile", "*.txt custom=global"); + writeAttributesFile(".git/info/attributes", "*.txt custom=info"); + writeAttributesFile(".gitattributes", "*.txt custom=root"); + writeAttributesFile("level1/.gitattributes", "*.txt custom=parent"); + writeAttributesFile("level1/level2/.gitattributes", + "*.txt custom=current"); + + writeTrashFile("level1/level2/file.txt", ""); + + beginWalk(); + + assertEntry(F, ".gitattributes"); + + assertEntry(D, "level1"); + assertEntry(F, "level1/.gitattributes"); + + assertEntry(D, "level1/level2"); + assertEntry(F, "level1/level2/.gitattributes"); + assertEntry(F, "level1/level2/file.txt", asSet(CUSTOM_INFO)); + + endWalk(); + } + + /** + * Checks that a subfolder ".gitattributes" file has precedence over its + * parent. + * + * @throws IOException + */ + @Test + public void testPrecedenceCurrent() throws IOException { + writeGlobalAttributeFile("globalAttributesFile", "*.txt custom=global"); + writeAttributesFile(".gitattributes", "*.txt custom=root"); + writeAttributesFile("level1/.gitattributes", "*.txt custom=parent"); + writeAttributesFile("level1/level2/.gitattributes", + "*.txt custom=current"); + + writeTrashFile("level1/level2/file.txt", ""); + + beginWalk(); + + assertEntry(F, ".gitattributes"); + + assertEntry(D, "level1"); + assertEntry(F, "level1/.gitattributes"); + + assertEntry(D, "level1/level2"); + assertEntry(F, "level1/level2/.gitattributes"); + assertEntry(F, "level1/level2/file.txt", asSet(CUSTOM_CURRENT)); + + endWalk(); + } + + /** + * Checks that the parent ".gitattributes" file is used as fallback. + * + * @throws IOException + */ + @Test + public void testPrecedenceParent() throws IOException { + writeGlobalAttributeFile("globalAttributesFile", "*.txt custom=global"); + writeAttributesFile(".gitattributes", "*.txt custom=root"); + writeAttributesFile("level1/.gitattributes", "*.txt custom=parent"); + + writeTrashFile("level1/level2/file.txt", ""); + + beginWalk(); + + assertEntry(F, ".gitattributes"); + + assertEntry(D, "level1"); + assertEntry(F, "level1/.gitattributes"); + + assertEntry(D, "level1/level2"); + assertEntry(F, "level1/level2/file.txt", asSet(CUSTOM_PARENT)); + + endWalk(); + } + + /** + * Checks that the grand parent ".gitattributes" file is used as fallback. + * + * @throws IOException + */ + @Test + public void testPrecedenceRoot() throws IOException { + writeGlobalAttributeFile("globalAttributesFile", "*.txt custom=global"); + writeAttributesFile(".gitattributes", "*.txt custom=root"); + + writeTrashFile("level1/level2/file.txt", ""); + + beginWalk(); + + assertEntry(F, ".gitattributes"); + + assertEntry(D, "level1"); + + assertEntry(D, "level1/level2"); + assertEntry(F, "level1/level2/file.txt", asSet(CUSTOM_ROOT)); + + endWalk(); + } + + /** + * Checks that the global attribute file is used as fallback. + * + * @throws IOException + */ + @Test + public void testPrecedenceGlobal() throws IOException { + writeGlobalAttributeFile("globalAttributesFile", "*.txt custom=global"); + + writeTrashFile("level1/level2/file.txt", ""); + + beginWalk(); + + assertEntry(D, "level1"); + + assertEntry(D, "level1/level2"); + assertEntry(F, "level1/level2/file.txt", asSet(CUSTOM_GLOBAL)); + + endWalk(); + } + + /** + * Checks the precedence on a hierarchy with multiple attributes. + *

+ * In this test all file are present in both the working tree and the index. + *

+ * + * @throws IOException + * @throws GitAPIException + * @throws NoFilepatternException + */ + @Test + public void testHierarchyBothIterator() throws IOException, + NoFilepatternException, GitAPIException { + writeAttributesFile(".git/info/attributes", "*.global eol=crlf"); + writeAttributesFile(".gitattributes", "*.local eol=lf"); + writeAttributesFile("level1/.gitattributes", "*.local text"); + writeAttributesFile("level1/level2/.gitattributes", "*.local -text"); + + writeTrashFile("l0.global", ""); + writeTrashFile("l0.local", ""); + + writeTrashFile("level1/l1.global", ""); + writeTrashFile("level1/l1.local", ""); + + writeTrashFile("level1/level2/l2.global", ""); + writeTrashFile("level1/level2/l2.local", ""); + + beginWalk(); + + git.add().addFilepattern(".").call(); + + assertEntry(F, ".gitattributes"); + assertEntry(F, "l0.global", asSet(EOL_CRLF)); + assertEntry(F, "l0.local", asSet(EOL_LF)); + + assertEntry(D, "level1"); + assertEntry(F, "level1/.gitattributes"); + assertEntry(F, "level1/l1.global", asSet(EOL_CRLF)); + assertEntry(F, "level1/l1.local", asSet(EOL_LF, TEXT_SET)); + + assertEntry(D, "level1/level2"); + assertEntry(F, "level1/level2/.gitattributes"); + assertEntry(F, "level1/level2/l2.global", asSet(EOL_CRLF)); + assertEntry(F, "level1/level2/l2.local", asSet(EOL_LF, TEXT_UNSET)); + + endWalk(); + + } + + /** + * Checks the precedence on a hierarchy with multiple attributes. + *

+ * In this test all file are present only in the working tree. + *

+ * + * @throws IOException + * @throws GitAPIException + * @throws NoFilepatternException + */ + @Test + public void testHierarchyWorktreeOnly() + throws IOException, NoFilepatternException, GitAPIException { + writeAttributesFile(".git/info/attributes", "*.global eol=crlf"); + writeAttributesFile(".gitattributes", "*.local eol=lf"); + writeAttributesFile("level1/.gitattributes", "*.local text"); + writeAttributesFile("level1/level2/.gitattributes", "*.local -text"); + + writeTrashFile("l0.global", ""); + writeTrashFile("l0.local", ""); + + writeTrashFile("level1/l1.global", ""); + writeTrashFile("level1/l1.local", ""); + + writeTrashFile("level1/level2/l2.global", ""); + writeTrashFile("level1/level2/l2.local", ""); + + beginWalk(); + + assertEntry(F, ".gitattributes"); + assertEntry(F, "l0.global", asSet(EOL_CRLF)); + assertEntry(F, "l0.local", asSet(EOL_LF)); + + assertEntry(D, "level1"); + assertEntry(F, "level1/.gitattributes"); + assertEntry(F, "level1/l1.global", asSet(EOL_CRLF)); + assertEntry(F, "level1/l1.local", asSet(EOL_LF, TEXT_SET)); + + assertEntry(D, "level1/level2"); + assertEntry(F, "level1/level2/.gitattributes"); + assertEntry(F, "level1/level2/l2.global", asSet(EOL_CRLF)); + assertEntry(F, "level1/level2/l2.local", asSet(EOL_LF, TEXT_UNSET)); + + endWalk(); + + } + + /** + * Checks that the list of attributes is an aggregation of all the + * attributes from the attributes files hierarchy. + * + * @throws IOException + */ + @Test + public void testAggregation() throws IOException { + writeGlobalAttributeFile("globalAttributesFile", "*.txt -custom2"); + writeAttributesFile(".git/info/attributes", "*.txt eol=crlf"); + writeAttributesFile(".gitattributes", "*.txt custom=root"); + writeAttributesFile("level1/.gitattributes", "*.txt text"); + writeAttributesFile("level1/level2/.gitattributes", "*.txt -delta"); + + writeTrashFile("l0.txt", ""); + + writeTrashFile("level1/l1.txt", ""); + + writeTrashFile("level1/level2/l2.txt", ""); + + beginWalk(); + + assertEntry(F, ".gitattributes"); + assertEntry(F, "l0.txt", asSet(EOL_CRLF, CUSTOM_ROOT, CUSTOM2_UNSET)); + + assertEntry(D, "level1"); + assertEntry(F, "level1/.gitattributes"); + assertEntry(F, "level1/l1.txt", + asSet(EOL_CRLF, CUSTOM_ROOT, TEXT_SET, CUSTOM2_UNSET)); + + assertEntry(D, "level1/level2"); + assertEntry(F, "level1/level2/.gitattributes"); + assertEntry( + F, + "level1/level2/l2.txt", + asSet(EOL_CRLF, CUSTOM_ROOT, TEXT_SET, DELTA_UNSET, + CUSTOM2_UNSET)); + + endWalk(); + + } + + /** + * Checks that the last entry in .gitattributes is used if 2 lines match the + * same attribute + * + * @throws IOException + */ + @Test + public void testOverriding() throws IOException { + writeAttributesFile(".git/info/attributes",// + // + "*.txt custom=current",// + "*.txt custom=parent",// + "*.txt custom=root",// + "*.txt custom=info", + // + "*.txt delta",// + "*.txt -delta", + // + "*.txt eol=lf",// + "*.txt eol=crlf", + // + "*.txt text",// + "*.txt -text"); + + writeTrashFile("l0.txt", ""); + beginWalk(); + + assertEntry(F, "l0.txt", + asSet(TEXT_UNSET, EOL_CRLF, DELTA_UNSET, CUSTOM_INFO)); + + endWalk(); + } + + /** + * Checks that the last value of an attribute is used if in the same line an + * attribute is defined several time. + * + * @throws IOException + */ + @Test + public void testOverriding2() throws IOException { + writeAttributesFile(".git/info/attributes", + "*.txt custom=current custom=parent custom=root custom=info",// + "*.txt delta -delta",// + "*.txt eol=lf eol=crlf",// + "*.txt text -text"); + writeTrashFile("l0.txt", ""); + beginWalk(); + + assertEntry(F, "l0.txt", + asSet(TEXT_UNSET, EOL_CRLF, DELTA_UNSET, CUSTOM_INFO)); + + endWalk(); + } + + @Test + public void testRulesInherited() throws Exception { + writeAttributesFile(".gitattributes", "**/*.txt eol=lf"); + writeTrashFile("src/config/readme.txt", ""); + writeTrashFile("src/config/windows.file", ""); + + beginWalk(); + + assertEntry(F, ".gitattributes"); + assertEntry(D, "src"); + assertEntry(D, "src/config"); + + assertEntry(F, "src/config/readme.txt", asSet(EOL_LF)); + assertEntry(F, "src/config/windows.file", + Collections. emptySet()); + + endWalk(); + } + + private void beginWalk() throws NoWorkTreeException, IOException { + walk = new TreeWalk(db); + walk.addTree(new FileTreeIterator(db)); + walk.addTree(new DirCacheIterator(db.readDirCache())); + + ci_walk = new TreeWalk(db); + ci_walk.setOperationType(OperationType.CHECKIN_OP); + ci_walk.addTree(new FileTreeIterator(db)); + ci_walk.addTree(new DirCacheIterator(db.readDirCache())); + } + + /** + * Assert an entry in which checkin and checkout attributes are expected to + * be the same. + * + * @param type + * @param pathName + * @param forBothOperaiton + * @throws IOException + */ + private void assertEntry(FileMode type, String pathName, + Set forBothOperaiton) throws IOException { + assertEntry(type, pathName, forBothOperaiton, forBothOperaiton); + } + + /** + * Assert an entry with no attribute expected. + * + * @param type + * @param pathName + * @throws IOException + */ + private void assertEntry(FileMode type, String pathName) throws IOException { + assertEntry(type, pathName, Collections. emptySet(), + Collections. emptySet()); + } + + /** + * Assert that an entry; + *
    + *
  • Has the correct type
  • + *
  • Exist in the tree walk
  • + *
  • Has the expected attributes on a checkin operation
  • + *
  • Has the expected attributes on a checkout operation
  • + *
+ * + * @param type + * @param pathName + * @param checkinAttributes + * @param checkoutAttributes + * @throws IOException + */ + private void assertEntry(FileMode type, String pathName, + Set checkinAttributes, Set checkoutAttributes) + throws IOException { + assertTrue("walk has entry", walk.next()); + assertTrue("walk has entry", ci_walk.next()); + assertEquals(pathName, walk.getPathString()); + assertEquals(type, walk.getFileMode(0)); + + assertEquals(checkinAttributes, + asSet(ci_walk.getAttributes().values())); + assertEquals(checkoutAttributes, asSet(walk.getAttributes().values())); + + if (D.equals(type)) { + walk.enterSubtree(); + ci_walk.enterSubtree(); + } + } + + private static Set asSet(Collection attributes) { + Set ret = new HashSet(); + for (Attribute a : attributes) { + ret.add(a); + } + return (ret); + } + + private File writeAttributesFile(String name, String... rules) + throws IOException { + StringBuilder data = new StringBuilder(); + for (String line : rules) + data.append(line + "\n"); + return writeTrashFile(name, data.toString()); + } + + /** + * Creates an attributes file and set its location in the git configuration. + * + * @param fileName + * @param attributes + * @return The attribute file + * @throws IOException + * @see Repository#getConfig() + */ + private File writeGlobalAttributeFile(String fileName, String... attributes) + throws IOException { + customAttributeFile = File.createTempFile("tmp_", fileName, null); + customAttributeFile.deleteOnExit(); + StringBuilder attributesFileContent = new StringBuilder(); + for (String attr : attributes) { + attributesFileContent.append(attr).append("\n"); + } + JGitTestUtil.write(customAttributeFile, + attributesFileContent.toString()); + db.getConfig().setString("core", null, "attributesfile", + customAttributeFile.getAbsolutePath()); + return customAttributeFile; + } + + static Set asSet(Attribute... attrs) { + HashSet result = new HashSet(); + for (Attribute attr : attrs) + result.add(attr); + return result; + } + + private void endWalk() throws IOException { + assertFalse("Not all files tested", walk.next()); + assertFalse("Not all files tested", ci_walk.next()); + } +} 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 @@ + + + + + + + + + + + + + + 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 { 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 { 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 { 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 + * 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 + * 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 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 paths = new ArrayList(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. 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 Arthur Daussy + * + */ + 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 + * Copyright (C) 2015, Christian Halstrick + * 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 + * Copyright (C) 2015, Christian Halstrick + * 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; @@ -209,6 +210,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 */ 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,9 +92,38 @@ 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. *

@@ -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 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}. + *

+ * 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. + *

+ * + * @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. + * + *

Git attribute computation

+ * + *
    + *
  • Get the attributes matching the current path entry from the info file + * (see {@link AttributesNodeProvider#getInfoAttributesNode()}).
  • + *
  • 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.
  • + *
  • In the end, completes the list of matching attributes using the + * global attribute file define in the configuration (see + * {@link AttributesNodeProvider#getGlobalAttributesNode()})
  • + * + *
+ * + * + *

Iterator constraints

+ * + *

+ * 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}. + *

+ * + * @return a {@link Set} of {@link Attribute}s that match the current entry. + * @since 4.2 + */ + public Map 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. emptyMap(); + } + + String path = currentHead.getEntryPathString(); + final boolean isDir = FileMode.TREE.equals(currentHead.mode); + Map attributes = new LinkedHashMap(); + 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 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 getParent(T current, + Class type) { + if (current != null) { + AbstractTreeIterator parent = current.parent; + if (type.isInstance(parent)) { + return type.cast(parent); + } + } + return null; + } + + private T getTree(Class 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. + *

+ * This method implements the fallback mechanism between the index and the + * working tree depending on the operation type + *

+ * + * @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_CMP = new Comparator() { @@ -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. */ -- cgit v1.2.3 From 6389948a814412267f46de375563f9d009d76ccb Mon Sep 17 00:00:00 2001 From: Christian Halstrick Date: Tue, 10 Nov 2015 16:21:00 +0100 Subject: Add an attribute accessor to CanonicalTreeParser and use it in Treewalk When checking out a branch we need to access the attributes stored in the tree to be checked out. E.g. directly after a clone we checkout the remote HEAD. In this case index and workingtree are still empty. So we have to search the tree to be checked out for attributes. Change-Id: I6d96f5d095ed2e3c259d4b12124e404f5215bd9f --- org.eclipse.jgit/.settings/.api_filters | 14 +++++ .../eclipse/jgit/dircache/DirCacheIterator.java | 3 -- .../jgit/treewalk/AbstractTreeIterator.java | 8 +++ .../eclipse/jgit/treewalk/CanonicalTreeParser.java | 61 ++++++++++++++++++++++ .../src/org/eclipse/jgit/treewalk/TreeWalk.java | 53 ++++++++++++++----- .../eclipse/jgit/treewalk/WorkingTreeIterator.java | 59 --------------------- 6 files changed, 124 insertions(+), 74 deletions(-) diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters index c7a96a2f25..e98e360f7c 100644 --- a/org.eclipse.jgit/.settings/.api_filters +++ b/org.eclipse.jgit/.settings/.api_filters @@ -49,6 +49,20 @@
+ + + + + + + + + + + + + + diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheIterator.java index 354a07439a..ad93f7213f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheIterator.java @@ -103,9 +103,6 @@ public class DirCacheIterator extends AbstractTreeIterator { /** The subtree containing {@link #currentEntry} if this is first entry. */ protected DirCacheTree currentSubtree; - /** Holds an {@link AttributesNode} for the current entry */ - private AttributesNode attributesNode; - /** * Create a new iterator for an already loaded DirCache instance. *

diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java index 41e593eaa2..aa5f32a870 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java @@ -49,6 +49,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; +import org.eclipse.jgit.attributes.AttributesNode; import org.eclipse.jgit.dircache.DirCacheCheckout; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.IncorrectObjectTypeException; @@ -92,6 +93,13 @@ public abstract class AbstractTreeIterator { /** The iterator this current entry is path equal to. */ AbstractTreeIterator matches; + /** + * Parsed rules of .gitattributes file if it exists. + * + * @since 4.2 + */ + protected AttributesNode attributesNode; + /** * Number of entries we moved forward to force a D/F conflict match. * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java index 0805e5068c..df31558ff9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java @@ -45,8 +45,12 @@ package org.eclipse.jgit.treewalk; import java.io.IOException; +import java.io.InputStream; import java.util.Arrays; +import java.util.Collections; +import org.eclipse.jgit.attributes.AttributesNode; +import org.eclipse.jgit.attributes.AttributesRule; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.lib.AnyObjectId; @@ -54,10 +58,15 @@ import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.MutableObjectId; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.lib.ObjectReader; +import org.eclipse.jgit.util.RawParseUtils; /** Parses raw Git trees from the canonical semi-text/semi-binary format. */ public class CanonicalTreeParser extends AbstractTreeIterator { + private static final int ATTRIBUTESLENGTH = Constants.DOT_GIT_ATTRIBUTES + .getBytes().length; + private static final byte[] EMPTY = {}; private byte[] raw; @@ -364,5 +373,57 @@ public class CanonicalTreeParser extends AbstractTreeIterator { } pathLen = tmp; nextPtr = ptr + Constants.OBJECT_ID_LENGTH; + + // Check if this entry is a .gitattributes file + if (RawParseUtils.match(path, pathOffset, + Constants.DOT_GIT_ATTRIBUTES.getBytes()) == ATTRIBUTESLENGTH) + attributesNode = new LazyLoadingAttributesNode( + ObjectId.fromRaw(idBuffer(), idOffset())); + + } + + /** + * Retrieve the {@link AttributesNode} for the current entry. + * + * @param reader + * {@link ObjectReader} used to parse the .gitattributes entry. + * @return {@link AttributesNode} for the current entry. + * @throws IOException + * @since 4.2 + */ + public AttributesNode getEntryAttributesNode(ObjectReader reader) + throws IOException { + if (attributesNode instanceof LazyLoadingAttributesNode) + attributesNode = ((LazyLoadingAttributesNode) attributesNode) + .load(reader); + return attributesNode; } + + /** + * {@link AttributesNode} implementation that provides lazy loading + */ + private static class LazyLoadingAttributesNode extends AttributesNode { + final ObjectId objectId; + + LazyLoadingAttributesNode(ObjectId objectId) { + super(Collections. emptyList()); + this.objectId = objectId; + + } + + AttributesNode load(ObjectReader reader) throws IOException { + AttributesNode r = new AttributesNode(); + ObjectLoader loader = reader.open(objectId); + if (loader != null) { + InputStream in = loader.openStream(); + try { + r.parse(in); + } finally { + in.close(); + } + } + return r.getRules().isEmpty() ? null : r; + } + } + } 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 7f7a5c3938..826ce0973d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java @@ -50,6 +50,7 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; +import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.attributes.Attribute; import org.eclipse.jgit.attributes.AttributesNode; @@ -1131,8 +1132,10 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { WorkingTreeIterator workingTreeIterator = getTree(WorkingTreeIterator.class); DirCacheIterator dirCacheIterator = getTree(DirCacheIterator.class); + CanonicalTreeParser other = getTree(CanonicalTreeParser.class); - if (workingTreeIterator == null && dirCacheIterator == null) { + if (workingTreeIterator == null && dirCacheIterator == null + && other == null) { // Can not retrieve the attributes without at least one of the above // iterators. return Collections. emptyMap(); @@ -1152,7 +1155,7 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { // Gets the attributes located on the current entry path getPerDirectoryEntryAttributes(path, isDir, operationType, - workingTreeIterator, dirCacheIterator, + workingTreeIterator, dirCacheIterator, other, attributes); // Gets the attributes located in the global attribute file @@ -1180,6 +1183,8 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { * a {@link WorkingTreeIterator} matching the current entry * @param dirCacheIterator * a {@link DirCacheIterator} matching the current entry + * @param other + * a {@link CanonicalTreeParser} 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. @@ -1189,18 +1194,21 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { */ private void getPerDirectoryEntryAttributes(String path, boolean isDir, OperationType opType, WorkingTreeIterator workingTreeIterator, - DirCacheIterator dirCacheIterator, Map attributes) + DirCacheIterator dirCacheIterator, CanonicalTreeParser other, + Map attributes) throws IOException { // Prevents infinite recurrence - if (workingTreeIterator != null || dirCacheIterator != null) { + if (workingTreeIterator != null || dirCacheIterator != null + || other != null) { AttributesNode currentAttributesNode = getCurrentAttributesNode( - opType, workingTreeIterator, dirCacheIterator); + opType, workingTreeIterator, dirCacheIterator, other); if (currentAttributesNode != null) { currentAttributesNode.getAttributes(path, isDir, attributes); } getPerDirectoryEntryAttributes(path, isDir, opType, getParent(workingTreeIterator, WorkingTreeIterator.class), getParent(dirCacheIterator, DirCacheIterator.class), + getParent(other, CanonicalTreeParser.class), attributes); } } @@ -1236,6 +1244,7 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { * @param opType * @param workingTreeIterator * @param dirCacheIterator + * @param other * @return a {@link AttributesNode} of the current entry, * {@link NullPointerException} otherwise. * @throws IOException @@ -1243,8 +1252,10 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { * parsing one on the attributes file. */ private AttributesNode getCurrentAttributesNode(OperationType opType, - WorkingTreeIterator workingTreeIterator, - DirCacheIterator dirCacheIterator) throws IOException { + @Nullable WorkingTreeIterator workingTreeIterator, + @Nullable DirCacheIterator dirCacheIterator, + @Nullable CanonicalTreeParser other) + throws IOException { AttributesNode attributesNode = null; switch (opType) { case CHECKIN_OP: @@ -1252,17 +1263,30 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { attributesNode = workingTreeIterator.getEntryAttributesNode(); } if (attributesNode == null && dirCacheIterator != null) { - attributesNode = dirCacheIterator - .getEntryAttributesNode(getObjectReader()); + attributesNode = getAttributesNode(dirCacheIterator + .getEntryAttributesNode(getObjectReader()), + attributesNode); + } + if (attributesNode == null && other != null) { + attributesNode = getAttributesNode( + other.getEntryAttributesNode(getObjectReader()), + attributesNode); } break; case CHECKOUT_OP: - if (dirCacheIterator != null) { - attributesNode = dirCacheIterator + if (other != null) { + attributesNode = other .getEntryAttributesNode(getObjectReader()); } + if (dirCacheIterator != null) { + attributesNode = getAttributesNode(dirCacheIterator + .getEntryAttributesNode(getObjectReader()), + attributesNode); + } if (attributesNode == null && workingTreeIterator != null) { - attributesNode = workingTreeIterator.getEntryAttributesNode(); + attributesNode = getAttributesNode( + workingTreeIterator.getEntryAttributesNode(), + attributesNode); } break; default: @@ -1274,4 +1298,9 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { return attributesNode; } + + private static AttributesNode getAttributesNode(AttributesNode value, + AttributesNode defaultValue) { + return (value == null) ? defaultValue : value; + } } 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 e36ce0faf5..8be7f9a84c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java @@ -74,8 +74,6 @@ 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; @@ -136,9 +134,6 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { /** If there is a .gitignore file present, the parsed rules from it. */ private IgnoreNode ignoreNode; - /** If there is a .gitattributes file present, the parsed rules from it. */ - private AttributesNode attributesNode; - /** Repository that is the root level being iterated over */ protected Repository repository; @@ -148,19 +143,6 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { /** The offset of the content id in {@link #idBuffer()} */ private int contentIdOffset; - /** - * Holds the {@link AttributesNode} that is stored in - * $GIT_DIR/info/attributes file. - */ - private AttributesNode infoAttributesNode; - - /** - * Holds the {@link AttributesNode} that is stored in global attribute file. - * - * @see CoreConfig#getAttributesFile() - */ - private AttributesNode globalAttributesNode; - /** * Create a new iterator with no parent. * @@ -204,8 +186,6 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { protected WorkingTreeIterator(final WorkingTreeIterator p) { super(p); state = p.state; - infoAttributesNode = p.infoAttributesNode; - globalAttributesNode = p.globalAttributesNode; } /** @@ -225,10 +205,6 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { else entry = null; ignoreNode = new RootIgnoreNode(entry, repo); - - infoAttributesNode = new InfoAttributesNode(repo); - - globalAttributesNode = new GlobalAttributesNode(repo); } /** @@ -669,41 +645,6 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { return attributesNode; } - /** - * Retrieves 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 - * @since 3.7 - */ - public AttributesNode getInfoAttributesNode() throws IOException { - if (infoAttributesNode instanceof InfoAttributesNode) - infoAttributesNode = ((InfoAttributesNode) infoAttributesNode).load(); - return infoAttributesNode; - } - - /** - * Retrieves the {@link AttributesNode} that holds the information located - * in system-wide file. - * - * @return the {@link AttributesNode} that holds the information located in - * system-wide file. - * @throws IOException - * IOException if an error is raised while parsing the - * attributes file - * @see CoreConfig#getAttributesFile() - * @since 3.7 - */ - public AttributesNode getGlobalAttributesNode() throws IOException { - if (globalAttributesNode instanceof GlobalAttributesNode) - globalAttributesNode = ((GlobalAttributesNode) globalAttributesNode) - .load(); - return globalAttributesNode; - } - private static final Comparator ENTRY_CMP = new Comparator() { public int compare(final Entry o1, final Entry o2) { final byte[] a = o1.encodedName; -- cgit v1.2.3 From 69cd6f586418291c980831cd92508c549c84ce94 Mon Sep 17 00:00:00 2001 From: Christian Halstrick Date: Wed, 28 Oct 2015 13:24:28 +0100 Subject: Introduce FS.execute() to execute a command defined by a ProcessBuilder Change-Id: I2ad2c71ad30b969455bdea89637b8e996b1dad8c Signed-off-by: Matthias Sohn --- .../eclipse/jgit/util/RunExternalScriptTest.java | 40 +++++++++++ org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java | 78 +++++++++++++++++++++- 2 files changed, 115 insertions(+), 3 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java index 82beab2dc8..b6a2519c59 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java @@ -52,6 +52,7 @@ import java.io.IOException; import java.io.InputStream; import org.eclipse.jgit.junit.JGitTestUtil; +import org.eclipse.jgit.util.FS.ExecutionResult; import org.junit.Before; import org.junit.Test; @@ -163,6 +164,45 @@ public class RunExternalScriptTest { assertEquals(127, rc); } + @Test + public void testCopyStdInExecute() + throws IOException, InterruptedException { + String inputStr = "a\nb\rc\r\nd"; + File script = writeTempFile("cat -"); + ProcessBuilder pb = new ProcessBuilder("/bin/sh", script.getPath()); + ExecutionResult res = FS.DETECTED.execute(pb, + new ByteArrayInputStream(inputStr.getBytes())); + assertEquals(0, res.getRc()); + assertEquals(inputStr, new String(res.getStdout().toByteArray())); + assertEquals("", new String(res.getStderr().toByteArray())); + } + + @Test + public void testStdErrExecute() throws IOException, InterruptedException { + File script = writeTempFile("echo hi >&2"); + ProcessBuilder pb = new ProcessBuilder("/bin/sh", script.getPath()); + ExecutionResult res = FS.DETECTED.execute(pb, null); + assertEquals(0, res.getRc()); + assertEquals("", new String(res.getStdout().toByteArray())); + assertEquals("hi" + sep, new String(res.getStderr().toByteArray())); + } + + @Test + public void testAllTogetherBinExecute() + throws IOException, InterruptedException { + String inputStr = "a\nb\rc\r\nd"; + File script = writeTempFile( + "echo $#,$1,$2,$3,$4,$5,$6 >&2 ; cat -; exit 5"); + ProcessBuilder pb = new ProcessBuilder("/bin/sh", script.getPath(), "a", + "b", "c"); + ExecutionResult res = FS.DETECTED.execute(pb, + new ByteArrayInputStream(inputStr.getBytes())); + assertEquals(5, res.getRc()); + assertEquals(inputStr, new String(res.getStdout().toByteArray())); + assertEquals("3,a,b,c,,," + sep, + new String(res.getStderr().toByteArray())); + } + private File writeTempFile(String body) throws IOException { File f = File.createTempFile("RunProcessTestScript_", ""); JGitTestUtil.write(f, body); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java index e407dd8be9..b61e47f5f6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java @@ -110,7 +110,54 @@ public abstract class FS { } } - final static Logger LOG = LoggerFactory.getLogger(FS.class); + /** + * Result of an executed process. The caller is responsible to close the + * contained {@link TemporaryBuffer}s + * + * @since 4.2 + */ + public static class ExecutionResult { + private TemporaryBuffer stdout; + + private TemporaryBuffer stderr; + + private int rc; + + /** + * @param stdout + * @param stderr + * @param rc + */ + public ExecutionResult(TemporaryBuffer stdout, TemporaryBuffer stderr, + int rc) { + this.stdout = stdout; + this.stderr = stderr; + this.rc = rc; + } + + /** + * @return buffered standard output stream + */ + public TemporaryBuffer getStdout() { + return stdout; + } + + /** + * @return buffered standard error stream + */ + public TemporaryBuffer getStderr() { + return stderr; + } + + /** + * @return the return code of the process + */ + public int getRc() { + return rc; + } + } + + private final static Logger LOG = LoggerFactory.getLogger(FS.class); /** The auto-detected implementation selected for this operating system and JRE. */ public static final FS DETECTED = detect(); @@ -1004,10 +1051,10 @@ public abstract class FS { pool.shutdown(); // Disable new tasks from being submitted try { // Wait a while for existing tasks to terminate - if (!pool.awaitTermination(5, TimeUnit.SECONDS)) { + if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { pool.shutdownNow(); // Cancel currently executing tasks // Wait a while for tasks to respond to being canceled - if (!pool.awaitTermination(5, TimeUnit.SECONDS)) + if (!pool.awaitTermination(60, TimeUnit.SECONDS)) hasShutdown = false; } } catch (InterruptedException ie) { @@ -1034,6 +1081,31 @@ public abstract class FS { */ public abstract ProcessBuilder runInShell(String cmd, String[] args); + /** + * Execute a command defined by a {@link ProcessBuilder}. + * + * @param pb + * The command to be executed + * @param in + * The standard input stream passed to the process + * @return The result of the executed command + * @throws InterruptedException + * @throws IOException + * @since 4.2 + */ + public ExecutionResult execute(ProcessBuilder pb, InputStream in) + throws IOException, InterruptedException { + TemporaryBuffer stdout = new TemporaryBuffer.LocalFile(null); + TemporaryBuffer stderr = new TemporaryBuffer.Heap(1024, 1024 * 1024); + try { + int rc = runProcess(pb, stdout, stderr, in); + return new ExecutionResult(stdout, stderr, rc); + } finally { + stdout.close(); + stderr.close(); + } + } + private static class Holder { final V value; -- cgit v1.2.3 From d3e61db455174ce8af70fcc80a19f414881dfea9 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Tue, 17 Nov 2015 17:26:53 +0100 Subject: Fix pre-push hook to not set null remoteName as first argument According to [1] the pre-push hook expects two parameters which provide the name and location of the destination remote, if a named remote is not being used both values should be the same. We did set the first parameter to null in that case which caused ProcessBuilder to throw a NullPointerException since its start() method doesn't accept null arguments. [1] https://git-scm.com/docs/githooks#_pre_push Bug: 482393 Change-Id: Idb9b0a48cefac01abfcfdf00f6d173f8fa1d9a7b Signed-off-by: Matthias Sohn --- org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java index 2e6582819f..a501fee901 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java @@ -113,6 +113,9 @@ public class PrePushHook extends GitHook { */ @Override protected String[] getParameters() { + if (remoteName == null) { + remoteName = remoteLocation; + } return new String[] { remoteName, remoteLocation }; } -- cgit v1.2.3 From 4b114d3c6bc1ed80ba55a5a42241ce1ead6d51cc Mon Sep 17 00:00:00 2001 From: Christian Halstrick Date: Thu, 19 Nov 2015 17:21:46 +0100 Subject: Throw IndexReadException if existing index can't be read If the index file exists but can't be read for example because of wrong filesystem permissions we should throw a specific exception. This allows EGit to handle this error situation. Bug: 482607 Change-Id: I50bfcb719c45caac3cb5550a8b16307c2ea9def4 Signed-off-by: Matthias Sohn --- .../org/eclipse/jgit/internal/JGitText.properties | 1 + .../src/org/eclipse/jgit/dircache/DirCache.java | 7 ++ .../eclipse/jgit/errors/IndexReadException.java | 82 ++++++++++++++++++++++ .../src/org/eclipse/jgit/internal/JGitText.java | 1 + 4 files changed, 91 insertions(+) create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/errors/IndexReadException.java diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index 51e44fd778..cdb2be151d 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -87,6 +87,7 @@ cannotReadBlob=Cannot read blob {0} cannotReadCommit=Cannot read commit {0} cannotReadFile=Cannot read file {0} cannotReadHEAD=cannot read HEAD: {0} {1} +cannotReadIndex=The index file {0} exists but cannot be read cannotReadObject=Cannot read object cannotReadObjectsPath=Cannot read {0}/{1}: {2} cannotReadTree=Cannot read tree {0} 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 92cdf391c1..387d8ce739 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java @@ -63,6 +63,7 @@ import java.util.Comparator; import java.util.List; import org.eclipse.jgit.errors.CorruptObjectException; +import org.eclipse.jgit.errors.IndexReadException; import org.eclipse.jgit.errors.LockFailedException; import org.eclipse.jgit.errors.UnmergedPathException; import org.eclipse.jgit.events.IndexChangedEvent; @@ -418,6 +419,12 @@ public class DirCache { } } } catch (FileNotFoundException fnfe) { + if (liveFile.exists()) { + // Panic: the index file exists but we can't read it + throw new IndexReadException( + MessageFormat.format(JGitText.get().cannotReadIndex, + liveFile.getAbsolutePath(), fnfe)); + } // Someone must have deleted it between our exists test // and actually opening the path. That's fine, its empty. // diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/IndexReadException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/IndexReadException.java new file mode 100644 index 0000000000..70f650dde6 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/IndexReadException.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2015, Christian Halstrick 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.errors; + +import java.io.IOException; + +import org.eclipse.jgit.internal.JGitText; + +/** + * Cannot read the index. This is a serious error that users need to be made + * aware of. + * + * @since 4.2 + */ +public class IndexReadException extends IOException { + private static final long serialVersionUID = 1L; + + /** + * Constructs an IndexReadException with the default message. + */ + public IndexReadException() { + super(JGitText.get().indexWriteException); + } + + /** + * Constructs an IndexReadException with the specified detail message. + * + * @param s + * message + */ + public IndexReadException(final String s) { + super(s); + } + + /** + * Constructs an IndexReadException with the specified detail message. + * + * @param s + * message + * @param cause + * root cause exception + */ + public IndexReadException(final String s, final Throwable cause) { + super(s); + initCause(cause); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index e39469bd8c..be29feabd0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -146,6 +146,7 @@ public class JGitText extends TranslationBundle { /***/ public String cannotReadCommit; /***/ public String cannotReadFile; /***/ public String cannotReadHEAD; + /***/ public String cannotReadIndex; /***/ public String cannotReadObject; /***/ public String cannotReadObjectsPath; /***/ public String cannotReadTree; -- cgit v1.2.3 From 68cea21f5384e184bb3fc2c33e5d2213721d6bf5 Mon Sep 17 00:00:00 2001 From: Thomas Meyer Date: Thu, 19 Nov 2015 23:14:03 +0100 Subject: git rev-parse: Add --verify option Add the --verify option to be more compatible with git Change-Id: I225a36ecc4711fd2eb9af67ca8fb79681d94c587 Signed-off-by: Thomas Meyer --- .../org/eclipse/jgit/pgm/internal/CLIText.properties | 1 + .../src/org/eclipse/jgit/pgm/RevParse.java | 18 +++++++++++++++--- .../src/org/eclipse/jgit/pgm/internal/CLIText.java | 1 + 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties index 64afdad51e..aa32478ff0 100644 --- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties +++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties @@ -128,6 +128,7 @@ metaVar_user=USER metaVar_version=VERSION mostCommonlyUsedCommandsAre=The most commonly used commands are: needApprovalToDestroyCurrentRepository=Need approval to destroy current repository +needSingleRevision=Needed a single revision noGitRepositoryConfigured=No Git repository configured. noNamesFound=No names found, cannot describe anything. noSuchFile=no such file: {0} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java index 5530ac5c99..4456fd5348 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java @@ -1,6 +1,7 @@ /* * Copyright (C) 2009, Daniel Cheng (aka SDiZ) * Copyright (C) 2009, Daniel Cheng (aka SDiZ) + * Copyright (C) 2015 Thomas Meyer * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -51,14 +52,19 @@ import java.util.List; import java.util.Map; import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.Option; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.pgm.internal.CLIText;; @Command(usage = "usage_RevParse") class RevParse extends TextBuiltin { @Option(name = "--all", usage = "usage_RevParseAll") - boolean all = false; + boolean all; + + @Option(name = "--verify", usage = "usage_RevParseVerify") + boolean verify; @Argument(index = 0, metaVar = "metaVar_commitish") private final List commits = new ArrayList(); @@ -67,11 +73,17 @@ class RevParse extends TextBuiltin { protected void run() throws Exception { if (all) { Map allRefs = db.getRefDatabase().getRefs(ALL); - for (final Ref r : allRefs.values()) + for (final Ref r : allRefs.values()) { outw.println(r.getObjectId().name()); + } } else { - for (final ObjectId o : commits) + if (verify && commits.size() > 1) { + throw new CmdLineException(CLIText.get().needSingleRevision); + } + + for (final ObjectId o : commits) { outw.println(o.name()); + } } } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java index 433ddf2b13..29d48ebd46 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java @@ -187,6 +187,7 @@ public class CLIText extends TranslationBundle { /***/ public String metaVar_version; /***/ public String mostCommonlyUsedCommandsAre; /***/ public String needApprovalToDestroyCurrentRepository; + /***/ public String needSingleRevision; /***/ public String noGitRepositoryConfigured; /***/ public String noNamesFound; /***/ public String noSuchFile; -- cgit v1.2.3 From 1e47c7058d930db920cb897faa2df14a4ae87c00 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Tue, 10 Nov 2015 16:34:00 -0800 Subject: RefDirectory.getRef: Treat fake missing symrefs like real ones getRef() loops over its search path to find a ref: Ref ref = null; for (String prefix : SEARCH_PATH) { ref = readRef(prefix + needle, packed); if (ref != null) { ref = resolve(ref, 0, null, null, packed); break; } } fireRefsChanged(); return ref; If readRef returns null (indicating that the ref does not exist), the loop continues so we can find the ref later in the search path. And resolve should never return null, so if we return null it should mean we exhausted the entire search path and didn't find the ref. ... except that resolve can return null: it does so when it has followed too many symrefs and concluded that there is a symref loop: if (MAX_SYMBOLIC_REF_DEPTH <= depth) return null; // claim it doesn't exist Continue the loop instead of returning null immediately. This makes the behavior more consistent. Arguably getRef should throw an exception when a symref loop is detected. That would be a more invasive change, so if it's a good idea it will have to wait for another patch. Change-Id: Icb1c7fafd4f1e34c9b43538e27ab5bbc17ad9eef Signed-off-by: Jonathan Nieder --- .../internal/storage/file/RefDirectoryTest.java | 30 ++++++++++++++++++++++ .../jgit/internal/storage/file/RefDirectory.java | 2 ++ 2 files changed, 32 insertions(+) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java index d66753da08..52e181bc80 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java @@ -857,6 +857,36 @@ public class RefDirectoryTest extends LocalDiskRepositoryTestCase { assertNull("mising 1 due to cycle", r); } + @Test + public void testGetRef_CycleInSymbolicRef() throws IOException { + Ref r; + + writeLooseRef("refs/1", "ref: refs/2\n"); + writeLooseRef("refs/2", "ref: refs/3\n"); + writeLooseRef("refs/3", "ref: refs/4\n"); + writeLooseRef("refs/4", "ref: refs/5\n"); + writeLooseRef("refs/5", "ref: refs/end\n"); + writeLooseRef("refs/end", A); + + r = refdir.getRef("1"); + assertEquals("refs/1", r.getName()); + assertEquals(A, r.getObjectId()); + assertTrue(r.isSymbolic()); + + writeLooseRef("refs/5", "ref: refs/6\n"); + writeLooseRef("refs/6", "ref: refs/end\n"); + + r = refdir.getRef("1"); + assertNull("missing 1 due to cycle", r); + + writeLooseRef("refs/heads/1", B); + + r = refdir.getRef("1"); + assertEquals("refs/heads/1", r.getName()); + assertEquals(B, r.getObjectId()); + assertFalse(r.isSymbolic()); + } + @Test public void testGetRefs_PackedNotPeeled_Sorted() throws IOException { Map all; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java index 7851678a88..c8c12f5b6c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java @@ -294,6 +294,8 @@ public class RefDirectory extends RefDatabase { ref = readRef(prefix + needle, packed); if (ref != null) { ref = resolve(ref, 0, null, null, packed); + } + if (ref != null) { break; } } catch (IOException e) { -- cgit v1.2.3 From a6bcc988e06d4ef041e9c0efe7232cc4a5648374 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Sat, 21 Nov 2015 00:18:14 +0100 Subject: Remove no longer needed outdated API warning filter This fixes a warning saying this filter isn't needed anymore. Change-Id: If77056378befe86c1773950dbe48a82c833fd532 Signed-off-by: Matthias Sohn --- org.eclipse.jgit/.settings/.api_filters | 6 ------ 1 file changed, 6 deletions(-) diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters index e98e360f7c..b89aad4c59 100644 --- a/org.eclipse.jgit/.settings/.api_filters +++ b/org.eclipse.jgit/.settings/.api_filters @@ -21,12 +21,6 @@ - - - - - - -- cgit v1.2.3 From fe85311b3a66d8cc7e7a66d4f0e01f88acbf1c0a Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Thu, 12 Nov 2015 11:28:01 +0100 Subject: Avoid UnknownHostException in WalkEncryptionTest Prevent that WalkEncryptionTest fails when it can't determine the public IP address using http://checkip.amazonws.com. Also set timeouts when determining IP address in order to prevent long wait times during tests. Change-Id: I1d2fe09f99df2a5f75f8077811a72fb2271cdddb Signed-off-by: Matthias Sohn --- .../eclipse/jgit/transport/WalkEncryptionTest.java | 41 +++++++++++++++++----- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java index 90d78e4b62..ac2bfd12f9 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java @@ -43,6 +43,20 @@ package org.eclipse.jgit.transport; +import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.UTF_8; +import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.cryptoCipherListPBE; +import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.cryptoCipherListTrans; +import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.folderDelete; +import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.permitLongTests; +import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.policySetup; +import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.product; +import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.proxySetup; +import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.publicAddress; +import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.reportPolicy; +import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.securityProviderName; +import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.textWrite; +import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.transferStream; +import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.verifyFileContent; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -59,7 +73,10 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; +import java.net.SocketTimeoutException; import java.net.URL; +import java.net.URLConnection; +import java.net.UnknownHostException; import java.nio.charset.Charset; import java.nio.file.Files; import java.security.GeneralSecurityException; @@ -94,8 +111,6 @@ import org.junit.runners.Suite; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.*; - /** * Amazon S3 encryption pipeline test. * @@ -401,14 +416,22 @@ public class WalkEncryptionTest { * @throws Exception */ static String publicAddress() throws Exception { - String service = "http://checkip.amazonaws.com"; - URL url = new URL(service); - BufferedReader reader = new BufferedReader( - new InputStreamReader(url.openStream())); try { - return reader.readLine(); - } finally { - reader.close(); + String service = "http://checkip.amazonaws.com"; + URL url = new URL(service); + URLConnection c = url.openConnection(); + c.setConnectTimeout(500); + c.setReadTimeout(500); + BufferedReader reader = new BufferedReader( + new InputStreamReader(c.getInputStream())); + try { + return reader.readLine(); + } finally { + reader.close(); + } + } catch (UnknownHostException | SocketTimeoutException e) { + return "Can't reach http://checkip.amazonaws.com to" + + " determine public address"; } } -- cgit v1.2.3 From 0353b1d3ff5554c6f84ee261c0c776efb58eec9b Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Thu, 19 Nov 2015 00:47:05 +0100 Subject: Fix classpath of test launch configurations Remove references to the bundle org.eclipse.jgit.java7 which was removed in 4.0. Change-Id: I85527eb2a34bb94979fdab1311043ae77a2b5ecd Signed-off-by: Matthias Sohn --- .../org.eclipse.jgit.pgm--All-Tests (Java7).launch | 6 ------ .../org.eclipse.jgit.pgm--All-Tests (Java8).launch | 1 - .../org.eclipse.jgit.core--All-Tests (Java 7).launch | 1 - .../org.eclipse.jgit.core--All-Tests (Java 8).launch | 1 - 4 files changed, 9 deletions(-) diff --git a/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests (Java7).launch b/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests (Java7).launch index 600ce7b729..3df0dcb645 100644 --- a/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests (Java7).launch +++ b/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests (Java7).launch @@ -15,12 +15,6 @@ - - - - - - diff --git a/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests (Java8).launch b/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests (Java8).launch index 1b61d3d3f1..ce473ed03d 100644 --- a/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests (Java8).launch +++ b/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests (Java8).launch @@ -19,7 +19,6 @@ - diff --git a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 7).launch b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 7).launch index af009c0d4b..a83fabb75e 100644 --- a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 7).launch +++ b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 7).launch @@ -18,7 +18,6 @@ - diff --git a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 8).launch b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 8).launch index 04aa3ea107..b221a11a55 100644 --- a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 8).launch +++ b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 8).launch @@ -19,7 +19,6 @@ - -- cgit v1.2.3 From 18af2d42657dbe758b0d7ef88efb0cc466105da9 Mon Sep 17 00:00:00 2001 From: Christian Halstrick Date: Fri, 20 Nov 2015 14:33:15 +0100 Subject: Let FS_Win32_Cygwin detect symlink support by creating temporary symlink The class FS_Win32 was always trying out to create a temporary symlink in order to find out whether symlinks are supported. FS_Win32_Cygwin was overwriting this method and always returned true. But when the user running JGit does not have administrative rights then the creation of symlinks is forbidden even if he is running on FS_Win32_Cygwin. A lot of tests failed only on the Windows platform because of this. It was correctly detected that FS_Win32_Cygwin is the filesystem abstraction to be used but creation of symlinks always failed because of lacking privileges of the user running the tests. This fix teaches FS_Win32_Cygwin to behave like FS_Win32 and to test whether symlinks can be created in order to find out whether symlinks are supported. Change-Id: Ie2394631ffc4c489bd37c3ec142ed44bbfcac726 Signed-off-by: Matthias Sohn --- .../tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java | 6 ++++++ .../tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java | 2 ++ .../tst/org/eclipse/jgit/treewalk/TreeWalkJava7Test.java | 1 + org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java | 2 ++ org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java | 1 + org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java | 5 ----- 6 files changed, 12 insertions(+), 5 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java index 6d62528f85..51a6b5a8f5 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java @@ -79,6 +79,7 @@ import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FileUtils; +import org.junit.Assume; import org.junit.Test; public class DirCacheCheckoutTest extends RepositoryTestCase { @@ -925,6 +926,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { @Test public void testCheckoutChangeLinkToEmptyDir() throws Exception { + Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); String fname = "was_file"; Git git = Git.wrap(db); @@ -961,6 +963,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { @Test public void testCheckoutChangeLinkToEmptyDirs() throws Exception { + Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); String fname = "was_file"; Git git = Git.wrap(db); @@ -999,6 +1002,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { @Test public void testCheckoutChangeLinkToNonEmptyDirs() throws Exception { + Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); String fname = "file"; Git git = Git.wrap(db); @@ -1043,6 +1047,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { @Test public void testCheckoutChangeLinkToNonEmptyDirsAndNewIndexEntry() throws Exception { + Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); String fname = "file"; Git git = Git.wrap(db); @@ -1364,6 +1369,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { @Test public void testOverwriteUntrackedLinkModeChange() throws Exception { + Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); String fname = "file.txt"; Git git = Git.wrap(db); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java index 88754109f7..429f35ea4b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java @@ -67,6 +67,7 @@ import org.junit.Test; public class FileTreeIteratorJava7Test extends RepositoryTestCase { @Test public void testFileModeSymLinkIsNotATree() throws IOException { + org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); FS fs = db.getFS(); // mĂ¥l = target in swedish, just to get som unicode in here writeTrashFile("mĂ¥l/data", "targetdata"); @@ -163,6 +164,7 @@ public class FileTreeIteratorJava7Test extends RepositoryTestCase { */ @Test public void testSymlinkActuallyModified() throws Exception { + org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); final String NORMALIZED = "target"; final byte[] NORMALIZED_BYTES = Constants.encode(NORMALIZED); try (ObjectInserter oi = db.newObjectInserter()) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkJava7Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkJava7Test.java index bb1f2a639b..1328b38e63 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkJava7Test.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkJava7Test.java @@ -55,6 +55,7 @@ import org.junit.Test; public class TreeWalkJava7Test extends RepositoryTestCase { @Test public void testSymlinkToDirNotRecursingViaSymlink() throws Exception { + org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); FS fs = db.getFS(); assertTrue(fs.supportsSymlinks()); writeTrashFile("target/data", "targetdata"); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java index e6a244e142..53b6fecfd8 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java @@ -57,6 +57,7 @@ import java.util.Set; import org.eclipse.jgit.junit.RepositoryTestCase; import org.junit.After; +import org.junit.Assume; import org.junit.Before; import org.junit.Test; @@ -87,6 +88,7 @@ public class FSJava7Test { */ @Test public void testSymlinkAttributes() throws IOException, InterruptedException { + Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); FS fs = FS.DETECTED; File link = new File(trash, "ä"); File target = new File(trash, "Ă¥"); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java index 4625f30683..cc1fdc21b9 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java @@ -73,6 +73,7 @@ public class FileUtils7Test { @Test public void testDeleteSymlinkToDirectoryDoesNotDeleteTarget() throws IOException { + org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); FS fs = FS.DETECTED; File dir = new File(trash, "dir"); File file = new File(dir, "file"); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java index 2450be4c17..28d628b345 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java @@ -162,11 +162,6 @@ public class FS_Win32_Cygwin extends FS_Win32 { errRedirect, stdinArgs); } - @Override - public boolean supportsSymlinks() { - return true; - } - /** * @since 3.7 */ -- cgit v1.2.3 From d2faec27a7af7c9ea7db6b4ac31f75533ca45b80 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Fri, 20 Nov 2015 14:40:41 +0100 Subject: Raise error if FileNotFoundException is caught for an existing file File, FileInputStream and friends may throw FileNotFoundException even if the file is existing e.g. when file permissions don't allow to access the file content. In most cases this is a severe error we should not suppress hence rethrow the FileNotFoundException in this case. This may also fix bug 451508. Bug: 451508 Change-Id: If4a94217fb5b7cfd4c04d881902f3e86193c7008 Signed-off-by: Matthias Sohn --- .../org/eclipse/jgit/internal/JGitText.properties | 1 + .../src/org/eclipse/jgit/api/RebaseCommand.java | 3 ++ .../src/org/eclipse/jgit/internal/JGitText.java | 1 + .../jgit/internal/storage/file/LockFile.java | 4 +++ .../internal/storage/file/ObjectDirectory.java | 37 +++++++++++----------- .../jgit/internal/storage/file/RefDirectory.java | 8 ++++- .../internal/storage/file/ReflogReaderImpl.java | 6 ++++ .../jgit/internal/storage/file/UnpackedObject.java | 3 ++ .../src/org/eclipse/jgit/lib/Repository.java | 6 ++++ .../eclipse/jgit/storage/file/FileBasedConfig.java | 3 ++ 10 files changed, 53 insertions(+), 19 deletions(-) diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index cdb2be151d..6e3b3047fb 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -451,6 +451,7 @@ packfileIsTruncated=Packfile {0} is truncated. packfileIsTruncatedNoParam=Packfile is truncated. packHandleIsStale=Pack file {0} handle is stale, removing it from pack list packHasUnresolvedDeltas=pack has unresolved deltas +packInaccessible=Pack file {0} now inaccessible; removing it from pack list packingCancelledDuringObjectsWriting=Packing cancelled during objects writing packObjectCountMismatch=Pack object count mismatch: pack {0} index {1}: {2} packRefs=Pack refs diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java index ff29008420..753bc85bc6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java @@ -980,6 +980,9 @@ public class RebaseCommand extends GitCommand { try { raw = IO.readFully(authorScriptFile); } catch (FileNotFoundException notFound) { + if (authorScriptFile.exists()) { + throw notFound; + } return null; } return parseAuthor(raw); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index be29feabd0..b03038b062 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -510,6 +510,7 @@ public class JGitText extends TranslationBundle { /***/ public String packfileIsTruncatedNoParam; /***/ public String packHandleIsStale; /***/ public String packHasUnresolvedDeltas; + /***/ public String packInaccessible; /***/ public String packingCancelledDuringObjectsWriting; /***/ public String packObjectCountMismatch; /***/ public String packRefs; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java index 50297a97a0..e23ca741b8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java @@ -227,6 +227,10 @@ public class LockFile { fis.close(); } } catch (FileNotFoundException fnfe) { + if (ref.exists()) { + unlock(); + throw fnfe; + } // Don't worry about a file that doesn't exist yet, it // conceptually has no current content to copy. // diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java index e7ef127dd7..bd1d488d94 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java @@ -433,16 +433,14 @@ public class ObjectDirectory extends FileObjectDatabase { ObjectLoader openLooseObject(WindowCursor curs, AnyObjectId id) throws IOException { - try { - File path = fileFor(id); - FileInputStream in = new FileInputStream(path); - try { - unpackedObjectCache.add(id); - return UnpackedObject.open(in, path, id, curs); - } finally { - in.close(); - } + File path = fileFor(id); + try (FileInputStream in = new FileInputStream(path)) { + unpackedObjectCache.add(id); + return UnpackedObject.open(in, path, id, curs); } catch (FileNotFoundException noFile) { + if (path.exists()) { + throw noFile; + } unpackedObjectCache.remove(id); return null; } @@ -513,15 +511,14 @@ public class ObjectDirectory extends FileObjectDatabase { private long getLooseObjectSize(WindowCursor curs, AnyObjectId id) throws IOException { - try { - FileInputStream in = new FileInputStream(fileFor(id)); - try { - unpackedObjectCache.add(id); - return UnpackedObject.getSize(in, id, curs); - } finally { - in.close(); - } + File f = fileFor(id); + try (FileInputStream in = new FileInputStream(f)) { + unpackedObjectCache.add(id); + return UnpackedObject.getSize(in, id, curs); } catch (FileNotFoundException noFile) { + if (f.exists()) { + throw noFile; + } unpackedObjectCache.remove(id); return -1; } @@ -561,7 +558,11 @@ public class ObjectDirectory extends FileObjectDatabase { // Assume the pack is corrupted, and remove it from the list. removePack(p); } else if (e instanceof FileNotFoundException) { - warnTmpl = JGitText.get().packWasDeleted; + if (p.getPackFile().exists()) { + warnTmpl = JGitText.get().packInaccessible; + } else { + warnTmpl = JGitText.get().packWasDeleted; + } removePack(p); } else if (FileUtils.isStaleFileHandle(e)) { warnTmpl = JGitText.get().packHandleIsStale; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java index c8c12f5b6c..69f7e97071 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java @@ -788,6 +788,9 @@ public class RefDirectory extends RefDatabase { new DigestInputStream(new FileInputStream(packedRefsFile), digest), CHARSET)); } catch (FileNotFoundException noPackedRefs) { + if (packedRefsFile.exists()) { + throw noPackedRefs; + } // Ignore it and leave the new list empty. return PackedRefList.NO_PACKED_REFS; } @@ -944,7 +947,10 @@ public class RefDirectory extends RefDatabase { try { buf = IO.readSome(path, limit); } catch (FileNotFoundException noFile) { - return null; // doesn't exist; not a reference. + if (path.exists() && path.isFile()) { + throw noFile; + } + return null; // doesn't exist or no file; not a reference. } int n = buf.length; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java index dadc631194..2f583b275a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java @@ -96,6 +96,9 @@ class ReflogReaderImpl implements ReflogReader { try { log = IO.readFully(logName); } catch (FileNotFoundException e) { + if (logName.exists()) { + throw e; + } return null; } @@ -118,6 +121,9 @@ class ReflogReaderImpl implements ReflogReader { try { log = IO.readFully(logName); } catch (FileNotFoundException e) { + if (logName.exists()) { + throw e; + } return Collections.emptyList(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObject.java index 2cc2563962..a02743720d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObject.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObject.java @@ -399,6 +399,9 @@ public class UnpackedObject { try { in = buffer(new FileInputStream(path)); } catch (FileNotFoundException gone) { + if (path.exists()) { + throw gone; + } // If the loose file no longer exists, it may have been // moved into a pack file in the mean time. Try again // to locate the object. 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 eda02dea4e..8d512ccb24 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java @@ -1590,6 +1590,9 @@ public abstract class Repository implements AutoCloseable { try { return RawParseUtils.decode(IO.readFully(mergeMsgFile)); } catch (FileNotFoundException e) { + if (mergeMsgFile.exists()) { + throw e; + } // the file has disappeared in the meantime ignore it return null; } @@ -1621,6 +1624,9 @@ public abstract class Repository implements AutoCloseable { byte[] raw = IO.readFully(file); return raw.length > 0 ? raw : null; } catch (FileNotFoundException notFound) { + if (file.exists()) { + throw notFound; + } return null; } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java index 5509fc6a70..29c7f98411 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java @@ -163,6 +163,9 @@ public class FileBasedConfig extends StoredConfig { hash = newHash; } } catch (FileNotFoundException noFile) { + if (configFile.exists()) { + throw noFile; + } clear(); snapshot = newSnapshot; } catch (IOException e) { -- cgit v1.2.3 From 1020f40813356ffa4b2576f38c749fc0db30ea20 Mon Sep 17 00:00:00 2001 From: Andrey Loskutov Date: Sun, 15 Nov 2015 23:59:41 +0100 Subject: Null-annotated Repository class and fixed related compiler errors org.eclipse.jgit.lib.Repository class is an example of the API which should be written with Java 8 java.util.Optional type. Unfortunately this API is already released and widely used. The good clients are currently doing their best with checking return values for null and bad clients do not know how bad their code is. I've tried not to change any logic and to be as less intrusive as possible. Most of the JGit code was well prepared to this, only few classes needed some smaller fixes. This change fixes all compiler errors in JGit and replaces possible NPE's with either appropriate exceptions, avoiding multiple "Nullable return" method calls or early returning from the method. Because annotating getDirectory() and getFS() as Nullable would cause lot of additional changes in JGit and EGit they are postponed. Change-Id: Ie8369d2c9c5fac5ce83b3b1b9bc217d7b55502a3 Signed-off-by: Andrey Loskutov --- .../eclipse/jgit/pgm/internal/CLIText.properties | 1 + .../src/org/eclipse/jgit/pgm/Branch.java | 10 +- .../src/org/eclipse/jgit/pgm/Commit.java | 3 + .../src/org/eclipse/jgit/pgm/Merge.java | 10 +- .../org/eclipse/jgit/pgm/debug/DiffAlgorithms.java | 7 +- .../eclipse/jgit/pgm/debug/RebuildCommitGraph.java | 5 +- .../eclipse/jgit/pgm/debug/TextHashFunctions.java | 7 +- .../src/org/eclipse/jgit/pgm/internal/CLIText.java | 1 + .../org/eclipse/jgit/internal/JGitText.properties | 2 + .../src/org/eclipse/jgit/api/CheckoutCommand.java | 6 ++ .../src/org/eclipse/jgit/api/RebaseCommand.java | 11 +- .../org/eclipse/jgit/api/RenameBranchCommand.java | 5 + .../src/org/eclipse/jgit/internal/JGitText.java | 2 + .../org/eclipse/jgit/internal/storage/file/GC.java | 12 ++- .../src/org/eclipse/jgit/lib/RefRename.java | 2 +- .../src/org/eclipse/jgit/lib/Repository.java | 112 +++++++++++++++++---- .../src/org/eclipse/jgit/merge/ResolveMerger.java | 5 - .../jgit/transport/HMACSHA1NonceGenerator.java | 15 ++- .../eclipse/jgit/transport/TransportAmazonS3.java | 5 +- .../eclipse/jgit/transport/TransportGitSsh.java | 6 +- .../src/org/eclipse/jgit/util/FS_Win32_Cygwin.java | 3 + 21 files changed, 175 insertions(+), 55 deletions(-) diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties index aa32478ff0..8aeb7e8753 100644 --- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties +++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties @@ -143,6 +143,7 @@ notAJgitCommand={0} is not a jgit command notARevision=Not a revision: {0} notATree={0} is not a tree notAValidRefName={0} is not a valid ref name +notAValidCommitName={0} is not a valid commit name notAnIndexFile={0} is not an index file notAnObject={0} is not an object notFound=!! NOT FOUND !! diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java index 83a1ca7e25..65aa24f356 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java @@ -154,10 +154,14 @@ class Branch extends TextBuiltin { startBranch = Constants.HEAD; Ref startRef = db.getRef(startBranch); ObjectId startAt = db.resolve(startBranch + "^0"); //$NON-NLS-1$ - if (startRef != null) + if (startRef != null) { startBranch = startRef.getName(); - else + } else if (startAt != null) { startBranch = startAt.name(); + } else { + throw die(MessageFormat.format( + CLIText.get().notAValidCommitName, startBranch)); + } startBranch = Repository.shortenRefName(startBranch); String newRefName = newHead; if (!newRefName.startsWith(Constants.R_HEADS)) @@ -249,7 +253,7 @@ class Branch extends TextBuiltin { String current = db.getBranch(); ObjectId head = db.resolve(Constants.HEAD); for (String branch : branches) { - if (current.equals(branch)) { + if (branch.equals(current)) { throw die(MessageFormat.format(CLIText.get().cannotDeleteTheBranchWhichYouAreCurrentlyOn, branch)); } RefUpdate update = db.updateRef((remote ? Constants.R_REMOTES diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java index f18242d684..38d8d70cef 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java @@ -96,6 +96,9 @@ class Commit extends TextBuiltin { commitCmd.setAmend(amend); commitCmd.setAll(all); Ref head = db.getRef(Constants.HEAD); + if (head == null) { + throw die(CLIText.get().onBranchToBeBorn); + } RevCommit commit; try { commit = commitCmd.call(); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java index e0ff0583cb..cd65af9549 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java @@ -120,7 +120,7 @@ class Merge extends TextBuiltin { throw die(MessageFormat.format( CLIText.get().refDoesNotExistOrNoCommit, ref)); - Ref oldHead = db.getRef(Constants.HEAD); + Ref oldHead = getOldHead(); MergeResult result; try (Git git = new Git(db)) { MergeCommand mergeCmd = git.merge().setStrategy(mergeStrategy) @@ -205,6 +205,14 @@ class Merge extends TextBuiltin { } } + private Ref getOldHead() throws IOException { + Ref oldHead = db.getRef(Constants.HEAD); + if (oldHead == null) { + throw die(CLIText.get().onBranchToBeBorn); + } + return oldHead; + } + private boolean isMergedInto(Ref oldHead, AnyObjectId src) throws IOException { try (RevWalk revWalk = new RevWalk(db)) { diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java index df7ebb78b8..d856989011 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java @@ -242,9 +242,10 @@ class DiffAlgorithms extends TextBuiltin { } }); - if (db.getDirectory() != null) { - String name = db.getDirectory().getName(); - File parent = db.getDirectory().getParentFile(); + File directory = db.getDirectory(); + if (directory != null) { + String name = directory.getName(); + File parent = directory.getParentFile(); if (name.equals(Constants.DOT_GIT) && parent != null) name = parent.getName(); outw.println(name + ": start at " + startId.name()); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java index 494055a265..6260cd99fa 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java @@ -117,9 +117,12 @@ class RebuildCommitGraph extends TextBuiltin { @Override protected void run() throws Exception { if (!really && !db.getRefDatabase().getRefs(ALL).isEmpty()) { + File directory = db.getDirectory(); + String absolutePath = directory == null ? "null" //$NON-NLS-1$ + : directory.getAbsolutePath(); errw.println( MessageFormat.format(CLIText.get().fatalThisProgramWillDestroyTheRepository - , db.getDirectory().getAbsolutePath(), REALLY)); + , absolutePath, REALLY)); throw die(CLIText.get().needApprovalToDestroyCurrentRepository); } if (!refList.isFile()) diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java index dcbc37bed6..887ad08af7 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java @@ -341,9 +341,10 @@ class TextHashFunctions extends TextBuiltin { } } - if (db.getDirectory() != null) { - String name = db.getDirectory().getName(); - File parent = db.getDirectory().getParentFile(); + File directory = db.getDirectory(); + if (directory != null) { + String name = directory.getName(); + File parent = directory.getParentFile(); if (name.equals(Constants.DOT_GIT) && parent != null) name = parent.getName(); outw.println(name + ":"); //$NON-NLS-1$ diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java index 29d48ebd46..ce2b10c98e 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java @@ -202,6 +202,7 @@ public class CLIText extends TranslationBundle { /***/ public String notARevision; /***/ public String notATree; /***/ public String notAValidRefName; + /***/ public String notAValidCommitName; /***/ public String notAnIndexFile; /***/ public String notAnObject; /***/ public String notFound; diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index 6e3b3047fb..5f80b8103b 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -45,6 +45,7 @@ cannotBeCombined=Cannot be combined. cannotBeRecursiveWhenTreesAreIncluded=TreeWalk shouldn't be recursive when tree objects are included. cannotChangeActionOnComment=Cannot change action on comment line in git-rebase-todo file, old action: {0}, new action: {1}. cannotChangeToComment=Cannot change a non-comment line to a comment line. +cannotCheckoutFromUnbornBranch=Cannot checkout from unborn branch cannotCheckoutOursSwitchBranch=Checking out ours/theirs is only possible when checking out index, not when switching branches. cannotCombineSquashWithNoff=Cannot combine --squash with --no-ff. cannotCombineTreeFilterWithRevFilter=Cannot combine TreeFilter {0} with RevFilter {1}. @@ -345,6 +346,7 @@ invalidPathReservedOnWindows=Invalid path (''{0}'' is reserved on Windows): {1} invalidReflogRevision=Invalid reflog revision: {0} invalidRefName=Invalid ref name: {0} invalidRemote=Invalid remote: {0} +invalidRepositoryStateNoHead=Invalid repository --- cannot read HEAD invalidShallowObject=invalid shallow object {0}, expected commit invalidStageForPath=Invalid stage {0} for path {1} invalidTagOption=Invalid tag option: {0} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java index 8d85bfcb15..8743ea9ac7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java @@ -222,6 +222,12 @@ public class CheckoutCommand extends GitCommand { } Ref headRef = repo.getRef(Constants.HEAD); + if (headRef == null) { + // TODO Git CLI supports checkout from unborn branch, we should + // also allow this + throw new UnsupportedOperationException( + JGitText.get().cannotCheckoutFromUnbornBranch); + } String shortHeadRef = getShortBranchName(headRef); String refLogMessage = "checkout: moving from " + shortHeadRef; //$NON-NLS-1$ ObjectId branch; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java index 753bc85bc6..8582bbb0dc 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java @@ -668,12 +668,13 @@ public class RebaseCommand extends GitCommand { } private void writeRewrittenHashes() throws RevisionSyntaxException, - IOException { + IOException, RefNotFoundException { File currentCommitFile = rebaseState.getFile(CURRENT_COMMIT); if (!currentCommitFile.exists()) return; - String head = repo.resolve(Constants.HEAD).getName(); + ObjectId headId = getHead().getObjectId(); + String head = headId.getName(); String currentCommits = rebaseState.readFile(CURRENT_COMMIT); for (String current : currentCommits.split("\n")) //$NON-NLS-1$ RebaseState @@ -743,8 +744,8 @@ public class RebaseCommand extends GitCommand { private void resetSoftToParent() throws IOException, GitAPIException, CheckoutConflictException { - Ref orig_head = repo.getRef(Constants.ORIG_HEAD); - ObjectId orig_headId = orig_head.getObjectId(); + Ref ref = repo.getRef(Constants.ORIG_HEAD); + ObjectId orig_head = ref == null ? null : ref.getObjectId(); try { // we have already commited the cherry-picked commit. // what we need is to have changes introduced by this @@ -755,7 +756,7 @@ public class RebaseCommand extends GitCommand { } finally { // set ORIG_HEAD back to where we started because soft // reset moved it - repo.writeOrigHead(orig_headId); + repo.writeOrigHead(orig_head); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java index 607253b76d..0731dd45ec 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java @@ -51,6 +51,7 @@ import org.eclipse.jgit.api.errors.DetachedHeadException; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.InvalidRefNameException; import org.eclipse.jgit.api.errors.JGitInternalException; +import org.eclipse.jgit.api.errors.NoHeadException; import org.eclipse.jgit.api.errors.RefAlreadyExistsException; import org.eclipse.jgit.api.errors.RefNotFoundException; import org.eclipse.jgit.internal.JGitText; @@ -121,6 +122,10 @@ public class RenameBranchCommand extends GitCommand { fullOldName = ref.getName(); } else { fullOldName = repo.getFullBranch(); + if (fullOldName == null) { + throw new NoHeadException( + JGitText.get().invalidRepositoryStateNoHead); + } if (ObjectId.isId(fullOldName)) throw new DetachedHeadException(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index b03038b062..6680564ade 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -104,6 +104,7 @@ public class JGitText extends TranslationBundle { /***/ public String cannotBeRecursiveWhenTreesAreIncluded; /***/ public String cannotChangeActionOnComment; /***/ public String cannotChangeToComment; + /***/ public String cannotCheckoutFromUnbornBranch; /***/ public String cannotCheckoutOursSwitchBranch; /***/ public String cannotCombineSquashWithNoff; /***/ public String cannotCombineTreeFilterWithRevFilter; @@ -411,6 +412,7 @@ public class JGitText extends TranslationBundle { /***/ public String invalidURL; /***/ public String invalidWildcards; /***/ public String invalidRefSpec; + /***/ public String invalidRepositoryStateNoHead; /***/ public String invalidWindowSize; /***/ public String isAStaticFlagAndHasNorevWalkInstance; /***/ public String JRELacksMD5Implementation; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java index e7005c247e..4c40538b6a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java @@ -90,6 +90,7 @@ import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref.Storage; import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.ReflogEntry; +import org.eclipse.jgit.lib.ReflogReader; import org.eclipse.jgit.revwalk.ObjectWalk; import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevWalk; @@ -592,7 +593,11 @@ public class GC { * @throws IOException */ private Set listRefLogObjects(Ref ref, long minTime) throws IOException { - List rlEntries = repo.getReflogReader(ref.getName()) + ReflogReader reflogReader = repo.getReflogReader(ref.getName()); + if (reflogReader == null) { + return Collections.emptySet(); + } + List rlEntries = reflogReader .getReverseEntries(); if (rlEntries == null || rlEntries.isEmpty()) return Collections. emptySet(); @@ -635,10 +640,7 @@ public class GC { */ private Set listNonHEADIndexObjects() throws CorruptObjectException, IOException { - try { - if (repo.getIndexFile() == null) - return Collections.emptySet(); - } catch (NoWorkTreeException e) { + if (repo.isBare()) { return Collections.emptySet(); } try (TreeWalk treeWalk = new TreeWalk(repo)) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java index 05eb31183d..59f852b8c7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java @@ -170,7 +170,7 @@ public abstract class RefRename { */ protected boolean needToUpdateHEAD() throws IOException { Ref head = source.getRefDatabase().getRef(Constants.HEAD); - if (head.isSymbolic()) { + if (head != null && head.isSymbolic()) { head = head.getTarget(); return head.getName().equals(source.getName()); } 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 8d512ccb24..c91f2dab72 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,8 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; +import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.attributes.AttributesNodeProvider; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.errors.AmbiguousObjectException; @@ -138,6 +140,7 @@ public abstract class Repository implements AutoCloseable { } /** @return listeners observing only events on this repository. */ + @NonNull public ListenerList getListenerList() { return myListeners; } @@ -182,7 +185,16 @@ public abstract class Repository implements AutoCloseable { */ public abstract void create(boolean bare) throws IOException; - /** @return local metadata directory; null if repository isn't local. */ + /** + * @return local metadata directory; {@code null} if repository isn't local. + */ + /* + * TODO This method should be annotated as Nullable, because in some + * specific configurations metadata is not located in the local file system + * (for example in memory databases). In "usual" repositories this + * annotation would only cause compiler errors at places where the actual + * directory can never be null. + */ public File getDirectory() { return gitDir; } @@ -190,24 +202,29 @@ public abstract class Repository implements AutoCloseable { /** * @return the object database which stores this repository's data. */ + @NonNull public abstract ObjectDatabase getObjectDatabase(); /** @return a new inserter to create objects in {@link #getObjectDatabase()} */ + @NonNull public ObjectInserter newObjectInserter() { return getObjectDatabase().newInserter(); } /** @return a new reader to read objects from {@link #getObjectDatabase()} */ + @NonNull public ObjectReader newObjectReader() { return getObjectDatabase().newReader(); } /** @return the reference database which stores the reference namespace. */ + @NonNull public abstract RefDatabase getRefDatabase(); /** * @return the configuration of this repository */ + @NonNull public abstract StoredConfig getConfig(); /** @@ -217,11 +234,20 @@ public abstract class Repository implements AutoCloseable { * instance for each use. * @since 4.2 */ + @NonNull public abstract AttributesNodeProvider createAttributesNodeProvider(); /** - * @return the used file system abstraction + * @return the used file system abstraction, or or {@code null} if + * repository isn't local. + */ + /* + * TODO This method should be annotated as Nullable, because in some + * specific configurations metadata is not located in the local file system + * (for example in memory databases). In "usual" repositories this + * annotation would only cause compiler errors at places where the actual + * directory can never be null. */ public FS getFS() { return fs; @@ -255,6 +281,7 @@ public abstract class Repository implements AutoCloseable { * @throws IOException * the object store cannot be accessed. */ + @NonNull public ObjectLoader open(final AnyObjectId objectId) throws MissingObjectException, IOException { return getObjectDatabase().open(objectId); @@ -282,6 +309,7 @@ public abstract class Repository implements AutoCloseable { * @throws IOException * the object store cannot be accessed. */ + @NonNull public ObjectLoader open(AnyObjectId objectId, int typeHint) throws MissingObjectException, IncorrectObjectTypeException, IOException { @@ -300,6 +328,7 @@ public abstract class Repository implements AutoCloseable { * a symbolic ref was passed in and could not be resolved back * to the base ref, as the symbolic ref could not be read. */ + @NonNull public RefUpdate updateRef(final String ref) throws IOException { return updateRef(ref, false); } @@ -318,6 +347,7 @@ public abstract class Repository implements AutoCloseable { * a symbolic ref was passed in and could not be resolved back * to the base ref, as the symbolic ref could not be read. */ + @NonNull public RefUpdate updateRef(final String ref, final boolean detach) throws IOException { return getRefDatabase().newUpdate(ref, detach); } @@ -334,6 +364,7 @@ public abstract class Repository implements AutoCloseable { * the rename could not be performed. * */ + @NonNull public RefRename renameRef(final String fromRef, final String toRef) throws IOException { return getRefDatabase().newRename(fromRef, toRef); } @@ -373,7 +404,8 @@ public abstract class Repository implements AutoCloseable { * * @param revstr * A git object references expression - * @return an ObjectId or null if revstr can't be resolved to any ObjectId + * @return an ObjectId or {@code null} if revstr can't be resolved to any + * ObjectId * @throws AmbiguousObjectException * {@code revstr} contains an abbreviated ObjectId and this * repository contains more than one object which match to the @@ -387,6 +419,7 @@ public abstract class Repository implements AutoCloseable { * @throws IOException * on serious errors */ + @Nullable public ObjectId resolve(final String revstr) throws AmbiguousObjectException, IncorrectObjectTypeException, RevisionSyntaxException, IOException { @@ -408,10 +441,12 @@ public abstract class Repository implements AutoCloseable { * expects a branch or revision id. * * @param revstr - * @return object id or ref name from resolved expression + * @return object id or ref name from resolved expression or {@code null} if + * given expression cannot be resolved * @throws AmbiguousObjectException * @throws IOException */ + @Nullable public String simplify(final String revstr) throws AmbiguousObjectException, IOException { try (RevWalk rw = new RevWalk(this)) { @@ -425,6 +460,7 @@ public abstract class Repository implements AutoCloseable { } } + @Nullable private Object resolve(final RevWalk rw, final String revstr) throws IOException { char[] revChars = revstr.toCharArray(); @@ -728,11 +764,13 @@ public abstract class Repository implements AutoCloseable { return true; } + @Nullable private RevObject parseSimple(RevWalk rw, String revstr) throws IOException { ObjectId id = resolveSimple(revstr); return id != null ? rw.parseAny(id) : null; } + @Nullable private ObjectId resolveSimple(final String revstr) throws IOException { if (ObjectId.isId(revstr)) return ObjectId.fromString(revstr); @@ -760,6 +798,7 @@ public abstract class Repository implements AutoCloseable { return null; } + @Nullable private String resolveReflogCheckout(int checkoutNo) throws IOException { ReflogReader reader = getReflogReader(Constants.HEAD); @@ -801,6 +840,7 @@ public abstract class Repository implements AutoCloseable { return rw.parseCommit(entry.getNewId()); } + @Nullable private ObjectId resolveAbbreviation(final String revstr) throws IOException, AmbiguousObjectException { AbbreviatedObjectId id = AbbreviatedObjectId.fromString(revstr); @@ -837,11 +877,13 @@ public abstract class Repository implements AutoCloseable { getRefDatabase().close(); } + @NonNull @SuppressWarnings("nls") public String toString() { String desc; - if (getDirectory() != null) - desc = getDirectory().getPath(); + File directory = getDirectory(); + if (directory != null) + desc = directory.getPath(); else desc = getClass().getSimpleName() + "-" //$NON-NLS-1$ + System.identityHashCode(this); @@ -861,10 +903,12 @@ public abstract class Repository implements AutoCloseable { * current ObjectId in hexadecimal string format. * * @return name of current branch (for example {@code refs/heads/master}), - * an ObjectId in hex format if the current branch is detached, - * or null if the repository is corrupt and has no HEAD reference. + * an ObjectId in hex format if the current branch is detached, or + * {@code null} if the repository is corrupt and has no HEAD + * reference. * @throws IOException */ + @Nullable public String getFullBranch() throws IOException { Ref head = getRef(Constants.HEAD); if (head == null) @@ -883,16 +927,17 @@ public abstract class Repository implements AutoCloseable { * leading prefix {@code refs/heads/} is removed from the reference before * it is returned to the caller. * - * @return name of current branch (for example {@code master}), an - * ObjectId in hex format if the current branch is detached, - * or null if the repository is corrupt and has no HEAD reference. + * @return name of current branch (for example {@code master}), an ObjectId + * in hex format if the current branch is detached, or {@code null} + * if the repository is corrupt and has no HEAD reference. * @throws IOException */ + @Nullable public String getBranch() throws IOException { String name = getFullBranch(); if (name != null) return shortenRefName(name); - return name; + return null; } /** @@ -905,6 +950,7 @@ public abstract class Repository implements AutoCloseable { * * @return unmodifiable collection of other known objects. */ + @NonNull public Set getAdditionalHaves() { return Collections.emptySet(); } @@ -916,9 +962,10 @@ public abstract class Repository implements AutoCloseable { * the name of the ref to lookup. May be a short-hand form, e.g. * "master" which is is automatically expanded to * "refs/heads/master" if "refs/heads/master" already exists. - * @return the Ref with the given name, or null if it does not exist + * @return the Ref with the given name, or {@code null} if it does not exist * @throws IOException */ + @Nullable public Ref getRef(final String name) throws IOException { return getRefDatabase().getRef(name); } @@ -926,6 +973,7 @@ public abstract class Repository implements AutoCloseable { /** * @return mutable map of all known refs (heads, tags, remotes). */ + @NonNull public Map getAllRefs() { try { return getRefDatabase().getRefs(RefDatabase.ALL); @@ -939,6 +987,7 @@ public abstract class Repository implements AutoCloseable { * of the entry contains the ref with the full tag name * ("refs/tags/v1.0"). */ + @NonNull public Map getTags() { try { return getRefDatabase().getRefs(Constants.R_TAGS); @@ -960,6 +1009,7 @@ public abstract class Repository implements AutoCloseable { * will be true and getPeeledObjectId will contain the peeled object * (or null). */ + @NonNull public Ref peel(final Ref ref) { try { return getRefDatabase().peel(ref); @@ -974,6 +1024,7 @@ public abstract class Repository implements AutoCloseable { /** * @return a map with all objects referenced by a peeled ref. */ + @NonNull public Map> getAllRefsByPeeledObjectId() { Map allRefs = getAllRefs(); Map> ret = new HashMap>(allRefs.size()); @@ -998,11 +1049,13 @@ public abstract class Repository implements AutoCloseable { } /** - * @return the index file location + * @return the index file location or {@code null} if repository isn't + * local. * @throws NoWorkTreeException * if this is bare, which implies it has no working directory. * See {@link #isBare()}. */ + @NonNull public File getIndexFile() throws NoWorkTreeException { if (isBare()) throw new NoWorkTreeException(); @@ -1027,6 +1080,7 @@ public abstract class Repository implements AutoCloseable { * the index file is using a format or extension that this * library does not support. */ + @NonNull public DirCache readDirCache() throws NoWorkTreeException, CorruptObjectException, IOException { return DirCache.read(this); @@ -1051,6 +1105,7 @@ public abstract class Repository implements AutoCloseable { * the index file is using a format or extension that this * library does not support. */ + @NonNull public DirCache lockDirCache() throws NoWorkTreeException, CorruptObjectException, IOException { // we want DirCache to inform us so that we can inform registered @@ -1076,6 +1131,7 @@ public abstract class Repository implements AutoCloseable { /** * @return an important state */ + @NonNull public RepositoryState getRepositoryState() { if (isBare() || getDirectory() == null) return RepositoryState.BARE; @@ -1218,6 +1274,7 @@ public abstract class Repository implements AutoCloseable { * @return normalized repository relative path or the empty * string if the file is not relative to the work directory. */ + @NonNull public static String stripWorkDir(File workDir, File file) { final String filePath = file.getPath(); final String workDirPath = workDir.getPath(); @@ -1252,6 +1309,7 @@ public abstract class Repository implements AutoCloseable { * if this is bare, which implies it has no working directory. * See {@link #isBare()}. */ + @NonNull public File getWorkTree() throws NoWorkTreeException { if (isBare()) throw new NoWorkTreeException(); @@ -1275,6 +1333,7 @@ public abstract class Repository implements AutoCloseable { * * @return a more user friendly ref name */ + @NonNull public static String shortenRefName(String refName) { if (refName.startsWith(Constants.R_HEADS)) return refName.substring(Constants.R_HEADS.length()); @@ -1290,9 +1349,10 @@ public abstract class Repository implements AutoCloseable { * @return the remote branch name part of refName, i.e. without * the refs/remotes/<remote> prefix, if * refName represents a remote tracking branch; - * otherwise null. + * otherwise {@code null}. * @since 3.4 */ + @Nullable public String shortenRemoteBranchName(String refName) { for (String remote : getRemoteNames()) { String remotePrefix = Constants.R_REMOTES + remote + "/"; //$NON-NLS-1$ @@ -1307,9 +1367,10 @@ public abstract class Repository implements AutoCloseable { * @return the remote name part of refName, i.e. without the * refs/remotes/<remote> prefix, if * refName represents a remote tracking branch; - * otherwise null. + * otherwise {@code null}. * @since 3.4 */ + @Nullable public String getRemoteName(String refName) { for (String remote : getRemoteNames()) { String remotePrefix = Constants.R_REMOTES + remote + "/"; //$NON-NLS-1$ @@ -1321,12 +1382,13 @@ public abstract class Repository implements AutoCloseable { /** * @param refName - * @return a {@link ReflogReader} for the supplied refname, or null if the - * named ref does not exist. + * @return a {@link ReflogReader} for the supplied refname, or {@code null} + * if the named ref does not exist. * @throws IOException * the ref could not be accessed. * @since 3.0 */ + @Nullable public abstract ReflogReader getReflogReader(String refName) throws IOException; @@ -1342,6 +1404,7 @@ public abstract class Repository implements AutoCloseable { * if this is bare, which implies it has no working directory. * See {@link #isBare()}. */ + @Nullable public String readMergeCommitMsg() throws IOException, NoWorkTreeException { return readCommitMsgFile(Constants.MERGE_MSG); } @@ -1376,6 +1439,7 @@ public abstract class Repository implements AutoCloseable { * See {@link #isBare()}. * @since 4.0 */ + @Nullable public String readCommitEditMsg() throws IOException, NoWorkTreeException { return readCommitMsgFile(Constants.COMMIT_EDITMSG); } @@ -1410,6 +1474,7 @@ public abstract class Repository implements AutoCloseable { * if this is bare, which implies it has no working directory. * See {@link #isBare()}. */ + @Nullable public List readMergeHeads() throws IOException, NoWorkTreeException { if (isBare() || getDirectory() == null) throw new NoWorkTreeException(); @@ -1453,6 +1518,7 @@ public abstract class Repository implements AutoCloseable { * if this is bare, which implies it has no working directory. * See {@link #isBare()}. */ + @Nullable public ObjectId readCherryPickHead() throws IOException, NoWorkTreeException { if (isBare() || getDirectory() == null) @@ -1476,6 +1542,7 @@ public abstract class Repository implements AutoCloseable { * if this is bare, which implies it has no working directory. * See {@link #isBare()}. */ + @Nullable public ObjectId readRevertHead() throws IOException, NoWorkTreeException { if (isBare() || getDirectory() == null) throw new NoWorkTreeException(); @@ -1541,6 +1608,7 @@ public abstract class Repository implements AutoCloseable { * if this is bare, which implies it has no working directory. * See {@link #isBare()}. */ + @Nullable public ObjectId readOrigHead() throws IOException, NoWorkTreeException { if (isBare() || getDirectory() == null) throw new NoWorkTreeException(); @@ -1561,6 +1629,7 @@ public abstract class Repository implements AutoCloseable { * if this is bare, which implies it has no working directory. * See {@link #isBare()}. */ + @Nullable public String readSquashCommitMsg() throws IOException { return readCommitMsgFile(Constants.SQUASH_MSG); } @@ -1582,6 +1651,7 @@ public abstract class Repository implements AutoCloseable { writeCommitMsg(squashMsgFile, msg); } + @Nullable private String readCommitMsgFile(String msgFilename) throws IOException { if (isBare() || getDirectory() == null) throw new NoWorkTreeException(); @@ -1615,9 +1685,11 @@ public abstract class Repository implements AutoCloseable { * Read a file from the git directory. * * @param filename - * @return the raw contents or null if the file doesn't exist or is empty + * @return the raw contents or {@code null} if the file doesn't exist or is + * empty * @throws IOException */ + @Nullable private byte[] readGitDirectoryFile(String filename) throws IOException { File file = new File(getDirectory(), filename); try { @@ -1674,6 +1746,7 @@ public abstract class Repository implements AutoCloseable { * @throws IOException * @since 3.2 */ + @NonNull public List readRebaseTodo(String path, boolean includeComments) throws IOException { @@ -1703,6 +1776,7 @@ public abstract class Repository implements AutoCloseable { * @return the names of all known remotes * @since 3.4 */ + @NonNull public Set getRemoteNames() { return getConfig() .getSubsections(ConfigConstants.CONFIG_REMOTE_SECTION); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java index 8a6343c3cc..de08e4b6a0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java @@ -786,11 +786,6 @@ public class ResolveMerger extends ThreeWayMerger { private File writeMergedFile(MergeResult result) throws FileNotFoundException, IOException { File workTree = db.getWorkTree(); - if (workTree == null) - // TODO: This should be handled by WorkingTreeIterators which - // support write operations - throw new UnsupportedOperationException(); - FS fs = db.getFS(); File of = new File(workTree, tw.getPathString()); File parentFolder = of.getParentFile(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java index 7e9434a0f0..622680a27f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java @@ -42,6 +42,7 @@ */ package org.eclipse.jgit.transport; +import java.io.File; import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -85,12 +86,16 @@ public class HMACSHA1NonceGenerator implements NonceGenerator { public synchronized String createNonce(Repository repo, long timestamp) throws IllegalStateException { String path; - if (repo instanceof DfsRepository) + if (repo instanceof DfsRepository) { path = ((DfsRepository) repo).getDescription().getRepositoryName(); - else if (repo.getDirectory() != null) - path = repo.getDirectory().getPath(); - else - throw new IllegalStateException(); + } else { + File directory = repo.getDirectory(); + if (directory != null) { + path = directory.getPath(); + } else { + throw new IllegalStateException(); + } + } String input = path + ":" + String.valueOf(timestamp); //$NON-NLS-1$ byte[] rawHmac; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java index 7729c11ff9..23c506b128 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java @@ -148,8 +148,9 @@ public class TransportAmazonS3 extends HttpTransport implements WalkTransport { super(local, uri); Properties props = loadProperties(); - if (!props.containsKey("tmpdir") && local.getDirectory() != null) //$NON-NLS-1$ - props.put("tmpdir", local.getDirectory().getPath()); //$NON-NLS-1$ + File directory = local.getDirectory(); + if (!props.containsKey("tmpdir") && directory != null) //$NON-NLS-1$ + props.put("tmpdir", directory.getPath()); //$NON-NLS-1$ s3 = new AmazonS3(props); bucket = uri.getHost(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java index b27fa0d6b2..52f0f04562 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java @@ -46,6 +46,7 @@ package org.eclipse.jgit.transport; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.text.MessageFormat; @@ -235,9 +236,10 @@ public class TransportGitSsh extends SshTransport implements PackTransport { ProcessBuilder pb = new ProcessBuilder(); pb.command(args); - if (local.getDirectory() != null) + File directory = local.getDirectory(); + if (directory != null) pb.environment().put(Constants.GIT_DIR_KEY, - local.getDirectory().getPath()); + directory.getPath()); try { return pb.start(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java index 28d628b345..ec581b397a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java @@ -168,6 +168,9 @@ public class FS_Win32_Cygwin extends FS_Win32 { @Override public File findHook(Repository repository, String hookName) { final File gitdir = repository.getDirectory(); + if (gitdir == null) { + return null; + } final Path hookPath = gitdir.toPath().resolve(Constants.HOOKS) .resolve(hookName); if (Files.isExecutable(hookPath)) -- cgit v1.2.3 From 830117e761bddc182e4dc57150ca661976868203 Mon Sep 17 00:00:00 2001 From: Andrey Loskutov Date: Wed, 25 Nov 2015 21:19:05 +0100 Subject: Null-annotated RefDatabase class No other code changes except adding nullness annotations. Change-Id: If2606fb208f6690bd4fd7ad953e709a3ebd6398c Signed-off-by: Andrey Loskutov --- .../src/org/eclipse/jgit/lib/RefDatabase.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java index b62033cbd2..986666f2f4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java @@ -51,6 +51,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.annotations.Nullable; + /** * Abstraction of name to {@link ObjectId} mapping. *

@@ -132,6 +135,7 @@ public abstract class RefDatabase { * @since 2.3 * @see #isNameConflicting(String) */ + @NonNull public Collection getConflictingNames(String name) throws IOException { Map allRefs = getRefs(ALL); @@ -169,6 +173,7 @@ public abstract class RefDatabase { * @throws IOException * the reference space cannot be accessed. */ + @NonNull public abstract RefUpdate newUpdate(String name, boolean detach) throws IOException; @@ -183,6 +188,7 @@ public abstract class RefDatabase { * @throws IOException * the reference space cannot be accessed. */ + @NonNull public abstract RefRename newRename(String fromName, String toName) throws IOException; @@ -193,6 +199,7 @@ public abstract class RefDatabase { * * @return a new batch update object. */ + @NonNull public BatchRefUpdate newBatchUpdate() { return new BatchRefUpdate(this); } @@ -223,6 +230,7 @@ public abstract class RefDatabase { * @throws IOException * the reference space cannot be accessed. */ + @Nullable public abstract Ref getRef(String name) throws IOException; /** @@ -238,6 +246,7 @@ public abstract class RefDatabase { * the reference space cannot be accessed. * @since 4.1 */ + @Nullable public Ref exactRef(String name) throws IOException { Ref ref = getRef(name); if (ref == null || !name.equals(ref.getName())) { @@ -261,6 +270,7 @@ public abstract class RefDatabase { * the reference space cannot be accessed. * @since 4.1 */ + @NonNull public Map exactRef(String... refs) throws IOException { Map result = new HashMap<>(refs.length); for (String name : refs) { @@ -285,6 +295,7 @@ public abstract class RefDatabase { * the reference space cannot be accessed. * @since 4.1 */ + @Nullable public Ref firstExactRef(String... refs) throws IOException { for (String name : refs) { Ref ref = exactRef(name); @@ -308,6 +319,7 @@ public abstract class RefDatabase { * @throws IOException * the reference space cannot be accessed. */ + @NonNull public abstract Map getRefs(String prefix) throws IOException; /** @@ -322,6 +334,7 @@ public abstract class RefDatabase { * @throws IOException * the reference space cannot be accessed. */ + @NonNull public abstract List getAdditionalRefs() throws IOException; /** @@ -338,10 +351,11 @@ public abstract class RefDatabase { * @return {@code ref} if {@code ref.isPeeled()} is true; otherwise a new * Ref object representing the same data as Ref, but isPeeled() will * be true and getPeeledObjectId() will contain the peeled object - * (or null). + * (or {@code null}). * @throws IOException * the reference space or object space cannot be accessed. */ + @NonNull public abstract Ref peel(Ref ref) throws IOException; /** @@ -365,9 +379,10 @@ public abstract class RefDatabase { * @param name * short name of ref to find, e.g. "master" to find * "refs/heads/master" in map. - * @return The first ref matching the name, or null if not found. + * @return The first ref matching the name, or {@code null} if not found. * @since 3.4 */ + @Nullable public static Ref findRef(Map map, String name) { for (String prefix : SEARCH_PATH) { String fullname = prefix + name; -- cgit v1.2.3 From 5be4814e38f2c3983dc27ac6d74f95f2d73ed400 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Fri, 5 Jun 2015 15:20:24 -0700 Subject: Repository: Introduce exactRef and findRef, deprecate getRef The Repository class provides only one method to look up a ref by name, getRef. If I request refs/heads/master and that ref does not exist, getRef will look further in the search path: ref/refs/heads/master refs/heads/refs/heads/master refs/remotes/refs/heads/master This behavior is counterintuitive, needlessly inexpensive, and usually not what the caller expects. Allow callers to specify whether to use the search path by providing two separate methods: - exactRef, which looks up a ref when its exact name is known - findRef, which looks for a ref along the search path For backward compatibility, keep getRef as a deprecated synonym for findRef. This change introduces findRef and exactRef but does not update callers outside tests to use them yet. Change-Id: I35375d942baeb3ded15520388f8ebb9c0cc86f8c Signed-off-by: Jonathan Nieder --- .../jgit/http/test/DumbClientDumbServerTest.java | 4 +- .../jgit/http/test/DumbClientSmartServerTest.java | 4 +- .../eclipse/jgit/http/test/HookMessageTest.java | 4 +- .../jgit/http/test/SmartClientSmartServerTest.java | 18 ++-- .../tst/org/eclipse/jgit/pgm/CheckoutTest.java | 3 +- .../tst/org/eclipse/jgit/pgm/ResetTest.java | 8 +- .../tst/org/eclipse/jgit/pgm/StatusTest.java | 5 +- .../org/eclipse/jgit/api/CheckoutCommandTest.java | 12 ++- .../org/eclipse/jgit/api/CommitCommandTest.java | 6 +- .../tst/org/eclipse/jgit/api/MergeCommandTest.java | 54 ++++++----- .../org/eclipse/jgit/api/NameRevCommandTest.java | 4 +- .../tst/org/eclipse/jgit/api/ResetCommandTest.java | 6 +- .../eclipse/jgit/api/StashCreateCommandTest.java | 2 +- .../org/eclipse/jgit/api/StashDropCommandTest.java | 102 ++++++++++----------- .../jgit/internal/storage/file/GcPackRefsTest.java | 38 ++++---- .../jgit/internal/storage/file/RefUpdateTest.java | 8 +- .../org/eclipse/jgit/junit/TestRepositoryTest.java | 40 ++++---- .../tst/org/eclipse/jgit/lib/RefTest.java | 24 ++--- .../jgit/merge/MergeMessageFormatterTest.java | 48 +++++----- .../org/eclipse/jgit/merge/ResolveMergerTest.java | 2 +- .../jgit/merge/SquashMessageFormatterTest.java | 2 +- .../eclipse/jgit/transport/TestProtocolTest.java | 12 +-- .../src/org/eclipse/jgit/lib/Repository.java | 35 +++++++ 23 files changed, 246 insertions(+), 195 deletions(-) diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java index dec9b59f2d..362a09d64f 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java @@ -209,7 +209,7 @@ public class DumbClientDumbServerTest extends HttpTestCase { } assertTrue(dst.hasObject(A_txt)); - assertEquals(B, dst.getRef(master).getObjectId()); + assertEquals(B, dst.exactRef(master).getObjectId()); fsck(dst, B); List loose = getRequests(loose(remoteURI, A_txt)); @@ -234,7 +234,7 @@ public class DumbClientDumbServerTest extends HttpTestCase { } assertTrue(dst.hasObject(A_txt)); - assertEquals(B, dst.getRef(master).getObjectId()); + assertEquals(B, dst.exactRef(master).getObjectId()); fsck(dst, B); List req; diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java index e385b9538d..da3a09809b 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java @@ -225,7 +225,7 @@ public class DumbClientSmartServerTest extends HttpTestCase { } assertTrue(dst.hasObject(A_txt)); - assertEquals(B, dst.getRef(master).getObjectId()); + assertEquals(B, dst.exactRef(master).getObjectId()); fsck(dst, B); List loose = getRequests(loose(remoteURI, A_txt)); @@ -253,7 +253,7 @@ public class DumbClientSmartServerTest extends HttpTestCase { } assertTrue(dst.hasObject(A_txt)); - assertEquals(B, dst.getRef(master).getObjectId()); + assertEquals(B, dst.exactRef(master).getObjectId()); fsck(dst, B); List req; diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java index f1056f2d6a..d67c8173cb 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java @@ -164,8 +164,8 @@ public class HookMessageTest extends HttpTestCase { } assertTrue(remoteRepository.hasObject(Q_txt)); - assertNotNull("has " + dstName, remoteRepository.getRef(dstName)); - assertEquals(Q, remoteRepository.getRef(dstName).getObjectId()); + assertNotNull("has " + dstName, remoteRepository.exactRef(dstName)); + assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId()); fsck(remoteRepository, Q); List requests = getRequests(); diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java index 1b6c552cef..9ca0789e29 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java @@ -296,7 +296,7 @@ public class SmartClientSmartServerTest extends HttpTestCase { } assertTrue(dst.hasObject(A_txt)); - assertEquals(B, dst.getRef(master).getObjectId()); + assertEquals(B, dst.exactRef(master).getObjectId()); fsck(dst, B); List requests = getRequests(); @@ -337,7 +337,7 @@ public class SmartClientSmartServerTest extends HttpTestCase { } finally { t.close(); } - assertEquals(B, dst.getRepository().getRef(master).getObjectId()); + assertEquals(B, dst.getRepository().exactRef(master).getObjectId()); List cloneRequests = getRequests(); // Only create a few new commits. @@ -358,7 +358,7 @@ public class SmartClientSmartServerTest extends HttpTestCase { } finally { t.close(); } - assertEquals(Z, dst.getRepository().getRef(master).getObjectId()); + assertEquals(Z, dst.getRepository().exactRef(master).getObjectId()); List requests = getRequests(); requests.removeAll(cloneRequests); @@ -400,7 +400,7 @@ public class SmartClientSmartServerTest extends HttpTestCase { } finally { t.close(); } - assertEquals(B, dst.getRepository().getRef(master).getObjectId()); + assertEquals(B, dst.getRepository().exactRef(master).getObjectId()); List cloneRequests = getRequests(); // Force enough into the local client that enumeration will @@ -424,7 +424,7 @@ public class SmartClientSmartServerTest extends HttpTestCase { } finally { t.close(); } - assertEquals(Z, dst.getRepository().getRef(master).getObjectId()); + assertEquals(Z, dst.getRepository().exactRef(master).getObjectId()); List requests = getRequests(); requests.removeAll(cloneRequests); @@ -579,8 +579,8 @@ public class SmartClientSmartServerTest extends HttpTestCase { } assertTrue(remoteRepository.hasObject(Q_txt)); - assertNotNull("has " + dstName, remoteRepository.getRef(dstName)); - assertEquals(Q, remoteRepository.getRef(dstName).getObjectId()); + assertNotNull("has " + dstName, remoteRepository.exactRef(dstName)); + assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId()); fsck(remoteRepository, Q); final ReflogReader log = remoteRepository.getReflogReader(dstName); @@ -657,8 +657,8 @@ public class SmartClientSmartServerTest extends HttpTestCase { } assertTrue(remoteRepository.hasObject(Q_bin)); - assertNotNull("has " + dstName, remoteRepository.getRef(dstName)); - assertEquals(Q, remoteRepository.getRef(dstName).getObjectId()); + assertNotNull("has " + dstName, remoteRepository.exactRef(dstName)); + assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId()); fsck(remoteRepository, Q); List requests = getRequests(); diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java index 7bf4c26c38..939a9f6fdd 100644 --- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java @@ -198,7 +198,8 @@ public class CheckoutTest extends CLIRepositoryTestCase { assertStringArrayEquals("Switched to a new branch 'new_branch'", execute("git checkout --orphan new_branch")); - assertEquals("refs/heads/new_branch", db.getRef("HEAD").getTarget().getName()); + assertEquals("refs/heads/new_branch", + db.exactRef("HEAD").getTarget().getName()); RevCommit commit = git.commit().setMessage("orphan commit").call(); assertEquals(0, commit.getParentCount()); } diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.java index 0785c5c5ff..dae477928b 100644 --- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.java +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.java @@ -67,7 +67,7 @@ public class ResetTest extends CLIRepositoryTestCase { assertStringArrayEquals("", execute("git reset --hard " + commit.getId().name())); assertEquals(commit.getId(), - git.getRepository().getRef("HEAD").getObjectId()); + git.getRepository().exactRef("HEAD").getObjectId()); } @Test @@ -77,7 +77,7 @@ public class ResetTest extends CLIRepositoryTestCase { assertStringArrayEquals("", execute("git reset --hard " + commit.getId().name())); assertEquals(commit.getId(), - git.getRepository().getRef("HEAD").getObjectId()); + git.getRepository().exactRef("HEAD").getObjectId()); } @Test @@ -86,7 +86,7 @@ public class ResetTest extends CLIRepositoryTestCase { assertStringArrayEquals("", execute("git reset --hard " + commit.getId().name() + " --")); assertEquals(commit.getId(), - git.getRepository().getRef("HEAD").getObjectId()); + git.getRepository().exactRef("HEAD").getObjectId()); } @Test @@ -119,7 +119,7 @@ public class ResetTest extends CLIRepositoryTestCase { (useDoubleDash) ? " --" : ""); assertStringArrayEquals("", execute(cmd)); assertEquals(commit.getId(), - git.getRepository().getRef("HEAD").getObjectId()); + git.getRepository().exactRef("HEAD").getObjectId()); org.eclipse.jgit.api.Status status = git.status().call(); // assert that file a is unstaged diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java index 793fc7daf6..854c52d88b 100644 --- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java @@ -42,13 +42,14 @@ */ package org.eclipse.jgit.pgm; +import static org.eclipse.jgit.lib.Constants.MASTER; +import static org.eclipse.jgit.lib.Constants.R_HEADS; import java.io.IOException; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.CLIRepositoryTestCase; -import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.revwalk.RevCommit; import org.junit.Test; @@ -254,7 +255,7 @@ public class StatusTest extends CLIRepositoryTestCase { } private void detachHead(Git git) throws IOException, GitAPIException { - String commitId = db.getRef(Constants.MASTER).getObjectId().name(); + String commitId = db.exactRef(R_HEADS + MASTER).getObjectId().name(); git.checkout().setName(commitId).call(); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java index f7a50dffcb..82d509f6f3 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java @@ -43,6 +43,8 @@ */ package org.eclipse.jgit.api; +import static org.eclipse.jgit.lib.Constants.MASTER; +import static org.eclipse.jgit.lib.Constants.R_HEADS; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; @@ -134,7 +136,7 @@ public class CheckoutCommandTest extends RepositoryTestCase { @Test public void testCreateBranchOnCheckout() throws Exception { git.checkout().setCreateBranch(true).setName("test2").call(); - assertNotNull(db.getRef("test2")); + assertNotNull(db.exactRef("refs/heads/test2")); } @Test @@ -237,8 +239,8 @@ public class CheckoutCommandTest extends RepositoryTestCase { .setStartPoint("origin/test") .setUpstreamMode(SetupUpstreamMode.TRACK).call(); - assertEquals("refs/heads/test", db2.getRef(Constants.HEAD).getTarget() - .getName()); + assertEquals("refs/heads/test", + db2.exactRef(Constants.HEAD).getTarget().getName()); StoredConfig config = db2.getConfig(); assertEquals("origin", config.getString( ConfigConstants.CONFIG_BRANCH_SECTION, "test", @@ -345,7 +347,7 @@ public class CheckoutCommandTest extends RepositoryTestCase { CheckoutCommand co = git.checkout(); co.setName("master").call(); - String commitId = db.getRef(Constants.MASTER).getObjectId().name(); + String commitId = db.exactRef(R_HEADS + MASTER).getObjectId().name(); co = git.checkout(); co.setName(commitId).call(); @@ -443,7 +445,7 @@ public class CheckoutCommandTest extends RepositoryTestCase { } private void assertHeadDetached() throws IOException { - Ref head = db.getRef(Constants.HEAD); + Ref head = db.exactRef(Constants.HEAD); assertFalse(head.isSymbolic()); assertSame(head, head.getTarget()); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java index 060a5b65c6..0d03047d53 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java @@ -408,8 +408,10 @@ public class CommitCommandTest extends RepositoryTestCase { checkoutBranch("refs/heads/master"); - MergeResult result = git.merge().include(db.getRef("branch1")) - .setSquash(true).call(); + MergeResult result = git.merge() + .include(db.exactRef("refs/heads/branch1")) + .setSquash(true) + .call(); assertTrue(new File(db.getWorkTree(), "file1").exists()); assertTrue(new File(db.getWorkTree(), "file2").exists()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java index 0c0c6e5b55..cea8393ff7 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java @@ -43,6 +43,8 @@ */ package org.eclipse.jgit.api; +import static org.eclipse.jgit.lib.Constants.MASTER; +import static org.eclipse.jgit.lib.Constants.R_HEADS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -97,7 +99,7 @@ public class MergeCommandTest extends RepositoryTestCase { Git git = new Git(db); git.commit().setMessage("initial commit").call(); - MergeResult result = git.merge().include(db.getRef(Constants.HEAD)).call(); + MergeResult result = git.merge().include(db.exactRef(Constants.HEAD)).call(); assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus()); // no reflog entry written by merge assertEquals("commit (initial): initial commit", @@ -115,7 +117,7 @@ public class MergeCommandTest extends RepositoryTestCase { createBranch(first, "refs/heads/branch1"); RevCommit second = git.commit().setMessage("second commit").call(); - MergeResult result = git.merge().include(db.getRef("refs/heads/branch1")).call(); + MergeResult result = git.merge().include(db.exactRef("refs/heads/branch1")).call(); assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus()); assertEquals(second, result.getNewHead()); // no reflog entry written by merge @@ -135,7 +137,7 @@ public class MergeCommandTest extends RepositoryTestCase { checkoutBranch("refs/heads/branch1"); - MergeResult result = git.merge().include(db.getRef(Constants.MASTER)).call(); + MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER)).call(); assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus()); assertEquals(second, result.getNewHead()); @@ -155,7 +157,7 @@ public class MergeCommandTest extends RepositoryTestCase { checkoutBranch("refs/heads/branch1"); - MergeResult result = git.merge().include(db.getRef(Constants.MASTER)) + MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER)) .setCommit(false).call(); assertEquals(MergeResult.MergeStatus.FAST_FORWARD, @@ -186,7 +188,7 @@ public class MergeCommandTest extends RepositoryTestCase { checkoutBranch("refs/heads/branch1"); assertFalse(new File(db.getWorkTree(), "file2").exists()); - MergeResult result = git.merge().include(db.getRef(Constants.MASTER)).call(); + MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER)).call(); assertTrue(new File(db.getWorkTree(), "file1").exists()); assertTrue(new File(db.getWorkTree(), "file2").exists()); @@ -221,7 +223,7 @@ public class MergeCommandTest extends RepositoryTestCase { MergeCommand merge = git.merge(); merge.include(second.getId()); - merge.include(db.getRef(Constants.MASTER)); + merge.include(db.exactRef(R_HEADS + MASTER)); try { merge.call(); fail("Expected exception not thrown when merging multiple heads"); @@ -248,7 +250,7 @@ public class MergeCommandTest extends RepositoryTestCase { git.commit().setMessage("third").call(); MergeResult result = git.merge().setStrategy(mergeStrategy) - .include(db.getRef(Constants.MASTER)).call(); + .include(db.exactRef(R_HEADS + MASTER)).call(); assertEquals(MergeStatus.MERGED, result.getMergeStatus()); assertEquals( "merge refs/heads/master: Merge made by " @@ -279,9 +281,9 @@ public class MergeCommandTest extends RepositoryTestCase { MergeResult result = git.merge().setStrategy(mergeStrategy) .setCommit(false) - .include(db.getRef(Constants.MASTER)).call(); + .include(db.exactRef(R_HEADS + MASTER)).call(); assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus()); - assertEquals(db.getRef(Constants.HEAD).getTarget().getObjectId(), + assertEquals(db.exactRef(Constants.HEAD).getTarget().getObjectId(), thirdCommit.getId()); } @@ -378,7 +380,7 @@ public class MergeCommandTest extends RepositoryTestCase { git.add().addFilepattern("a").call(); git.commit().setMessage("main").call(); - Ref sideBranch = db.getRef("side"); + Ref sideBranch = db.exactRef("refs/heads/side"); git.merge().include(sideBranch) .setStrategy(MergeStrategy.RESOLVE).call(); @@ -590,7 +592,7 @@ public class MergeCommandTest extends RepositoryTestCase { .setCommit(false) .setStrategy(MergeStrategy.RESOLVE).call(); assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus()); - assertEquals(db.getRef(Constants.HEAD).getTarget().getObjectId(), + assertEquals(db.exactRef(Constants.HEAD).getTarget().getObjectId(), thirdCommit.getId()); assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(), @@ -1310,8 +1312,10 @@ public class MergeCommandTest extends RepositoryTestCase { assertFalse(new File(db.getWorkTree(), "file2").exists()); assertFalse(new File(db.getWorkTree(), "file3").exists()); - MergeResult result = git.merge().include(db.getRef("branch1")) - .setSquash(true).call(); + MergeResult result = git.merge() + .include(db.exactRef("refs/heads/branch1")) + .setSquash(true) + .call(); assertTrue(new File(db.getWorkTree(), "file1").exists()); assertTrue(new File(db.getWorkTree(), "file2").exists()); @@ -1375,8 +1379,10 @@ public class MergeCommandTest extends RepositoryTestCase { assertTrue(new File(db.getWorkTree(), "file2").exists()); assertFalse(new File(db.getWorkTree(), "file3").exists()); - MergeResult result = git.merge().include(db.getRef("branch1")) - .setSquash(true).call(); + MergeResult result = git.merge() + .include(db.exactRef("refs/heads/branch1")) + .setSquash(true) + .call(); assertTrue(new File(db.getWorkTree(), "file1").exists()); assertTrue(new File(db.getWorkTree(), "file2").exists()); @@ -1430,8 +1436,10 @@ public class MergeCommandTest extends RepositoryTestCase { assertTrue(new File(db.getWorkTree(), "file1").exists()); assertTrue(new File(db.getWorkTree(), "file2").exists()); - MergeResult result = git.merge().include(db.getRef("branch1")) - .setSquash(true).call(); + MergeResult result = git.merge() + .include(db.exactRef("refs/heads/branch1")) + .setSquash(true) + .call(); assertTrue(new File(db.getWorkTree(), "file1").exists()); assertTrue(new File(db.getWorkTree(), "file2").exists()); @@ -1468,7 +1476,7 @@ public class MergeCommandTest extends RepositoryTestCase { MergeCommand merge = git.merge(); merge.setFastForward(FastForwardMode.FF_ONLY); - merge.include(db.getRef(Constants.MASTER)); + merge.include(db.exactRef(R_HEADS + MASTER)); MergeResult result = merge.call(); assertEquals(MergeStatus.FAST_FORWARD, result.getMergeStatus()); @@ -1485,7 +1493,7 @@ public class MergeCommandTest extends RepositoryTestCase { MergeCommand merge = git.merge(); merge.setFastForward(FastForwardMode.NO_FF); - merge.include(db.getRef(Constants.MASTER)); + merge.include(db.exactRef(R_HEADS + MASTER)); MergeResult result = merge.call(); assertEquals(MergeStatus.MERGED, result.getMergeStatus()); @@ -1505,7 +1513,7 @@ public class MergeCommandTest extends RepositoryTestCase { // when MergeCommand merge = git.merge(); merge.setFastForward(FastForwardMode.NO_FF); - merge.include(db.getRef(Constants.MASTER)); + merge.include(db.exactRef(R_HEADS + MASTER)); merge.setCommit(false); MergeResult result = merge.call(); @@ -1531,7 +1539,7 @@ public class MergeCommandTest extends RepositoryTestCase { git.commit().setMessage("second commit on branch1").call(); MergeCommand merge = git.merge(); merge.setFastForward(FastForwardMode.FF_ONLY); - merge.include(db.getRef(Constants.MASTER)); + merge.include(db.exactRef(R_HEADS + MASTER)); MergeResult result = merge.call(); assertEquals(MergeStatus.ABORTED, result.getMergeStatus()); @@ -1588,7 +1596,7 @@ public class MergeCommandTest extends RepositoryTestCase { git.add().addFilepattern("c").call(); git.commit().setMessage("main").call(); - Ref sideBranch = db.getRef("side"); + Ref sideBranch = db.exactRef("refs/heads/side"); git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE) .setMessage("user message").call(); @@ -1621,7 +1629,7 @@ public class MergeCommandTest extends RepositoryTestCase { git.add().addFilepattern("a").call(); git.commit().setMessage("main").call(); - Ref sideBranch = db.getRef("side"); + Ref sideBranch = db.exactRef("refs/heads/side"); git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE) .setMessage("user message").call(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NameRevCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NameRevCommandTest.java index 491595498e..bd62200fce 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NameRevCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NameRevCommandTest.java @@ -95,9 +95,9 @@ public class NameRevCommandTest extends RepositoryTestCase { tr.update("refs/heads/master", c); tr.update("refs/tags/tag", c); assertOneResult("master", - git.nameRev().addRef(db.getRef("refs/heads/master")), c); + git.nameRev().addRef(db.exactRef("refs/heads/master")), c); assertOneResult("tag", - git.nameRev().addRef(db.getRef("refs/tags/tag")), c); + git.nameRev().addRef(db.exactRef("refs/tags/tag")), c); } @Test diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java index 9997c8c426..a67f2b912a 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java @@ -477,8 +477,10 @@ public class ResetCommandTest extends RepositoryTestCase { checkoutBranch("refs/heads/master"); - MergeResult result = g.merge().include(db.getRef("branch1")) - .setSquash(true).call(); + MergeResult result = g.merge() + .include(db.exactRef("refs/heads/branch1")) + .setSquash(true) + .call(); assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED, result.getMergeStatus()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java index c317e3beef..ae8551e641 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java @@ -110,7 +110,7 @@ public class StashCreateCommandTest extends RepositoryTestCase { int parentCount) throws IOException { assertNotNull(commit); - Ref stashRef = db.getRef(Constants.R_STASH); + Ref stashRef = db.exactRef(Constants.R_STASH); assertNotNull(stashRef); assertEquals(commit, stashRef.getObjectId()); assertNotNull(commit.getAuthorIdent()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashDropCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashDropCommandTest.java index cfad817d23..859277e93f 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashDropCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashDropCommandTest.java @@ -96,13 +96,13 @@ public class StashDropCommandTest extends RepositoryTestCase { @Test public void dropWithInvalidLogIndex() throws Exception { write(committedFile, "content2"); - Ref stashRef = git.getRepository().getRef(Constants.R_STASH); + Ref stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNull(stashRef); RevCommit stashed = git.stashCreate().call(); assertNotNull(stashed); - stashRef = git.getRepository().getRef(Constants.R_STASH); - assertEquals(stashed, git.getRepository().getRef(Constants.R_STASH) - .getObjectId()); + stashRef = git.getRepository().exactRef(Constants.R_STASH); + assertEquals(stashed, + git.getRepository().exactRef(Constants.R_STASH).getObjectId()); try { assertNull(git.stashDrop().setStashRef(100).call()); fail("Exception not thrown"); @@ -115,15 +115,15 @@ public class StashDropCommandTest extends RepositoryTestCase { @Test public void dropSingleStashedCommit() throws Exception { write(committedFile, "content2"); - Ref stashRef = git.getRepository().getRef(Constants.R_STASH); + Ref stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNull(stashRef); RevCommit stashed = git.stashCreate().call(); assertNotNull(stashed); - stashRef = git.getRepository().getRef(Constants.R_STASH); - assertEquals(stashed, git.getRepository().getRef(Constants.R_STASH) - .getObjectId()); + stashRef = git.getRepository().exactRef(Constants.R_STASH); + assertEquals(stashed, + git.getRepository().exactRef(Constants.R_STASH).getObjectId()); assertNull(git.stashDrop().call()); - stashRef = git.getRepository().getRef(Constants.R_STASH); + stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNull(stashRef); ReflogReader reader = git.getRepository().getReflogReader( @@ -134,25 +134,25 @@ public class StashDropCommandTest extends RepositoryTestCase { @Test public void dropAll() throws Exception { write(committedFile, "content2"); - Ref stashRef = git.getRepository().getRef(Constants.R_STASH); + Ref stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNull(stashRef); RevCommit firstStash = git.stashCreate().call(); assertNotNull(firstStash); - stashRef = git.getRepository().getRef(Constants.R_STASH); + stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNotNull(stashRef); - assertEquals(firstStash, git.getRepository().getRef(Constants.R_STASH) - .getObjectId()); + assertEquals(firstStash, + git.getRepository().exactRef(Constants.R_STASH).getObjectId()); write(committedFile, "content3"); RevCommit secondStash = git.stashCreate().call(); assertNotNull(secondStash); - stashRef = git.getRepository().getRef(Constants.R_STASH); + stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNotNull(stashRef); - assertEquals(secondStash, git.getRepository().getRef(Constants.R_STASH) - .getObjectId()); + assertEquals(secondStash, + git.getRepository().exactRef(Constants.R_STASH).getObjectId()); assertNull(git.stashDrop().setAll(true).call()); - assertNull(git.getRepository().getRef(Constants.R_STASH)); + assertNull(git.getRepository().exactRef(Constants.R_STASH)); ReflogReader reader = git.getRepository().getReflogReader( Constants.R_STASH); @@ -162,25 +162,25 @@ public class StashDropCommandTest extends RepositoryTestCase { @Test public void dropFirstStashedCommit() throws Exception { write(committedFile, "content2"); - Ref stashRef = git.getRepository().getRef(Constants.R_STASH); + Ref stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNull(stashRef); RevCommit firstStash = git.stashCreate().call(); assertNotNull(firstStash); - stashRef = git.getRepository().getRef(Constants.R_STASH); + stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNotNull(stashRef); - assertEquals(firstStash, git.getRepository().getRef(Constants.R_STASH) - .getObjectId()); + assertEquals(firstStash, + git.getRepository().exactRef(Constants.R_STASH).getObjectId()); write(committedFile, "content3"); RevCommit secondStash = git.stashCreate().call(); assertNotNull(secondStash); - stashRef = git.getRepository().getRef(Constants.R_STASH); + stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNotNull(stashRef); - assertEquals(secondStash, git.getRepository().getRef(Constants.R_STASH) - .getObjectId()); + assertEquals(secondStash, + git.getRepository().exactRef(Constants.R_STASH).getObjectId()); assertEquals(firstStash, git.stashDrop().call()); - stashRef = git.getRepository().getRef(Constants.R_STASH); + stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNotNull(stashRef); assertEquals(firstStash, stashRef.getObjectId()); @@ -196,33 +196,33 @@ public class StashDropCommandTest extends RepositoryTestCase { @Test public void dropMiddleStashCommit() throws Exception { write(committedFile, "content2"); - Ref stashRef = git.getRepository().getRef(Constants.R_STASH); + Ref stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNull(stashRef); RevCommit firstStash = git.stashCreate().call(); assertNotNull(firstStash); - stashRef = git.getRepository().getRef(Constants.R_STASH); + stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNotNull(stashRef); - assertEquals(firstStash, git.getRepository().getRef(Constants.R_STASH) - .getObjectId()); + assertEquals(firstStash, + git.getRepository().exactRef(Constants.R_STASH).getObjectId()); write(committedFile, "content3"); RevCommit secondStash = git.stashCreate().call(); assertNotNull(secondStash); - stashRef = git.getRepository().getRef(Constants.R_STASH); + stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNotNull(stashRef); - assertEquals(secondStash, git.getRepository().getRef(Constants.R_STASH) - .getObjectId()); + assertEquals(secondStash, + git.getRepository().exactRef(Constants.R_STASH).getObjectId()); write(committedFile, "content4"); RevCommit thirdStash = git.stashCreate().call(); assertNotNull(thirdStash); - stashRef = git.getRepository().getRef(Constants.R_STASH); + stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNotNull(stashRef); - assertEquals(thirdStash, git.getRepository().getRef(Constants.R_STASH) - .getObjectId()); + assertEquals(thirdStash, + git.getRepository().exactRef(Constants.R_STASH).getObjectId()); assertEquals(thirdStash, git.stashDrop().setStashRef(1).call()); - stashRef = git.getRepository().getRef(Constants.R_STASH); + stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNotNull(stashRef); assertEquals(thirdStash, stashRef.getObjectId()); @@ -241,46 +241,46 @@ public class StashDropCommandTest extends RepositoryTestCase { @Test public void dropBoundaryStashedCommits() throws Exception { write(committedFile, "content2"); - Ref stashRef = git.getRepository().getRef(Constants.R_STASH); + Ref stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNull(stashRef); RevCommit firstStash = git.stashCreate().call(); assertNotNull(firstStash); - stashRef = git.getRepository().getRef(Constants.R_STASH); + stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNotNull(stashRef); - assertEquals(firstStash, git.getRepository().getRef(Constants.R_STASH) - .getObjectId()); + assertEquals(firstStash, + git.getRepository().exactRef(Constants.R_STASH).getObjectId()); write(committedFile, "content3"); RevCommit secondStash = git.stashCreate().call(); assertNotNull(secondStash); - stashRef = git.getRepository().getRef(Constants.R_STASH); + stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNotNull(stashRef); - assertEquals(secondStash, git.getRepository().getRef(Constants.R_STASH) - .getObjectId()); + assertEquals(secondStash, + git.getRepository().exactRef(Constants.R_STASH).getObjectId()); write(committedFile, "content4"); RevCommit thirdStash = git.stashCreate().call(); assertNotNull(thirdStash); - stashRef = git.getRepository().getRef(Constants.R_STASH); + stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNotNull(stashRef); - assertEquals(thirdStash, git.getRepository().getRef(Constants.R_STASH) - .getObjectId()); + assertEquals(thirdStash, + git.getRepository().exactRef(Constants.R_STASH).getObjectId()); write(committedFile, "content5"); RevCommit fourthStash = git.stashCreate().call(); assertNotNull(fourthStash); - stashRef = git.getRepository().getRef(Constants.R_STASH); + stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNotNull(stashRef); - assertEquals(fourthStash, git.getRepository().getRef(Constants.R_STASH) - .getObjectId()); + assertEquals(fourthStash, + git.getRepository().exactRef(Constants.R_STASH).getObjectId()); assertEquals(thirdStash, git.stashDrop().call()); - stashRef = git.getRepository().getRef(Constants.R_STASH); + stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNotNull(stashRef); assertEquals(thirdStash, stashRef.getObjectId()); assertEquals(thirdStash, git.stashDrop().setStashRef(2).call()); - stashRef = git.getRepository().getRef(Constants.R_STASH); + stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNotNull(stashRef); assertEquals(thirdStash, stashRef.getObjectId()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java index c7336da408..fa40458f34 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java @@ -77,7 +77,7 @@ public class GcPackRefsTest extends GcTestCase { tr.lightweightTag("t", a); gc.packRefs(); - assertSame(repo.getRef("t").getStorage(), Storage.PACKED); + assertSame(repo.exactRef("refs/tags/t").getStorage(), Storage.PACKED); } @Test @@ -126,8 +126,8 @@ public class GcPackRefsTest extends GcTestCase { refLock.unlock(); } - assertSame(repo.getRef("refs/tags/t1").getStorage(), Storage.LOOSE); - assertSame(repo.getRef("refs/tags/t2").getStorage(), Storage.PACKED); + assertSame(repo.exactRef("refs/tags/t1").getStorage(), Storage.LOOSE); + assertSame(repo.exactRef("refs/tags/t2").getStorage(), Storage.PACKED); } @Test @@ -146,7 +146,7 @@ public class GcPackRefsTest extends GcTestCase { public Result call() throws Exception { RefUpdate update = new RefDirectoryUpdate( (RefDirectory) repo.getRefDatabase(), - repo.getRef("refs/tags/t")) { + repo.exactRef("refs/tags/t")) { @Override public boolean isForceUpdate() { try { @@ -182,7 +182,7 @@ public class GcPackRefsTest extends GcTestCase { pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); } - assertEquals(repo.getRef("refs/tags/t").getObjectId(), b); + assertEquals(repo.exactRef("refs/tags/t").getObjectId(), b); } @Test @@ -194,23 +194,23 @@ public class GcPackRefsTest extends GcTestCase { // check for the unborn branch master. HEAD should point to master and // master doesn't exist. - assertEquals(repo.getRef("HEAD").getTarget().getName(), + assertEquals(repo.exactRef("HEAD").getTarget().getName(), "refs/heads/master"); - assertNull(repo.getRef("HEAD").getTarget().getObjectId()); + assertNull(repo.exactRef("HEAD").getTarget().getObjectId()); gc.packRefs(); - assertSame(repo.getRef("HEAD").getStorage(), Storage.LOOSE); - assertEquals(repo.getRef("HEAD").getTarget().getName(), + assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE); + assertEquals(repo.exactRef("HEAD").getTarget().getName(), "refs/heads/master"); - assertNull(repo.getRef("HEAD").getTarget().getObjectId()); + assertNull(repo.exactRef("HEAD").getTarget().getObjectId()); git.checkout().setName("refs/heads/side").call(); gc.packRefs(); - assertSame(repo.getRef("HEAD").getStorage(), Storage.LOOSE); + assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE); // check for detached HEAD git.checkout().setName(first.getName()).call(); gc.packRefs(); - assertSame(repo.getRef("HEAD").getStorage(), Storage.LOOSE); + assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE); } @Test @@ -229,20 +229,20 @@ public class GcPackRefsTest extends GcTestCase { // check for the unborn branch master. HEAD should point to master and // master doesn't exist. - assertEquals(repo.getRef("HEAD").getTarget().getName(), + assertEquals(repo.exactRef("HEAD").getTarget().getName(), "refs/heads/master"); - assertNull(repo.getRef("HEAD").getTarget().getObjectId()); + assertNull(repo.exactRef("HEAD").getTarget().getObjectId()); gc.packRefs(); - assertSame(repo.getRef("HEAD").getStorage(), Storage.LOOSE); - assertEquals(repo.getRef("HEAD").getTarget().getName(), + assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE); + assertEquals(repo.exactRef("HEAD").getTarget().getName(), "refs/heads/master"); - assertNull(repo.getRef("HEAD").getTarget().getObjectId()); + assertNull(repo.exactRef("HEAD").getTarget().getObjectId()); // check for non-detached HEAD repo.updateRef(Constants.HEAD).link("refs/heads/side"); gc.packRefs(); - assertSame(repo.getRef("HEAD").getStorage(), Storage.LOOSE); - assertEquals(repo.getRef("HEAD").getTarget().getObjectId(), + assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE); + assertEquals(repo.exactRef("HEAD").getTarget().getObjectId(), second.getId()); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java index 098b31fccf..8744ed1bd6 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java @@ -347,7 +347,7 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase { Result update = updateRef.update(); assertEquals(Result.FORCED, update); assertEquals(ppid, db.resolve("HEAD")); - Ref ref = db.getRef("HEAD"); + Ref ref = db.exactRef("HEAD"); assertEquals("HEAD", ref.getName()); assertTrue("is detached", !ref.isSymbolic()); @@ -377,7 +377,7 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase { Result update = updateRef.update(); assertEquals(Result.NEW, update); assertEquals(ppid, db.resolve("HEAD")); - Ref ref = db.getRef("HEAD"); + Ref ref = db.exactRef("HEAD"); assertEquals("HEAD", ref.getName()); assertTrue("is detached", !ref.isSymbolic()); @@ -681,13 +681,13 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase { public void testRenameBranchAlsoInPack() throws IOException { ObjectId rb = db.resolve("refs/heads/b"); ObjectId rb2 = db.resolve("refs/heads/b~1"); - assertEquals(Ref.Storage.PACKED, db.getRef("refs/heads/b").getStorage()); + assertEquals(Ref.Storage.PACKED, db.exactRef("refs/heads/b").getStorage()); RefUpdate updateRef = db.updateRef("refs/heads/b"); updateRef.setNewObjectId(rb2); updateRef.setForceUpdate(true); Result update = updateRef.update(); assertEquals("internal check new ref is loose", Result.FORCED, update); - assertEquals(Ref.Storage.LOOSE, db.getRef("refs/heads/b").getStorage()); + assertEquals(Ref.Storage.LOOSE, db.exactRef("refs/heads/b").getStorage()); writeReflog(db, rb, "Just a message", "refs/heads/b"); assertTrue("log on old branch", new File(db.getDirectory(), "logs/refs/heads/b").exists()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java index b69b8e01e0..8b54dabce3 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java @@ -127,25 +127,25 @@ public class TestRepositoryTest { @Test public void resetFromSymref() throws Exception { repo.updateRef("HEAD").link("refs/heads/master"); - Ref head = repo.getRef("HEAD"); + Ref head = repo.exactRef("HEAD"); RevCommit master = tr.branch("master").commit().create(); RevCommit branch = tr.branch("branch").commit().create(); RevCommit detached = tr.commit().create(); assertTrue(head.isSymbolic()); assertEquals("refs/heads/master", head.getTarget().getName()); - assertEquals(master, repo.getRef("refs/heads/master").getObjectId()); - assertEquals(branch, repo.getRef("refs/heads/branch").getObjectId()); + assertEquals(master, repo.exactRef("refs/heads/master").getObjectId()); + assertEquals(branch, repo.exactRef("refs/heads/branch").getObjectId()); // Reset to branches preserves symref. tr.reset("master"); - head = repo.getRef("HEAD"); + head = repo.exactRef("HEAD"); assertEquals(master, head.getObjectId()); assertTrue(head.isSymbolic()); assertEquals("refs/heads/master", head.getTarget().getName()); tr.reset("branch"); - head = repo.getRef("HEAD"); + head = repo.exactRef("HEAD"); assertEquals(branch, head.getObjectId()); assertTrue(head.isSymbolic()); assertEquals("refs/heads/master", head.getTarget().getName()); @@ -153,50 +153,50 @@ public class TestRepositoryTest { // Reset to a SHA-1 detaches. tr.reset(detached); - head = repo.getRef("HEAD"); + head = repo.exactRef("HEAD"); assertEquals(detached, head.getObjectId()); assertFalse(head.isSymbolic()); tr.reset(detached.name()); - head = repo.getRef("HEAD"); + head = repo.exactRef("HEAD"); assertEquals(detached, head.getObjectId()); assertFalse(head.isSymbolic()); // Reset back to a branch remains detached. tr.reset("master"); - head = repo.getRef("HEAD"); + head = repo.exactRef("HEAD"); assertEquals(lastHeadBeforeDetach, head.getObjectId()); assertFalse(head.isSymbolic()); } @Test public void resetFromDetachedHead() throws Exception { - Ref head = repo.getRef("HEAD"); + Ref head = repo.exactRef("HEAD"); RevCommit master = tr.branch("master").commit().create(); RevCommit branch = tr.branch("branch").commit().create(); RevCommit detached = tr.commit().create(); assertNull(head); - assertEquals(master, repo.getRef("refs/heads/master").getObjectId()); - assertEquals(branch, repo.getRef("refs/heads/branch").getObjectId()); + assertEquals(master, repo.exactRef("refs/heads/master").getObjectId()); + assertEquals(branch, repo.exactRef("refs/heads/branch").getObjectId()); tr.reset("master"); - head = repo.getRef("HEAD"); + head = repo.exactRef("HEAD"); assertEquals(master, head.getObjectId()); assertFalse(head.isSymbolic()); tr.reset("branch"); - head = repo.getRef("HEAD"); + head = repo.exactRef("HEAD"); assertEquals(branch, head.getObjectId()); assertFalse(head.isSymbolic()); tr.reset(detached); - head = repo.getRef("HEAD"); + head = repo.exactRef("HEAD"); assertEquals(detached, head.getObjectId()); assertFalse(head.isSymbolic()); tr.reset(detached.name()); - head = repo.getRef("HEAD"); + head = repo.exactRef("HEAD"); assertEquals(detached, head.getObjectId()); assertFalse(head.isSymbolic()); } @@ -222,7 +222,7 @@ public class TestRepositoryTest { .tick(3) .add("bar", "fixed bar contents") .create(); - assertEquals(amended, repo.getRef("refs/heads/master").getObjectId()); + assertEquals(amended, repo.exactRef("refs/heads/master").getObjectId()); rw.parseBody(amended); assertEquals(1, amended.getParentCount()); @@ -257,7 +257,7 @@ public class TestRepositoryTest { .add("foo", "fixed foo contents") .create(); - Ref head = repo.getRef(Constants.HEAD); + Ref head = repo.exactRef(Constants.HEAD); assertEquals(amended, head.getObjectId()); assertTrue(head.isSymbolic()); assertEquals("refs/heads/master", head.getTarget().getName()); @@ -291,7 +291,7 @@ public class TestRepositoryTest { public void commitToUnbornHead() throws Exception { repo.updateRef("HEAD").link("refs/heads/master"); RevCommit root = tr.branch("HEAD").commit().create(); - Ref ref = repo.getRef(Constants.HEAD); + Ref ref = repo.exactRef(Constants.HEAD); assertEquals(root, ref.getObjectId()); assertTrue(ref.isSymbolic()); assertEquals("refs/heads/master", ref.getTarget().getName()); @@ -316,7 +316,7 @@ public class TestRepositoryTest { RevCommit result = tr.cherryPick(toPick); rw.parseBody(result); - Ref headRef = tr.getRepository().getRef("HEAD"); + Ref headRef = tr.getRepository().exactRef("HEAD"); assertEquals(result, headRef.getObjectId()); assertTrue(headRef.isSymbolic()); assertEquals("refs/heads/master", headRef.getLeaf().getName()); @@ -371,7 +371,7 @@ public class TestRepositoryTest { .create(); assertNotEquals(head, toPick); assertNull(tr.cherryPick(toPick)); - assertEquals(head, repo.getRef("HEAD").getObjectId()); + assertEquals(head, repo.exactRef("HEAD").getObjectId()); } private String blobAsString(AnyObjectId treeish, String path) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java index 109f401898..707757b343 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java @@ -163,7 +163,7 @@ public class RefTest extends SampleDataRepositoryTestCase { @Test public void testReadSymRefToPacked() throws IOException { writeSymref("HEAD", "refs/heads/b"); - Ref ref = db.getRef("HEAD"); + Ref ref = db.exactRef("HEAD"); assertEquals(Ref.Storage.LOOSE, ref.getStorage()); assertTrue("is symref", ref.isSymbolic()); ref = ref.getTarget(); @@ -181,7 +181,7 @@ public class RefTest extends SampleDataRepositoryTestCase { assertEquals(Result.FORCED, update); // internal writeSymref("HEAD", "refs/heads/master"); - Ref ref = db.getRef("HEAD"); + Ref ref = db.exactRef("HEAD"); assertEquals(Ref.Storage.LOOSE, ref.getStorage()); ref = ref.getTarget(); assertEquals("refs/heads/master", ref.getName()); @@ -194,13 +194,13 @@ public class RefTest extends SampleDataRepositoryTestCase { updateRef.setNewObjectId(db.resolve("refs/heads/master")); Result update = updateRef.update(); assertEquals(Result.NEW, update); - Ref ref = db.getRef("ref/heads/new"); + Ref ref = db.exactRef("ref/heads/new"); assertEquals(Storage.LOOSE, ref.getStorage()); } @Test public void testGetShortRef() throws IOException { - Ref ref = db.getRef("master"); + Ref ref = db.exactRef("refs/heads/master"); assertEquals("refs/heads/master", ref.getName()); assertEquals(db.resolve("refs/heads/master"), ref.getObjectId()); } @@ -222,7 +222,7 @@ public class RefTest extends SampleDataRepositoryTestCase { assertNull(db.getRefDatabase().exactRef("refs/foo/bar")); - Ref ref = db.getRef("refs/foo/bar"); + Ref ref = db.findRef("refs/foo/bar"); assertEquals("refs/heads/refs/foo/bar", ref.getName()); assertEquals(db.resolve("refs/heads/master"), ref.getObjectId()); } @@ -237,7 +237,7 @@ public class RefTest extends SampleDataRepositoryTestCase { assertEquals("refs/foo/bar", exactRef.getName()); assertEquals(masterId, exactRef.getObjectId()); - Ref ref = db.getRef("refs/foo/bar"); + Ref ref = db.findRef("refs/foo/bar"); assertEquals("refs/foo/bar", ref.getName()); assertEquals(masterId, ref.getObjectId()); } @@ -251,7 +251,7 @@ public class RefTest extends SampleDataRepositoryTestCase { @Test public void testReadLoosePackedRef() throws IOException, InterruptedException { - Ref ref = db.getRef("refs/heads/master"); + Ref ref = db.exactRef("refs/heads/master"); assertEquals(Storage.PACKED, ref.getStorage()); FileOutputStream os = new FileOutputStream(new File(db.getDirectory(), "refs/heads/master")); @@ -259,7 +259,7 @@ public class RefTest extends SampleDataRepositoryTestCase { os.write('\n'); os.close(); - ref = db.getRef("refs/heads/master"); + ref = db.exactRef("refs/heads/master"); assertEquals(Storage.LOOSE, ref.getStorage()); } @@ -271,7 +271,7 @@ public class RefTest extends SampleDataRepositoryTestCase { */ @Test public void testReadSimplePackedRefSameRepo() throws IOException { - Ref ref = db.getRef("refs/heads/master"); + Ref ref = db.exactRef("refs/heads/master"); ObjectId pid = db.resolve("refs/heads/master^"); assertEquals(Storage.PACKED, ref.getStorage()); RefUpdate updateRef = db.updateRef("refs/heads/master"); @@ -280,19 +280,19 @@ public class RefTest extends SampleDataRepositoryTestCase { Result update = updateRef.update(); assertEquals(Result.FORCED, update); - ref = db.getRef("refs/heads/master"); + ref = db.exactRef("refs/heads/master"); assertEquals(Storage.LOOSE, ref.getStorage()); } @Test public void testResolvedNamesBranch() throws IOException { - Ref ref = db.getRef("a"); + Ref ref = db.findRef("a"); assertEquals("refs/heads/a", ref.getName()); } @Test public void testResolvedSymRef() throws IOException { - Ref ref = db.getRef(Constants.HEAD); + Ref ref = db.exactRef(Constants.HEAD); assertEquals(Constants.HEAD, ref.getName()); assertTrue("is symbolic ref", ref.isSymbolic()); assertSame(Ref.Storage.LOOSE, ref.getStorage()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java index 21ef7479a2..6c90f7d44b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java @@ -84,44 +84,44 @@ public class MergeMessageFormatterTest extends SampleDataRepositoryTestCase { @Test public void testOneBranch() throws IOException { - Ref a = db.getRef("refs/heads/a"); - Ref master = db.getRef("refs/heads/master"); + Ref a = db.exactRef("refs/heads/a"); + Ref master = db.exactRef("refs/heads/master"); String message = formatter.format(Arrays.asList(a), master); assertEquals("Merge branch 'a'", message); } @Test public void testTwoBranches() throws IOException { - Ref a = db.getRef("refs/heads/a"); - Ref b = db.getRef("refs/heads/b"); - Ref master = db.getRef("refs/heads/master"); + Ref a = db.exactRef("refs/heads/a"); + Ref b = db.exactRef("refs/heads/b"); + Ref master = db.exactRef("refs/heads/master"); String message = formatter.format(Arrays.asList(a, b), master); assertEquals("Merge branches 'a' and 'b'", message); } @Test public void testThreeBranches() throws IOException { - Ref c = db.getRef("refs/heads/c"); - Ref b = db.getRef("refs/heads/b"); - Ref a = db.getRef("refs/heads/a"); - Ref master = db.getRef("refs/heads/master"); + Ref c = db.exactRef("refs/heads/c"); + Ref b = db.exactRef("refs/heads/b"); + Ref a = db.exactRef("refs/heads/a"); + Ref master = db.exactRef("refs/heads/master"); String message = formatter.format(Arrays.asList(c, b, a), master); assertEquals("Merge branches 'c', 'b' and 'a'", message); } @Test public void testRemoteBranch() throws Exception { - Ref remoteA = db.getRef("refs/remotes/origin/remote-a"); - Ref master = db.getRef("refs/heads/master"); + Ref remoteA = db.exactRef("refs/remotes/origin/remote-a"); + Ref master = db.exactRef("refs/heads/master"); String message = formatter.format(Arrays.asList(remoteA), master); assertEquals("Merge remote-tracking branch 'origin/remote-a'", message); } @Test public void testMixed() throws IOException { - Ref c = db.getRef("refs/heads/c"); - Ref remoteA = db.getRef("refs/remotes/origin/remote-a"); - Ref master = db.getRef("refs/heads/master"); + Ref c = db.exactRef("refs/heads/c"); + Ref remoteA = db.exactRef("refs/remotes/origin/remote-a"); + Ref master = db.exactRef("refs/heads/master"); String message = formatter.format(Arrays.asList(c, remoteA), master); assertEquals("Merge branch 'c', remote-tracking branch 'origin/remote-a'", message); @@ -129,8 +129,8 @@ public class MergeMessageFormatterTest extends SampleDataRepositoryTestCase { @Test public void testTag() throws IOException { - Ref tagA = db.getRef("refs/tags/A"); - Ref master = db.getRef("refs/heads/master"); + Ref tagA = db.exactRef("refs/tags/A"); + Ref master = db.exactRef("refs/heads/master"); String message = formatter.format(Arrays.asList(tagA), master); assertEquals("Merge tag 'A'", message); } @@ -141,7 +141,7 @@ public class MergeMessageFormatterTest extends SampleDataRepositoryTestCase { .fromString("6db9c2ebf75590eef973081736730a9ea169a0c4"); Ref commit = new ObjectIdRef.Unpeeled(Storage.LOOSE, objectId.getName(), objectId); - Ref master = db.getRef("refs/heads/master"); + Ref master = db.exactRef("refs/heads/master"); String message = formatter.format(Arrays.asList(commit), master); assertEquals("Merge commit '6db9c2ebf75590eef973081736730a9ea169a0c4'", message); @@ -154,7 +154,7 @@ public class MergeMessageFormatterTest extends SampleDataRepositoryTestCase { .fromString("6db9c2ebf75590eef973081736730a9ea169a0c4"); Ref remoteBranch = new ObjectIdRef.Unpeeled(Storage.LOOSE, name, objectId); - Ref master = db.getRef("refs/heads/master"); + Ref master = db.exactRef("refs/heads/master"); String message = formatter.format(Arrays.asList(remoteBranch), master); assertEquals("Merge branch 'test' of http://egit.eclipse.org/jgit.git", message); @@ -162,16 +162,16 @@ public class MergeMessageFormatterTest extends SampleDataRepositoryTestCase { @Test public void testIntoOtherThanMaster() throws IOException { - Ref a = db.getRef("refs/heads/a"); - Ref b = db.getRef("refs/heads/b"); + Ref a = db.exactRef("refs/heads/a"); + Ref b = db.exactRef("refs/heads/b"); String message = formatter.format(Arrays.asList(a), b); assertEquals("Merge branch 'a' into b", message); } @Test public void testIntoHeadOtherThanMaster() throws IOException { - Ref a = db.getRef("refs/heads/a"); - Ref b = db.getRef("refs/heads/b"); + Ref a = db.exactRef("refs/heads/a"); + Ref b = db.exactRef("refs/heads/b"); SymbolicRef head = new SymbolicRef("HEAD", b); String message = formatter.format(Arrays.asList(a), head); assertEquals("Merge branch 'a' into b", message); @@ -179,8 +179,8 @@ public class MergeMessageFormatterTest extends SampleDataRepositoryTestCase { @Test public void testIntoSymbolicRefHeadPointingToMaster() throws IOException { - Ref a = db.getRef("refs/heads/a"); - Ref master = db.getRef("refs/heads/master"); + Ref a = db.exactRef("refs/heads/a"); + Ref master = db.exactRef("refs/heads/master"); SymbolicRef head = new SymbolicRef("HEAD", master); String message = formatter.format(Arrays.asList(a), head); assertEquals("Merge branch 'a'", message); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java index cd6a4bea2e..674619f0de 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java @@ -630,7 +630,7 @@ public class ResolveMergerTest extends RepositoryTestCase { // ResolveMerge try { MergeResult mergeResult = git.merge().setStrategy(strategy) - .include(git.getRepository().getRef("refs/heads/side")) + .include(git.getRepository().exactRef("refs/heads/side")) .call(); assertEquals(MergeStrategy.RECURSIVE, strategy); assertEquals(MergeResult.MergeStatus.MERGED, diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SquashMessageFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SquashMessageFormatterTest.java index b7b2291429..cddbbd528b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SquashMessageFormatterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SquashMessageFormatterTest.java @@ -76,7 +76,7 @@ public class SquashMessageFormatterTest extends SampleDataRepositoryTestCase { Git git = new Git(db); revCommit = git.commit().setMessage("squash_me").call(); - Ref master = db.getRef("refs/heads/master"); + Ref master = db.exactRef("refs/heads/master"); String message = msgFormatter.format(Arrays.asList(revCommit), master); assertEquals( "Squashed commit of the following:\n\ncommit " diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java index 7f865263d6..31b64187c8 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java @@ -125,7 +125,7 @@ public class TestProtocolTest { .setRefSpecs(HEADS) .call(); assertEquals(master, - local.getRepository().getRef("master").getObjectId()); + local.getRepository().exactRef("refs/heads/master").getObjectId()); } } @@ -142,7 +142,7 @@ public class TestProtocolTest { .setRefSpecs(HEADS) .call(); assertEquals(master, - remote.getRepository().getRef("master").getObjectId()); + remote.getRepository().exactRef("refs/heads/master").getObjectId()); } } @@ -177,7 +177,7 @@ public class TestProtocolTest { // Expected. } assertEquals(1, rejected.get()); - assertNull(local.getRepository().getRef("master")); + assertNull(local.getRepository().exactRef("refs/heads/master")); git.fetch() .setRemote(user2Uri.toString()) @@ -185,7 +185,7 @@ public class TestProtocolTest { .call(); assertEquals(1, rejected.get()); assertEquals(master, - local.getRepository().getRef("master").getObjectId()); + local.getRepository().exactRef("refs/heads/master").getObjectId()); } } @@ -222,7 +222,7 @@ public class TestProtocolTest { JGitText.get().pushNotPermitted)); } assertEquals(1, rejected.get()); - assertNull(remote.getRepository().getRef("master")); + assertNull(remote.getRepository().exactRef("refs/heads/master")); git.push() .setRemote(user2Uri.toString()) @@ -230,7 +230,7 @@ public class TestProtocolTest { .call(); assertEquals(1, rejected.get()); assertEquals(master, - remote.getRepository().getRef("master").getObjectId()); + remote.getRepository().exactRef("refs/heads/master").getObjectId()); } } 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 c91f2dab72..49a970d03a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java @@ -964,9 +964,44 @@ public abstract class Repository implements AutoCloseable { * "refs/heads/master" if "refs/heads/master" already exists. * @return the Ref with the given name, or {@code null} if it does not exist * @throws IOException + * @deprecated Use {@link #exactRef(String)} or {@link #findRef(String)} + * instead. */ + @Deprecated @Nullable public Ref getRef(final String name) throws IOException { + return findRef(name); + } + + /** + * Get a ref by name. + * + * @param name + * the name of the ref to lookup. Must not be a short-hand + * form; e.g., "master" is not automatically expanded to + * "refs/heads/master". + * @return the Ref with the given name, or {@code null} if it does not exist + * @throws IOException + * @since 4.2 + */ + @Nullable + public Ref exactRef(String name) throws IOException { + return getRefDatabase().exactRef(name); + } + + /** + * Search for a ref by (possibly abbreviated) name. + * + * @param name + * the name of the ref to lookup. May be a short-hand form, e.g. + * "master" which is is automatically expanded to + * "refs/heads/master" if "refs/heads/master" already exists. + * @return the Ref with the given name, or {@code null} if it does not exist + * @throws IOException + * @since 4.2 + */ + @Nullable + public Ref findRef(String name) throws IOException { return getRefDatabase().getRef(name); } -- cgit v1.2.3 From fe98218e0df85012cb9b901c71c44f232f65cb3a Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Thu, 19 Nov 2015 12:47:18 -0800 Subject: repo: Do not use search path to find refs/remotes/origin/ When running from a non-bare repository, "jgit repo" checks whether the rev passed in is a sha1 or branch name and in the latter case will check out origin/. We are expecting refs/remotes/origin/, but as a side effect of using getRef we also end up looking for refs/origin/, refs/heads/origin/, and so on. Avoid that by using exactRef instead. Signed-off-by: Jonathan Nieder Change-Id: I670b2e48a88138a1f2104ea201baa958e9edbddb --- org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java index 1d2d3bfaaf..ff9f233aa5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java @@ -42,6 +42,9 @@ */ package org.eclipse.jgit.gitrepo; +import static org.eclipse.jgit.lib.Constants.DEFAULT_REMOTE_NAME; +import static org.eclipse.jgit.lib.Constants.R_REMOTES; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -574,7 +577,7 @@ public class RepoCommand extends GitCommand { private static String findRef(String ref, Repository repo) throws IOException { if (!ObjectId.isId(ref)) { - Ref r = repo.getRef(Constants.DEFAULT_REMOTE_NAME + "/" + ref); //$NON-NLS-1$ + Ref r = repo.exactRef(R_REMOTES + DEFAULT_REMOTE_NAME + "/" + ref); //$NON-NLS-1$ if (r != null) return r.getName(); } -- cgit v1.2.3 From 55fb18feaa096b47acebbc8fb8c37942d68f49d5 Mon Sep 17 00:00:00 2001 From: Christian Halstrick Date: Tue, 24 Nov 2015 11:18:59 +0100 Subject: Fix FS.runProcess() to close the InputStream When FS.runProcess was called and an InputStream was given the method tried to pump the whole InputStream to the process. When the method ended the InputStream was not giving any data anymore. Consequently close the InputStream inside the method. Change-Id: I0ed738a775e5c977b21447d195acee1ecf5e2cb9 --- org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java index b61e47f5f6..253acbb76a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java @@ -949,9 +949,7 @@ public abstract class FS { * @param outRedirect * An OutputStream on which to redirect the processes stdout. Can * be null, in which case the processes standard - * output will be lost. If binary is set to false - * then it is expected that the process emits text data which - * should be processed line by line. + * output will be lost. * @param errRedirect * An OutputStream on which to redirect the processes stderr. Can * be null, in which case the processes standard @@ -959,9 +957,9 @@ public abstract class FS { * @param inRedirect * An InputStream from which to redirect the processes stdin. Can * be null, in which case the process doesn't get - * any data over stdin. If binary is set to - * false then it is expected that the process - * expects text data which should be processed line by line. + * any data over stdin. It is assumed that the whole InputStream + * will be consumed by the process. The method will close the + * inputstream after all bytes are read. * @return the return code of this process. * @throws IOException * if an I/O error occurs while executing this process. @@ -1011,6 +1009,9 @@ public abstract class FS { // A process doesn't clean its own resources even when destroyed // Explicitly try and close all three streams, preserving the // outer I/O exception if any. + if (inRedirect != null) { + inRedirect.close(); + } try { process.getErrorStream().close(); } catch (IOException e) { -- cgit v1.2.3 From 5c8f2d8feb60ddf380c46080ff290936b18f6277 Mon Sep 17 00:00:00 2001 From: Christian Halstrick Date: Fri, 20 Nov 2015 14:38:24 +0100 Subject: Fix HookTest when running on Win32_Cygwin This test expected that the test scripts emit a platform-dependent newline (crlf on windows, lf on linux). But that's not true. Expected result should always be a trailing "\n" because the test scripts explicitly echo a "\n" in the end. Change-Id: I604e08cda8cebe276b5214ba0f618b6112c3441f --- .../tst/org/eclipse/jgit/util/HookTest.java | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java index 8aa14c5218..e07076e322 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java @@ -92,11 +92,9 @@ public class HookTest extends RepositoryTestCase { fail("expected commit-msg hook to abort commit"); } catch (AbortedByHookException e) { assertEquals("unexpected error message from commit-msg hook", - "Rejected by \"commit-msg\" hook.\nstderr" - + System.lineSeparator(), + "Rejected by \"commit-msg\" hook.\nstderr\n", e.getMessage()); - assertEquals("unexpected output from commit-msg hook", - "test" + System.lineSeparator(), + assertEquals("unexpected output from commit-msg hook", "test\n", out.toString()); } } @@ -114,7 +112,7 @@ public class HookTest extends RepositoryTestCase { ByteArrayOutputStream out = new ByteArrayOutputStream(); git.commit().setMessage("commit") .setHookOutputStream(new PrintStream(out)).call(); - assertEquals(".git/COMMIT_EDITMSG" + System.lineSeparator(), + assertEquals(".git/COMMIT_EDITMSG\n", out.toString("UTF-8")); } @@ -147,11 +145,10 @@ public class HookTest extends RepositoryTestCase { new String[] { "arg1", "arg2" }, new PrintStream(out), new PrintStream(err), "stdin"); - assertEquals("unexpected hook output", "test arg1 arg2" - + System.lineSeparator() + "stdin" + System.lineSeparator(), + + assertEquals("unexpected hook output", "test arg1 arg2\nstdin\n", out.toString("UTF-8")); - assertEquals("unexpected output on stderr stream", - "stderr" + System.lineSeparator(), + assertEquals("unexpected output on stderr stream", "stderr\n", err.toString("UTF-8")); assertEquals("unexpected exit code", 0, res.getExitCode()); assertEquals("unexpected process status", ProcessResult.Status.OK, @@ -175,11 +172,9 @@ public class HookTest extends RepositoryTestCase { fail("expected pre-commit hook to abort commit"); } catch (AbortedByHookException e) { assertEquals("unexpected error message from pre-commit hook", - "Rejected by \"pre-commit\" hook.\nstderr" - + System.lineSeparator(), + "Rejected by \"pre-commit\" hook.\nstderr\n", e.getMessage()); - assertEquals("unexpected output from pre-commit hook", - "test" + System.lineSeparator(), + assertEquals("unexpected output from pre-commit hook", "test\n", out.toString()); } } -- cgit v1.2.3 From 2cdc130dfc06179acce47a57cfa9562290598b64 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Thu, 26 Nov 2015 00:32:37 +0100 Subject: Add missing @since tags and missing javadoc Change-Id: I8575797127fc96abea8af56f019ca39f5897486f Signed-off-by: Matthias Sohn --- .../src/org/eclipse/jgit/junit/JGitTestUtil.java | 11 +++++++++++ .../org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java | 5 ++++- .../src/org/eclipse/jgit/junit/MockSystemReader.java | 1 + .../src/org/eclipse/jgit/junit/RepositoryTestCase.java | 11 +++++++++++ .../src/org/eclipse/jgit/junit/TestRepository.java | 6 +++++- org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java | 4 +++- 6 files changed, 35 insertions(+), 3 deletions(-) diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java index 521593ea80..2962e7192f 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java @@ -241,6 +241,17 @@ public abstract class JGitTestUtil { FileUtils.delete(path); } + /** + * @param db + * the repository + * @param link + * the path of the symbolic link to create + * @param target + * the target of the symbolic link + * @return the path to the symbolic link + * @throws Exception + * @since 4.2 + */ public static Path writeLink(Repository db, String link, String target) throws Exception { return FileUtils.createSymLink(new File(db.getWorkTree(), link), diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java index bb5f9efb8f..4d713b5e73 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java @@ -91,7 +91,10 @@ public abstract class LocalDiskRepositoryTestCase { /** A fake (but stable) identity for committer fields in the test. */ protected PersonIdent committer; - /** A {@link SystemReader} used to coordinate time, envars, etc. */ + /** + * A {@link SystemReader} used to coordinate time, envars, etc. + * @since 4.2 + */ protected MockSystemReader mockSystemReader; private final List toClose = new ArrayList(); diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java index 03a2b1a584..28a95569e8 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java @@ -151,6 +151,7 @@ public class MockSystemReader extends SystemReader { * * @param secDelta * number of seconds to add to the current time. + * @since 4.2 */ public void tick(final int secDelta) { now += secDelta * 1000L; diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java index 28c61778c7..56962e869f 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java @@ -108,6 +108,17 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { return JGitTestUtil.writeTrashFile(db, name, data); } + /** + * Create a symbolic link + * + * @param link + * the path of the symbolic link to create + * @param target + * the target of the symbolic link + * @return the path to the symbolic link + * @throws Exception + * @since 4.2 + */ protected Path writeLink(final String link, final String target) throws Exception { return JGitTestUtil.writeLink(db, link, target); diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java index 251e65f553..ac9685d375 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java @@ -175,6 +175,7 @@ public class TestRepository { * the MockSystemReader to use for clock and other system * operations. * @throws IOException + * @since 4.2 */ public TestRepository(R db, RevWalk rw, MockSystemReader reader) throws IOException { @@ -203,7 +204,10 @@ public class TestRepository { return git; } - /** @return current date. */ + /** + * @return current date. + * @since 4.2 + */ public Date getDate() { return new Date(mockSystemReader.getCurrentTime()); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java index 6d0318c029..727ea79cc9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java @@ -398,8 +398,10 @@ public class FileUtils { * Create a symbolic link * * @param path + * the path of the symbolic link to create * @param target - * @return path to the created link + * the target of the symbolic link + * @return the path to the symbolic link * @throws IOException * @since 4.2 */ -- cgit v1.2.3 From adbe9006831a5d03a3513f4a09dbda8703e19f7c Mon Sep 17 00:00:00 2001 From: Christian Halstrick Date: Tue, 24 Nov 2015 15:16:42 +0100 Subject: Fix unit tests on Windows PushCommandTest and RunExternalScriptTest didn't succeed on Windows. Fix this by expecting a simple line-feed as line ending (instead of the platform dependent line separator. Additionally correct the computation of expected URLs in PushCommandTest. Change-Id: Idcdc41cd7e535ff88df33ea0a249333ed8fc91b0 Signed-off-by: Matthias Sohn --- .../tst/org/eclipse/jgit/api/PushCommandTest.java | 8 ++--- .../eclipse/jgit/util/RunExternalScriptTest.java | 35 +++++++++++----------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java index ccf1a51f1b..1fcfef9c71 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java @@ -138,11 +138,9 @@ public class PushCommandTest extends RepositoryTestCase { RefSpec spec = new RefSpec("refs/heads/master:refs/heads/x"); git1.push().setRemote("test").setRefSpecs(spec).call(); - assertEquals( - "1:test, 2:file://" + db2.getDirectory().toPath() // - + "/, 3:\n" + "refs/heads/master " + commit.getName() - + " refs/heads/x " + ObjectId.zeroId().name(), - read(hookOutput)); + assertEquals("1:test, 2:" + uri + ", 3:\n" + "refs/heads/master " + + commit.getName() + " refs/heads/x " + + ObjectId.zeroId().name(), read(hookOutput)); } private File writeHookFile(final String name, final String data) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java index b6a2519c59..7c0985ef42 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java @@ -57,12 +57,12 @@ import org.junit.Before; import org.junit.Test; public class RunExternalScriptTest { + private static final String LF = "\n"; + private ByteArrayOutputStream out; private ByteArrayOutputStream err; - private String sep = System.getProperty("line.separator"); - @Before public void setUp() throws Exception { out = new ByteArrayOutputStream(); @@ -74,7 +74,7 @@ public class RunExternalScriptTest { String inputStr = "a\nb\rc\r\nd"; File script = writeTempFile("cat -"); int rc = FS.DETECTED.runProcess( - new ProcessBuilder("/bin/sh", script.getPath()), out, err, + new ProcessBuilder("sh", script.getPath()), out, err, new ByteArrayInputStream(inputStr.getBytes())); assertEquals(0, rc); assertEquals(inputStr, new String(out.toByteArray())); @@ -85,7 +85,7 @@ public class RunExternalScriptTest { public void testCopyNullStdIn() throws IOException, InterruptedException { File script = writeTempFile("cat -"); int rc = FS.DETECTED.runProcess( - new ProcessBuilder("/bin/sh", script.getPath()), out, err, + new ProcessBuilder("sh", script.getPath()), out, err, (InputStream) null); assertEquals(0, rc); assertEquals("", new String(out.toByteArray())); @@ -95,7 +95,8 @@ public class RunExternalScriptTest { @Test public void testArguments() throws IOException, InterruptedException { File script = writeTempFile("echo $#,$1,$2,$3,$4,$5,$6"); - int rc = FS.DETECTED.runProcess(new ProcessBuilder("/bin/bash", + int rc = FS.DETECTED.runProcess( + new ProcessBuilder("sh", script.getPath(), "a", "b", "c"), out, err, (InputStream) null); assertEquals(0, rc); assertEquals("3,a,b,c,,,\n", new String(out.toByteArray())); @@ -106,7 +107,7 @@ public class RunExternalScriptTest { public void testRc() throws IOException, InterruptedException { File script = writeTempFile("exit 3"); int rc = FS.DETECTED.runProcess( - new ProcessBuilder("/bin/sh", script.getPath(), "a", "b", "c"), + new ProcessBuilder("sh", script.getPath(), "a", "b", "c"), out, err, (InputStream) null); assertEquals(3, rc); assertEquals("", new String(out.toByteArray())); @@ -117,7 +118,7 @@ public class RunExternalScriptTest { public void testNullStdout() throws IOException, InterruptedException { File script = writeTempFile("echo hi"); int rc = FS.DETECTED.runProcess( - new ProcessBuilder("/bin/sh", script.getPath()), null, err, + new ProcessBuilder("sh", script.getPath()), null, err, (InputStream) null); assertEquals(0, rc); assertEquals("", new String(out.toByteArray())); @@ -128,11 +129,11 @@ public class RunExternalScriptTest { public void testStdErr() throws IOException, InterruptedException { File script = writeTempFile("echo hi >&2"); int rc = FS.DETECTED.runProcess( - new ProcessBuilder("/bin/sh", script.getPath()), null, err, + new ProcessBuilder("sh", script.getPath()), null, err, (InputStream) null); assertEquals(0, rc); assertEquals("", new String(out.toByteArray())); - assertEquals("hi" + sep, new String(err.toByteArray())); + assertEquals("hi" + LF, new String(err.toByteArray())); } @Test @@ -140,11 +141,11 @@ public class RunExternalScriptTest { String inputStr = "a\nb\rc\r\nd"; File script = writeTempFile("echo $#,$1,$2,$3,$4,$5,$6 >&2 ; cat -; exit 5"); int rc = FS.DETECTED.runProcess( - new ProcessBuilder("/bin/sh", script.getPath(), "a", "b", "c"), + new ProcessBuilder("sh", script.getPath(), "a", "b", "c"), out, err, new ByteArrayInputStream(inputStr.getBytes())); assertEquals(5, rc); assertEquals(inputStr, new String(out.toByteArray())); - assertEquals("3,a,b,c,,," + sep, new String(err.toByteArray())); + assertEquals("3,a,b,c,,," + LF, new String(err.toByteArray())); } @Test(expected = IOException.class) @@ -159,7 +160,7 @@ public class RunExternalScriptTest { public void testWrongScript() throws IOException, InterruptedException { File script = writeTempFile("cat-foo -"); int rc = FS.DETECTED.runProcess( - new ProcessBuilder("/bin/sh", script.getPath(), "a", "b", "c"), + new ProcessBuilder("sh", script.getPath(), "a", "b", "c"), out, err, (InputStream) null); assertEquals(127, rc); } @@ -169,7 +170,7 @@ public class RunExternalScriptTest { throws IOException, InterruptedException { String inputStr = "a\nb\rc\r\nd"; File script = writeTempFile("cat -"); - ProcessBuilder pb = new ProcessBuilder("/bin/sh", script.getPath()); + ProcessBuilder pb = new ProcessBuilder("sh", script.getPath()); ExecutionResult res = FS.DETECTED.execute(pb, new ByteArrayInputStream(inputStr.getBytes())); assertEquals(0, res.getRc()); @@ -180,11 +181,11 @@ public class RunExternalScriptTest { @Test public void testStdErrExecute() throws IOException, InterruptedException { File script = writeTempFile("echo hi >&2"); - ProcessBuilder pb = new ProcessBuilder("/bin/sh", script.getPath()); + ProcessBuilder pb = new ProcessBuilder("sh", script.getPath()); ExecutionResult res = FS.DETECTED.execute(pb, null); assertEquals(0, res.getRc()); assertEquals("", new String(res.getStdout().toByteArray())); - assertEquals("hi" + sep, new String(res.getStderr().toByteArray())); + assertEquals("hi" + LF, new String(res.getStderr().toByteArray())); } @Test @@ -193,13 +194,13 @@ public class RunExternalScriptTest { String inputStr = "a\nb\rc\r\nd"; File script = writeTempFile( "echo $#,$1,$2,$3,$4,$5,$6 >&2 ; cat -; exit 5"); - ProcessBuilder pb = new ProcessBuilder("/bin/sh", script.getPath(), "a", + ProcessBuilder pb = new ProcessBuilder("sh", script.getPath(), "a", "b", "c"); ExecutionResult res = FS.DETECTED.execute(pb, new ByteArrayInputStream(inputStr.getBytes())); assertEquals(5, res.getRc()); assertEquals(inputStr, new String(res.getStdout().toByteArray())); - assertEquals("3,a,b,c,,," + sep, + assertEquals("3,a,b,c,,," + LF, new String(res.getStderr().toByteArray())); } -- cgit v1.2.3 From 75697adc5a0024449351aacac89618c3b83add11 Mon Sep 17 00:00:00 2001 From: Ivan Motsch Date: Tue, 17 Nov 2015 13:32:20 +0100 Subject: Add the new class Attributes holding multiple Attribute(s) Attributes represents a semantic collector of Attribute(s) and replaces the anonymous Map. This class will be returned by TreeWalk.getAttributes(). It offers convenient access to the attributes wrapped in the Attributes object. Adds preparations for a future Attribute Macro Expansion Change-Id: I8348c8c457a2a7f1f0c48050e10399b0fa1cdbe1 Signed-off-by: Ivan Motsch --- .../AttributesNodeDirCacheIteratorTest.java | 10 +- .../jgit/attributes/AttributesNodeTest.java | 27 +-- .../AttributesNodeWorkingTreeIteratorTest.java | 10 +- .../jgit/attributes/TreeWalkAttributeTest.java | 5 +- org.eclipse.jgit/.settings/.api_filters | 8 + .../src/org/eclipse/jgit/attributes/Attribute.java | 16 +- .../org/eclipse/jgit/attributes/Attributes.java | 202 +++++++++++++++++++++ .../eclipse/jgit/attributes/AttributesNode.java | 12 +- .../jgit/attributes/AttributesProvider.java | 6 +- .../eclipse/jgit/attributes/AttributesRule.java | 19 ++ .../internal/storage/file/InfoAttributesNode.java | 3 +- .../src/org/eclipse/jgit/lib/Constants.java | 7 + .../src/org/eclipse/jgit/treewalk/TreeWalk.java | 41 +++-- 13 files changed, 306 insertions(+), 60 deletions(-) create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java index 3e6ca62202..0e595e61f8 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java @@ -52,9 +52,7 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.attributes.Attribute.State; @@ -258,12 +256,14 @@ public class AttributesNodeDirCacheIteratorTest extends RepositoryTestCase { assertTrue(nodeAttrs == null || nodeAttrs.isEmpty()); else { - Map entryAttributes = new LinkedHashMap(); - attributesNode.getAttributes(pathName, false, entryAttributes); + Attributes entryAttributes = new Attributes(); + attributesNode.getAttributes(pathName, + false, entryAttributes); if (nodeAttrs != null && !nodeAttrs.isEmpty()) { for (Attribute attribute : nodeAttrs) { - assertThat(entryAttributes.values(), hasItem(attribute)); + assertThat(entryAttributes.getAll(), + hasItem(attribute)); } } else { assertTrue( diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java index d82baaa36e..d478a7cf08 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java @@ -49,10 +49,6 @@ import static org.junit.Assert.assertEquals; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; import org.junit.After; import org.junit.Test; @@ -104,8 +100,8 @@ public class AttributesNodeTest { is = new ByteArrayInputStream(attributeFileContent.getBytes()); AttributesNode node = new AttributesNode(); node.parse(is); - assertAttribute("file.type1", node, Collections. emptySet()); - assertAttribute("file.type2", node, Collections. emptySet()); + assertAttribute("file.type1", node, new Attributes()); + assertAttribute("file.type2", node, new Attributes()); } @Test @@ -115,7 +111,7 @@ public class AttributesNodeTest { is = new ByteArrayInputStream(attributeFileContent.getBytes()); AttributesNode node = new AttributesNode(); node.parse(is); - assertAttribute("file.type1", node, Collections. emptySet()); + assertAttribute("file.type1", node, new Attributes()); assertAttribute("file.type2", node, asSet(A_UNSET_ATTR)); } @@ -127,8 +123,8 @@ public class AttributesNodeTest { is = new ByteArrayInputStream(attributeFileContent.getBytes()); AttributesNode node = new AttributesNode(); node.parse(is); - assertAttribute("file.type1", node, Collections. emptySet()); - assertAttribute("file.type2", node, Collections. emptySet()); + assertAttribute("file.type1", node, new Attributes()); + assertAttribute("file.type2", node, new Attributes()); assertAttribute("file.type3", node, asSet(new Attribute("attr", ""))); } @@ -166,17 +162,14 @@ public class AttributesNodeTest { } private void assertAttribute(String path, AttributesNode node, - Set attrs) { - HashMap attributes = new HashMap(); + Attributes attrs) { + Attributes attributes = new Attributes(); node.getAttributes(path, false, attributes); - assertEquals(attrs, new HashSet(attributes.values())); + assertEquals(attrs, attributes); } - static Set asSet(Attribute... attrs) { - Set result = new HashSet(); - for (Attribute attr : attrs) - result.add(attr); - return result; + static Attributes asSet(Attribute... attrs) { + return new Attributes(attrs); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java index bcf17174b8..6ad19a2491 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java @@ -53,9 +53,7 @@ import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import org.eclipse.jgit.attributes.Attribute.State; import org.eclipse.jgit.errors.CorruptObjectException; @@ -227,12 +225,14 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase { assertTrue(nodeAttrs == null || nodeAttrs.isEmpty()); else { - Map entryAttributes = new LinkedHashMap(); - attributesNode.getAttributes(pathName, false, entryAttributes); + Attributes entryAttributes = new Attributes(); + attributesNode.getAttributes(pathName, + false, entryAttributes); if (nodeAttrs != null && !nodeAttrs.isEmpty()) { for (Attribute attribute : nodeAttrs) { - assertThat(entryAttributes.values(), hasItem(attribute)); + assertThat(entryAttributes.getAll(), + hasItem(attribute)); } } else { assertTrue( diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java index c3d5e8752c..b044c01db6 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java @@ -802,8 +802,9 @@ public class TreeWalkAttributeTest extends RepositoryTestCase { assertEquals(type, walk.getFileMode(0)); assertEquals(checkinAttributes, - asSet(ci_walk.getAttributes().values())); - assertEquals(checkoutAttributes, asSet(walk.getAttributes().values())); + asSet(ci_walk.getAttributes().getAll())); + assertEquals(checkoutAttributes, + asSet(walk.getAttributes().getAll())); if (D.equals(type)) { walk.enterSubtree(); diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters index b89aad4c59..b2a8f677f3 100644 --- a/org.eclipse.jgit/.settings/.api_filters +++ b/org.eclipse.jgit/.settings/.api_filters @@ -1,5 +1,13 @@ + + + + + + + + diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java index d3ce685187..905ad76929 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java @@ -50,8 +50,10 @@ package org.eclipse.jgit.attributes; *

  • Set - represented by {@link State#SET}
  • *
  • Unset - represented by {@link State#UNSET}
  • *
  • Set to a value - represented by {@link State#CUSTOM}
  • - *
  • Unspecified - null is used instead of an instance of this - * class
  • + *
  • Unspecified - used to revert an attribute . This is crucial in order to + * mark an attribute as unspecified in the attributes map and thus preventing + * following (with lower priority) nodes from setting the attribute to a value + * at all
  • * *

    * @@ -61,6 +63,7 @@ public final class Attribute { /** * The attribute value state + * see also https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html */ public static enum State { /** the attribute is set */ @@ -69,6 +72,13 @@ public final class Attribute { /** the attribute is unset */ UNSET, + /** + * the attribute appears as if it would not be defined at all + * + * @since 4.2 + */ + UNSPECIFIED, + /** the attribute is set to a custom value */ CUSTOM } @@ -176,6 +186,8 @@ public final class Attribute { return key; case UNSET: return "-" + key; //$NON-NLS-1$ + case UNSPECIFIED: + return "!" + key; //$NON-NLS-1$ case CUSTOM: default: return key + "=" + value; //$NON-NLS-1$ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java new file mode 100644 index 0000000000..0810e31682 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2015, Ivan Motsch + * + * 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.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.eclipse.jgit.attributes.Attribute.State; + +/** + * Represents a set of attributes for a path + *

    + * + * @since 4.2 + */ +public final class Attributes { + private final Map map = new LinkedHashMap<>(); + + /** + * Creates a new instance + * + * @param attributes + */ + public Attributes(Attribute... attributes) { + if (attributes != null) { + for (Attribute a : attributes) { + put(a); + } + } + } + + /** + * @return true if the set does not contain any attributes + */ + public boolean isEmpty() { + return map.isEmpty(); + } + + /** + * @param key + * @return the attribute or null + */ + public Attribute get(String key) { + return map.get(key); + } + + /** + * @return all attributes + */ + public Collection getAll() { + return new ArrayList<>(map.values()); + } + + /** + * @param a + */ + public void put(Attribute a) { + map.put(a.getKey(), a); + } + + /** + * @param key + */ + public void remove(String key) { + map.remove(key); + } + + /** + * @param key + * @return true if the {@link Attributes} contains this key + */ + public boolean containsKey(String key) { + return map.containsKey(key); + } + + /** + * Returns the state. + * + * @param key + * + * @return the state (never returns null) + */ + public Attribute.State getState(String key) { + Attribute a = map.get(key); + return a != null ? a.getState() : Attribute.State.UNSPECIFIED; + } + + /** + * @param key + * @return true if the key is {@link State#SET}, false in all other cases + */ + public boolean isSet(String key) { + return (getState(key) == State.SET); + } + + /** + * @param key + * @return true if the key is {@link State#UNSET}, false in all other cases + */ + public boolean isUnset(String key) { + return (getState(key) == State.UNSET); + } + + /** + * @param key + * @return true if the key is {@link State#UNSPECIFIED}, false in all other + * cases + */ + public boolean isUnspecified(String key) { + return (getState(key) == State.UNSPECIFIED); + } + + /** + * @param key + * @return true if the key is {@link State#CUSTOM}, false in all other cases + * see {@link #getValue(String)} for the value of the key + */ + public boolean isCustom(String key) { + return (getState(key) == State.CUSTOM); + } + + /** + * @param key + * @return the attribute value (may be null) + */ + public String getValue(String key) { + Attribute a = map.get(key); + return a != null ? a.getValue() : null; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(getClass().getSimpleName()); + buf.append("["); //$NON-NLS-1$ + buf.append(" "); //$NON-NLS-1$ + for (Attribute a : map.values()) { + buf.append(a.toString()); + buf.append(" "); //$NON-NLS-1$ + } + buf.append("]"); //$NON-NLS-1$ + return buf.toString(); + } + + @Override + public int hashCode() { + return map.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!(obj instanceof Attributes)) + return false; + Attributes other = (Attributes) obj; + return this.map.equals(other.map); + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNode.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNode.java index 70f56ff964..5c0aba2e0e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNode.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNode.java @@ -50,7 +50,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ListIterator; -import java.util.Map; import org.eclipse.jgit.lib.Constants; @@ -134,11 +133,12 @@ public class AttributesNode { * true if the target item is a directory. * @param attributes * Map that will hold the attributes matching this entry path. If - * it is not empty, this method will NOT override any - * existing entry. + * it is not empty, this method will NOT override any existing + * entry. + * @since 4.2 */ - public void getAttributes(String entryPath, boolean isDirectory, - Map attributes) { + public void getAttributes(String entryPath, + boolean isDirectory, Attributes attributes) { // Parse rules in the reverse order that they were read since the last // entry should be used ListIterator ruleIterator = rules.listIterator(rules @@ -153,7 +153,7 @@ public class AttributesNode { while (attributeIte.hasPrevious()) { Attribute attr = attributeIte.previous(); if (!attributes.containsKey(attr.getKey())) - attributes.put(attr.getKey(), attr); + attributes.put(attr); } } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java index 8f23a83f78..1037f697d4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java @@ -42,8 +42,6 @@ */ package org.eclipse.jgit.attributes; -import java.util.Map; - /** * Interface for classes which provide git attributes * @@ -51,7 +49,7 @@ import java.util.Map; */ public interface AttributesProvider { /** - * @return the currently active attributes by attribute key + * @return the currently active attributes */ - public Map getAttributes(); + public Attributes getAttributes(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java index bcac14b5ff..35d18c4b2a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java @@ -84,6 +84,13 @@ public class AttributesRule { continue; } + if (attribute.startsWith("!")) {//$NON-NLS-1$ + if (attribute.length() > 1) + result.add(new Attribute(attribute.substring(1), + State.UNSPECIFIED)); + continue; + } + final int equalsIndex = attribute.indexOf("="); //$NON-NLS-1$ if (equalsIndex == -1) result.add(new Attribute(attribute, State.SET)); @@ -200,4 +207,16 @@ public class AttributesRule { boolean match = matcher.matches(relativeTarget, isDirectory); return match; } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(pattern); + for (Attribute a : attributes) { + sb.append(" "); //$NON-NLS-1$ + sb.append(a); + } + return sb.toString(); + + } } \ No newline at end of file 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 index eb53434b74..bda5cbeba4 100644 --- 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 @@ -47,6 +47,7 @@ import java.io.File; import java.io.IOException; import org.eclipse.jgit.attributes.AttributesNode; +import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.util.FS; @@ -71,7 +72,7 @@ public class InfoAttributesNode extends AttributesNode { FS fs = repository.getFS(); File attributes = fs.resolve(repository.getDirectory(), - "info/attributes"); //$NON-NLS-1$ + Constants.INFO_ATTRIBUTES); FileRepository.AttributesNodeProviderImpl.loadRulesFromFile(r, attributes); return r.getRules().isEmpty() ? null : r; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java index 535a6ee175..613df37a75 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java @@ -272,6 +272,13 @@ public final class Constants { */ public static final String INFO_EXCLUDE = "info/exclude"; + /** + * Attributes-override-file + * + * @since 4.2 + */ + public static final String INFO_ATTRIBUTES = "info/attributes"; + /** * The system property that contains the system user name * 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 826ce0973d..8a59a700e3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java @@ -45,17 +45,16 @@ 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.annotations.Nullable; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.attributes.Attribute; +import org.eclipse.jgit.attributes.Attributes; import org.eclipse.jgit.attributes.AttributesNode; import org.eclipse.jgit.attributes.AttributesNodeProvider; import org.eclipse.jgit.attributes.AttributesProvider; +import org.eclipse.jgit.attributes.Attribute.State; import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.IncorrectObjectTypeException; @@ -258,7 +257,7 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { AbstractTreeIterator currentHead; /** Cached attribute for the current entry */ - private Map attrs = null; + private Attributes attrs = null; /** * Create a new tree walker for a given repository. @@ -1119,7 +1118,7 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { * @return a {@link Set} of {@link Attribute}s that match the current entry. * @since 4.2 */ - public Map getAttributes() { + public Attributes getAttributes() { if (attrs != null) return attrs; @@ -1138,35 +1137,42 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { && other == null) { // Can not retrieve the attributes without at least one of the above // iterators. - return Collections. emptyMap(); + return new Attributes(); } String path = currentHead.getEntryPathString(); final boolean isDir = FileMode.TREE.equals(currentHead.mode); - Map attributes = new LinkedHashMap(); + Attributes attributes = new Attributes(); try { - // Gets the info attributes + // Gets the global attributes node + AttributesNode globalNodeAttr = attributesNodeProvider + .getGlobalAttributesNode(); + // Gets the info attributes node AttributesNode infoNodeAttr = attributesNodeProvider .getInfoAttributesNode(); + + // Gets the info attributes if (infoNodeAttr != null) { infoNodeAttr.getAttributes(path, isDir, attributes); } - // Gets the attributes located on the current entry path getPerDirectoryEntryAttributes(path, isDir, operationType, - workingTreeIterator, dirCacheIterator, other, - attributes); + workingTreeIterator, dirCacheIterator, other, 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$ } + // now after all attributes are collected - in the correct hierarchy + // order - remove all unspecified entries (the ! marker) + for (Attribute a : attributes.getAll()) { + if (a.getState() == State.UNSPECIFIED) + attributes.remove(a.getKey()); + } return attributes; } @@ -1195,7 +1201,7 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { private void getPerDirectoryEntryAttributes(String path, boolean isDir, OperationType opType, WorkingTreeIterator workingTreeIterator, DirCacheIterator dirCacheIterator, CanonicalTreeParser other, - Map attributes) + Attributes attributes) throws IOException { // Prevents infinite recurrence if (workingTreeIterator != null || dirCacheIterator != null @@ -1208,12 +1214,11 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { getPerDirectoryEntryAttributes(path, isDir, opType, getParent(workingTreeIterator, WorkingTreeIterator.class), getParent(dirCacheIterator, DirCacheIterator.class), - getParent(other, CanonicalTreeParser.class), - attributes); + getParent(other, CanonicalTreeParser.class), attributes); } } - private T getParent(T current, + private static T getParent(T current, Class type) { if (current != null) { AbstractTreeIterator parent = current.parent; @@ -1224,7 +1229,7 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { return null; } - private T getTree(Class type) { + private T getTree(Class type) { for (int i = 0; i < trees.length; i++) { AbstractTreeIterator tree = trees[i]; if (type.isInstance(tree)) { -- cgit v1.2.3 From 5d9f595eb87fba31c2253051102116fc7876e6c0 Mon Sep 17 00:00:00 2001 From: Christian Halstrick Date: Wed, 28 Oct 2015 13:25:09 +0100 Subject: Add support for clean filters When filters are defined for certain paths in gitattributes make sure that clean filters are processed when adding new content to the object database. Change-Id: Iffd72914cec5b434ba4d0de232e285b7492db868 Signed-off-by: Matthias Sohn --- .../org/eclipse/jgit/junit/RepositoryTestCase.java | 13 ++ .../tst/org/eclipse/jgit/api/AddCommandTest.java | 188 +++++++++++++++++++++ .../org/eclipse/jgit/internal/JGitText.properties | 2 + .../src/org/eclipse/jgit/api/AddCommand.java | 4 + .../src/org/eclipse/jgit/api/CommitCommand.java | 4 +- .../jgit/api/errors/FilterFailedException.java | 144 ++++++++++++++++ .../src/org/eclipse/jgit/dircache/DirCache.java | 1 + .../src/org/eclipse/jgit/internal/JGitText.java | 2 + .../src/org/eclipse/jgit/lib/Constants.java | 14 ++ .../src/org/eclipse/jgit/lib/IndexDiff.java | 1 + .../src/org/eclipse/jgit/treewalk/TreeWalk.java | 77 ++++++++- .../eclipse/jgit/treewalk/WorkingTreeIterator.java | 74 +++++++- .../src/org/eclipse/jgit/util/TemporaryBuffer.java | 31 ++++ 13 files changed, 546 insertions(+), 9 deletions(-) create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/api/errors/FilterFailedException.java diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java index 56962e869f..c649eb9086 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java @@ -282,6 +282,19 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { return name; } + /** + * Replaces '\' by '/' + * + * @param str + * the string in which backslashes should be replaced + * @return the resulting string with slashes + * @since 4.2 + */ + public static String slashify(String str) { + str = str.replace('\\', '/'); + return str; + } + /** * Waits until it is guaranteed that a subsequent file modification has a * younger modification timestamp than the modification timestamp of the diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java index 2abed3adc8..a5ad18d102 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java @@ -45,6 +45,7 @@ package org.eclipse.jgit.api; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; @@ -52,11 +53,13 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.PrintWriter; +import org.eclipse.jgit.api.errors.FilterFailedException; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.NoFilepatternException; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheBuilder; import org.eclipse.jgit.dircache.DirCacheEntry; +import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; @@ -111,6 +114,191 @@ public class AddCommandTest extends RepositoryTestCase { indexState(CONTENT)); } + @Test + public void testCleanFilter() throws IOException, + GitAPIException { + writeTrashFile(".gitattributes", "*.txt filter=tstFilter"); + writeTrashFile("src/a.tmp", "foo"); + // Caution: we need a trailing '\n' since sed on mac always appends + // linefeeds if missing + writeTrashFile("src/a.txt", "foo\n"); + File script = writeTempFile("sed s/o/e/g"); + + Git git = new Git(db); + StoredConfig config = git.getRepository().getConfig(); + config.setString("filter", "tstFilter", "clean", + "sh " + slashify(script.getPath())); + config.save(); + + git.add().addFilepattern("src/a.txt").addFilepattern("src/a.tmp") + .call(); + + assertEquals( + "[src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:fee\n]", + indexState(CONTENT)); + } + + @Test + public void testCleanFilterEnvironment() + throws IOException, GitAPIException { + writeTrashFile(".gitattributes", "*.txt filter=tstFilter"); + writeTrashFile("src/a.txt", "foo"); + File script = writeTempFile("echo $GIT_DIR; echo 1 >xyz"); + + Git git = new Git(db); + StoredConfig config = git.getRepository().getConfig(); + config.setString("filter", "tstFilter", "clean", + "sh " + slashify(script.getPath())); + config.save(); + git.add().addFilepattern("src/a.txt").call(); + + String gitDir = db.getDirectory().getAbsolutePath(); + assertEquals("[src/a.txt, mode:100644, content:" + gitDir + + "\n]", indexState(CONTENT)); + assertTrue(new File(db.getWorkTree(), "xyz").exists()); + } + + @Test + public void testMultipleCleanFilter() throws IOException, GitAPIException { + writeTrashFile(".gitattributes", + "*.txt filter=tstFilter\n*.tmp filter=tstFilter2"); + // Caution: we need a trailing '\n' since sed on mac always appends + // linefeeds if missing + writeTrashFile("src/a.tmp", "foo\n"); + writeTrashFile("src/a.txt", "foo\n"); + File script = writeTempFile("sed s/o/e/g"); + File script2 = writeTempFile("sed s/f/x/g"); + + Git git = new Git(db); + StoredConfig config = git.getRepository().getConfig(); + config.setString("filter", "tstFilter", "clean", + "sh " + slashify(script.getPath())); + config.setString("filter", "tstFilter2", "clean", + "sh " + slashify(script2.getPath())); + config.save(); + + git.add().addFilepattern("src/a.txt").addFilepattern("src/a.tmp") + .call(); + + assertEquals( + "[src/a.tmp, mode:100644, content:xoo\n][src/a.txt, mode:100644, content:fee\n]", + indexState(CONTENT)); + + // TODO: multiple clean filters for one file??? + } + + /** + * The path of an added file name contains ';' and afterwards malicious + * commands. Make sure when calling filter commands to properly escape the + * filenames + * + * @throws IOException + * @throws GitAPIException + */ + @Test + public void testCommandInjection() throws IOException, GitAPIException { + // Caution: we need a trailing '\n' since sed on mac always appends + // linefeeds if missing + writeTrashFile("; echo virus", "foo\n"); + File script = writeTempFile("sed s/o/e/g"); + + Git git = new Git(db); + StoredConfig config = git.getRepository().getConfig(); + config.setString("filter", "tstFilter", "clean", + "sh " + slashify(script.getPath()) + " %f"); + writeTrashFile(".gitattributes", "* filter=tstFilter"); + + git.add().addFilepattern("; echo virus").call(); + // Without proper escaping the content would be "feovirus". The sed + // command and the "echo virus" would contribute to the content + assertEquals("[; echo virus, mode:100644, content:fee\n]", + indexState(CONTENT)); + } + + @Test + public void testBadCleanFilter() throws IOException, GitAPIException { + writeTrashFile("a.txt", "foo"); + File script = writeTempFile("sedfoo s/o/e/g"); + + Git git = new Git(db); + StoredConfig config = git.getRepository().getConfig(); + config.setString("filter", "tstFilter", "clean", + "sh " + script.getPath()); + config.save(); + writeTrashFile(".gitattributes", "*.txt filter=tstFilter"); + + try { + git.add().addFilepattern("a.txt").call(); + fail("Didn't received the expected exception"); + } catch (FilterFailedException e) { + assertEquals(127, e.getReturnCode()); + } + } + + @Test + public void testBadCleanFilter2() throws IOException, GitAPIException { + writeTrashFile("a.txt", "foo"); + File script = writeTempFile("sed s/o/e/g"); + + Git git = new Git(db); + StoredConfig config = git.getRepository().getConfig(); + config.setString("filter", "tstFilter", "clean", + "shfoo " + script.getPath()); + config.save(); + writeTrashFile(".gitattributes", "*.txt filter=tstFilter"); + + try { + git.add().addFilepattern("a.txt").call(); + fail("Didn't received the expected exception"); + } catch (FilterFailedException e) { + assertEquals(127, e.getReturnCode()); + } + } + + @Test + public void testCleanFilterReturning12() throws IOException, + GitAPIException { + writeTrashFile("a.txt", "foo"); + File script = writeTempFile("exit 12"); + + Git git = new Git(db); + StoredConfig config = git.getRepository().getConfig(); + config.setString("filter", "tstFilter", "clean", + "sh " + slashify(script.getPath())); + config.save(); + writeTrashFile(".gitattributes", "*.txt filter=tstFilter"); + + try { + git.add().addFilepattern("a.txt").call(); + fail("Didn't received the expected exception"); + } catch (FilterFailedException e) { + assertEquals(12, e.getReturnCode()); + } + } + + @Test + public void testNotApplicableFilter() throws IOException, GitAPIException { + writeTrashFile("a.txt", "foo"); + File script = writeTempFile("sed s/o/e/g"); + + Git git = new Git(db); + StoredConfig config = git.getRepository().getConfig(); + config.setString("filter", "tstFilter", "something", + "sh " + script.getPath()); + config.save(); + writeTrashFile(".gitattributes", "*.txt filter=tstFilter"); + + git.add().addFilepattern("a.txt").call(); + + assertEquals("[a.txt, mode:100644, content:foo]", indexState(CONTENT)); + } + + private File writeTempFile(String body) throws IOException { + File f = File.createTempFile("AddCommandTest_", ""); + JGitTestUtil.write(f, body); + return f; + } + @Test public void testAddExistingSingleSmallFileWithNewLine() throws IOException, GitAPIException { diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index 5f80b8103b..d0e1c779e4 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -281,6 +281,8 @@ fileCannotBeDeleted=File cannot be deleted: {0} fileIsTooBigForThisConvenienceMethod=File is too big for this convenience method ({0} bytes). fileIsTooLarge=File is too large: {0} fileModeNotSetForPath=FileMode not set for path {0} +filterExecutionFailed=Execution of filter command ''{0}'' on file ''{1}'' failed +filterExecutionFailedRc=Execution of filter command ''{0}'' on file ''{1}'' failed with return code ''{2}'', message on stderr: ''{3}'' findingGarbage=Finding garbage flagIsDisposed={0} is disposed. flagNotFromThis={0} not from this. 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 ae297a6438..67fb342fe2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java @@ -48,6 +48,7 @@ import java.io.InputStream; import java.util.Collection; import java.util.LinkedList; +import org.eclipse.jgit.api.errors.FilterFailedException; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.NoFilepatternException; @@ -211,6 +212,9 @@ public class AddCommand extends GitCommand { builder.commit(); setCallable(false); } catch (IOException e) { + Throwable cause = e.getCause(); + if (cause != null && cause instanceof FilterFailedException) + throw (FilterFailedException) cause; throw new JGitInternalException( JGitText.get().exceptionCaughtDuringExecutionOfAddCommand, e); } finally { 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 53e18df479..9466dab74e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java @@ -332,7 +332,9 @@ public class CommitCommand extends GitCommand { treeWalk.setOperationType(OperationType.CHECKIN_OP); int dcIdx = treeWalk .addTree(new DirCacheBuildIterator(existingBuilder)); - int fIdx = treeWalk.addTree(new FileTreeIterator(repo)); + FileTreeIterator fti = new FileTreeIterator(repo); + fti.setDirCacheIterator(treeWalk, 0); + int fIdx = treeWalk.addTree(fti); int hIdx = -1; if (headId != null) hIdx = treeWalk.addTree(rw.parseTree(headId)); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/FilterFailedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/FilterFailedException.java new file mode 100644 index 0000000000..fbc30ef162 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/FilterFailedException.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2015, Christian Halstrick 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.api.errors; + +import java.text.MessageFormat; + +import org.eclipse.jgit.internal.JGitText; + +/** + * Exception thrown when the execution of a filter command failed + * + * @since 4.2 + */ +public class FilterFailedException extends GitAPIException { + private static final long serialVersionUID = 1L; + + private String filterCommand; + + private String path; + + private byte[] stdout; + + private String stderr; + + private int rc; + + /** + * Thrown if during execution of filter command an exception occurred + * + * @param cause + * the exception + * @param filterCommand + * the command which failed + * @param path + * the path processed by the filter + */ + public FilterFailedException(Exception cause, String filterCommand, + String path) { + super(MessageFormat.format(JGitText.get().filterExecutionFailed, + filterCommand, path), cause); + this.filterCommand = filterCommand; + this.path = path; + } + + /** + * Thrown if a filter command returns a non-zero return code + * + * @param rc + * the return code + * @param filterCommand + * the command which failed + * @param path + * the path processed by the filter + * @param stdout + * the output the filter generated so far. This should be limited + * to reasonable size. + * @param stderr + * the stderr output of the filter + */ + @SuppressWarnings("boxing") + public FilterFailedException(int rc, String filterCommand, String path, + byte[] stdout, String stderr) { + super(MessageFormat.format(JGitText.get().filterExecutionFailedRc, + filterCommand, path, rc, stderr)); + this.rc = rc; + this.filterCommand = filterCommand; + this.path = path; + this.stdout = stdout; + this.stderr = stderr; + } + + /** + * @return the filterCommand + */ + public String getFilterCommand() { + return filterCommand; + } + + /** + * @return the path of the file processed by the filter command + */ + public String getPath() { + return path; + } + + /** + * @return the output generated by the filter command. Might be truncated to + * limit memory consumption. + */ + public byte[] getOutput() { + return stdout; + } + + /** + * @return the error output returned by the filter command + */ + public String getError() { + return stderr; + } + + /** + * @return the return code returned by the filter command + */ + public int getReturnCode() { + return rc; + } + +} 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 387d8ce739..a3980d2126 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java @@ -983,6 +983,7 @@ public class DirCache { FileTreeIterator fIter = new FileTreeIterator(repository); walk.addTree(iIter); walk.addTree(fIter); + fIter.setDirCacheIterator(walk, 0); walk.setRecursive(true); while (walk.next()) { iIter = walk.getTree(0, DirCacheIterator.class); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index 6680564ade..f6fd8a396a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -340,6 +340,8 @@ public class JGitText extends TranslationBundle { /***/ public String fileIsTooBigForThisConvenienceMethod; /***/ public String fileIsTooLarge; /***/ public String fileModeNotSetForPath; + /***/ public String filterExecutionFailed; + /***/ public String filterExecutionFailedRc; /***/ public String findingGarbage; /***/ public String flagIsDisposed; /***/ public String flagNotFromThis; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java index 613df37a75..1a3111ab49 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java @@ -370,6 +370,20 @@ public final class Constants { */ public static final String DOT_GIT_ATTRIBUTES = ".gitattributes"; + /** + * Key for filters in .gitattributes + * + * @since 4.2 + */ + public static final String ATTR_FILTER = "filter"; + + /** + * clean command name, used to call filter driver + * + * @since 4.2 + */ + public static final String ATTR_FILTER_TYPE_CLEAN = "clean"; + /** Name of the ignore file */ public static final String DOT_GIT_IGNORE = ".gitignore"; 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 281cde8750..9e474f86a8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java @@ -413,6 +413,7 @@ public class IndexDiff { treeWalk.addTree(new EmptyTreeIterator()); treeWalk.addTree(new DirCacheIterator(dirCache)); treeWalk.addTree(initialWorkingTreeIterator); + initialWorkingTreeIterator.setDirCacheIterator(treeWalk, 1); Collection filters = new ArrayList(4); if (monitor != null) { 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 8a59a700e3..06dc0bf6d0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java @@ -45,22 +45,25 @@ package org.eclipse.jgit.treewalk; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; import java.util.Set; import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.attributes.Attribute; +import org.eclipse.jgit.attributes.Attribute.State; import org.eclipse.jgit.attributes.Attributes; import org.eclipse.jgit.attributes.AttributesNode; import org.eclipse.jgit.attributes.AttributesNodeProvider; import org.eclipse.jgit.attributes.AttributesProvider; -import org.eclipse.jgit.attributes.Attribute.State; import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.StopWalkException; import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.MutableObjectId; @@ -70,6 +73,7 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.treewalk.filter.PathFilter; import org.eclipse.jgit.treewalk.filter.TreeFilter; +import org.eclipse.jgit.util.QuotedString; import org.eclipse.jgit.util.RawParseUtils; /** @@ -116,6 +120,12 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { */ private OperationType operationType = OperationType.CHECKOUT_OP; + /** + * The filter command as defined in gitattributes. The keys are + * filterName+"."+filterCommandType. E.g. "lfs.clean" + */ + private Map filterCommandsByNameDotType = new HashMap(); + /** * @param operationType * @since 4.2 @@ -259,6 +269,8 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { /** Cached attribute for the current entry */ private Attributes attrs = null; + private Config config; + /** * Create a new tree walker for a given repository. * @@ -269,6 +281,7 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { */ public TreeWalk(final Repository repo) { this(repo.newObjectReader(), true); + config = repo.getConfig(); attributesNodeProvider = repo.createAttributesNodeProvider(); } @@ -1308,4 +1321,66 @@ public class TreeWalk implements AutoCloseable, AttributesProvider { AttributesNode defaultValue) { return (value == null) ? defaultValue : value; } + + /** + * Inspect config and attributes to return a filtercommand applicable for + * the current path + * + * @param filterCommandType + * which type of filterCommand should be executed. E.g. "clean", + * "smudge" + * @return a filter command + * @throws IOException + * @since 4.2 + */ + public String getFilterCommand(String filterCommandType) + throws IOException { + Attributes attributes = getAttributes(); + + Attribute f = attributes.get(Constants.ATTR_FILTER); + if (f == null) { + return null; + } + String filterValue = f.getValue(); + if (filterValue == null) { + return null; + } + + String filterCommand = getFilterCommandDefinition(filterValue, + filterCommandType); + if (filterCommand == null) { + return null; + } + return filterCommand.replaceAll("%f", //$NON-NLS-1$ + QuotedString.BOURNE.quote((getPathString()))); + } + + /** + * Get the filter command how it is defined in gitconfig. The returned + * string may contain "%f" which needs to be replaced by the current path + * before executing the filter command. These filter definitions are cached + * for better performance. + * + * @param filterDriverName + * The name of the filter driver as it is referenced in the + * gitattributes file. E.g. "lfs". For each filter driver there + * may be many commands defined in the .gitconfig + * @param filterCommandType + * The type of the filter command for a specific filter driver. + * May be "clean" or "smudge". + * @return the definition of the command to be executed for this filter + * driver and filter command + */ + private String getFilterCommandDefinition(String filterDriverName, + String filterCommandType) { + String key = filterDriverName + "." + filterCommandType; //$NON-NLS-1$ + String filterCommand = filterCommandsByNameDotType.get(key); + if (filterCommand != null) + return filterCommand; + filterCommand = config.getString(Constants.ATTR_FILTER, + filterDriverName, filterCommandType); + if (filterCommand != null) + filterCommandsByNameDotType.put(key, filterCommand); + return filterCommand; + } } 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 8be7f9a84c..94beeeb56f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java @@ -62,6 +62,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; +import org.eclipse.jgit.api.errors.FilterFailedException; import org.eclipse.jgit.attributes.AttributesNode; import org.eclipse.jgit.attributes.AttributesRule; import org.eclipse.jgit.diff.RawText; @@ -76,6 +77,7 @@ import org.eclipse.jgit.ignore.IgnoreNode; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.CoreConfig; +import org.eclipse.jgit.lib.CoreConfig.AutoCRLF; import org.eclipse.jgit.lib.CoreConfig.CheckStat; import org.eclipse.jgit.lib.CoreConfig.SymLinks; import org.eclipse.jgit.lib.FileMode; @@ -85,6 +87,7 @@ import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.submodule.SubmoduleWalk; import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.FS.ExecutionResult; import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.RawParseUtils; import org.eclipse.jgit.util.io.EolCanonicalizingInputStream; @@ -101,6 +104,8 @@ import org.eclipse.jgit.util.io.EolCanonicalizingInputStream; * @see FileTreeIterator */ public abstract class WorkingTreeIterator extends AbstractTreeIterator { + private static final int MAX_EXCEPTION_TEXT_SIZE = 10 * 1024; + /** An empty entry array, suitable for {@link #init(Entry[])}. */ protected static final Entry[] EOF = {}; @@ -134,6 +139,8 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { /** If there is a .gitignore file present, the parsed rules from it. */ private IgnoreNode ignoreNode; + private String cleanFilterCommand; + /** Repository that is the root level being iterated over */ protected Repository repository; @@ -186,6 +193,7 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { protected WorkingTreeIterator(final WorkingTreeIterator p) { super(p); state = p.state; + repository = p.repository; } /** @@ -348,7 +356,8 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { private InputStream possiblyFilteredInputStream(final Entry e, final InputStream is, final long len) throws IOException { - if (!mightNeedCleaning()) { + boolean mightNeedCleaning = mightNeedCleaning(); + if (!mightNeedCleaning) { canonLen = len; return is; } @@ -366,7 +375,8 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { return new ByteArrayInputStream(raw, 0, n); } - if (isBinary(e)) { + // TODO: fix autocrlf causing mightneedcleaning + if (!mightNeedCleaning && isBinary(e)) { canonLen = len; return is; } @@ -390,10 +400,12 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { } } - private boolean mightNeedCleaning() { + private boolean mightNeedCleaning() throws IOException { switch (getOptions().getAutoCRLF()) { case FALSE: default: + if (getCleanFilterCommand() != null) + return true; return false; case TRUE: @@ -415,8 +427,7 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { } } - private static ByteBuffer filterClean(byte[] src, int n) - throws IOException { + private ByteBuffer filterClean(byte[] src, int n) throws IOException { InputStream in = new ByteArrayInputStream(src); try { return IO.readWholeStream(filterClean(in), n); @@ -425,8 +436,42 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { } } - private static InputStream filterClean(InputStream in) { - return new EolCanonicalizingInputStream(in, true); + private InputStream filterClean(InputStream in) throws IOException { + in = handleAutoCRLF(in); + String filterCommand = getCleanFilterCommand(); + if (filterCommand != null) { + FS fs = repository.getFS(); + ProcessBuilder filterProcessBuilder = fs.runInShell(filterCommand, + new String[0]); + filterProcessBuilder.directory(repository.getWorkTree()); + filterProcessBuilder.environment().put(Constants.GIT_DIR_KEY, + repository.getDirectory().getAbsolutePath()); + ExecutionResult result; + try { + result = fs.execute(filterProcessBuilder, in); + } catch (IOException | InterruptedException e) { + throw new IOException(new FilterFailedException(e, + filterCommand, getEntryPathString())); + } + int rc = result.getRc(); + if (rc != 0) { + throw new IOException(new FilterFailedException(rc, + filterCommand, getEntryPathString(), + result.getStdout().toByteArray(MAX_EXCEPTION_TEXT_SIZE), + RawParseUtils.decode(result.getStderr() + .toByteArray(MAX_EXCEPTION_TEXT_SIZE)))); + } + return result.getStdout().openInputStream(); + } + return in; + } + + private InputStream handleAutoCRLF(InputStream in) { + AutoCRLF autoCRLF = getOptions().getAutoCRLF(); + if (autoCRLF == AutoCRLF.TRUE || autoCRLF == AutoCRLF.INPUT) { + in = new EolCanonicalizingInputStream(in, true); + } + return in; } /** @@ -485,6 +530,7 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { System.arraycopy(e.encodedName, 0, path, pathOffset, nameLen); pathLen = pathOffset + nameLen; canonLen = -1; + cleanFilterCommand = null; } /** @@ -1271,4 +1317,18 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { } } } + + /** + * @return the clean filter command for the current entry or + * null if no such command is defined + * @throws IOException + * @since 4.2 + */ + public String getCleanFilterCommand() throws IOException { + if (cleanFilterCommand == null && state.walk != null) { + cleanFilterCommand = state.walk + .getFilterCommand(Constants.ATTR_FILTER_TYPE_CLEAN); + } + return cleanFilterCommand; + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java index ca47f50fd9..3cd5929c7f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java @@ -246,6 +246,37 @@ public abstract class TemporaryBuffer extends OutputStream { return out; } + /** + * Convert this buffer's contents into a contiguous byte array. If this size + * of the buffer exceeds the limit only return the first {@code limit} bytes + *

    + * The buffer is only complete after {@link #close()} has been invoked. + * + * @param limit + * the maximum number of bytes to be returned + * + * @return the byte array limited to {@code limit} bytes. + * @throws IOException + * an error occurred reading from a local temporary file + * @throws OutOfMemoryError + * the buffer cannot fit in memory + * + * @since 4.2 + */ + public byte[] toByteArray(int limit) throws IOException { + final long len = Math.min(length(), limit); + if (Integer.MAX_VALUE < len) + throw new OutOfMemoryError( + JGitText.get().lengthExceedsMaximumArraySize); + final byte[] out = new byte[(int) len]; + int outPtr = 0; + for (final Block b : blocks) { + System.arraycopy(b.buffer, 0, out, outPtr, b.count); + outPtr += b.count; + } + return out; + } + /** * Send this buffer to an output stream. *

    -- cgit v1.2.3 From bd31555ee507cd29a11060756297031354b9b0c3 Mon Sep 17 00:00:00 2001 From: Christian Halstrick Date: Thu, 29 Oct 2015 14:15:08 +0100 Subject: Add support for smudge filters If defined in .gitattributes call smudge filter during checkout. To support checkout where current HEAD,index do not contain attributes we need to also consider attributes from the tree we checkout. Therefore CanonicalTreeParser has to learn how to provide attributes. Change-Id: I168fdb81a8e1a9f991587b3e95a36550ea845f0a Signed-off-by: Matthias Sohn --- .../org/eclipse/jgit/api/CheckoutCommandTest.java | 124 +++++++++++++++++++++ .../org/eclipse/jgit/lib/DirCacheCheckoutTest.java | 7 +- .../eclipse/jgit/dircache/DirCacheCheckout.java | 115 ++++++++++++++++--- .../src/org/eclipse/jgit/lib/Constants.java | 7 ++ 4 files changed, 234 insertions(+), 19 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java index 82d509f6f3..4bfb128cbc 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java @@ -72,12 +72,14 @@ import org.eclipse.jgit.api.errors.RefNotFoundException; import org.eclipse.jgit.api.errors.TransportException; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheEntry; +import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.Sets; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.storage.file.FileBasedConfig; @@ -86,6 +88,7 @@ import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.URIish; import org.eclipse.jgit.util.FileUtils; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; public class CheckoutCommandTest extends RepositoryTestCase { @@ -556,4 +559,125 @@ public class CheckoutCommandTest extends RepositoryTestCase { } org.junit.Assume.assumeTrue(foundUnsmudged); } + + @Test + public void testSmudgeFilter_modifyExisting() throws IOException, GitAPIException { + File script = writeTempFile("sed s/o/e/g"); + StoredConfig config = git.getRepository().getConfig(); + config.setString("filter", "tstFilter", "smudge", + "sh " + slashify(script.getPath())); + config.save(); + + writeTrashFile(".gitattributes", "*.txt filter=tstFilter"); + git.add().addFilepattern(".gitattributes").call(); + git.commit().setMessage("add filter").call(); + + writeTrashFile("src/a.tmp", "x"); + // Caution: we need a trailing '\n' since sed on mac always appends + // linefeeds if missing + writeTrashFile("src/a.txt", "x\n"); + git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt") + .call(); + RevCommit content1 = git.commit().setMessage("add content").call(); + + writeTrashFile("src/a.tmp", "foo"); + writeTrashFile("src/a.txt", "foo\n"); + git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt") + .call(); + RevCommit content2 = git.commit().setMessage("changed content").call(); + + git.checkout().setName(content1.getName()).call(); + git.checkout().setName(content2.getName()).call(); + + assertEquals( + "[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some change][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]", + indexState(CONTENT)); + assertEquals(Sets.of("src/a.txt"), git.status().call().getModified()); + assertEquals("foo", read("src/a.tmp")); + assertEquals("fee\n", read("src/a.txt")); + } + + @Test + public void testSmudgeFilter_createNew() + throws IOException, GitAPIException { + File script = writeTempFile("sed s/o/e/g"); + StoredConfig config = git.getRepository().getConfig(); + config.setString("filter", "tstFilter", "smudge", + "sh " + slashify(script.getPath())); + config.save(); + + writeTrashFile("foo", "foo"); + git.add().addFilepattern("foo").call(); + RevCommit initial = git.commit().setMessage("initial").call(); + + writeTrashFile(".gitattributes", "*.txt filter=tstFilter"); + git.add().addFilepattern(".gitattributes").call(); + git.commit().setMessage("add filter").call(); + + writeTrashFile("src/a.tmp", "foo"); + // Caution: we need a trailing '\n' since sed on mac always appends + // linefeeds if missing + writeTrashFile("src/a.txt", "foo\n"); + git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt") + .call(); + RevCommit content = git.commit().setMessage("added content").call(); + + git.checkout().setName(initial.getName()).call(); + git.checkout().setName(content.getName()).call(); + + assertEquals( + "[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some change][foo, mode:100644, content:foo][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]", + indexState(CONTENT)); + assertEquals("foo", read("src/a.tmp")); + assertEquals("fee\n", read("src/a.txt")); + } + + @Test + @Ignore + public void testSmudgeAndClean() throws IOException, GitAPIException { + // @TODO: fix this test + File clean_filter = writeTempFile("sed s/V1/@version/g -"); + File smudge_filter = writeTempFile("sed s/@version/V1/g -"); + + Git git = new Git(db); + StoredConfig config = git.getRepository().getConfig(); + config.setString("filter", "tstFilter", "smudge", + "sh " + slashify(smudge_filter.getPath())); + config.setString("filter", "tstFilter", "clean", + "sh " + slashify(clean_filter.getPath())); + config.save(); + writeTrashFile(".gitattributes", "*.txt filter=tstFilter"); + git.add().addFilepattern(".gitattributes").call(); + git.commit().setMessage("add attributes").call(); + + writeTrashFile("filterTest.txt", "hello world, V1"); + git.add().addFilepattern("filterTest.txt").call(); + git.commit().setMessage("add filterText.txt").call(); + assertEquals( + "[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some other change][filterTest.txt, mode:100644, content:hello world, @version]", + indexState(CONTENT)); + + git.checkout().setCreateBranch(true).setName("test2").call(); + writeTrashFile("filterTest.txt", "bon giorno world, V1"); + git.add().addFilepattern("filterTest.txt").call(); + git.commit().setMessage("modified filterText.txt").call(); + + assertTrue(git.status().call().isClean()); + assertEquals( + "[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some other change][filterTest.txt, mode:100644, content:bon giorno world, @version]", + indexState(CONTENT)); + + git.checkout().setName("refs/heads/test").call(); + assertTrue(git.status().call().isClean()); + assertEquals( + "[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some other change][filterTest.txt, mode:100644, content:hello world, @version]", + indexState(CONTENT)); + assertEquals("hello world, V1", read("filterTest.txt")); + } + + private File writeTempFile(String body) throws IOException { + File f = File.createTempFile("AddCommandTest_", ""); + JGitTestUtil.write(f, body); + return f; + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java index 51a6b5a8f5..d768e0fa0b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java @@ -113,7 +113,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { return dco.getRemoved(); } - private Map getUpdated() { + private Map getUpdated() { return dco.getUpdated(); } @@ -268,8 +268,6 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { @Test public void testRules1thru3_NoIndexEntry() throws IOException { ObjectId head = buildTree(mk("foo")); - TreeWalk tw = TreeWalk.forPath(db, "foo", head); - ObjectId objectId = tw.getObjectId(0); ObjectId merge = db.newObjectInserter().insert(Constants.OBJ_TREE, new byte[0]); @@ -279,10 +277,9 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { prescanTwoTrees(merge, head); - assertEquals(objectId, getUpdated().get("foo")); + assertTrue(getUpdated().containsKey("foo")); merge = buildTree(mkmap("foo", "a")); - tw = TreeWalk.forPath(db, "foo", merge); prescanTwoTrees(head, merge); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java index 0036ab5089..393a854945 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java @@ -52,15 +52,18 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.eclipse.jgit.api.errors.FilterFailedException; import org.eclipse.jgit.errors.CheckoutConflictException; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.IndexWriteException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.CoreConfig.AutoCRLF; import org.eclipse.jgit.lib.CoreConfig.SymLinks; import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectChecker; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectLoader; @@ -76,6 +79,7 @@ import org.eclipse.jgit.treewalk.WorkingTreeIterator; import org.eclipse.jgit.treewalk.WorkingTreeOptions; import org.eclipse.jgit.treewalk.filter.PathFilter; import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.FS.ExecutionResult; import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.RawParseUtils; import org.eclipse.jgit.util.SystemReader; @@ -85,9 +89,10 @@ import org.eclipse.jgit.util.io.AutoCRLFOutputStream; * This class handles checking out one or two trees merging with the index. */ public class DirCacheCheckout { + private static final int MAX_EXCEPTION_TEXT_SIZE = 10 * 1024; private Repository repo; - private HashMap updated = new HashMap(); + private HashMap updated = new HashMap(); private ArrayList conflicts = new ArrayList(); @@ -112,9 +117,9 @@ public class DirCacheCheckout { private boolean emptyDirCache; /** - * @return a list of updated paths and objectIds + * @return a list of updated paths and smudgeFilterCommands */ - public Map getUpdated() { + public Map getUpdated() { return updated; } @@ -447,7 +452,8 @@ public class DirCacheCheckout { for (String path : updated.keySet()) { DirCacheEntry entry = dc.getEntry(path); if (!FileMode.GITLINK.equals(entry.getRawMode())) - checkoutEntry(repo, entry, objectReader, false); + checkoutEntry(repo, entry, objectReader, false, + updated.get(path)); } // commit the index builder - a new index is persisted @@ -996,9 +1002,12 @@ public class DirCacheCheckout { removed.add(path); } - private void update(String path, ObjectId mId, FileMode mode) { + private void update(String path, ObjectId mId, FileMode mode) + throws IOException { if (!FileMode.TREE.equals(mode)) { - updated.put(path, mId); + updated.put(path, + walk.getFilterCommand(Constants.ATTR_FILTER_TYPE_SMUDGE)); + DirCacheEntry entry = new DirCacheEntry(path, DirCacheEntry.STAGE_0); entry.setObjectId(mId); entry.setFileMode(mode); @@ -1150,7 +1159,7 @@ public class DirCacheCheckout { */ public static void checkoutEntry(Repository repo, DirCacheEntry entry, ObjectReader or) throws IOException { - checkoutEntry(repo, entry, or, false); + checkoutEntry(repo, entry, or, false, null); } /** @@ -1186,6 +1195,46 @@ public class DirCacheCheckout { */ public static void checkoutEntry(Repository repo, DirCacheEntry entry, ObjectReader or, boolean deleteRecursive) throws IOException { + checkoutEntry(repo, entry, or, deleteRecursive, null); + } + + /** + * Updates the file in the working tree with content and mode from an entry + * in the index. The new content is first written to a new temporary file in + * the same directory as the real file. Then that new file is renamed to the + * final filename. + * + *

    + * Note: if the entry path on local file system exists as a file, it + * will be deleted and if it exists as a directory, it will be deleted + * recursively, independently if has any content. + *

    + * + *

    + * TODO: this method works directly on File IO, we may need another + * abstraction (like WorkingTreeIterator). This way we could tell e.g. + * Eclipse that Files in the workspace got changed + *

    + * + * @param repo + * repository managing the destination work tree. + * @param entry + * the entry containing new mode and content + * @param or + * object reader to use for checkout + * @param deleteRecursive + * true to recursively delete final path if it exists on the file + * system + * @param smudgeFilterCommand + * the filter command to be run for smudging the entry to be + * checked out + * + * @throws IOException + * @since 4.2 + */ + public static void checkoutEntry(Repository repo, DirCacheEntry entry, + ObjectReader or, boolean deleteRecursive, + String smudgeFilterCommand) throws IOException { ObjectLoader ol = or.open(entry.getObjectId()); File f = new File(repo.getWorkTree(), entry.getPathString()); File parentDir = f.getParentFile(); @@ -1210,14 +1259,52 @@ public class DirCacheCheckout { OutputStream channel = new FileOutputStream(tmpFile); if (opt.getAutoCRLF() == AutoCRLF.TRUE) channel = new AutoCRLFOutputStream(channel); - try { - ol.copyTo(channel); - } finally { - channel.close(); + if (smudgeFilterCommand != null) { + ProcessBuilder filterProcessBuilder = fs + .runInShell(smudgeFilterCommand, new String[0]); + filterProcessBuilder.directory(repo.getWorkTree()); + filterProcessBuilder.environment().put(Constants.GIT_DIR_KEY, + repo.getDirectory().getAbsolutePath()); + ExecutionResult result; + int rc; + try { + // TODO: wire correctly with AUTOCRLF + result = fs.execute(filterProcessBuilder, ol.openStream()); + rc = result.getRc(); + if (rc == 0) { + result.getStdout().writeTo(channel, + NullProgressMonitor.INSTANCE); + } + } catch (IOException | InterruptedException e) { + throw new IOException(new FilterFailedException(e, + smudgeFilterCommand, entry.getPathString())); + + } finally { + channel.close(); + } + if (rc != 0) { + throw new IOException(new FilterFailedException(rc, + smudgeFilterCommand, entry.getPathString(), + result.getStdout().toByteArray(MAX_EXCEPTION_TEXT_SIZE), + RawParseUtils.decode(result.getStderr() + .toByteArray(MAX_EXCEPTION_TEXT_SIZE)))); + } + } else { + try { + ol.copyTo(channel); + } finally { + channel.close(); + } + } + // The entry needs to correspond to the on-disk filesize. If the content + // was filtered (either by autocrlf handling or smudge filters) ask the + // filesystem again for the length. Otherwise the objectloader knows the + // size + if (opt.getAutoCRLF() == AutoCRLF.TRUE || smudgeFilterCommand != null) { + entry.setLength(tmpFile.length()); + } else { + entry.setLength(ol.getSize()); } - entry.setLength(opt.getAutoCRLF() == AutoCRLF.TRUE ? // - tmpFile.length() // AutoCRLF wants on-disk-size - : (int) ol.getSize()); if (opt.isFileMode() && fs.supportsExecute()) { if (FileMode.EXECUTABLE_FILE.equals(entry.getRawMode())) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java index 1a3111ab49..d30edaf41b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java @@ -384,6 +384,13 @@ public final class Constants { */ public static final String ATTR_FILTER_TYPE_CLEAN = "clean"; + /** + * smudge command name, used to call filter driver + * + * @since 4.2 + */ + public static final String ATTR_FILTER_TYPE_SMUDGE = "smudge"; + /** Name of the ignore file */ public static final String DOT_GIT_IGNORE = ".gitignore"; -- cgit v1.2.3 From 46e4992e9267211a55aae03b744b50edb87740fd Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Fri, 27 Nov 2015 23:21:33 -0800 Subject: Fix performance regression in CanonicalTreeParser Change-Id: I14046559fddb9656d890d3099010117e84cd9439 --- .../eclipse/jgit/treewalk/CanonicalTreeParser.java | 27 ++++++++++------------ 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java index df31558ff9..c24efe20aa 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java @@ -64,11 +64,11 @@ import org.eclipse.jgit.util.RawParseUtils; /** Parses raw Git trees from the canonical semi-text/semi-binary format. */ public class CanonicalTreeParser extends AbstractTreeIterator { - private static final int ATTRIBUTESLENGTH = Constants.DOT_GIT_ATTRIBUTES - .getBytes().length; - private static final byte[] EMPTY = {}; + private static final byte[] ATTRS = Constants + .encode(Constants.DOT_GIT_ATTRIBUTES); + private byte[] raw; /** First offset within {@link #raw} of the prior entry. */ @@ -375,11 +375,9 @@ public class CanonicalTreeParser extends AbstractTreeIterator { nextPtr = ptr + Constants.OBJECT_ID_LENGTH; // Check if this entry is a .gitattributes file - if (RawParseUtils.match(path, pathOffset, - Constants.DOT_GIT_ATTRIBUTES.getBytes()) == ATTRIBUTESLENGTH) - attributesNode = new LazyLoadingAttributesNode( - ObjectId.fromRaw(idBuffer(), idOffset())); - + if (path[pathOffset] == '.' + && RawParseUtils.match(path, pathOffset, ATTRS) > 0) + attributesNode = new LazyLoadingAttributesNode(idOffset()); } /** @@ -402,18 +400,18 @@ public class CanonicalTreeParser extends AbstractTreeIterator { /** * {@link AttributesNode} implementation that provides lazy loading */ - private static class LazyLoadingAttributesNode extends AttributesNode { - final ObjectId objectId; + private class LazyLoadingAttributesNode extends AttributesNode { + private final int idOffset; - LazyLoadingAttributesNode(ObjectId objectId) { + LazyLoadingAttributesNode(int idOffset) { super(Collections. emptyList()); - this.objectId = objectId; - + this.idOffset = idOffset; } AttributesNode load(ObjectReader reader) throws IOException { AttributesNode r = new AttributesNode(); - ObjectLoader loader = reader.open(objectId); + ObjectId id = ObjectId.fromRaw(raw, idOffset); + ObjectLoader loader = reader.open(id); if (loader != null) { InputStream in = loader.openStream(); try { @@ -425,5 +423,4 @@ public class CanonicalTreeParser extends AbstractTreeIterator { return r.getRules().isEmpty() ? null : r; } } - } -- cgit v1.2.3 From 885879ffe907a5df1c6fcc40ef6972e27dfecdd6 Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Fri, 27 Nov 2015 21:34:16 -0800 Subject: DirCache: Fix getEntriesWithin("") to not include null entries The internal array may be longer than entryCnt, in this case the tail of the array is padded with null entries. Do not return those to the caller of getEntriesWithin(). Change-Id: I19efb05e103fab6b739ced407f6e28155a48dba6 --- org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 a3980d2126..6dcb9488b9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java @@ -877,8 +877,8 @@ public class DirCache { */ public DirCacheEntry[] getEntriesWithin(String path) { if (path.length() == 0) { - final DirCacheEntry[] r = new DirCacheEntry[sortedEntries.length]; - System.arraycopy(sortedEntries, 0, r, 0, sortedEntries.length); + DirCacheEntry[] r = new DirCacheEntry[entryCnt]; + System.arraycopy(sortedEntries, 0, r, 0, entryCnt); return r; } if (!path.endsWith("/")) //$NON-NLS-1$ -- cgit v1.2.3 From 761814fe9c3fc0503d4654ef4aace6a804da5ae7 Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Sat, 28 Nov 2015 08:58:15 -0800 Subject: DirCacheEntry: Speed up creation by avoiding string cast The checkPath function is available as a byte[] form, in fact the String form just converts to byte[] to run the algorithm. Having DirCacheEntry take a byte[] -> String -> byte[] to check if each path is valid is a huge waste of CPU time. On some systems it can double the time required to read 38,999 files from trees to the DirCache. This slows down any operation using a DirCache. Expose the byte[] form and use it for DirCacheEntry creation. Change-Id: I6db7bc793ece99ff3c356338d793c07c061aeac7 --- .../eclipse/jgit/dircache/DirCacheEntryTest.java | 4 ++-- .../eclipse/jgit/dircache/DirCacheCheckout.java | 18 ----------------- .../org/eclipse/jgit/dircache/DirCacheEntry.java | 23 ++++++++++++++++------ .../src/org/eclipse/jgit/util/SystemReader.java | 15 ++++++++++++++ 4 files changed, 34 insertions(+), 26 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java index e159ed939e..dc7181aece 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java @@ -69,9 +69,9 @@ public class DirCacheEntryTest { assertFalse(isValidPath("a\u0000b")); } - private static boolean isValidPath(final String path) { + private static boolean isValidPath(String path) { try { - DirCacheCheckout.checkValidPath(path); + new DirCacheEntry(path); return true; } catch (InvalidPathException e) { return false; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java index 393a854945..4eb688170c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java @@ -1342,24 +1342,6 @@ public class DirCacheCheckout { checkValidPathSegment(chk, i); } - /** - * Check if path is a valid path for a checked out file name or ref name. - * - * @param path - * @throws InvalidPathException - * if the path is invalid - * @since 3.3 - */ - static void checkValidPath(String path) throws InvalidPathException { - try { - SystemReader.getInstance().checkPath(path); - } catch (CorruptObjectException e) { - InvalidPathException p = new InvalidPathException(path); - p.initCause(e); - throw p; - } - } - private static void checkValidPathSegment(ObjectChecker chk, CanonicalTreeParser t) throws InvalidPathException { try { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java index eef2e6d3c3..404ff1738e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java @@ -65,6 +65,7 @@ import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.MutableInteger; import org.eclipse.jgit.util.NB; +import org.eclipse.jgit.util.SystemReader; /** * A single file (or stage of a file) in a {@link DirCache}. @@ -191,7 +192,7 @@ public class DirCacheEntry { } try { - DirCacheCheckout.checkValidPath(toString(path)); + checkPath(path); } catch (InvalidPathException e) { CorruptObjectException p = new CorruptObjectException(e.getMessage()); @@ -263,7 +264,7 @@ public class DirCacheEntry { /** * Create an empty entry at the specified stage. * - * @param newPath + * @param path * name of the cache entry, in the standard encoding. * @param stage * the stage index of the new entry. @@ -274,16 +275,16 @@ public class DirCacheEntry { * range 0..3, inclusive. */ @SuppressWarnings("boxing") - public DirCacheEntry(final byte[] newPath, final int stage) { - DirCacheCheckout.checkValidPath(toString(newPath)); + public DirCacheEntry(byte[] path, final int stage) { + checkPath(path); if (stage < 0 || 3 < stage) throw new IllegalArgumentException(MessageFormat.format( JGitText.get().invalidStageForPath, - stage, toString(newPath))); + stage, toString(path))); info = new byte[INFO_LEN]; infoOffset = 0; - path = newPath; + this.path = path; int flags = ((stage & 0x3) << 12); if (path.length < NAME_MASK) @@ -730,6 +731,16 @@ public class DirCacheEntry { return 0; } + private static void checkPath(byte[] path) { + try { + SystemReader.getInstance().checkPath(path); + } catch (CorruptObjectException e) { + InvalidPathException p = new InvalidPathException(toString(path)); + p.initCause(e); + throw p; + } + } + private static String toString(final byte[] path) { return Constants.CHARSET.decode(ByteBuffer.wrap(path)).toString(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java index 4795c89e73..9860ef070f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java @@ -339,4 +339,19 @@ public abstract class SystemReader { public void checkPath(String path) throws CorruptObjectException { platformChecker.checkPath(path); } + + /** + * Check tree path entry for validity. + *

    + * Scans a multi-directory path string such as {@code "src/main.c"}. + * + * @param path + * path string to scan. + * @throws CorruptObjectException + * path is invalid. + * @since 4.2 + */ + public void checkPath(byte[] path) throws CorruptObjectException { + platformChecker.checkPath(path, 0, path.length); + } } -- cgit v1.2.3 From 45cc76524bc29d856340736a9de8d0889b17bc13 Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Sat, 28 Nov 2015 09:21:31 -0800 Subject: DirCache: Fix bad code formatting Line breaking before , is ugly to read. Most formatters and humans expect line break after , so update a few offensive locations. Use String.format() for the construction of the error message when a bad DirCachEntry is being failed on. This simplifies the code and its not a performance critical section. Change-Id: I5d990389e7ba24ef0861cf8ec0026ed030d4aeda --- .../src/org/eclipse/jgit/dircache/DirCacheBuilder.java | 13 +++++++------ .../src/org/eclipse/jgit/dircache/DirCacheEntry.java | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java index 6c7a70c52e..73405cb40a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java @@ -102,8 +102,9 @@ public class DirCacheBuilder extends BaseDirCacheEditor { */ public void add(final DirCacheEntry newEntry) { if (newEntry.getRawMode() == 0) - throw new IllegalArgumentException(MessageFormat.format(JGitText.get().fileModeNotSetForPath - , newEntry.getPathString())); + throw new IllegalArgumentException(MessageFormat.format( + JGitText.get().fileModeNotSetForPath, + newEntry.getPathString())); beforeAdd(newEntry); fastAdd(newEntry); } @@ -242,9 +243,9 @@ public class DirCacheBuilder extends BaseDirCacheEditor { sorted = true; } - private static IllegalStateException bad(final DirCacheEntry a, - final String msg) { - return new IllegalStateException(msg + ": " + a.getStage() + " " //$NON-NLS-1$ //$NON-NLS-2$ - + a.getPathString()); + private static IllegalStateException bad(DirCacheEntry a, String msg) { + return new IllegalStateException(String.format( + "%s: %d %s", //$NON-NLS-1$ + msg, Integer.valueOf(a.getStage()), a.getPathString())); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java index 404ff1738e..22c32ffd17 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java @@ -499,8 +499,8 @@ public class DirCacheEntry { switch (mode.getBits() & FileMode.TYPE_MASK) { case FileMode.TYPE_MISSING: case FileMode.TYPE_TREE: - throw new IllegalArgumentException(MessageFormat.format(JGitText.get().invalidModeForPath - , mode, getPathString())); + throw new IllegalArgumentException(MessageFormat.format( + JGitText.get().invalidModeForPath, mode, getPathString())); } NB.encodeInt32(info, infoOffset + P_MODE, mode.getBits()); } -- cgit v1.2.3 From b0eb744604391c94ec505f846604df1a07a166b1 Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Sun, 29 Nov 2015 12:04:03 -0800 Subject: Delay locating .gitattributes until requested Instead of checking every entry for .gitattributes only look for the entry on request by TreeWalk. This avoids impacting uses like RevWalk filtering history. When the attrs is requested skip to the start of the tree and look for .gitattributes until either it is found, or it is impossible to be present. Due to the sorting rules of tree entries .gitattributes should be among the first or second entries in the tree so very few entries will need to be considered. Waiting to find the .gitattributes file by native ordering may miss attrs for files like .config, which sorts before .gitattributes. Starting from the front of the tree on demand ensures the attributes are parsed as early as necessary to process any entry in the tree. Due to TreeWalk recursively processing up the tree of iterators we cannot just reset the current CanonicalTreeParser to the start as parent parsers share the same path buffer as their children. Resetting a parent to look for .gitattributes may overwrite path buffer data used by a child iterator. Work around this by building a new temporary CanonicalTreeParser instance. Change-Id: Ife950253b687be325340d27e9915c9a40df2641c --- .../jgit/treewalk/CanonicalTreeParserTest.java | 41 +++++++++++ .../jgit/treewalk/AbstractTreeIterator.java | 36 ++++++++++ .../eclipse/jgit/treewalk/CanonicalTreeParser.java | 80 ++++++++++------------ 3 files changed, 114 insertions(+), 43 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java index 52da69ef52..f5e97c2dc2 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java @@ -43,6 +43,8 @@ package org.eclipse.jgit.treewalk; +import static org.eclipse.jgit.lib.FileMode.REGULAR_FILE; +import static org.eclipse.jgit.lib.FileMode.SYMLINK; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; @@ -50,9 +52,11 @@ import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; +import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.TreeFormatter; import org.eclipse.jgit.util.RawParseUtils; import org.junit.Before; import org.junit.Test; @@ -369,4 +373,41 @@ public class CanonicalTreeParserTest { assertEquals(name, RawParseUtils.decode(Constants.CHARSET, ctp.path, ctp.pathOffset, ctp.pathLen)); } + + @Test + public void testFindAttributesWhenFirst() throws CorruptObjectException { + TreeFormatter tree = new TreeFormatter(); + tree.append(".gitattributes", REGULAR_FILE, hash_a); + ctp.reset(tree.toByteArray()); + + assertTrue(ctp.findFile(".gitattributes")); + assertEquals(REGULAR_FILE.getBits(), ctp.getEntryRawMode()); + assertEquals(".gitattributes", ctp.getEntryPathString()); + assertEquals(hash_a, ctp.getEntryObjectId()); + } + + @Test + public void testFindAttributesWhenSecond() throws CorruptObjectException { + TreeFormatter tree = new TreeFormatter(); + tree.append(".config", SYMLINK, hash_a); + tree.append(".gitattributes", REGULAR_FILE, hash_foo); + ctp.reset(tree.toByteArray()); + + assertTrue(ctp.findFile(".gitattributes")); + assertEquals(REGULAR_FILE.getBits(), ctp.getEntryRawMode()); + assertEquals(".gitattributes", ctp.getEntryPathString()); + assertEquals(hash_foo, ctp.getEntryObjectId()); + } + + @Test + public void testFindAttributesWhenMissing() throws CorruptObjectException { + TreeFormatter tree = new TreeFormatter(); + tree.append("src", REGULAR_FILE, hash_a); + tree.append("zoo", REGULAR_FILE, hash_foo); + ctp.reset(tree.toByteArray()); + + assertFalse(ctp.findFile(".gitattributes")); + assertEquals(11, ctp.idOffset()); // Did not walk the entire tree. + assertEquals("src", ctp.getEntryPathString()); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java index aa5f32a870..5e71889574 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java @@ -327,6 +327,42 @@ public abstract class AbstractTreeIterator { return pathCompare(p.path, cPos, p.pathLen, pMode, cPos); } + /** + * Seek the iterator on a file, if present. + * + * @param name + * file name to find (will not find a directory). + * @return true if the file exists in this tree; false otherwise. + * @throws CorruptObjectException + * tree is invalid. + * @since 4.2 + */ + public boolean findFile(String name) throws CorruptObjectException { + return findFile(Constants.encode(name)); + } + + /** + * Seek the iterator on a file, if present. + * + * @param name + * file name to find (will not find a directory). + * @return true if the file exists in this tree; false otherwise. + * @throws CorruptObjectException + * tree is invalid. + * @since 4.2 + */ + public boolean findFile(byte[] name) throws CorruptObjectException { + for (; !eof(); next(1)) { + int cmp = pathCompare(name, 0, name.length, 0, pathOffset); + if (cmp == 0) { + return true; + } else if (cmp > 0) { + return false; + } + } + return false; + } + /** * Compare the path of this current entry to a raw buffer. * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java index c24efe20aa..c038f07725 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java @@ -44,6 +44,13 @@ package org.eclipse.jgit.treewalk; +import static org.eclipse.jgit.lib.Constants.DOT_GIT_ATTRIBUTES; +import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH; +import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; +import static org.eclipse.jgit.lib.Constants.OBJ_TREE; +import static org.eclipse.jgit.lib.Constants.TYPE_TREE; +import static org.eclipse.jgit.lib.Constants.encode; + import java.io.IOException; import java.io.InputStream; import java.util.Arrays; @@ -54,20 +61,15 @@ import org.eclipse.jgit.attributes.AttributesRule; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.lib.AnyObjectId; -import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.MutableObjectId; import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.lib.ObjectReader; -import org.eclipse.jgit.util.RawParseUtils; /** Parses raw Git trees from the canonical semi-text/semi-binary format. */ public class CanonicalTreeParser extends AbstractTreeIterator { private static final byte[] EMPTY = {}; - - private static final byte[] ATTRS = Constants - .encode(Constants.DOT_GIT_ATTRIBUTES); + private static final byte[] ATTRS = encode(DOT_GIT_ATTRIBUTES); private byte[] raw; @@ -133,6 +135,7 @@ public class CanonicalTreeParser extends AbstractTreeIterator { * the raw tree content. */ public void reset(final byte[] treeData) { + attributesNode = null; raw = treeData; prevPtr = -1; currPtr = 0; @@ -208,7 +211,7 @@ public class CanonicalTreeParser extends AbstractTreeIterator { */ public void reset(final ObjectReader reader, final AnyObjectId id) throws IncorrectObjectTypeException, IOException { - reset(reader.open(id, Constants.OBJ_TREE).getCachedBytes()); + reset(reader.open(id, OBJ_TREE).getCachedBytes()); } @Override @@ -218,7 +221,7 @@ public class CanonicalTreeParser extends AbstractTreeIterator { idBuffer.fromRaw(idBuffer(), idOffset()); if (!FileMode.TREE.equals(mode)) { final ObjectId me = idBuffer.toObjectId(); - throw new IncorrectObjectTypeException(me, Constants.TYPE_TREE); + throw new IncorrectObjectTypeException(me, TYPE_TREE); } return createSubtreeIterator0(reader, idBuffer); } @@ -263,7 +266,7 @@ public class CanonicalTreeParser extends AbstractTreeIterator { @Override public int idOffset() { - return nextPtr - Constants.OBJECT_ID_LENGTH; + return nextPtr - OBJECT_ID_LENGTH; } @Override @@ -301,7 +304,7 @@ public class CanonicalTreeParser extends AbstractTreeIterator { prevPtr = ptr; while (raw[ptr] != 0) ptr++; - ptr += Constants.OBJECT_ID_LENGTH + 1; + ptr += OBJECT_ID_LENGTH + 1; } if (delta != 0) throw new ArrayIndexOutOfBoundsException(delta); @@ -337,7 +340,7 @@ public class CanonicalTreeParser extends AbstractTreeIterator { trace[delta] = ptr; while (raw[ptr] != 0) ptr++; - ptr += Constants.OBJECT_ID_LENGTH + 1; + ptr += OBJECT_ID_LENGTH + 1; } if (trace[1] == -1) throw new ArrayIndexOutOfBoundsException(delta); @@ -372,12 +375,7 @@ public class CanonicalTreeParser extends AbstractTreeIterator { } } pathLen = tmp; - nextPtr = ptr + Constants.OBJECT_ID_LENGTH; - - // Check if this entry is a .gitattributes file - if (path[pathOffset] == '.' - && RawParseUtils.match(path, pathOffset, ATTRS) > 0) - attributesNode = new LazyLoadingAttributesNode(idOffset()); + nextPtr = ptr + OBJECT_ID_LENGTH; } /** @@ -391,36 +389,32 @@ public class CanonicalTreeParser extends AbstractTreeIterator { */ public AttributesNode getEntryAttributesNode(ObjectReader reader) throws IOException { - if (attributesNode instanceof LazyLoadingAttributesNode) - attributesNode = ((LazyLoadingAttributesNode) attributesNode) - .load(reader); - return attributesNode; + if (attributesNode == null) { + attributesNode = findAttributes(reader); + } + return attributesNode.getRules().isEmpty() ? null : attributesNode; } - /** - * {@link AttributesNode} implementation that provides lazy loading - */ - private class LazyLoadingAttributesNode extends AttributesNode { - private final int idOffset; - - LazyLoadingAttributesNode(int idOffset) { - super(Collections. emptyList()); - this.idOffset = idOffset; + private AttributesNode findAttributes(ObjectReader reader) + throws IOException { + CanonicalTreeParser itr = new CanonicalTreeParser(); + itr.reset(raw); + if (itr.findFile(ATTRS)) { + return loadAttributes(reader, itr.getEntryObjectId()); } + return noAttributes(); + } - AttributesNode load(ObjectReader reader) throws IOException { - AttributesNode r = new AttributesNode(); - ObjectId id = ObjectId.fromRaw(raw, idOffset); - ObjectLoader loader = reader.open(id); - if (loader != null) { - InputStream in = loader.openStream(); - try { - r.parse(in); - } finally { - in.close(); - } - } - return r.getRules().isEmpty() ? null : r; + private static AttributesNode loadAttributes(ObjectReader reader, + AnyObjectId id) throws IOException { + AttributesNode r = new AttributesNode(); + try (InputStream in = reader.open(id, OBJ_BLOB).openStream()) { + r.parse(in); } + return r.getRules().isEmpty() ? noAttributes() : r; + } + + private static AttributesNode noAttributes() { + return new AttributesNode(Collections. emptyList()); } } -- cgit v1.2.3 From 93eca6dfe1c013ab49fab3816c72e84e12e8112a Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Sat, 28 Nov 2015 12:34:55 -0800 Subject: DirCache: Add helper to read from a tree Application code sometimes wants to read a DirCache from an ObjectId, but its confusing how to do this because its buried inside the DirCacheBuilder. Use this utility in a few places within JGit that also want to read a DirCache from a tree's ObjectId. Change-Id: I578b7e18e58753d154937f4ab835012b09e5adca --- .../src/org/eclipse/jgit/dircache/DirCache.java | 24 +++++++++++++++++ .../org/eclipse/jgit/merge/RecursiveMerger.java | 31 +--------------------- .../jgit/transport/PushCertificateStore.java | 8 ++---- 3 files changed, 27 insertions(+), 36 deletions(-) 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 6dcb9488b9..fa0339544f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java @@ -71,9 +71,11 @@ import org.eclipse.jgit.events.IndexChangedListener; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.file.FileSnapshot; import org.eclipse.jgit.internal.storage.file.LockFile; +import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectInserter; +import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.TreeWalk; @@ -146,6 +148,28 @@ public class DirCache { return new DirCache(null, null); } + /** + * Create a new in memory index read from the contents of a tree. + * + * @param reader + * reader to access the tree objects from a repository. + * @param treeId + * tree to read. Must identify a tree, not a tree-ish. + * @return a new cache which has no backing store file, but contains the + * contents of {@code treeId}. + * @throws IOException + * one or more trees not available from the ObjectReader. + * @since 4.2 + */ + public static DirCache read(ObjectReader reader, AnyObjectId treeId) + throws IOException { + DirCache d = newInCore(); + DirCacheBuilder b = d.builder(); + b.addTree(null, DirCacheEntry.STAGE_0, reader, treeId); + b.finish(); + return d; + } + /** * Create a new in-core index representation and read an index from disk. *

    diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java index aef47c58cf..e0556447ce 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java @@ -57,8 +57,6 @@ import java.util.List; import java.util.TimeZone; import org.eclipse.jgit.dircache.DirCache; -import org.eclipse.jgit.dircache.DirCacheBuilder; -import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.NoMergeBaseException; import org.eclipse.jgit.internal.JGitText; @@ -70,7 +68,6 @@ import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.filter.RevFilter; import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.EmptyTreeIterator; -import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.WorkingTreeIterator; /** @@ -181,7 +178,7 @@ public class RecursiveMerger extends ResolveMerger { WorkingTreeIterator oldWTreeIt = workingTreeIterator; workingTreeIterator = null; try { - dircache = dircacheFromTree(currentBase.getTree()); + dircache = DirCache.read(reader, currentBase.getTree()); inCore = true; List parents = new ArrayList(); @@ -256,30 +253,4 @@ public class RecursiveMerger extends ResolveMerger { new Date((time + 1) * 1000L), TimeZone.getTimeZone("GMT+0000")); //$NON-NLS-1$ } - - /** - * Create a new in memory dircache which has the same content as a given - * tree. - * - * @param treeId - * the tree which should be used to fill the dircache - * @return a new in memory dircache - * @throws IOException - */ - private DirCache dircacheFromTree(ObjectId treeId) throws IOException { - DirCache ret = DirCache.newInCore(); - DirCacheBuilder aBuilder = ret.builder(); - try (TreeWalk atw = new TreeWalk(reader)) { - atw.addTree(treeId); - atw.setRecursive(true); - while (atw.next()) { - DirCacheEntry e = new DirCacheEntry(atw.getRawPath()); - e.setFileMode(atw.getFileMode(0)); - e.setObjectId(atw.getObjectId(0)); - aBuilder.add(e); - } - } - aBuilder.finish(); - return ret; - } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java index 8947f2779d..d436e08df1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java @@ -65,7 +65,6 @@ import java.util.Map; import java.util.NoSuchElementException; import org.eclipse.jgit.dircache.DirCache; -import org.eclipse.jgit.dircache.DirCacheBuilder; import org.eclipse.jgit.dircache.DirCacheEditor; import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit; import org.eclipse.jgit.dircache.DirCacheEntry; @@ -448,13 +447,10 @@ public class PushCertificateStore implements AutoCloseable { } private DirCache newDirCache() throws IOException { - DirCache dc = DirCache.newInCore(); if (commit != null) { - DirCacheBuilder b = dc.builder(); - b.addTree(new byte[0], DirCacheEntry.STAGE_0, reader, commit.getTree()); - b.finish(); + return DirCache.read(reader, commit.getTree()); } - return dc; + return DirCache.newInCore(); } private ObjectId saveCert(ObjectInserter inserter, DirCache dc, -- cgit v1.2.3 From 2d011cd648ce33bc6eee577c380a178cb22bfe54 Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Sat, 28 Nov 2015 09:23:59 -0800 Subject: DirCacheBuilder: Speed up reading from trees Recursively copying a tree into a DirCache is a bottleneck for some algorithms like the in memory merge code in Gerrit Code Review. Drop a layer down in the stack and use CanonicalTreeParser directly as the addition logic only processes 1 tree at a time and does not need the merge sorting feature (or overhead) of TreeWalk. Combined with 761814fe9c ("DirCacheEntry: Speed up creation by avoiding string cast") tree loading 38,900 entries nearly halves in running time from 70ms to 36ms on some platforms. Change-Id: If1490ca25de0679a71cf508f59b486f9cc816165 --- .../org/eclipse/jgit/dircache/DirCacheBuilder.java | 68 ++++++++++++++++------ .../org/eclipse/jgit/dircache/DirCacheEntry.java | 4 ++ 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java index 73405cb40a..cfebe2d073 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java @@ -44,6 +44,9 @@ package org.eclipse.jgit.dircache; +import static org.eclipse.jgit.lib.FileMode.TYPE_MASK; +import static org.eclipse.jgit.lib.FileMode.TYPE_TREE; + import java.io.IOException; import java.text.MessageFormat; import java.util.Arrays; @@ -51,9 +54,7 @@ import java.util.Arrays; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.ObjectReader; -import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.CanonicalTreeParser; -import org.eclipse.jgit.treewalk.TreeWalk; /** * Updates a {@link DirCache} by adding individual {@link DirCacheEntry}s. @@ -163,27 +164,56 @@ public class DirCacheBuilder extends BaseDirCacheEditor { * @throws IOException * a tree cannot be read to iterate through its entries. */ - public void addTree(final byte[] pathPrefix, final int stage, - final ObjectReader reader, final AnyObjectId tree) throws IOException { - final TreeWalk tw = new TreeWalk(reader); - tw.addTree(new CanonicalTreeParser(pathPrefix, reader, tree - .toObjectId())); - tw.setRecursive(true); - if (tw.next()) { - final DirCacheEntry newEntry = toEntry(stage, tw); - beforeAdd(newEntry); - fastAdd(newEntry); - while (tw.next()) - fastAdd(toEntry(stage, tw)); + public void addTree(byte[] pathPrefix, int stage, ObjectReader reader, + AnyObjectId tree) throws IOException { + CanonicalTreeParser p = createTreeParser(pathPrefix, reader, tree); + while (!p.eof()) { + if (isTree(p)) { + p = enterTree(p, reader); + continue; + } + + DirCacheEntry first = toEntry(stage, p); + beforeAdd(first); + fastAdd(first); + p = p.next(); + break; + } + + // Rest of tree entries are correctly sorted; use fastAdd(). + while (!p.eof()) { + if (isTree(p)) { + p = enterTree(p, reader); + } else { + fastAdd(toEntry(stage, p)); + p = p.next(); + } } } - private DirCacheEntry toEntry(final int stage, final TreeWalk tw) { - final DirCacheEntry e = new DirCacheEntry(tw.getRawPath(), stage); - final AbstractTreeIterator i; + private static CanonicalTreeParser createTreeParser(byte[] pathPrefix, + ObjectReader reader, AnyObjectId tree) throws IOException { + return new CanonicalTreeParser(pathPrefix, reader, tree); + } + + private static boolean isTree(CanonicalTreeParser p) { + return (p.getEntryRawMode() & TYPE_MASK) == TYPE_TREE; + } + + private static CanonicalTreeParser enterTree(CanonicalTreeParser p, + ObjectReader reader) throws IOException { + p = p.createSubtreeIterator(reader); + return p.eof() ? p.next() : p; + } + + private static DirCacheEntry toEntry(int stage, CanonicalTreeParser i) { + byte[] buf = i.getEntryPathBuffer(); + int len = i.getEntryPathLength(); + byte[] path = new byte[len]; + System.arraycopy(buf, 0, path, 0, len); - i = tw.getTree(0, AbstractTreeIterator.class); - e.setFileMode(tw.getFileMode(0)); + DirCacheEntry e = new DirCacheEntry(path, stage); + e.setFileMode(i.getEntryRawMode()); e.setObjectIdFromRaw(i.idBuffer(), i.idOffset()); return e; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java index 22c32ffd17..c8bc0960f4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java @@ -505,6 +505,10 @@ public class DirCacheEntry { NB.encodeInt32(info, infoOffset + P_MODE, mode.getBits()); } + void setFileMode(int mode) { + NB.encodeInt32(info, infoOffset + P_MODE, mode); + } + /** * Get the cached creation time of this file, in milliseconds. * -- cgit v1.2.3 From f89f30ffcdfbd6d18e674f9d5e565bd6a21ee938 Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Tue, 1 Dec 2015 14:20:44 -0800 Subject: ReceiveCommand.filter: Accept Iterable PreReceiveHook is given a Collection and it can be very useful here to call ReceiveCommand.filter(cmds, NOT_ATTEMPTED). Overload filter to accept both Iterable and List. Keep backwards binary compatibility for List by upcasting to Iterable. Change-Id: Ib1341876c703670945ef209edc8259715ee86c26 --- .../org/eclipse/jgit/transport/ReceiveCommand.java | 35 +++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java index 7c44dba4a2..0cc7e5c50e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java @@ -46,6 +46,7 @@ package org.eclipse.jgit.transport; import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import org.eclipse.jgit.internal.JGitText; @@ -127,26 +128,46 @@ public class ReceiveCommand { } /** - * Filter a list of commands according to result. + * Filter a collection of commands according to result. * - * @param commands + * @param in * commands to filter. * @param want * desired status to filter by. * @return a copy of the command list containing only those commands with * the desired status. - * @since 2.0 + * @since 4.3 */ - public static List filter(List commands, - final Result want) { - List r = new ArrayList(commands.size()); - for (final ReceiveCommand cmd : commands) { + public static List filter(Iterable in, + Result want) { + List r; + if (in instanceof Collection) + r = new ArrayList<>(((Collection) in).size()); + else + r = new ArrayList<>(); + for (ReceiveCommand cmd : in) { if (cmd.getResult() == want) r.add(cmd); } return r; } + /** + * Filter a list of commands according to result. + * + * @param commands + * commands to filter. + * @param want + * desired status to filter by. + * @return a copy of the command list containing only those commands with + * the desired status. + * @since 2.0 + */ + public static List filter(List commands, + Result want) { + return filter((Iterable) commands, want); + } + private final ObjectId oldId; private final ObjectId newId; -- cgit v1.2.3 From f109af47d07ecc20767f245a384ebd1dc201b6af Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Wed, 2 Dec 2015 15:24:26 +0100 Subject: Fix wrong @since tag In ReceiveCommand Change-Id: I58fa657dd4783fed0ffca94020c87c49d99009c6 Signed-off-by: Matthias Sohn --- org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java index 0cc7e5c50e..5702b6d7b9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java @@ -136,7 +136,7 @@ public class ReceiveCommand { * desired status to filter by. * @return a copy of the command list containing only those commands with * the desired status. - * @since 4.3 + * @since 4.2 */ public static List filter(Iterable in, Result want) { -- cgit v1.2.3 From 3d8e6b1e16092701c31463092e945b8f00886bb7 Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Wed, 2 Dec 2015 21:47:58 -0800 Subject: Support atomic push in JGit client This should mirror the behavior of `git push --atomic` where the client asks the server to apply all-or-nothing. Some JGit servers already support this based on a custom DFS backend. InMemoryRepository is extended to support atomic push for unit testing purposes. Local disk server side support inside of JGit is a more complex animal due to the excessive amount of file locking required to protect every reference as a loose reference. Change-Id: I15083fbe48447678e034afeffb4639572a32f50c --- .../src/org/eclipse/jgit/pgm/Push.java | 4 + .../org/eclipse/jgit/transport/AtomicPushTest.java | 200 +++++++++++++++++++++ .../org/eclipse/jgit/internal/JGitText.properties | 1 + .../src/org/eclipse/jgit/api/PushCommand.java | 27 ++- .../src/org/eclipse/jgit/internal/JGitText.java | 1 + .../internal/storage/dfs/InMemoryRepository.java | 180 ++++++++++++++++--- .../jgit/transport/BasePackPushConnection.java | 16 +- .../org/eclipse/jgit/transport/PushProcess.java | 23 ++- .../src/org/eclipse/jgit/transport/Transport.java | 28 +++ 9 files changed, 446 insertions(+), 34 deletions(-) create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java index 1879ef51ff..9098c1263d 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java @@ -82,6 +82,9 @@ class Push extends TextBuiltin { @Option(name = "--all") private boolean all; + @Option(name = "--atomic") + private boolean atomic; + @Option(name = "--tags") private boolean tags; @@ -122,6 +125,7 @@ class Push extends TextBuiltin { push.setPushTags(); push.setRemote(remote); push.setThin(thin); + push.setAtomic(atomic); push.setTimeout(timeout); Iterable results = push.call(); for (PushResult result : results) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java new file mode 100644 index 0000000000..782e414b62 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2015, Google Inc. + * 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.transport; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jgit.errors.TransportException; +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; +import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectInserter; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.transport.resolver.ReceivePackFactory; +import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; +import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AtomicPushTest { + private URIish uri; + private TestProtocol testProtocol; + private Object ctx = new Object(); + private InMemoryRepository server; + private InMemoryRepository client; + private ObjectId obj1; + private ObjectId obj2; + + @Before + public void setUp() throws Exception { + server = newRepo("server"); + client = newRepo("client"); + testProtocol = new TestProtocol<>( + null, + new ReceivePackFactory() { + @Override + public ReceivePack create(Object req, Repository db) + throws ServiceNotEnabledException, + ServiceNotAuthorizedException { + return new ReceivePack(db); + } + }); + uri = testProtocol.register(ctx, server); + + try (ObjectInserter ins = client.newObjectInserter()) { + obj1 = ins.insert(Constants.OBJ_BLOB, Constants.encode("test")); + obj2 = ins.insert(Constants.OBJ_BLOB, Constants.encode("file")); + ins.flush(); + } + } + + @After + public void tearDown() { + Transport.unregister(testProtocol); + } + + private static InMemoryRepository newRepo(String name) { + return new InMemoryRepository(new DfsRepositoryDescription(name)); + } + + @Test + public void pushNonAtomic() throws Exception { + PushResult r; + server.setPerformsAtomicTransactions(false); + Transport tn = testProtocol.open(uri, client, "server"); + try { + tn.setPushAtomic(false); + r = tn.push(NullProgressMonitor.INSTANCE, commands()); + } finally { + tn.close(); + } + + RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one"); + RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two"); + assertSame(RemoteRefUpdate.Status.OK, one.getStatus()); + assertSame( + RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED, + two.getStatus()); + } + + @Test + public void pushAtomicClientGivesUpEarly() throws Exception { + PushResult r; + Transport tn = testProtocol.open(uri, client, "server"); + try { + tn.setPushAtomic(true); + r = tn.push(NullProgressMonitor.INSTANCE, commands()); + } finally { + tn.close(); + } + + RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one"); + RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two"); + assertSame( + RemoteRefUpdate.Status.REJECTED_OTHER_REASON, + one.getStatus()); + assertSame( + RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED, + two.getStatus()); + assertEquals(JGitText.get().transactionAborted, one.getMessage()); + } + + @Test + public void pushAtomicDisabled() throws Exception { + List cmds = new ArrayList<>(); + cmds.add(new RemoteRefUpdate( + null, null, + obj1, "refs/heads/one", + true /* force update */, + null /* no local tracking ref */, + ObjectId.zeroId())); + cmds.add(new RemoteRefUpdate( + null, null, + obj2, "refs/heads/two", + true /* force update */, + null /* no local tracking ref */, + ObjectId.zeroId())); + + server.setPerformsAtomicTransactions(false); + Transport tn = testProtocol.open(uri, client, "server"); + try { + tn.setPushAtomic(true); + tn.push(NullProgressMonitor.INSTANCE, cmds); + fail("did not throw TransportException"); + } catch (TransportException e) { + assertEquals( + uri + ": " + JGitText.get().atomicPushNotSupported, + e.getMessage()); + } finally { + tn.close(); + } + } + + private List commands() throws IOException { + List cmds = new ArrayList<>(); + cmds.add(new RemoteRefUpdate( + null, null, + obj1, "refs/heads/one", + true /* force update */, + null /* no local tracking ref */, + ObjectId.zeroId())); + cmds.add(new RemoteRefUpdate( + null, null, + obj2, "refs/heads/two", + true /* force update */, + null /* no local tracking ref */, + obj1)); + return cmds; + } +} diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index d0e1c779e4..0e9b0b59e6 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -20,6 +20,7 @@ argumentIsNotAValidCommentString=Invalid comment: {0} atLeastOnePathIsRequired=At least one path is required. atLeastOnePatternIsRequired=At least one pattern is required. atLeastTwoFiltersNeeded=At least two filters needed. +atomicPushNotSupported=Atomic push not supported. authenticationNotSupported=authentication not supported badBase64InputCharacterAt=Bad Base64 input character at {0} : {1} (decimal) badEntryDelimiter=Bad entry delimiter diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java index 227e32236d..f5b82bdd7d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java @@ -89,9 +89,8 @@ public class PushCommand extends private String receivePack = RemoteConfig.DEFAULT_RECEIVE_PACK; private boolean dryRun; - + private boolean atomic; private boolean force; - private boolean thin = Transport.DEFAULT_PUSH_THIN; private OutputStream out; @@ -145,6 +144,7 @@ public class PushCommand extends transports = Transport.openAll(repo, remote, Transport.Operation.PUSH); for (final Transport transport : transports) { transport.setPushThin(thin); + transport.setPushAtomic(atomic); if (receivePack != null) transport.setOptionReceivePack(receivePack); transport.setDryRun(dryRun); @@ -396,6 +396,29 @@ public class PushCommand extends return this; } + /** + * @return true if all-or-nothing behavior is requested. + * @since 4.2 + */ + public boolean isAtomic() { + return atomic; + } + + /** + * Requests atomic push (all references updated, or no updates). + * + * Default setting is false. + * + * @param atomic + * @return {@code this} + * @since 4.2 + */ + public PushCommand setAtomic(boolean atomic) { + checkCallable(); + this.atomic = atomic; + return this; + } + /** * @return the force preference for push operation */ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index f6fd8a396a..796eaaebf5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -79,6 +79,7 @@ public class JGitText extends TranslationBundle { /***/ public String atLeastOnePathIsRequired; /***/ public String atLeastOnePatternIsRequired; /***/ public String atLeastTwoFiltersNeeded; + /***/ public String atomicPushNotSupported; /***/ public String authenticationNotSupported; /***/ public String badBase64InputCharacterAt; /***/ public String badEntryDelimiter; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java index 832e4fb6a8..1c664b4097 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java @@ -13,14 +13,22 @@ import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.eclipse.jgit.lib.BatchRefUpdate; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectIdRef; +import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref.Storage; import org.eclipse.jgit.lib.SymbolicRef; +import org.eclipse.jgit.revwalk.RevObject; +import org.eclipse.jgit.revwalk.RevTag; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.ReceiveCommand; import org.eclipse.jgit.util.RefList; /** @@ -46,8 +54,8 @@ public class InMemoryRepository extends DfsRepository { static final AtomicInteger packId = new AtomicInteger(); private final DfsObjDatabase objdb; - private final DfsRefDatabase refdb; + private boolean performsAtomicTransactions = true; /** * Initialize a new in-memory repository. @@ -76,6 +84,17 @@ public class InMemoryRepository extends DfsRepository { return refdb; } + /** + * Enable (or disable) the atomic reference transaction support. + *

    + * Useful for testing atomic support enabled or disabled. + * + * @param atomic + */ + public void setPerformsAtomicTransactions(boolean atomic) { + performsAtomicTransactions = atomic; + } + private class MemObjDatabase extends DfsObjDatabase { private List packs = new ArrayList(); @@ -235,41 +254,143 @@ public class InMemoryRepository extends DfsRepository { private class MemRefDatabase extends DfsRefDatabase { private final ConcurrentMap refs = new ConcurrentHashMap(); + private final ReadWriteLock lock = new ReentrantReadWriteLock(true /* fair */); MemRefDatabase() { super(InMemoryRepository.this); } + @Override + public boolean performsAtomicTransactions() { + return performsAtomicTransactions; + } + + @Override + public BatchRefUpdate newBatchUpdate() { + return new BatchRefUpdate(this) { + @Override + public void execute(RevWalk walk, ProgressMonitor monitor) + throws IOException { + if (performsAtomicTransactions()) { + try { + lock.writeLock().lock(); + batch(walk, getCommands()); + } finally { + lock.writeLock().unlock(); + } + } else { + super.execute(walk, monitor); + } + } + }; + } + @Override protected RefCache scanAllRefs() throws IOException { RefList.Builder ids = new RefList.Builder(); RefList.Builder sym = new RefList.Builder(); - for (Ref ref : refs.values()) { - if (ref.isSymbolic()) - sym.add(ref); - ids.add(ref); + try { + lock.readLock().lock(); + for (Ref ref : refs.values()) { + if (ref.isSymbolic()) + sym.add(ref); + ids.add(ref); + } + } finally { + lock.readLock().unlock(); } ids.sort(); sym.sort(); return new RefCache(ids.toRefList(), sym.toRefList()); } + private void batch(RevWalk walk, List cmds) { + // Validate that the target exists in a new RevWalk, as the RevWalk + // from the RefUpdate might be reading back unflushed objects. + Map peeled = new HashMap<>(); + try (RevWalk rw = new RevWalk(getRepository())) { + for (ReceiveCommand c : cmds) { + if (!ObjectId.zeroId().equals(c.getNewId())) { + try { + RevObject o = rw.parseAny(c.getNewId()); + if (o instanceof RevTag) { + peeled.put(o, rw.peel(o).copy()); + } + } catch (IOException e) { + c.setResult(ReceiveCommand.Result.REJECTED_MISSING_OBJECT); + reject(cmds); + return; + } + } + } + } + + // Check all references conform to expected old value. + for (ReceiveCommand c : cmds) { + Ref r = refs.get(c.getRefName()); + if (r == null) { + if (c.getType() != ReceiveCommand.Type.CREATE) { + c.setResult(ReceiveCommand.Result.LOCK_FAILURE); + reject(cmds); + return; + } + } else if (r.isSymbolic() || r.getObjectId() == null + || !r.getObjectId().equals(c.getOldId())) { + c.setResult(ReceiveCommand.Result.LOCK_FAILURE); + reject(cmds); + return; + } + } + + // Write references. + for (ReceiveCommand c : cmds) { + if (c.getType() == ReceiveCommand.Type.DELETE) { + refs.remove(c.getRefName()); + c.setResult(ReceiveCommand.Result.OK); + continue; + } + + ObjectId p = peeled.get(c.getNewId()); + Ref r; + if (p != null) { + r = new ObjectIdRef.PeeledTag(Storage.PACKED, + c.getRefName(), c.getNewId(), p); + } else { + r = new ObjectIdRef.PeeledNonTag(Storage.PACKED, + c.getRefName(), c.getNewId()); + } + refs.put(r.getName(), r); + c.setResult(ReceiveCommand.Result.OK); + } + clearCache(); + } + + private void reject(List cmds) { + for (ReceiveCommand c : cmds) { + if (c.getResult() == ReceiveCommand.Result.NOT_ATTEMPTED) { + c.setResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, + JGitText.get().transactionAborted); + } + } + } + @Override protected boolean compareAndPut(Ref oldRef, Ref newRef) throws IOException { - ObjectId id = newRef.getObjectId(); - if (id != null) { - try (RevWalk rw = new RevWalk(getRepository())) { - // Validate that the target exists in a new RevWalk, as the RevWalk - // from the RefUpdate might be reading back unflushed objects. - rw.parseAny(id); + try { + lock.writeLock().lock(); + ObjectId id = newRef.getObjectId(); + if (id != null) { + try (RevWalk rw = new RevWalk(getRepository())) { + // Validate that the target exists in a new RevWalk, as the RevWalk + // from the RefUpdate might be reading back unflushed objects. + rw.parseAny(id); + } } - } - String name = newRef.getName(); - if (oldRef == null) - return refs.putIfAbsent(name, newRef) == null; + String name = newRef.getName(); + if (oldRef == null) + return refs.putIfAbsent(name, newRef) == null; - synchronized (refs) { Ref cur = refs.get(name); Ref toCompare = cur; if (toCompare != null) { @@ -294,22 +415,29 @@ public class InMemoryRepository extends DfsRepository { if (eq(toCompare, oldRef)) return refs.replace(name, cur, newRef); } - } - if (oldRef.getStorage() == Storage.NEW) - return refs.putIfAbsent(name, newRef) == null; + if (oldRef.getStorage() == Storage.NEW) + return refs.putIfAbsent(name, newRef) == null; - return false; + return false; + } finally { + lock.writeLock().unlock(); + } } @Override protected boolean compareAndRemove(Ref oldRef) throws IOException { - String name = oldRef.getName(); - Ref cur = refs.get(name); - if (cur != null && eq(cur, oldRef)) - return refs.remove(name, cur); - else - return false; + try { + lock.writeLock().lock(); + String name = oldRef.getName(); + Ref cur = refs.get(name); + if (cur != null && eq(cur, oldRef)) + return refs.remove(name, cur); + else + return false; + } finally { + lock.writeLock().unlock(); + } } private boolean eq(Ref a, Ref b) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java index 24fb3be64c..f7bac6d060 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java @@ -44,6 +44,8 @@ package org.eclipse.jgit.transport; +import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC; + import java.io.IOException; import java.io.OutputStream; import java.text.MessageFormat; @@ -110,17 +112,15 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen public static final String CAPABILITY_SIDE_BAND_64K = GitProtocolConstants.CAPABILITY_SIDE_BAND_64K; private final boolean thinPack; + private final boolean atomic; + private boolean capableAtomic; private boolean capableDeleteRefs; - private boolean capableReport; - private boolean capableSideBand; - private boolean capableOfsDelta; private boolean sentCommand; - private boolean writePack; /** Time in milliseconds spent transferring the pack data. */ @@ -135,6 +135,7 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen public BasePackPushConnection(final PackTransport packTransport) { super(packTransport); thinPack = transport.isPushThin(); + atomic = transport.isPushAtomic(); } public void push(final ProgressMonitor monitor, @@ -224,6 +225,11 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen private void writeCommands(final Collection refUpdates, final ProgressMonitor monitor, OutputStream outputStream) throws IOException { final String capabilities = enableCapabilities(monitor, outputStream); + if (atomic && !capableAtomic) { + throw new TransportException(uri, + JGitText.get().atomicPushNotSupported); + } + for (final RemoteRefUpdate rru : refUpdates) { if (!capableDeleteRefs && rru.isDelete()) { rru.setStatus(Status.REJECTED_NODELETE); @@ -259,6 +265,8 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen private String enableCapabilities(final ProgressMonitor monitor, OutputStream outputStream) { final StringBuilder line = new StringBuilder(); + if (atomic) + capableAtomic = wantCapability(line, CAPABILITY_ATOMIC); capableReport = wantCapability(line, CAPABILITY_REPORT_STATUS); capableDeleteRefs = wantCapability(line, CAPABILITY_DELETE_REFS); capableOfsDelta = wantCapability(line, CAPABILITY_OFS_DELTA); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java index 9721ee9eb0..b557812ad1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java @@ -47,6 +47,7 @@ import java.io.IOException; import java.io.OutputStream; import java.text.MessageFormat; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -183,6 +184,7 @@ class PushProcess { private Map prepareRemoteUpdates() throws TransportException { + boolean atomic = transport.isPushAtomic(); final Map result = new HashMap(); for (final RemoteRefUpdate rru : toPush.values()) { final Ref advertisedRef = connection.getRef(rru.getRemoteName()); @@ -205,6 +207,9 @@ class PushProcess { if (rru.isExpectingOldObjectId() && !rru.getExpectedOldObjectId().equals(advertisedOld)) { rru.setStatus(Status.REJECTED_REMOTE_CHANGED); + if (atomic) { + return rejectAll(); + } continue; } @@ -236,14 +241,28 @@ class PushProcess { JGitText.get().readingObjectsFromLocalRepositoryFailed, x.getMessage()), x); } rru.setFastForward(fastForward); - if (!fastForward && !rru.isForceUpdate()) + if (!fastForward && !rru.isForceUpdate()) { rru.setStatus(Status.REJECTED_NONFASTFORWARD); - else + if (atomic) { + return rejectAll(); + } + } else { result.put(rru.getRemoteName(), rru); + } } return result; } + private Map rejectAll() { + for (RemoteRefUpdate rru : toPush.values()) { + if (rru.getStatus() == Status.NOT_ATTEMPTED) { + rru.setStatus(RemoteRefUpdate.Status.REJECTED_OTHER_REASON); + rru.setMessage(JGitText.get().transactionAborted); + } + } + return Collections.emptyMap(); + } + private void modifyUpdatesForDryRun() { for (final RemoteRefUpdate rru : toPush.values()) if (rru.getStatus() == Status.NOT_ATTEMPTED) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java index cc7db47df5..6af153cbc9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java @@ -752,6 +752,9 @@ public abstract class Transport { /** Should push produce thin-pack when sending objects to remote repository. */ private boolean pushThin = DEFAULT_PUSH_THIN; + /** Should push be all-or-nothing atomic behavior? */ + private boolean pushAtomic; + /** Should push just check for operation result, not really push. */ private boolean dryRun; @@ -969,6 +972,31 @@ public abstract class Transport { this.pushThin = pushThin; } + /** + * Default setting is false. + * + * @return true if push requires all-or-nothing atomic behavior. + * @since 4.2 + */ + public boolean isPushAtomic() { + return pushAtomic; + } + + /** + * Request atomic push (all references succeed, or none do). + *

    + * Server must also support atomic push. If the server does not support the + * feature the push will abort without making changes. + * + * @param atomic + * true when push should be an all-or-nothing operation. + * @see PackTransport + * @since 4.2 + */ + public void setPushAtomic(final boolean atomic) { + this.pushAtomic = atomic; + } + /** * @return true if destination refs should be removed if they no longer * exist at the source repository. -- cgit v1.2.3 From ac89b47eeb3c843b2686739cc4ca75e7b14b7bbb Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Fri, 27 Nov 2015 11:02:32 +0100 Subject: Fix NPE in HttpAuthMethod If the password char array is null constructing a new String from this array fails with a NPE. Add a null check to fix this. Change-Id: Ifae6eecca38d5f114861f44658a32521e6e96866 Signed-off-by: Matthias Sohn --- org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java index 3594ea91b4..998f280014 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java @@ -219,7 +219,8 @@ abstract class HttpAuthMethod { if (credentialsProvider.supports(u, p) && credentialsProvider.get(uri, u, p)) { username = u.getValue(); - password = new String(p.getValue()); + char[] v = p.getValue(); + password = (v == null) ? null : new String(p.getValue()); p.clear(); } else return false; -- cgit v1.2.3 From e12482deed7b6120b4f65da042dc73912c4c4075 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Mon, 7 Dec 2015 12:56:32 -0800 Subject: Use runtime retention for Nullable annotation JGit's Nullable type was added[1] in the hope of being able to add nullness annotations that (a) do not preclude building and running with Java 7 and (b) could be shared by Gerrit, which uses a custom Nullable type for other reasons[2]. Sharing a type is useful because Eclipse's null analysis is only able to use one Nullable type at a time in a given workspace (so for this analysis to function in a workspace used to develop Gerrit, JGit and Gerrit would need to use the same Nullable type). The new Nullable type has CLASS instead of RUNTIME retention because there wasn't any obvious use for the annotation at run time. Gerrit uses the Nullable annotation to communicate with Guice. Guice injection happens at runtime, so it needs to be able to read the @Nullable annotations at run time[3]. Otherwise Guice produces provisioning errors, such as 3) null returned by binding at com.google.gerrit.lucene.LuceneChangeIndex$Factory.create() but parameter 7 of com.google.gerrit.lucene.LuceneChangeIndex.() is not @Nullable Switch to RUNTIME retention to avoid this. While at it, update the javadoc to explain more clearly how this annotation relates to other Nullable types[4]. This should make it clearer why JGit needed another Nullable type: A. Avoiding dependency on Java 8 B. RUNTIME retention to allow Guice to read the annotation at run time C. Named Nullable so Guice can recognize the annotation D. Not an addition to Java EE's javax.annotation package, to avoid the split-package problem[2] that prevents the annotation from being readable at run time when loaded from an OSGi container E. Avoiding heavyweight dependencies, deprecated dependencies, and dependencies on package internals org.checkerframework.checker.nullness.qual.Nullable: A com.sun.istack.internal.Nullable: B, E *.CheckForNull, *.NullAllowed, etc: C edu.umd.cs.findbugs.annotations.Nullable: B, E javax.annotation.Nullable: D org.eclipse.jdt.annotation.Nullable: B org.jetbrains.annotations.Nullable: B org.jmlspecs.annotation.Nullable: E android.annotation.Nullable, android.support.annotation.Nullable: E [1] https://git.eclipse.org/r/59993 [2] https://gerrit-review.googlesource.com/50112 [3] https://github.com/google/guice/blob/master/core/src/com/google/inject/internal/Nullability.java [4] https://github.com/typetools/checker-framework/blob/5832a01f1/checker/src/org/checkerframework/checker/nullness/NullnessAnnotatedTypeFactory.java#L118 http://types.cs.washington.edu/checker-framework/current/checker-framework-manual.html#nullness-related-work Change-Id: I6c482653d2b53e3509abb11211b67fc29cf2949c Signed-off-by: Jonathan Nieder --- .../src/org/eclipse/jgit/annotations/Nullable.java | 39 +++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java index 4275dc4fad..7b9156710f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java @@ -54,15 +54,46 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * JGit's replacement for the {@code javax.annotations.Nullable}. + * Marks types that can hold the value {@code null} at run time. *

    - * Denotes that a local variable, parameter, field, method return value can be - * {@code null}. + * Unlike {@code org.eclipse.jdt.annotation.Nullable}, this has run-time + * retention, allowing the annotation to be recognized by + * Guice. Unlike + * {@code javax.annotation.Nullable}, this does not involve importing new classes + * to a standard (Java EE) package, so it can be deployed in an OSGi container + * without running into + * split-package + * problems. + *

    + * You can use this annotation to qualify a type in a method signature or local + * variable declaration. The entity whose type has this annotation is allowed to + * hold the value {@code null} at run time. This allows annotation based null + * analysis to infer that + *

      + *
    • Binding a {@code null} value to the entity is legal. + *
    • Dereferencing the entity is unsafe and can trigger a + * {@code NullPointerException}. + *
    + *

    + * To avoid a dependency on Java 8, this annotation does not use + * {@link Target @Target} {@code TYPE_USE}. That may change when JGit starts + * requiring Java 8. + *

    + * Warning: Please do not use this annotation on arrays. Different + * annotation processors treat {@code @Nullable Object[]} differently: some + * treat it as an array of nullable objects, for consistency with versions of + * {@code Nullable} defined with {@code @Target} {@code TYPE_USE}, while others + * treat it as a nullable array of objects. JGit therefore avoids using this + * annotation on arrays altogether. + * + * @see + * The checker-framework manual * * @since 4.2 */ @Documented -@Retention(RetentionPolicy.CLASS) +@Retention(RetentionPolicy.RUNTIME) @Target({ FIELD, METHOD, PARAMETER, LOCAL_VARIABLE }) public @interface Nullable { // marker annotation with no members -- cgit v1.2.3 From e23521f0d9040d49dead2ce6fbfab6bde3b7b2c6 Mon Sep 17 00:00:00 2001 From: Kaloyan Raev Date: Mon, 6 Jan 2014 14:40:47 +0200 Subject: Add remote command to JGit CLI Supported subcommands are: - (lists available remotes) - add - remove - set-url - update Supported options are: --verbose --push --prune Bug: 481316 Change-Id: I57c34ed6daabb7d308bc383b17c1ef4af433e714 Signed-off-by: Kaloyan Raev Signed-off-by: Matthias Sohn --- .../tst/org/eclipse/jgit/pgm/RemoteTest.java | 159 +++++++++++++++++ .../services/org.eclipse.jgit.pgm.TextBuiltin | 1 + .../eclipse/jgit/pgm/internal/CLIText.properties | 3 + .../src/org/eclipse/jgit/pgm/Remote.java | 197 +++++++++++++++++++++ .../src/org/eclipse/jgit/pgm/internal/CLIText.java | 1 + .../jgit/api/AbstractRemoteCommandTest.java | 96 ++++++++++ .../org/eclipse/jgit/api/RemoteAddCommandTest.java | 81 +++++++++ .../eclipse/jgit/api/RemoteDeleteCommandTest.java | 68 +++++++ .../eclipse/jgit/api/RemoteListCommandTest.java | 68 +++++++ .../eclipse/jgit/api/RemoteSetUrlCommandTest.java | 100 +++++++++++ org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java | 44 ++++- .../src/org/eclipse/jgit/api/RemoteAddCommand.java | 133 ++++++++++++++ .../org/eclipse/jgit/api/RemoteListCommand.java | 91 ++++++++++ .../org/eclipse/jgit/api/RemoteRemoveCommand.java | 110 ++++++++++++ .../org/eclipse/jgit/api/RemoteSetUrlCommand.java | 155 ++++++++++++++++ .../src/org/eclipse/jgit/transport/URIish.java | 2 + 16 files changed, 1307 insertions(+), 2 deletions(-) create mode 100644 org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RemoteTest.java create mode 100644 org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AbstractRemoteCommandTest.java create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteAddCommandTest.java create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteDeleteCommandTest.java create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteListCommandTest.java create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteSetUrlCommandTest.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteAddCommand.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteListCommand.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RemoteTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RemoteTest.java new file mode 100644 index 0000000000..58e0e19f8d --- /dev/null +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RemoteTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2015, Kaloyan Raev + * 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.pgm; + + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.lib.CLIRepositoryTestCase; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.transport.RefSpec; +import org.eclipse.jgit.transport.RemoteConfig; +import org.eclipse.jgit.transport.URIish; +import org.junit.Before; +import org.junit.Test; + +public class RemoteTest extends CLIRepositoryTestCase { + + private StoredConfig config; + + private RemoteConfig remote; + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + + // create another repository + Repository remoteRepository = createWorkRepository(); + + // set it up as a remote to this repository + config = db.getConfig(); + remote = new RemoteConfig(config, "test"); + remote.addFetchRefSpec( + new RefSpec("+refs/heads/*:refs/remotes/test/*")); + URIish uri = new URIish( + remoteRepository.getDirectory().toURI().toURL()); + remote.addURI(uri); + remote.update(config); + config.save(); + + Git.wrap(remoteRepository).commit().setMessage("initial commit").call(); + } + + @Test + public void testList() throws Exception { + assertArrayEquals(new String[] { remote.getName(), "" }, + execute("git remote")); + } + + @Test + public void testVerboseList() throws Exception { + assertArrayEquals( + new String[] { + String.format("%s\t%s (fetch)", remote.getName(), + remote.getURIs().get(0)), + String.format("%s\t%s (push)", remote.getName(), + remote.getURIs().get(0)), + "" }, + execute("git remote -v")); + } + + @Test + public void testAdd() throws Exception { + assertArrayEquals(new String[] { "" }, + execute("git remote add second git://test.com/second")); + + List remotes = RemoteConfig.getAllRemoteConfigs(config); + assertEquals(2, remotes.size()); + assertEquals("second", remotes.get(0).getName()); + assertEquals("test", remotes.get(1).getName()); + } + + @Test + public void testRemove() throws Exception { + assertArrayEquals(new String[] { "" }, + execute("git remote remove test")); + + assertTrue(RemoteConfig.getAllRemoteConfigs(config).isEmpty()); + } + + @Test + public void testSetUrl() throws Exception { + assertArrayEquals(new String[] { "" }, + execute("git remote set-url test git://test.com/test")); + + RemoteConfig result = new RemoteConfig(config, "test"); + assertEquals("test", result.getName()); + assertArrayEquals(new URIish[] { new URIish("git://test.com/test") }, + result.getURIs().toArray()); + assertTrue(result.getPushURIs().isEmpty()); + } + + @Test + public void testSetUrlPush() throws Exception { + assertArrayEquals(new String[] { "" }, + execute("git remote set-url --push test git://test.com/test")); + + RemoteConfig result = new RemoteConfig(config, "test"); + assertEquals("test", result.getName()); + assertEquals(remote.getURIs(), result.getURIs()); + assertArrayEquals(new URIish[] { new URIish("git://test.com/test") }, + result.getPushURIs().toArray()); + } + + @Test + public void testUpdate() throws Exception { + assertArrayEquals(new String[] { + "From " + remote.getURIs().get(0).toString(), + " * [new branch] master -> test/master", "", "" }, + execute("git remote update test")); + } + +} diff --git a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin index e1b05491b7..c13f63e80f 100644 --- a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin +++ b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin @@ -24,6 +24,7 @@ org.eclipse.jgit.pgm.MergeBase org.eclipse.jgit.pgm.Push org.eclipse.jgit.pgm.ReceivePack org.eclipse.jgit.pgm.Reflog +org.eclipse.jgit.pgm.Remote org.eclipse.jgit.pgm.Repo org.eclipse.jgit.pgm.Reset org.eclipse.jgit.pgm.RevList diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties index 8aeb7e8753..335336da28 100644 --- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties +++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties @@ -188,6 +188,7 @@ treeIsRequired=argument tree is required tooManyRefsGiven=Too many refs given unknownIoErrorStdout=An unknown I/O error occurred on standard output unknownMergeStrategy=unknown merge strategy {0} specified +unknownSubcommand=Unknown subcommand: {0} unmergedPaths=Unmerged paths: unsupportedOperation=Unsupported operation: {0} untrackedFiles=Untracked files: @@ -222,6 +223,7 @@ usage_MergeBase=Find as good common ancestors as possible for a merge usage_MergesTwoDevelopmentHistories=Merges two development histories usage_ReadDirCache= Read the DirCache 100 times usage_RebuildCommitGraph=Recreate a repository from another one's commit graph +usage_Remote=Manage set of tracked repositories usage_RepositoryToReadFrom=Repository to read from usage_RepositoryToReceiveInto=Repository to receive into usage_RevList=List commit objects in reverse chronological order @@ -329,6 +331,7 @@ usage_performFsckStyleChecksOnReceive=perform fsck style checks on receive usage_portNumberToListenOn=port number to listen on usage_printOnlyBranchesThatContainTheCommit=print only branches that contain the commit usage_pruneStaleTrackingRefs=prune stale tracking refs +usage_pushUrls=push URLs are manipulated usage_quiet=don't show progress messages usage_recordChangesToRepository=Record changes to the repository usage_recurseIntoSubtrees=recurse into subtrees diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java new file mode 100644 index 0000000000..70868e920e --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2015, Kaloyan Raev + * 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.pgm; + +import java.io.IOException; +import java.io.StringWriter; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.RemoteAddCommand; +import org.eclipse.jgit.api.RemoteListCommand; +import org.eclipse.jgit.api.RemoteRemoveCommand; +import org.eclipse.jgit.api.RemoteSetUrlCommand; +import org.eclipse.jgit.api.errors.JGitInternalException; +import org.eclipse.jgit.pgm.internal.CLIText; +import org.eclipse.jgit.pgm.opt.CmdLineParser; +import org.eclipse.jgit.transport.RemoteConfig; +import org.eclipse.jgit.transport.URIish; +import org.eclipse.jgit.util.io.ThrowingPrintWriter; +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; + +@Command(common = false, usage = "usage_Remote") +class Remote extends TextBuiltin { + + @Option(name = "--verbose", aliases = { "-v" }, usage = "usage_beVerbose") + private boolean verbose = false; + + @Option(name = "--prune", aliases = { + "-p" }, usage = "usage_pruneStaleTrackingRefs") + private boolean prune; + + @Option(name = "--push", usage = "usage_pushUrls") + private boolean push; + + @Argument(index = 0, metaVar = "metaVar_command") + private String command; + + @Argument(index = 1, metaVar = "metaVar_remoteName") + private String name; + + @Argument(index = 2, metaVar = "metaVar_uriish") + private String uri; + + @Override + protected void run() throws Exception { + try (Git git = new Git(db)) { + if (command == null) { + RemoteListCommand cmd = git.remoteList(); + List remotes = cmd.call(); + print(remotes); + } else if ("add".equals(command)) { //$NON-NLS-1$ + RemoteAddCommand cmd = git.remoteAdd(); + cmd.setName(name); + cmd.setUri(new URIish(uri)); + cmd.call(); + } else if ("remove".equals(command) || "rm".equals(command)) { //$NON-NLS-1$ //$NON-NLS-2$ + RemoteRemoveCommand cmd = git.remoteRemove(); + cmd.setName(name); + cmd.call(); + } else if ("set-url".equals(command)) { //$NON-NLS-1$ + RemoteSetUrlCommand cmd = git.remoteSetUrl(); + cmd.setName(name); + cmd.setUri(new URIish(uri)); + cmd.setPush(push); + cmd.call(); + } else if ("update".equals(command)) { //$NON-NLS-1$ + // reuse fetch command for basic implementation of remote update + Fetch fetch = new Fetch(); + fetch.init(db, gitdir); + + // redirect the output stream + StringWriter osw = new StringWriter(); + fetch.outw = new ThrowingPrintWriter(osw); + // redirect the error stream + StringWriter esw = new StringWriter(); + fetch.errw = new ThrowingPrintWriter(esw); + + List fetchArgs = new ArrayList<>(); + if (verbose) { + fetchArgs.add("--verbose"); //$NON-NLS-1$ + } + if (prune) { + fetchArgs.add("--prune"); //$NON-NLS-1$ + } + if (name != null) { + fetchArgs.add(name); + } + + fetch.execute(fetchArgs.toArray(new String[fetchArgs.size()])); + + // flush the streams + fetch.outw.flush(); + fetch.errw.flush(); + outw.println(osw.toString()); + errw.println(esw.toString()); + } else { + throw new JGitInternalException(MessageFormat + .format(CLIText.get().unknownSubcommand, command)); + } + } + } + + @Override + public void printUsageAndExit(final String message, final CmdLineParser clp) + throws IOException { + errw.println(message); + errw.println("jgit remote [--verbose (-v)] [--help (-h)]"); //$NON-NLS-1$ + errw.println("jgit remote add name uri-ish [--help (-h)]"); //$NON-NLS-1$ + errw.println("jgit remote remove name [--help (-h)]"); //$NON-NLS-1$ + errw.println("jgit remote rm name [--help (-h)]"); //$NON-NLS-1$ + errw.println( + "jgit remote [--verbose (-v)] update [name] [--prune (-p)] [--help (-h)]"); //$NON-NLS-1$ + errw.println("jgit remote set-url name uri-ish [--push] [--help (-h)]"); //$NON-NLS-1$ + + errw.println(); + clp.printUsage(errw, getResourceBundle()); + errw.println(); + + errw.flush(); + throw die(true); + } + + private void print(List remotes) throws IOException { + for (RemoteConfig remote : remotes) { + String remoteName = remote.getName(); + if (verbose) { + List fetchURIs = remote.getURIs(); + List pushURIs = remote.getPushURIs(); + + String fetchURI = ""; //$NON-NLS-1$ + if (!fetchURIs.isEmpty()) { + fetchURI = fetchURIs.get(0).toString(); + } else if (!pushURIs.isEmpty()) { + fetchURI = pushURIs.get(0).toString(); + } + + String pushURI = ""; //$NON-NLS-1$ + if (!pushURIs.isEmpty()) { + pushURI = pushURIs.get(0).toString(); + } else if (!fetchURIs.isEmpty()) { + pushURI = fetchURIs.get(0).toString(); + } + + outw.println( + String.format("%s\t%s (fetch)", remoteName, fetchURI)); //$NON-NLS-1$ + outw.println( + String.format("%s\t%s (push)", remoteName, pushURI)); //$NON-NLS-1$ + } else { + outw.println(remoteName); + } + } + } + +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java index ce2b10c98e..f5d581ad01 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java @@ -247,6 +247,7 @@ public class CLIText extends TranslationBundle { /***/ public String treeIsRequired; /***/ public char[] unknownIoErrorStdout; /***/ public String unknownMergeStrategy; + /***/ public String unknownSubcommand; /***/ public String unmergedPaths; /***/ public String unsupportedOperation; /***/ public String untrackedFiles; diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AbstractRemoteCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AbstractRemoteCommandTest.java new file mode 100644 index 0000000000..d6a6342cb7 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AbstractRemoteCommandTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2015, Kaloyan Raev + * 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.api; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.net.URISyntaxException; + +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.transport.RefSpec; +import org.eclipse.jgit.transport.RemoteConfig; +import org.eclipse.jgit.transport.URIish; + +public class AbstractRemoteCommandTest extends RepositoryTestCase { + + protected static final String REMOTE_NAME = "test"; + + protected RemoteConfig setupRemote() + throws IOException, URISyntaxException { + // create another repository + Repository remoteRepository = createWorkRepository(); + + // set it up as a remote to this repository + final StoredConfig config = db.getConfig(); + RemoteConfig remoteConfig = new RemoteConfig(config, REMOTE_NAME); + + RefSpec refSpec = new RefSpec(); + refSpec = refSpec.setForceUpdate(true); + refSpec = refSpec.setSourceDestination(Constants.R_HEADS + "*", + Constants.R_REMOTES + REMOTE_NAME + "/*"); + remoteConfig.addFetchRefSpec(refSpec); + + URIish uri = new URIish( + remoteRepository.getDirectory().toURI().toURL()); + remoteConfig.addURI(uri); + + remoteConfig.update(config); + config.save(); + + return remoteConfig; + } + + protected void assertRemoteConfigEquals(RemoteConfig expected, + RemoteConfig actual) { + assertEquals(expected.getName(), actual.getName()); + assertEquals(expected.getURIs(), actual.getURIs()); + assertEquals(expected.getPushURIs(), actual.getPushURIs()); + assertEquals(expected.getFetchRefSpecs(), actual.getFetchRefSpecs()); + assertEquals(expected.getPushRefSpecs(), actual.getPushRefSpecs()); + } + +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteAddCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteAddCommandTest.java new file mode 100644 index 0000000000..ed0944676a --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteAddCommandTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2015, Kaloyan Raev + * 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.api; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.transport.RemoteConfig; +import org.eclipse.jgit.transport.URIish; +import org.junit.Test; + +public class RemoteAddCommandTest extends AbstractRemoteCommandTest { + + @Test + public void testAdd() throws Exception { + // create another repository + Repository remoteRepository = createWorkRepository(); + URIish uri = new URIish( + remoteRepository.getDirectory().toURI().toURL()); + + // execute the command to add a new remote + RemoteAddCommand cmd = Git.wrap(db).remoteAdd(); + cmd.setName(REMOTE_NAME); + cmd.setUri(uri); + RemoteConfig remote = cmd.call(); + + // assert that the added remote represents the remote repository + assertEquals(REMOTE_NAME, remote.getName()); + assertArrayEquals(new URIish[] { uri }, remote.getURIs().toArray()); + assertEquals(1, remote.getFetchRefSpecs().size()); + assertEquals( + String.format("+refs/heads/*:refs/remotes/%s/*", REMOTE_NAME), + remote.getFetchRefSpecs().get(0).toString()); + + // assert that the added remote is available in the git configuration + assertRemoteConfigEquals(remote, + new RemoteConfig(db.getConfig(), REMOTE_NAME)); + } + +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteDeleteCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteDeleteCommandTest.java new file mode 100644 index 0000000000..7055daff9a --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteDeleteCommandTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015, Kaloyan Raev + * 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.api; + +import static org.junit.Assert.assertTrue; + +import org.eclipse.jgit.transport.RemoteConfig; +import org.junit.Test; + +public class RemoteDeleteCommandTest extends AbstractRemoteCommandTest { + + @Test + public void testDelete() throws Exception { + // setup an initial remote + RemoteConfig remoteConfig = setupRemote(); + + // execute the command to remove the remote + RemoteRemoveCommand cmd = Git.wrap(db).remoteRemove(); + cmd.setName(REMOTE_NAME); + RemoteConfig remote = cmd.call(); + + // assert that the removed remote is the initial remote + assertRemoteConfigEquals(remoteConfig, remote); + // assert that there are no remotes left + assertTrue(RemoteConfig.getAllRemoteConfigs(db.getConfig()).isEmpty()); + } + +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteListCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteListCommandTest.java new file mode 100644 index 0000000000..cf522ff664 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteListCommandTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015, Kaloyan Raev + * 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.api; + +import static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.eclipse.jgit.transport.RemoteConfig; +import org.junit.Test; + +public class RemoteListCommandTest extends AbstractRemoteCommandTest { + + @Test + public void testList() throws Exception { + // setup an initial remote + RemoteConfig remoteConfig = setupRemote(); + + // execute the command to list the remotes + List remotes = Git.wrap(db).remoteList().call(); + + // assert that there is only one remote + assertEquals(1, remotes.size()); + // assert that the available remote is the initial remote + assertRemoteConfigEquals(remoteConfig, remotes.get(0)); + } + +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteSetUrlCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteSetUrlCommandTest.java new file mode 100644 index 0000000000..6969c3df6c --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteSetUrlCommandTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2015, Kaloyan Raev + * 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.api; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import org.eclipse.jgit.transport.RemoteConfig; +import org.eclipse.jgit.transport.URIish; +import org.junit.Test; + +public class RemoteSetUrlCommandTest extends AbstractRemoteCommandTest { + + @Test + public void testSetUrl() throws Exception { + // setup an initial remote + setupRemote(); + + // execute the command to change the fetch url + RemoteSetUrlCommand cmd = Git.wrap(db).remoteSetUrl(); + cmd.setName(REMOTE_NAME); + URIish newUri = new URIish("git://test.com/test"); + cmd.setUri(newUri); + RemoteConfig remote = cmd.call(); + + // assert that the changed remote has the new fetch url + assertEquals(REMOTE_NAME, remote.getName()); + assertArrayEquals(new URIish[] { newUri }, remote.getURIs().toArray()); + + // assert that the changed remote is available in the git configuration + assertRemoteConfigEquals(remote, + new RemoteConfig(db.getConfig(), REMOTE_NAME)); + } + + @Test + public void testSetPushUrl() throws Exception { + // setup an initial remote + RemoteConfig remoteConfig = setupRemote(); + + // execute the command to change the push url + RemoteSetUrlCommand cmd = Git.wrap(db).remoteSetUrl(); + cmd.setName(REMOTE_NAME); + URIish newUri = new URIish("git://test.com/test"); + cmd.setUri(newUri); + cmd.setPush(true); + RemoteConfig remote = cmd.call(); + + // assert that the changed remote has the old fetch url and the new push + // url + assertEquals(REMOTE_NAME, remote.getName()); + assertEquals(remoteConfig.getURIs(), remote.getURIs()); + assertArrayEquals(new URIish[] { newUri }, + remote.getPushURIs().toArray()); + + // assert that the changed remote is available in the git configuration + assertRemoteConfigEquals(remote, + new RemoteConfig(db.getConfig(), REMOTE_NAME)); + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java index addca4c469..2cd5f59a71 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java @@ -713,8 +713,48 @@ public class Git implements AutoCloseable { } /** - * @return the git repository this class is interacting with; see {@link - * #close()} for notes on closing this repository. + * Return a command used to list the available remotes. + * + * @return a {@link RemoteListCommand} + * @since 4.2 + */ + public RemoteListCommand remoteList() { + return new RemoteListCommand(repo); + } + + /** + * Return a command used to add a new remote. + * + * @return a {@link RemoteAddCommand} + * @since 4.2 + */ + public RemoteAddCommand remoteAdd() { + return new RemoteAddCommand(repo); + } + + /** + * Return a command used to remove an existing remote. + * + * @return a {@link RemoteRemoveCommand} + * @since 4.2 + */ + public RemoteRemoveCommand remoteRemove() { + return new RemoteRemoveCommand(repo); + } + + /** + * Return a command used to change the URL of an existing remote. + * + * @return a {@link RemoteSetUrlCommand} + * @since 4.2 + */ + public RemoteSetUrlCommand remoteSetUrl() { + return new RemoteSetUrlCommand(repo); + } + + /** + * @return the git repository this class is interacting with; see + * {@link #close()} for notes on closing this repository. */ public Repository getRepository() { return repo; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteAddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteAddCommand.java new file mode 100644 index 0000000000..679566903f --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteAddCommand.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2015, Kaloyan Raev + * 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.api; + +import java.io.IOException; +import java.net.URISyntaxException; + +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.api.errors.JGitInternalException; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.transport.RefSpec; +import org.eclipse.jgit.transport.RemoteConfig; +import org.eclipse.jgit.transport.URIish; + +/** + * Used to add a new remote. + * + * This class has setters for all supported options and arguments of this + * command and a {@link #call()} method to finally execute the command. + * + * @see Git + * documentation about Remote + * + * @since 4.2 + */ +public class RemoteAddCommand extends GitCommand { + + private String name; + + private URIish uri; + + /** + * @param repo + */ + protected RemoteAddCommand(Repository repo) { + super(repo); + } + + /** + * The name of the remote to add. + * + * @param name + * a remote name + */ + public void setName(String name) { + this.name = name; + } + + /** + * The URL of the repository for the new remote. + * + * @param uri + * an URL for the remote + */ + public void setUri(URIish uri) { + this.uri = uri; + } + + /** + * Executes the {@code remote add} command with all the options and + * parameters collected by the setter methods of this class. + * + * @return the {@link RemoteConfig} object of the added remote + */ + @Override + public RemoteConfig call() throws GitAPIException { + checkCallable(); + + try { + StoredConfig config = repo.getConfig(); + RemoteConfig remote = new RemoteConfig(config, name); + + RefSpec refSpec = new RefSpec(); + refSpec = refSpec.setForceUpdate(true); + refSpec = refSpec.setSourceDestination(Constants.R_HEADS + "*", //$NON-NLS-1$ + Constants.R_REMOTES + name + "/*"); //$NON-NLS-1$ + remote.addFetchRefSpec(refSpec); + + remote.addURI(uri); + + remote.update(config); + config.save(); + return remote; + } catch (IOException | URISyntaxException e) { + throw new JGitInternalException(e.getMessage(), e); + } + + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteListCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteListCommand.java new file mode 100644 index 0000000000..f778eaa28c --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteListCommand.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2015, Kaloyan Raev + * 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.api; + +import java.net.URISyntaxException; +import java.util.List; + +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.api.errors.JGitInternalException; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.transport.RemoteConfig; + +/** + * Used to obtain the list of remotes. + * + * This class has setters for all supported options and arguments of this + * command and a {@link #call()} method to finally execute the command. + * + * @see Git + * documentation about Remote + * + * @since 4.2 + */ +public class RemoteListCommand extends GitCommand> { + + /** + * @param repo + */ + protected RemoteListCommand(Repository repo) { + super(repo); + } + + /** + * Executes the {@code remote} command with all the options and parameters + * collected by the setter methods of this class. + * + * @return a list of {@link RemoteConfig} objects. + */ + @Override + public List call() throws GitAPIException { + checkCallable(); + + try { + return RemoteConfig.getAllRemoteConfigs(repo.getConfig()); + } catch (URISyntaxException e) { + throw new JGitInternalException(e.getMessage(), e); + } + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java new file mode 100644 index 0000000000..5782bf61b5 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2015, Kaloyan Raev + * 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.api; + +import java.io.IOException; +import java.net.URISyntaxException; + +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.api.errors.JGitInternalException; +import org.eclipse.jgit.lib.ConfigConstants; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.transport.RemoteConfig; + +/** + * Used to remove an existing remote. + * + * This class has setters for all supported options and arguments of this + * command and a {@link #call()} method to finally execute the command. + * + * @see Git + * documentation about Remote + * + * @since 4.2 + */ +public class RemoteRemoveCommand extends GitCommand { + + private String name; + + /** + * @param repo + */ + protected RemoteRemoveCommand(Repository repo) { + super(repo); + } + + /** + * The name of the remote to remove. + * + * @param name + * a remote name + */ + public void setName(String name) { + this.name = name; + } + + /** + * Executes the {@code remote} command with all the options and parameters + * collected by the setter methods of this class. + * + * @return the {@link RemoteConfig} object of the removed remote + */ + @Override + public RemoteConfig call() throws GitAPIException { + checkCallable(); + + try { + StoredConfig config = repo.getConfig(); + RemoteConfig remote = new RemoteConfig(config, name); + config.unsetSection(ConfigConstants.CONFIG_KEY_REMOTE, name); + config.save(); + return remote; + } catch (IOException | URISyntaxException e) { + throw new JGitInternalException(e.getMessage(), e); + } + + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java new file mode 100644 index 0000000000..6bd2ac7993 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2015, Kaloyan Raev + * 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.api; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.api.errors.JGitInternalException; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.transport.RemoteConfig; +import org.eclipse.jgit.transport.URIish; + +/** + * Used to to change the URL of a remote. + * + * This class has setters for all supported options and arguments of this + * command and a {@link #call()} method to finally execute the command. + * + * @see Git + * documentation about Remote + * + * @since 4.2 + */ +public class RemoteSetUrlCommand extends GitCommand { + + private String name; + + private URIish uri; + + private boolean push; + + /** + * @param repo + */ + protected RemoteSetUrlCommand(Repository repo) { + super(repo); + } + + /** + * The name of the remote to change the URL for. + * + * @param name + * a remote name + */ + public void setName(String name) { + this.name = name; + } + + /** + * The new URL for the remote. + * + * @param uri + * an URL for the remote + */ + public void setUri(URIish uri) { + this.uri = uri; + } + + /** + * Whether to change the push URL of the remote instead of the fetch URL. + * + * @param push + * true to set the push url, false to + * set the fetch url + */ + public void setPush(boolean push) { + this.push = push; + } + + /** + * Executes the {@code remote} command with all the options and parameters + * collected by the setter methods of this class. + * + * @return the {@link RemoteConfig} object of the modified remote + */ + @Override + public RemoteConfig call() throws GitAPIException { + checkCallable(); + + try { + StoredConfig config = repo.getConfig(); + RemoteConfig remote = new RemoteConfig(config, name); + if (push) { + List uris = remote.getPushURIs(); + if (uris.size() > 1) { + throw new JGitInternalException( + "remote.newtest.pushurl has multiple values"); //$NON-NLS-1$ + } else if (uris.size() == 1) { + remote.removePushURI(uris.get(0)); + } + remote.addPushURI(uri); + } else { + List uris = remote.getURIs(); + if (uris.size() > 1) { + throw new JGitInternalException( + "remote.newtest.url has multiple values"); //$NON-NLS-1$ + } else if (uris.size() == 1) { + remote.removeURI(uris.get(0)); + } + remote.addURI(uri); + } + + remote.update(config); + config.save(); + return remote; + } catch (IOException | URISyntaxException e) { + throw new JGitInternalException(e.getMessage(), e); + } + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java index 3700b49555..3c22b1cad6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java @@ -593,6 +593,8 @@ public class URIish implements Serializable { private static boolean eq(final String a, final String b) { if (a == b) return true; + if (StringUtils.isEmptyOrNull(a) && StringUtils.isEmptyOrNull(b)) + return true; if (a == null || b == null) return false; return a.equals(b); -- cgit v1.2.3 From 85d09a9ec7d599d0234efd53b924dc2767a3843b Mon Sep 17 00:00:00 2001 From: Andrey Loskutov Date: Mon, 30 Nov 2015 22:48:13 +0100 Subject: URIish: fixed full uri pattern not expecting end of line after host name Bug: 483326 Change-Id: I8b6e3eb648c8ec2c38f73de22382537b1276b779 Signed-off-by: Andrey Loskutov --- .../tst/org/eclipse/jgit/transport/URIishTest.java | 15 +++++++++++++++ .../src/org/eclipse/jgit/transport/URIish.java | 12 ++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java index 745c322013..76eb18afdf 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java @@ -928,4 +928,19 @@ public class URIishTest { } } } + + @Test + public void testStringConstructor() throws Exception { + String str = "http://example.com/"; + URIish u = new URIish(str); + assertEquals("example.com", u.getHost()); + assertEquals("/", u.getPath()); + assertEquals(str, u.toString()); + + str = "http://example.com"; + u = new URIish(str); + assertEquals("example.com", u.getHost()); + assertEquals("", u.getPath()); + assertEquals(str, u.toString()); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java index 3c22b1cad6..9aeb840ebe 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java @@ -137,7 +137,11 @@ public class URIish implements Serializable { + OPT_PORT_P // + "(" // open a group capturing the user-home-dir-part //$NON-NLS-1$ + (USER_HOME_P + "?") //$NON-NLS-1$ - + "[\\\\/])" //$NON-NLS-1$ + + "(?:" // start non capturing group for host //$NON-NLS-1$ + // separator or end of line + + "[\\\\/])|$" //$NON-NLS-1$ + + ")" // close non capturing group for the host//$NON-NLS-1$ + // separator or end of line + ")?" // close the optional group containing hostname //$NON-NLS-1$ + "(.+)?" //$NON-NLS-1$ + "$"); //$NON-NLS-1$ @@ -640,7 +644,7 @@ public class URIish implements Serializable { if (getPath() != null) { if (getScheme() != null) { - if (!getPath().startsWith("/")) //$NON-NLS-1$ + if (!getPath().startsWith("/") && !getPath().isEmpty()) //$NON-NLS-1$ r.append('/'); } else if (getHost() != null) r.append(':'); @@ -711,9 +715,9 @@ public class URIish implements Serializable { */ public String getHumanishName() throws IllegalArgumentException { String s = getPath(); - if ("/".equals(s)) //$NON-NLS-1$ + if ("/".equals(s) || "".equals(s)) //$NON-NLS-1$ s = getHost(); - if ("".equals(s) || s == null) //$NON-NLS-1$ + if (s == null) // $NON-NLS-1$ throw new IllegalArgumentException(); String[] elements; -- cgit v1.2.3 From 5b55498b16267102b021a47b3a7c0bdbfae63e71 Mon Sep 17 00:00:00 2001 From: Christian Halstrick Date: Wed, 2 Dec 2015 09:16:03 +0100 Subject: Fix FileTreeIterator.idSubmodule(Entry) FileTreeIterator was calling by mistake WorkingTreeIterator.idSubmodule(Entry). Instead it should always compute idSubmodule on its own. Change-Id: Id1b988aded06939b1d7edd2671e34bf756896c0e --- .../tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java | 2 +- .../src/org/eclipse/jgit/treewalk/FileTreeIterator.java | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java index 863d79ddee..3259f622f3 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java @@ -87,7 +87,7 @@ public class IndexDiffSubmoduleTest extends RepositoryTestCase { .call(); submodule_db = (FileRepository) Git.wrap(db).submoduleAdd() - .setPath("submodule") + .setPath("modules/submodule") .setURI(submoduleStandalone.getDirectory().toURI().toString()) .call(); submoduleStandalone.close(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java index 8d2cb1d8cd..accf4956f6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java @@ -67,8 +67,8 @@ import org.eclipse.jgit.util.FS; */ public class FileTreeIterator extends WorkingTreeIterator { /** - * the starting directory. This directory should correspond to the root of - * the repository. + * the starting directory of this Iterator. All entries are located directly + * in this directory. */ protected final File directory; @@ -238,8 +238,6 @@ public class FileTreeIterator extends WorkingTreeIterator { @Override protected byte[] idSubmodule(final Entry e) { - if (repository == null) - return idSubmodule(getDirectory(), e); - return super.idSubmodule(e); + return idSubmodule(getDirectory(), e); } } -- cgit v1.2.3 From 4f8c993c494f1708eef264ca6e6e5193513ab51b Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Sun, 13 Dec 2015 20:26:01 -0800 Subject: push: Do not blindly overwrite peer If an application uses PushConnection directly on the native Git wire protocols JGit should send along the application's expected oldId, not the advertised value. This allows the remote peer to compare-and-swap since it was not tested inside JGit. Discovered when I tried to use a PushConnection (bypassing the standard PushProcess) and the client blindly overwrote the remote reference, even though my app had supplied the wrong ObjectId for the expectedOldObjectId. This was not expected and cost me over an hour of debugging, plus "corruption" in the remote repository. By passing along the exact expectedOldObjectId from the app the remote side can do the check that the application skipped, and avoid data loss. Change-Id: Id3920837e6c47100376225bb4dd61fa3e88c64db --- .../eclipse/jgit/transport/PushConnectionTest.java | 143 +++++++++++++++++++++ .../jgit/transport/BasePackPushConnection.java | 8 +- .../org/eclipse/jgit/transport/PushProcess.java | 3 + .../eclipse/jgit/transport/RemoteRefUpdate.java | 6 +- 4 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java new file mode 100644 index 0000000000..a3b4134aea --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2015, Google Inc. + * 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.transport; + +import static org.eclipse.jgit.transport.RemoteRefUpdate.Status.REJECTED_OTHER_REASON; +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; +import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectInserter; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.transport.resolver.ReceivePackFactory; +import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; +import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class PushConnectionTest { + private URIish uri; + private TestProtocol testProtocol; + private Object ctx = new Object(); + private InMemoryRepository server; + private InMemoryRepository client; + private ObjectId obj1; + private ObjectId obj2; + private ObjectId obj3; + private String refName = "refs/tags/blob"; + + @Before + public void setUp() throws Exception { + server = newRepo("server"); + client = newRepo("client"); + testProtocol = new TestProtocol<>( + null, + new ReceivePackFactory() { + @Override + public ReceivePack create(Object req, Repository db) + throws ServiceNotEnabledException, + ServiceNotAuthorizedException { + return new ReceivePack(db); + } + }); + uri = testProtocol.register(ctx, server); + + try (ObjectInserter ins = server.newObjectInserter()) { + obj1 = ins.insert(Constants.OBJ_BLOB, Constants.encode("test")); + obj3 = ins.insert(Constants.OBJ_BLOB, Constants.encode("not")); + ins.flush(); + + RefUpdate u = server.updateRef(refName); + u.setNewObjectId(obj1); + assertEquals(RefUpdate.Result.NEW, u.update()); + } + + try (ObjectInserter ins = client.newObjectInserter()) { + obj2 = ins.insert(Constants.OBJ_BLOB, Constants.encode("file")); + ins.flush(); + } + } + + @After + public void tearDown() { + Transport.unregister(testProtocol); + } + + private static InMemoryRepository newRepo(String name) { + return new InMemoryRepository(new DfsRepositoryDescription(name)); + } + + @Test + public void testWrongOldIdDoesNotReplace() throws IOException { + RemoteRefUpdate rru = new RemoteRefUpdate(null, null, obj2, refName, + false, null, obj3); + + Map updates = new HashMap<>(); + updates.put(rru.getRemoteName(), rru); + + Transport tn = testProtocol.open(uri, client, "server"); + try { + PushConnection connection = tn.openPush(); + try { + connection.push(NullProgressMonitor.INSTANCE, updates); + } finally { + connection.close(); + } + } finally { + tn.close(); + } + + assertEquals(REJECTED_OTHER_REASON, rru.getStatus()); + assertEquals("invalid old id sent", rru.getMessage()); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java index f7bac6d060..0834c359aa 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java @@ -237,9 +237,11 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen } final StringBuilder sb = new StringBuilder(); - final Ref advertisedRef = getRef(rru.getRemoteName()); - final ObjectId oldId = (advertisedRef == null ? ObjectId.zeroId() - : advertisedRef.getObjectId()); + ObjectId oldId = rru.getExpectedOldObjectId(); + if (oldId == null) { + Ref adv = getRef(rru.getRemoteName()); + oldId = adv != null ? adv.getObjectId() : ObjectId.zeroId(); + } sb.append(oldId.name()); sb.append(' '); sb.append(rru.getNewObjectId().name()); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java index b557812ad1..4fd192dbb2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java @@ -212,6 +212,9 @@ class PushProcess { } continue; } + if (!rru.isExpectingOldObjectId()) { + rru.setExpectedOldObjectId(advertisedOld); + } // create ref (hasn't existed on remote side) and delete ref // are always fast-forward commands, feasible at this level diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java index 1b82a36105..5c58346189 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java @@ -125,7 +125,7 @@ public class RemoteRefUpdate { OK; } - private final ObjectId expectedOldObjectId; + private ObjectId expectedOldObjectId; private final ObjectId newObjectId; @@ -440,6 +440,10 @@ public class RemoteRefUpdate { return message; } + void setExpectedOldObjectId(ObjectId id) { + expectedOldObjectId = id; + } + void setStatus(final Status status) { this.status = status; } -- cgit v1.2.3