diff options
author | Matthias Sohn <matthias.sohn@sap.com> | 2022-09-06 15:58:47 +0200 |
---|---|---|
committer | Matthias Sohn <matthias.sohn@sap.com> | 2022-09-06 15:58:47 +0200 |
commit | 370d1170e8cb1b93120e19e50c0648605ed95b52 (patch) | |
tree | 02d1864c36dc3a9373c313d3fc195d9fe35a4bbe | |
parent | 7c4a5421ccd16b84b1ea4f3c1e566bfdf9c0e30d (diff) | |
parent | 57087e2b92dda967f6e5e0e0a017afae2f782a80 (diff) | |
download | jgit-370d1170e8cb1b93120e19e50c0648605ed95b52.tar.gz jgit-370d1170e8cb1b93120e19e50c0648605ed95b52.zip |
Merge branch 'master' into stable-6.3
* master:
Move WorkTreeUpdater to merge package
WorkTreeUpdater: use DirCacheCheckout#StreamSupplier
DirCacheCheckout#getContent: also take InputStream supplier
WorkTreeUpdater: remove safeWrite option
Change-Id: I8be570dbc4ad0d0b46046b85cbda24c3adcba170
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java | 14 | ||||
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java | 109 | ||||
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java | 8 | ||||
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/merge/WorkTreeUpdater.java (renamed from org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java) | 165 |
4 files changed, 110 insertions, 186 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java index 64fba98b49..e7f40d811b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java @@ -58,7 +58,6 @@ import org.eclipse.jgit.util.FS.ExecutionResult; import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.RawParseUtils; -import org.eclipse.jgit.util.WorkTreeUpdater; import org.eclipse.jgit.util.StringUtils; import org.eclipse.jgit.util.TemporaryBuffer; import org.eclipse.jgit.util.TemporaryBuffer.LocalFile; @@ -398,7 +397,7 @@ public class ApplyCommand extends GitCommand<ApplyResult> { } private void applyBinary(Repository repository, String path, File f, - FileHeader fh, WorkTreeUpdater.StreamSupplier loader, ObjectId id, + FileHeader fh, DirCacheCheckout.StreamSupplier loader, ObjectId id, CheckoutMetadata checkOut) throws PatchApplyException, IOException { if (!fh.getOldId().isComplete() || !fh.getNewId().isComplete()) { @@ -430,9 +429,7 @@ public class ApplyCommand extends GitCommand<ApplyResult> { hunk.getBuffer(), start, length))))) { DirCacheCheckout.getContent(repository, path, checkOut, - WorkTreeUpdater.createStreamLoader(() -> inflated, - hunk.getSize()), - null, out); + () -> inflated, null, out); if (!fh.getNewId().toObjectId().equals(hash.toObjectId())) { throw new PatchApplyException(MessageFormat.format( JGitText.get().applyBinaryResultOidWrong, @@ -463,8 +460,7 @@ public class ApplyCommand extends GitCommand<ApplyResult> { SHA1InputStream hashed = new SHA1InputStream(hash, input)) { DirCacheCheckout.getContent(repository, path, checkOut, - WorkTreeUpdater.createStreamLoader(() -> hashed, finalSize), - null, out); + () -> hashed, null, out); if (!fh.getNewId().toObjectId() .equals(hash.toObjectId())) { throw new PatchApplyException(MessageFormat.format( @@ -632,9 +628,7 @@ public class ApplyCommand extends GitCommand<ApplyResult> { } try (OutputStream output = new FileOutputStream(f)) { DirCacheCheckout.getContent(repository, path, checkOut, - WorkTreeUpdater.createStreamLoader(buffer::openInputStream, - buffer.length()), - null, output); + buffer::openInputStream, null, output); } } finally { buffer.destroy(); 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 2365c90d0d..1fb81b71e9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java @@ -21,6 +21,7 @@ import static org.eclipse.jgit.treewalk.TreeWalk.OperationType.CHECKOUT_OP; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.nio.file.StandardCopyOption; import java.text.MessageFormat; @@ -1605,6 +1606,60 @@ public class DirCacheCheckout { CheckoutMetadata checkoutMetadata, ObjectLoader ol, WorkingTreeOptions opt, OutputStream os) throws IOException { + getContent(repo, path, checkoutMetadata, ol::openStream, opt, os); + } + + + /** + * Something that can supply an {@link InputStream}. + * + * @since 6.3 + */ + public interface StreamSupplier { + + /** + * Loads the input stream. + * + * @return the loaded stream + * @throws IOException + * if any reading error occurs + */ + InputStream load() throws IOException; + } + + /** + * Return filtered content for blob contents. EOL handling and smudge-filter + * handling are applied in the same way as it would be done during a + * checkout. + * + * @param repo + * the repository + * @param path + * the path used to determine the correct filters for the object + * @param checkoutMetadata + * containing + * <ul> + * <li>smudgeFilterCommand to be run for smudging the object</li> + * <li>eolStreamType used for stream conversion (can be + * null)</li> + * </ul> + * @param inputStream + * A supplier for the raw content of the object. Each call should + * yield a fresh stream of the same object. + * @param opt + * the working tree options where only 'core.autocrlf' is used + * for EOL handling if 'checkoutMetadata.eolStreamType' is not + * valid + * @param os + * the output stream the filtered content is written to. The + * caller is responsible to close the stream. + * @throws IOException + * @since 6.3 + */ + public static void getContent(Repository repo, String path, + CheckoutMetadata checkoutMetadata, StreamSupplier inputStream, + WorkingTreeOptions opt, OutputStream os) + throws IOException { EolStreamType nonNullEolStreamType; if (checkoutMetadata.eolStreamType != null) { nonNullEolStreamType = checkoutMetadata.eolStreamType; @@ -1618,21 +1673,23 @@ public class DirCacheCheckout { if (checkoutMetadata.smudgeFilterCommand != null) { if (FilterCommandRegistry .isRegistered(checkoutMetadata.smudgeFilterCommand)) { - runBuiltinFilterCommand(repo, checkoutMetadata, ol, + runBuiltinFilterCommand(repo, checkoutMetadata, inputStream, channel); } else { - runExternalFilterCommand(repo, path, checkoutMetadata, ol, + runExternalFilterCommand(repo, path, checkoutMetadata, inputStream, channel); } } else { - ol.copyTo(channel); + try (InputStream in = inputStream.load()) { + in.transferTo(channel); + } } } } // Run an external filter command private static void runExternalFilterCommand(Repository repo, String path, - CheckoutMetadata checkoutMetadata, ObjectLoader ol, + CheckoutMetadata checkoutMetadata, StreamSupplier inputStream, OutputStream channel) throws IOException { FS fs = repo.getFS(); ProcessBuilder filterProcessBuilder = fs.runInShell( @@ -1644,7 +1701,9 @@ public class DirCacheCheckout { int rc; try { // TODO: wire correctly with AUTOCRLF - result = fs.execute(filterProcessBuilder, ol.openStream()); + try (InputStream in = inputStream.load()) { + result = fs.execute(filterProcessBuilder, in); + } rc = result.getRc(); if (rc == 0) { result.getStdout().writeTo(channel, @@ -1665,31 +1724,35 @@ public class DirCacheCheckout { // Run a builtin filter command private static void runBuiltinFilterCommand(Repository repo, - CheckoutMetadata checkoutMetadata, ObjectLoader ol, + CheckoutMetadata checkoutMetadata, StreamSupplier inputStream, OutputStream channel) throws MissingObjectException, IOException { boolean isMandatory = repo.getConfig().getBoolean( ConfigConstants.CONFIG_FILTER_SECTION, ConfigConstants.CONFIG_SECTION_LFS, ConfigConstants.CONFIG_KEY_REQUIRED, false); FilterCommand command = null; - try { - command = FilterCommandRegistry.createFilterCommand( - checkoutMetadata.smudgeFilterCommand, repo, ol.openStream(), - channel); - } catch (IOException e) { - LOG.error(JGitText.get().failedToDetermineFilterDefinition, e); - if (!isMandatory) { - // In case an IOException occurred during creating of the - // command then proceed as if there would not have been a - // builtin filter (only if the filter is not mandatory). - ol.copyTo(channel); - } else { - throw e; + try (InputStream in = inputStream.load()) { + try { + command = FilterCommandRegistry.createFilterCommand( + checkoutMetadata.smudgeFilterCommand, repo, in, + channel); + } catch (IOException e) { + LOG.error(JGitText.get().failedToDetermineFilterDefinition, e); + if (!isMandatory) { + // In case an IOException occurred during creating of the + // command then proceed as if there would not have been a + // builtin filter (only if the filter is not mandatory). + try (InputStream again = inputStream.load()) { + again.transferTo(channel); + } + } else { + throw e; + } } - } - if (command != null) { - while (command.run() != -1) { - // loop as long as command.run() tells there is work to do + if (command != null) { + while (command.run() != -1) { + // loop as long as command.run() tells there is work to do + } } } } 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 d79f5d4100..23f8e4a5d5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java @@ -60,8 +60,6 @@ import org.eclipse.jgit.treewalk.WorkingTreeIterator; import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.LfsFactory; -import org.eclipse.jgit.util.WorkTreeUpdater; -import org.eclipse.jgit.util.WorkTreeUpdater.StreamLoader; import org.eclipse.jgit.util.TemporaryBuffer; /** @@ -912,10 +910,8 @@ public class ResolveMerger extends ThreeWayMerger { if (!fs.exists(parentFolder)) { parentFolder.mkdirs(); } - StreamLoader contentLoader = WorkTreeUpdater.createStreamLoader(rawMerged::openInputStream, - rawMerged.length()); - workTreeUpdater.updateFileWithContent(contentLoader, - eol, tw.getSmudgeCommand(attributes), of.getPath(), of, false); + workTreeUpdater.updateFileWithContent(rawMerged::openInputStream, + eol, tw.getSmudgeCommand(attributes), of.getPath(), of); return of; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/WorkTreeUpdater.java index e5de2b4a7d..1db9bc659c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/WorkTreeUpdater.java @@ -7,19 +7,16 @@ * * SPDX-License-Identifier: BSD-3-Clause */ -package org.eclipse.jgit.util; +package org.eclipse.jgit.merge; import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; -import java.io.BufferedInputStream; import java.io.Closeable; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; import java.time.Instant; import java.util.HashMap; import java.util.LinkedList; @@ -36,25 +33,23 @@ import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheBuildIterator; import org.eclipse.jgit.dircache.DirCacheBuilder; import org.eclipse.jgit.dircache.DirCacheCheckout; +import org.eclipse.jgit.dircache.DirCacheCheckout.StreamSupplier; import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata; import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.errors.IndexWriteException; -import org.eclipse.jgit.errors.LargeObjectException; import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.ConfigConstants; -import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.CoreConfig.EolStreamType; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectInserter; -import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.lib.ObjectReader; -import org.eclipse.jgit.lib.ObjectStream; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.treewalk.TreeWalk.OperationType; import org.eclipse.jgit.treewalk.WorkingTreeOptions; +import org.eclipse.jgit.util.LfsFactory; import org.eclipse.jgit.util.LfsFactory.LfsInputStream; import org.eclipse.jgit.util.io.EolStreamTypeUtil; @@ -64,10 +59,8 @@ import org.eclipse.jgit.util.io.EolStreamTypeUtil; * You should use a single instance for all of your file changes. In case of an * error, make sure your instance is released, and initiate a new one if * necessary. - * - * @since 6.3 */ -public class WorkTreeUpdater implements Closeable { +class WorkTreeUpdater implements Closeable { /** * The result of writing the index changes. @@ -247,77 +240,6 @@ public class WorkTreeUpdater implements Closeable { return new WorkTreeUpdater(repo, dirCache, oi); } - /** - * Something that can supply an {@link InputStream}. - */ - public interface StreamSupplier { - - /** - * Loads the input stream. - * - * @return the loaded stream - * @throws IOException - * if any reading error occurs - */ - InputStream load() throws IOException; - } - - /** - * We want to use DirCacheCheckout for its CR-LF and smudge filters, but DirCacheCheckout needs an - * ObjectLoader rather than InputStream. This class provides a bridge between the two. - */ - public static class StreamLoader extends ObjectLoader { - - private final StreamSupplier data; - - private final long size; - - private StreamLoader(StreamSupplier data, long length) { - this.data = data; - this.size = length; - } - - @Override - public int getType() { - return Constants.OBJ_BLOB; - } - - @Override - public long getSize() { - return size; - } - - @Override - public boolean isLarge() { - return true; - } - - @Override - public byte[] getCachedBytes() throws LargeObjectException { - throw new LargeObjectException(); - } - - @Override - public ObjectStream openStream() throws IOException { - return new ObjectStream.Filter(getType(), getSize(), - new BufferedInputStream(data.load())); - } - } - - /** - * Creates stream loader for the given supplier. - * - * @param supplier - * to wrap - * @param length - * of the supplied content - * @return the result stream loader - */ - public static StreamLoader createStreamLoader(StreamSupplier supplier, - long length) { - return new StreamLoader(supplier, length); - } - private static int getInCoreFileSizeLimit(Config config) { return config.getInt(ConfigConstants.CONFIG_MERGE_SECTION, ConfigConstants.CONFIG_KEY_IN_CORE_LIMIT, 10 << 20); @@ -601,8 +523,8 @@ public class WorkTreeUpdater implements Closeable { /** * Updates the file in the checkout with the given content. * - * @param resultStreamLoader - * with the content to be updated + * @param inputStream + * the content to be updated * @param streamType * for parsing the content * @param smudgeCommand @@ -611,40 +533,21 @@ public class WorkTreeUpdater implements Closeable { * of the file to be updated * @param file * to be updated - * @param safeWrite - * whether the content should be written to a buffer first * @throws IOException * if the file cannot be updated */ - public void updateFileWithContent(StreamLoader resultStreamLoader, + public void updateFileWithContent(StreamSupplier inputStream, EolStreamType streamType, String smudgeCommand, String path, - File file, boolean safeWrite) throws IOException { + File file) throws IOException { if (inCore) { return; } CheckoutMetadata metadata = new CheckoutMetadata(streamType, smudgeCommand); - if (safeWrite) { - // Write to a buffer and copy to the file only if everything was - // fine. - TemporaryBuffer buffer = new TemporaryBuffer.LocalFile(null); - try { - try (TemporaryBuffer buf = buffer) { - DirCacheCheckout.getContent(repo, path, metadata, - resultStreamLoader, workingTreeOptions, buf); - } - try (InputStream bufIn = buffer.openInputStream()) { - Files.copy(bufIn, file.toPath(), - StandardCopyOption.REPLACE_EXISTING); - } - } finally { - buffer.destroy(); - } - return; - } + try (OutputStream outputStream = new FileOutputStream(file)) { DirCacheCheckout.getContent(repo, path, metadata, - resultStreamLoader, workingTreeOptions, outputStream); + inputStream, workingTreeOptions, outputStream); } } @@ -652,38 +555,8 @@ public class WorkTreeUpdater implements Closeable { * Creates a path with the given content, and adds it to the specified stage * to the index builder. * - * @param inputStream - * with the content to be updated - * @param path - * of the file to be updated - * @param fileMode - * of the modified file - * @param entryStage - * of the new entry - * @param lastModified - * instant of the modified file - * @param len - * of the content - * @param lfsAttribute - * for checking for LFS enablement - * @return the entry which was added to the index - * @throws IOException - * if inserting the content fails - */ - public DirCacheEntry insertToIndex(InputStream inputStream, byte[] path, - FileMode fileMode, int entryStage, Instant lastModified, int len, - Attribute lfsAttribute) throws IOException { - StreamLoader contentLoader = createStreamLoader(() -> inputStream, len); - return insertToIndex(contentLoader, path, fileMode, entryStage, - lastModified, len, lfsAttribute); - } - - /** - * Creates a path with the given content, and adds it to the specified stage - * to the index builder. - * - * @param resultStreamLoader - * with the content to be updated + * @param input + * the content to be updated * @param path * of the file to be updated * @param fileMode @@ -700,13 +573,12 @@ public class WorkTreeUpdater implements Closeable { * @throws IOException * if inserting the content fails */ - public DirCacheEntry insertToIndex(StreamLoader resultStreamLoader, + public DirCacheEntry insertToIndex(InputStream input, byte[] path, FileMode fileMode, int entryStage, Instant lastModified, int len, Attribute lfsAttribute) throws IOException { - return addExistingToIndex( - insertResult(resultStreamLoader, lfsAttribute), path, fileMode, - entryStage, lastModified, len); + return addExistingToIndex(insertResult(input, lfsAttribute, len), path, + fileMode, entryStage, lastModified, len); } /** @@ -734,16 +606,15 @@ public class WorkTreeUpdater implements Closeable { dce.setLastModified(lastModified); } dce.setLength(inCore ? 0 : len); - dce.setObjectId(objectId); builder.add(dce); return dce; } - private ObjectId insertResult(StreamLoader resultStreamLoader, - Attribute lfsAttribute) throws IOException { + private ObjectId insertResult(InputStream input, + Attribute lfsAttribute, long length) throws IOException { try (LfsInputStream is = LfsFactory.getInstance().applyCleanFilter(repo, - resultStreamLoader.data.load(), resultStreamLoader.size, + input, length, lfsAttribute)) { return inserter.insert(OBJ_BLOB, is.getLength(), is); } |