Merge "WorkTreeUpdater: re-format and clean-up"

This commit is contained in:
Han-Wen NIenhuys 2022-08-18 11:22:46 -04:00 committed by Gerrit Code Review @ Eclipse.org
commit d718127a7e
1 changed files with 257 additions and 213 deletions

View File

@ -25,7 +25,10 @@
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.TreeMap; import java.util.TreeMap;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.attributes.Attribute; import org.eclipse.jgit.attributes.Attribute;
import org.eclipse.jgit.attributes.Attributes; import org.eclipse.jgit.attributes.Attributes;
@ -96,43 +99,48 @@ public static class Result {
private final Repository repo; private final Repository repo;
/** /**
* Set to true if this operation should work in-memory. The repo's dircache and * Set to true if this operation should work in-memory. The repo's dircache
* workingtree are not touched by this method. Eventually needed files are * and workingtree are not touched by this method. Eventually needed files
* created as temporary files and a new empty, in-memory dircache will be * are created as temporary files and a new empty, in-memory dircache will
* used instead the repo's one. Often used for bare repos where the repo * be used instead the repo's one. Often used for bare repos where the repo
* doesn't even have a workingtree and dircache. * doesn't even have a workingtree and dircache.
*/ */
private final boolean inCore; private final boolean inCore;
private final ObjectInserter inserter; private final ObjectInserter inserter;
private final ObjectReader reader; private final ObjectReader reader;
private DirCache dirCache; private DirCache dirCache;
private boolean implicitDirCache = false; private boolean implicitDirCache = false;
/** /**
* Builder to update the dir cache during this operation. * Builder to update the dir cache during this operation.
*/ */
private DirCacheBuilder builder = null; private DirCacheBuilder builder;
/** /**
* The {@link WorkingTreeOptions} are needed to determine line endings for affected files. * The {@link WorkingTreeOptions} are needed to determine line endings for
* affected files.
*/ */
private WorkingTreeOptions workingTreeOptions; private WorkingTreeOptions workingTreeOptions;
/** /**
* The size limit (bytes) which controls a file to be stored in {@code Heap} or {@code LocalFile} * The size limit (bytes) which controls a file to be stored in {@code Heap}
* during the operation. * or {@code LocalFile} during the operation.
*/ */
private int inCoreFileSizeLimit; private int inCoreFileSizeLimit;
/** /**
* If the operation has nothing to do for a file but check it out at the end of the operation, it * If the operation has nothing to do for a file but check it out at the end
* can be added here. * of the operation, it can be added here.
*/ */
private final Map<String, DirCacheEntry> toBeCheckedOut = new HashMap<>(); private final Map<String, DirCacheEntry> toBeCheckedOut = new HashMap<>();
/** /**
* Files in this list will be deleted from the local copy at the end of the operation. * Files in this list will be deleted from the local copy at the end of the
* operation.
*/ */
private final TreeMap<String, File> toBeDeleted = new TreeMap<>(); private final TreeMap<String, File> toBeDeleted = new TreeMap<>();
@ -147,46 +155,56 @@ public static class Result {
private Map<String, CheckoutMetadata> cleanupMetadata; private Map<String, CheckoutMetadata> cleanupMetadata;
/** /**
* Whether the changes were successfully written * Whether the changes were successfully written.
*/ */
private boolean indexChangesWritten = false; private boolean indexChangesWritten;
/** /**
* @param repo the {@link org.eclipse.jgit.lib.Repository}. * @param repo
* @param dirCache if set, use the provided dir cache. Otherwise, use the default repository one * the {@link Repository}.
* @param dirCache
* if set, use the provided dir cache. Otherwise, use the default
* repository one
*/ */
private WorkTreeUpdater( private WorkTreeUpdater(Repository repo, DirCache dirCache) {
Repository repo,
DirCache dirCache) {
this.repo = repo; this.repo = repo;
this.dirCache = dirCache; this.dirCache = dirCache;
this.inCore = false; this.inCore = false;
this.inserter = repo.newObjectInserter(); this.inserter = repo.newObjectInserter();
this.reader = inserter.newReader(); this.reader = inserter.newReader();
this.workingTreeOptions = repo.getConfig().get(WorkingTreeOptions.KEY); Config config = repo.getConfig();
this.workingTreeOptions = config.get(WorkingTreeOptions.KEY);
this.inCoreFileSizeLimit = getInCoreFileSizeLimit(config);
this.checkoutMetadata = new HashMap<>(); this.checkoutMetadata = new HashMap<>();
this.cleanupMetadata = new HashMap<>(); this.cleanupMetadata = new HashMap<>();
this.inCoreFileSizeLimit = setInCoreFileSizeLimit(repo.getConfig());
} }
/** /**
* @param repo the {@link org.eclipse.jgit.lib.Repository}. * Creates a new {@link WorkTreeUpdater} for the given repository.
* @param dirCache if set, use the provided dir cache. Otherwise, use the default repository one *
* @return an IO handler. * @param repo
* the {@link Repository}.
* @param dirCache
* if set, use the provided dir cache. Otherwise, use the default
* repository one
* @return the {@link WorkTreeUpdater}.
*/ */
public static WorkTreeUpdater createWorkTreeUpdater(Repository repo, DirCache dirCache) { public static WorkTreeUpdater createWorkTreeUpdater(Repository repo,
DirCache dirCache) {
return new WorkTreeUpdater(repo, dirCache); return new WorkTreeUpdater(repo, dirCache);
} }
/** /**
* @param repo the {@link org.eclipse.jgit.lib.Repository}. * @param repo
* @param dirCache if set, use the provided dir cache. Otherwise, creates a new one * the {@link Repository}.
* @param oi to use for writing the modified objects with. * @param dirCache
* if set, use the provided dir cache. Otherwise, creates a new
* one
* @param oi
* to use for writing the modified objects with.
*/ */
private WorkTreeUpdater( private WorkTreeUpdater(Repository repo, DirCache dirCache,
Repository repo,
DirCache dirCache,
ObjectInserter oi) { ObjectInserter oi) {
this.repo = repo; this.repo = repo;
this.dirCache = dirCache; this.dirCache = dirCache;
@ -195,18 +213,24 @@ private WorkTreeUpdater(
this.inCore = true; this.inCore = true;
this.reader = oi.newReader(); this.reader = oi.newReader();
if (repo != null) { if (repo != null) {
this.inCoreFileSizeLimit = setInCoreFileSizeLimit(repo.getConfig()); this.inCoreFileSizeLimit = getInCoreFileSizeLimit(repo.getConfig());
} }
} }
/** /**
* @param repo the {@link org.eclipse.jgit.lib.Repository}. * Creates a new {@link WorkTreeUpdater} that works in memory only.
* @param dirCache if set, use the provided dir cache. Otherwise, creates a new one *
* @param oi to use for writing the modified objects with. * @param repo
* @return an IO handler. * the {@link Repository}.
* @param dirCache
* if set, use the provided dir cache. Otherwise, creates a new
* one
* @param oi
* to use for writing the modified objects with.
* @return the {@link WorkTreeUpdater}
*/ */
public static WorkTreeUpdater createInCoreWorkTreeUpdater(Repository repo, DirCache dirCache, public static WorkTreeUpdater createInCoreWorkTreeUpdater(Repository repo,
ObjectInserter oi) { DirCache dirCache, ObjectInserter oi) {
return new WorkTreeUpdater(repo, dirCache, oi); return new WorkTreeUpdater(repo, dirCache, oi);
} }
@ -219,17 +243,15 @@ public interface StreamSupplier {
* Loads the input stream. * Loads the input stream.
* *
* @return the loaded stream * @return the loaded stream
* @throws IOException if any reading error occurs * @throws IOException
* if any reading error occurs
*/ */
InputStream load() throws IOException; InputStream load() throws IOException;
} }
/** /**
* We write the patch result to a {@link org.eclipse.jgit.util.TemporaryBuffer} and then use * We want to use DirCacheCheckout for its CR-LF and smudge filters, but DirCacheCheckout needs an
* {@link DirCacheCheckout}.getContent() to run the result through the CR-LF and smudge filters. * ObjectLoader rather than InputStream. This class provides a bridge between the two.
* DirCacheCheckout needs an ObjectLoader, not a TemporaryBuffer, so this class bridges between
* the two, making any Stream provided by a {@link StreamSupplier} look like an ordinary git blob
* to DirCacheCheckout.
*/ */
public static class StreamLoader extends ObjectLoader { public static class StreamLoader extends ObjectLoader {
@ -264,24 +286,28 @@ public byte[] getCachedBytes() throws LargeObjectException {
@Override @Override
public ObjectStream openStream() throws IOException { public ObjectStream openStream() throws IOException {
return new ObjectStream.Filter(getType(), getSize(), new BufferedInputStream(data.load())); return new ObjectStream.Filter(getType(), getSize(),
new BufferedInputStream(data.load()));
} }
} }
/** /**
* Creates stream loader for the given supplier. * Creates stream loader for the given supplier.
* *
* @param supplier to wrap * @param supplier
* @param length of the supplied content * to wrap
* @param length
* of the supplied content
* @return the result stream loader * @return the result stream loader
*/ */
public static StreamLoader createStreamLoader(StreamSupplier supplier, long length) { public static StreamLoader createStreamLoader(StreamSupplier supplier,
long length) {
return new StreamLoader(supplier, length); return new StreamLoader(supplier, length);
} }
private static int setInCoreFileSizeLimit(Config config) { private static int getInCoreFileSizeLimit(Config config) {
return config.getInt( return config.getInt(ConfigConstants.CONFIG_MERGE_SECTION,
ConfigConstants.CONFIG_MERGE_SECTION, ConfigConstants.CONFIG_KEY_IN_CORE_LIMIT, 10 << 20); ConfigConstants.CONFIG_KEY_IN_CORE_LIMIT, 10 << 20);
} }
/** /**
@ -297,7 +323,8 @@ public int getInCoreFileSizeLimit() {
* Gets dir cache for the repo. Locked if not inCore. * Gets dir cache for the repo. Locked if not inCore.
* *
* @return the result dir cache * @return the result dir cache
* @throws IOException is case the dir cache cannot be read * @throws IOException
* is case the dir cache cannot be read
*/ */
public DirCache getLockedDirCache() throws IOException { public DirCache getLockedDirCache() throws IOException {
if (dirCache == null) { if (dirCache == null) {
@ -305,7 +332,7 @@ public DirCache getLockedDirCache() throws IOException {
if (inCore) { if (inCore) {
dirCache = DirCache.newInCore(); dirCache = DirCache.newInCore();
} else { } else {
dirCache = nonNullNonBareRepo().lockDirCache(); dirCache = nonNullRepo().lockDirCache();
} }
} }
if (builder == null) { if (builder == null) {
@ -315,21 +342,25 @@ public DirCache getLockedDirCache() throws IOException {
} }
/** /**
* Creates build iterator for the handler's builder. * Creates a {@link DirCacheBuildIterator} for the builder of this
* {@link WorkTreeUpdater}.
* *
* @return the iterator * @return the {@link DirCacheBuildIterator}
*/ */
public DirCacheBuildIterator createDirCacheBuildIterator() { public DirCacheBuildIterator createDirCacheBuildIterator() {
return new DirCacheBuildIterator(builder); return new DirCacheBuildIterator(builder);
} }
/** /**
* Writes the changes to the WorkTree (but not the index). * Writes the changes to the working tree (but not to the index).
* *
* @param shouldCheckoutTheirs before committing the changes * @param shouldCheckoutTheirs
* @throws IOException if any of the writes fail * before committing the changes
* @throws IOException
* if any of the writes fail
*/ */
public void writeWorkTreeChanges(boolean shouldCheckoutTheirs) throws IOException { public void writeWorkTreeChanges(boolean shouldCheckoutTheirs)
throws IOException {
handleDeletedFiles(); handleDeletedFiles();
if (inCore) { if (inCore) {
@ -356,8 +387,9 @@ public void writeWorkTreeChanges(boolean shouldCheckoutTheirs) throws IOExceptio
/** /**
* Writes the changes to the index. * Writes the changes to the index.
* *
* @return the Result of the operation. * @return the {@link Result} of the operation.
* @throws IOException if any of the writes fail * @throws IOException
* if any of the writes fail
*/ */
public Result writeIndexChanges() throws IOException { public Result writeIndexChanges() throws IOException {
result.treeId = getLockedDirCache().writeTree(inserter); result.treeId = getLockedDirCache().writeTree(inserter);
@ -366,32 +398,42 @@ public Result writeIndexChanges() throws IOException {
} }
/** /**
* Adds a {@link DirCacheEntry} for direct checkout and remembers its {@link CheckoutMetadata}. * Adds a {@link DirCacheEntry} for direct checkout and remembers its
* {@link CheckoutMetadata}.
* *
* @param path of the entry * @param path
* @param entry to add * of the entry
* @param cleanupStreamType to use for the cleanup metadata * @param entry
* @param cleanupSmudgeCommand to use for the cleanup metadata * to add
* @param checkoutStreamType to use for the checkout metadata * @param cleanupStreamType
* @param checkoutSmudgeCommand to use for the checkout metadata * to use for the cleanup metadata
* @since 6.1 * @param cleanupSmudgeCommand
* to use for the cleanup metadata
* @param checkoutStreamType
* to use for the checkout metadata
* @param checkoutSmudgeCommand
* to use for the checkout metadata
*/ */
public void addToCheckout( public void addToCheckout(String path, DirCacheEntry entry,
String path, DirCacheEntry entry, EolStreamType cleanupStreamType, EolStreamType cleanupStreamType, String cleanupSmudgeCommand,
String cleanupSmudgeCommand, EolStreamType checkoutStreamType, String checkoutSmudgeCommand) { EolStreamType checkoutStreamType, String checkoutSmudgeCommand) {
if (entry != null) { if (entry != null) {
// In some cases, we just want to add the metadata. // In some cases, we just want to add the metadata.
toBeCheckedOut.put(path, entry); toBeCheckedOut.put(path, entry);
} }
addCheckoutMetadata(cleanupMetadata, path, cleanupStreamType, cleanupSmudgeCommand); addCheckoutMetadata(cleanupMetadata, path, cleanupStreamType,
addCheckoutMetadata(checkoutMetadata, path, checkoutStreamType, checkoutSmudgeCommand); cleanupSmudgeCommand);
addCheckoutMetadata(checkoutMetadata, path, checkoutStreamType,
checkoutSmudgeCommand);
} }
/** /**
* Get a map which maps the paths of files which have to be checked out because the operation * Gets a map which maps the paths of files which have to be checked out
* created new fully-merged content for this file into the index. * because the operation created new fully-merged content for this file into
* * the index.
* <p>This means: the operation wrote a new stage 0 entry for this path.</p> * <p>
* This means: the operation wrote a new stage 0 entry for this path.
* </p>
* *
* @return the map * @return the map
*/ */
@ -400,37 +442,43 @@ public Map<String, DirCacheEntry> getToBeCheckedOut() {
} }
/** /**
* Deletes the given file * Remembers the given file to be deleted.
* <p> * <p>
* Note the actual deletion is only done in {@link #writeWorkTreeChanges} * Note the actual deletion is only done in {@link #writeWorkTreeChanges}.
* *
* @param path of the file to be deleted * @param path
* @param file to be deleted * of the file to be deleted
* @param streamType to use for cleanup metadata * @param file
* @param smudgeCommand to use for cleanup metadata * to be deleted
* @throws IOException if the file cannot be deleted * @param streamType
* to use for cleanup metadata
* @param smudgeCommand
* to use for cleanup metadata
*/ */
public void deleteFile(String path, File file, EolStreamType streamType, String smudgeCommand) public void deleteFile(String path, File file, EolStreamType streamType,
throws IOException { String smudgeCommand) {
toBeDeleted.put(path, file); toBeDeleted.put(path, file);
if (file != null && file.isFile()) { if (file != null && file.isFile()) {
addCheckoutMetadata(cleanupMetadata, path, streamType, smudgeCommand); addCheckoutMetadata(cleanupMetadata, path, streamType,
smudgeCommand);
} }
} }
/** /**
* Remembers the {@link CheckoutMetadata} for the given path; it may be needed in {@link * Remembers the {@link CheckoutMetadata} for the given path; it may be
* #checkout()} or in {@link #revertModifiedFiles()}. * needed in {@link #checkout()} or in {@link #revertModifiedFiles()}.
* *
* @param map to add the metadata to * @param map
* @param path of the current node * to add the metadata to
* @param streamType to use for the metadata * @param path
* @param smudgeCommand to use for the metadata * of the current node
* @since 6.1 * @param streamType
* to use for the metadata
* @param smudgeCommand
* to use for the metadata
*/ */
private void addCheckoutMetadata( private void addCheckoutMetadata(Map<String, CheckoutMetadata> map,
Map<String, CheckoutMetadata> map, String path, EolStreamType streamType, String path, EolStreamType streamType, String smudgeCommand) {
String smudgeCommand) {
if (inCore || map == null) { if (inCore || map == null) {
return; return;
} }
@ -439,18 +487,20 @@ private void addCheckoutMetadata(
/** /**
* Detects if CRLF conversion has been configured. * Detects if CRLF conversion has been configured.
* <p></p> * <p>
* </p>
* See {@link EolStreamTypeUtil#detectStreamType} for more info. * See {@link EolStreamTypeUtil#detectStreamType} for more info.
* *
* @param attributes of the file for which the type is to be detected * @param attributes
* of the file for which the type is to be detected
* @return the detected type * @return the detected type
*/ */
public EolStreamType detectCheckoutStreamType(Attributes attributes) { public EolStreamType detectCheckoutStreamType(Attributes attributes) {
if (inCore) { if (inCore) {
return null; return null;
} }
return EolStreamTypeUtil.detectStreamType( return EolStreamTypeUtil.detectStreamType(OperationType.CHECKOUT_OP,
OperationType.CHECKOUT_OP, workingTreeOptions, attributes); workingTreeOptions, attributes);
} }
private void handleDeletedFiles() { private void handleDeletedFiles() {
@ -470,7 +520,8 @@ private void handleDeletedFiles() {
/** /**
* Marks the given path as modified in the operation. * Marks the given path as modified in the operation.
* *
* @param path to mark as modified * @param path
* to mark as modified
*/ */
public void markAsModified(String path) { public void markAsModified(String path) {
result.modifiedFiles.add(path); result.modifiedFiles.add(path);
@ -486,17 +537,15 @@ public List<String> getModifiedFiles() {
} }
private void checkout() throws NoWorkTreeException, IOException { private void checkout() throws NoWorkTreeException, IOException {
// Iterate in reverse so that "folder/file" is deleted before for (Map.Entry<String, DirCacheEntry> entry : toBeCheckedOut
// "folder". Otherwise, this could result in a failing path because .entrySet()) {
// of a non-empty directory, for which delete() would fail.
for (Map.Entry<String, DirCacheEntry> entry : toBeCheckedOut.entrySet()) {
DirCacheEntry dirCacheEntry = entry.getValue(); DirCacheEntry dirCacheEntry = entry.getValue();
if (dirCacheEntry.getFileMode() == FileMode.GITLINK) { if (dirCacheEntry.getFileMode() == FileMode.GITLINK) {
new File(nonNullNonBareRepo().getWorkTree(), entry.getKey()).mkdirs(); new File(nonNullRepo().getWorkTree(), entry.getKey())
.mkdirs();
} else { } else {
DirCacheCheckout.checkoutEntry( DirCacheCheckout.checkoutEntry(repo, dirCacheEntry, reader,
repo, dirCacheEntry, reader, false, false, checkoutMetadata.get(entry.getKey()),
checkoutMetadata.get(entry.getKey()),
workingTreeOptions); workingTreeOptions);
result.modifiedFiles.add(entry.getKey()); result.modifiedFiles.add(entry.getKey());
} }
@ -504,11 +553,13 @@ private void checkout() throws NoWorkTreeException, IOException {
} }
/** /**
* Reverts any uncommitted changes in the worktree. We know that for all modified files the * Reverts any uncommitted changes in the worktree. We know that for all
* old content was in the old index and the index contained only stage 0. In case if inCore * modified files the old content was in the old index and the index
* operation just clear the history of modified files. * contained only stage 0. In case of inCore operation just clear the
* history of modified files.
* *
* @throws java.io.IOException in case the cleaning up failed * @throws IOException
* in case the cleaning up failed
*/ */
public void revertModifiedFiles() throws IOException { public void revertModifiedFiles() throws IOException {
if (inCore) { if (inCore) {
@ -521,9 +572,8 @@ public void revertModifiedFiles() throws IOException {
for (String path : result.modifiedFiles) { for (String path : result.modifiedFiles) {
DirCacheEntry entry = dirCache.getEntry(path); DirCacheEntry entry = dirCache.getEntry(path);
if (entry != null) { if (entry != null) {
DirCacheCheckout.checkoutEntry( DirCacheCheckout.checkoutEntry(repo, entry, reader, false,
repo, entry, reader, false, cleanupMetadata.get(path), cleanupMetadata.get(path), workingTreeOptions);
workingTreeOptions);
} }
} }
} }
@ -538,22 +588,24 @@ public void close() throws IOException {
/** /**
* Updates the file in the checkout with the given content. * Updates the file in the checkout with the given content.
* *
* @param resultStreamLoader with the content to be updated * @param resultStreamLoader
* @param streamType for parsing the content * with the content to be updated
* @param smudgeCommand for formatting the content * @param streamType
* @param path of the file to be updated * for parsing the content
* @param file to be updated * @param smudgeCommand
* @param safeWrite whether the content should be written to a buffer first * for formatting the content
* @throws IOException if the {@link CheckoutMetadata} cannot be determined * @param path
* 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( public void updateFileWithContent(StreamLoader resultStreamLoader,
StreamLoader resultStreamLoader, EolStreamType streamType, String smudgeCommand, String path,
EolStreamType streamType, File file, boolean safeWrite) throws IOException {
String smudgeCommand,
String path,
File file,
boolean safeWrite)
throws IOException {
if (inCore) { if (inCore) {
return; return;
} }
@ -584,74 +636,85 @@ public void updateFileWithContent(
} }
/** /**
* Creates a path with the given content, and adds it to the specified stage to the index builder * 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 inputStream
* @param path of the file to be updated * with the content to be updated
* @param fileMode of the modified file * @param path
* @param entryStage of the new entry * of the file to be updated
* @param lastModified instant of the modified file * @param fileMode
* @param len of the content * of the modified file
* @param lfsAttribute for checking for LFS enablement * @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 * @return the entry which was added to the index
* @throws IOException if inserting the content fails * @throws IOException
* if inserting the content fails
*/ */
public DirCacheEntry insertToIndex( public DirCacheEntry insertToIndex(InputStream inputStream, byte[] path,
InputStream inputStream, FileMode fileMode, int entryStage, Instant lastModified, int len,
byte[] path,
FileMode fileMode,
int entryStage,
Instant lastModified,
int len,
Attribute lfsAttribute) throws IOException { Attribute lfsAttribute) throws IOException {
StreamLoader contentLoader = createStreamLoader(() -> inputStream, len); StreamLoader contentLoader = createStreamLoader(() -> inputStream, len);
return insertToIndex(contentLoader, path, fileMode, entryStage, lastModified, len, return insertToIndex(contentLoader, path, fileMode, entryStage,
lfsAttribute); lastModified, len, lfsAttribute);
} }
/** /**
* Creates a path with the given content, and adds it to the specified stage to the index builder * 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 resultStreamLoader
* @param path of the file to be updated * with the content to be updated
* @param fileMode of the modified file * @param path
* @param entryStage of the new entry * of the file to be updated
* @param lastModified instant of the modified file * @param fileMode
* @param len of the content * of the modified file
* @param lfsAttribute for checking for LFS enablement * @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 * @return the entry which was added to the index
* @throws IOException if inserting the content fails * @throws IOException
* if inserting the content fails
*/ */
public DirCacheEntry insertToIndex( public DirCacheEntry insertToIndex(StreamLoader resultStreamLoader,
StreamLoader resultStreamLoader, byte[] path, FileMode fileMode, int entryStage,
byte[] path, Instant lastModified, int len, Attribute lfsAttribute)
FileMode fileMode, throws IOException {
int entryStage, return addExistingToIndex(
Instant lastModified, insertResult(resultStreamLoader, lfsAttribute), path, fileMode,
int len, entryStage, lastModified, len);
Attribute lfsAttribute) throws IOException {
return addExistingToIndex(insertResult(resultStreamLoader, lfsAttribute),
path, fileMode, entryStage, lastModified, len);
} }
/** /**
* Adds a path with the specified stage to the index builder * Adds a path with the specified stage to the index builder.
* *
* @param objectId of the existing object to add * @param objectId
* @param path of the modified file * of the existing object to add
* @param fileMode of the modified file * @param path
* @param entryStage of the new entry * of the modified file
* @param lastModified instant of the modified file * @param fileMode
* @param len of the modified file content * of the modified file
* @param entryStage
* of the new entry
* @param lastModified
* instant of the modified file
* @param len
* of the modified file content
* @return the entry which was added to the index * @return the entry which was added to the index
*/ */
public DirCacheEntry addExistingToIndex( public DirCacheEntry addExistingToIndex(ObjectId objectId, byte[] path,
ObjectId objectId, FileMode fileMode, int entryStage, Instant lastModified, int len) {
byte[] path,
FileMode fileMode,
int entryStage,
Instant lastModified,
int len) {
DirCacheEntry dce = new DirCacheEntry(path, entryStage); DirCacheEntry dce = new DirCacheEntry(path, entryStage);
dce.setFileMode(fileMode); dce.setFileMode(fileMode);
if (lastModified != null) { if (lastModified != null) {
@ -664,44 +727,25 @@ public DirCacheEntry addExistingToIndex(
return dce; return dce;
} }
private ObjectId insertResult(StreamLoader resultStreamLoader, Attribute lfsAttribute) private ObjectId insertResult(StreamLoader resultStreamLoader,
throws IOException { Attribute lfsAttribute) throws IOException {
try (LfsInputStream is = try (LfsInputStream is = LfsFactory.getInstance().applyCleanFilter(repo,
org.eclipse.jgit.util.LfsFactory.getInstance() resultStreamLoader.data.load(), resultStreamLoader.size,
.applyCleanFilter( lfsAttribute)) {
repo,
resultStreamLoader.data.load(),
resultStreamLoader.size,
lfsAttribute)) {
return inserter.insert(OBJ_BLOB, is.getLength(), is); return inserter.insert(OBJ_BLOB, is.getLength(), is);
} }
} }
/** /**
* Gets non-null repository instance * Gets the non-null repository instance of this {@link WorkTreeUpdater}.
* *
* @return non-null repository instance * @return non-null repository instance
* @throws java.lang.NullPointerException if the handler was constructed without a repository. * @throws NullPointerException
* if the handler was constructed without a repository.
*/ */
@NonNull
private Repository nonNullRepo() throws NullPointerException { private Repository nonNullRepo() throws NullPointerException {
if (repo == null) { return Objects.requireNonNull(repo,
throw new NullPointerException(JGitText.get().repositoryIsRequired); () -> JGitText.get().repositoryIsRequired);
}
return repo;
}
/**
* Gets non-null and non-bare repository instance
*
* @return non-null and non-bare repository instance
* @throws java.lang.NullPointerException if the handler was constructed without a repository.
* @throws NoWorkTreeException if the handler was constructed with a bare repository
*/
private Repository nonNullNonBareRepo() throws NullPointerException, NoWorkTreeException {
if (nonNullRepo().isBare()) {
throw new NoWorkTreeException();
}
return repo;
} }
} }