diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java index 0d49cd339..e463e9070 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java @@ -303,12 +303,16 @@ public void testIsModifiedSymlinkAsFile() throws Exception { DirCacheEntry dce = db.readDirCache().getEntry("symlink"); dce.setFileMode(FileMode.SYMLINK); try (ObjectReader objectReader = db.newObjectReader()) { - DirCacheCheckout.checkoutEntry(db, dce, objectReader, false, null); + WorkingTreeOptions options = db.getConfig() + .get(WorkingTreeOptions.KEY); + DirCacheCheckout.checkoutEntry(db, dce, objectReader, false, null, + options); FileTreeIterator fti = new FileTreeIterator(trash, db.getFS(), - db.getConfig().get(WorkingTreeOptions.KEY)); - while (!fti.getEntryPathString().equals("symlink")) + options); + while (!fti.getEntryPathString().equals("symlink")) { fti.next(1); + } assertFalse(fti.isModified(dce, false, objectReader)); } } 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 847ab0a9a..7319ff4b2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java @@ -55,6 +55,7 @@ import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.WorkingTreeOptions; import org.eclipse.jgit.treewalk.filter.PathFilterGroup; /** @@ -411,6 +412,8 @@ public CheckoutCommand setAllPaths(boolean all) { protected CheckoutCommand checkoutPaths() throws IOException, RefNotFoundException { actuallyModifiedPaths = new HashSet<>(); + WorkingTreeOptions options = repo.getConfig() + .get(WorkingTreeOptions.KEY); DirCache dc = repo.lockDirCache(); try (RevWalk revWalk = new RevWalk(repo); TreeWalk treeWalk = new TreeWalk(repo, @@ -419,10 +422,10 @@ protected CheckoutCommand checkoutPaths() throws IOException, if (!checkoutAllPaths) treeWalk.setFilter(PathFilterGroup.createFromStrings(paths)); if (isCheckoutIndex()) - checkoutPathsFromIndex(treeWalk, dc); + checkoutPathsFromIndex(treeWalk, dc, options); else { RevCommit commit = revWalk.parseCommit(getStartPointObjectId()); - checkoutPathsFromCommit(treeWalk, dc, commit); + checkoutPathsFromCommit(treeWalk, dc, commit, options); } } finally { try { @@ -439,7 +442,8 @@ protected CheckoutCommand checkoutPaths() throws IOException, return this; } - private void checkoutPathsFromIndex(TreeWalk treeWalk, DirCache dc) + private void checkoutPathsFromIndex(TreeWalk treeWalk, DirCache dc, + WorkingTreeOptions options) throws IOException { DirCacheIterator dci = new DirCacheIterator(dc); treeWalk.addTree(dci); @@ -465,8 +469,9 @@ public void apply(DirCacheEntry ent) { if (stage > DirCacheEntry.STAGE_0) { if (checkoutStage != null) { if (stage == checkoutStage.number) { - checkoutPath(ent, r, new CheckoutMetadata( - eolStreamType, filterCommand)); + checkoutPath(ent, r, options, + new CheckoutMetadata(eolStreamType, + filterCommand)); actuallyModifiedPaths.add(path); } } else { @@ -475,8 +480,9 @@ public void apply(DirCacheEntry ent) { throw new JGitInternalException(e.getMessage(), e); } } else { - checkoutPath(ent, r, new CheckoutMetadata(eolStreamType, - filterCommand)); + checkoutPath(ent, r, options, + new CheckoutMetadata(eolStreamType, + filterCommand)); actuallyModifiedPaths.add(path); } } @@ -488,7 +494,7 @@ public void apply(DirCacheEntry ent) { } private void checkoutPathsFromCommit(TreeWalk treeWalk, DirCache dc, - RevCommit commit) throws IOException { + RevCommit commit, WorkingTreeOptions options) throws IOException { treeWalk.addTree(commit.getTree()); final ObjectReader r = treeWalk.getObjectReader(); DirCacheEditor editor = dc.editor(); @@ -510,7 +516,7 @@ public void apply(DirCacheEntry ent) { } ent.setObjectId(blobId); ent.setFileMode(mode); - checkoutPath(ent, r, + checkoutPath(ent, r, options, new CheckoutMetadata(eolStreamType, filterCommand)); actuallyModifiedPaths.add(path); } @@ -520,10 +526,10 @@ public void apply(DirCacheEntry ent) { } private void checkoutPath(DirCacheEntry entry, ObjectReader reader, - CheckoutMetadata checkoutMetadata) { + WorkingTreeOptions options, CheckoutMetadata checkoutMetadata) { try { DirCacheCheckout.checkoutEntry(repo, entry, reader, true, - checkoutMetadata); + checkoutMetadata, options); } catch (IOException e) { throw new JGitInternalException(MessageFormat.format( JGitText.get().checkoutConflictWithFile, diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java index 1004d3e50..17036a9cd 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java @@ -48,6 +48,7 @@ import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.WorkingTreeOptions; /** * Command class to apply a stashed commit. @@ -382,6 +383,8 @@ private void resetIndex(RevTree tree) throws IOException { private void resetUntracked(RevTree tree) throws CheckoutConflictException, IOException { Set actuallyModifiedPaths = new HashSet<>(); + WorkingTreeOptions options = repo.getConfig() + .get(WorkingTreeOptions.KEY); // TODO maybe NameConflictTreeWalk ? try (TreeWalk walk = new TreeWalk(repo)) { walk.addTree(tree); @@ -413,7 +416,7 @@ private void resetUntracked(RevTree tree) throws CheckoutConflictException, } } - checkoutPath(entry, reader, + checkoutPath(entry, reader, options, new CheckoutMetadata(eolStreamType, null)); actuallyModifiedPaths.add(entry.getPathString()); } @@ -426,10 +429,10 @@ private void resetUntracked(RevTree tree) throws CheckoutConflictException, } private void checkoutPath(DirCacheEntry entry, ObjectReader reader, - CheckoutMetadata checkoutMetadata) { + WorkingTreeOptions options, CheckoutMetadata checkoutMetadata) { try { DirCacheCheckout.checkoutEntry(repo, entry, reader, true, - checkoutMetadata); + checkoutMetadata, options); } catch (IOException e) { throw new JGitInternalException(MessageFormat.format( JGitText.get().checkoutConflictWithFile, 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 f6fc393c4..2365c90d0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java @@ -143,6 +143,8 @@ public CheckoutMetadata(EolStreamType eolStreamType, private boolean performingCheckout; + private WorkingTreeOptions options; + private ProgressMonitor monitor = NullProgressMonitor.INSTANCE; /** @@ -362,9 +364,12 @@ private int addTree(TreeWalk tw, ObjectId id) throws MissingObjectException, * Processing an entry in the context of {@link #prescanOneTree()} when only * one tree is given * - * @param m the tree to merge - * @param i the index - * @param f the working tree + * @param m + * the tree to merge + * @param i + * the index + * @param f + * the working tree * @throws IOException */ void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i, @@ -489,6 +494,8 @@ private boolean doCheckout() throws CorruptObjectException, IOException, MissingObjectException, IncorrectObjectTypeException, CheckoutConflictException, IndexWriteException, CanceledException { toBeDeleted.clear(); + options = repo.getConfig() + .get(WorkingTreeOptions.KEY); try (ObjectReader objectReader = repo.getObjectDatabase().newReader()) { if (headCommitTree != null) preScanTwoTrees(); @@ -558,7 +565,8 @@ private boolean doCheckout() throws CorruptObjectException, IOException, if (FileMode.GITLINK.equals(entry.getRawMode())) { checkoutGitlink(path, entry); } else { - checkoutEntry(repo, entry, objectReader, false, meta); + checkoutEntry(repo, entry, objectReader, false, meta, + options); } e = null; @@ -594,7 +602,7 @@ private boolean doCheckout() throws CorruptObjectException, IOException, } if (entry.getStage() == DirCacheEntry.STAGE_3) { checkoutEntry(repo, entry, objectReader, false, - null); + null, options); break; } ++entryIdx; @@ -1226,7 +1234,7 @@ private void keep(String path, DirCacheEntry e, WorkingTreeIterator f) checkoutEntry(repo, e, walk.getObjectReader(), false, new CheckoutMetadata(walk.getEolStreamType(CHECKOUT_OP), walk.getFilterCommand( - Constants.ATTR_FILTER_TYPE_SMUDGE))); + Constants.ATTR_FILTER_TYPE_SMUDGE)), options); } } } @@ -1392,12 +1400,6 @@ private boolean isModifiedSubtree_IndexTree(String path, ObjectId tree) * cannot be renamed to file or link without deleting it recursively. *

* - *

- * 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 @@ -1407,15 +1409,16 @@ private boolean isModifiedSubtree_IndexTree(String path, ObjectId tree) * @throws java.io.IOException * @since 3.6 * @deprecated since 5.1, use - * {@link #checkoutEntry(Repository, DirCacheEntry, ObjectReader, boolean, CheckoutMetadata)} + * {@link #checkoutEntry(Repository, DirCacheEntry, ObjectReader, boolean, CheckoutMetadata, WorkingTreeOptions)} * instead */ @Deprecated public static void checkoutEntry(Repository repo, DirCacheEntry entry, ObjectReader or) throws IOException { - checkoutEntry(repo, entry, or, false, null); + checkoutEntry(repo, entry, or, false, null, 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 @@ -1428,12 +1431,6 @@ public static void checkoutEntry(Repository repo, DirCacheEntry entry, * 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 @@ -1452,12 +1449,58 @@ public static void checkoutEntry(Repository repo, DirCacheEntry entry, * * @throws java.io.IOException * @since 4.2 + * @deprecated since 6.3, use + * {@link #checkoutEntry(Repository, DirCacheEntry, ObjectReader, boolean, CheckoutMetadata, WorkingTreeOptions)} + * instead */ + @Deprecated public static void checkoutEntry(Repository repo, DirCacheEntry entry, ObjectReader or, boolean deleteRecursive, CheckoutMetadata checkoutMetadata) throws IOException { - if (checkoutMetadata == null) + checkoutEntry(repo, entry, or, deleteRecursive, checkoutMetadata, 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. + *

+ * + * @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 checkoutMetadata + * containing + * + * @param options + * {@link WorkingTreeOptions} that are effective; if {@code null} + * they are loaded from the repository config + * @throws java.io.IOException + * @since 6.3 + */ + public static void checkoutEntry(Repository repo, DirCacheEntry entry, + ObjectReader or, boolean deleteRecursive, + CheckoutMetadata checkoutMetadata, WorkingTreeOptions options) + throws IOException { + if (checkoutMetadata == null) { checkoutMetadata = CheckoutMetadata.EMPTY; + } ObjectLoader ol = or.open(entry.getObjectId()); File f = new File(repo.getWorkTree(), entry.getPathString()); File parentDir = f.getParentFile(); @@ -1466,7 +1509,8 @@ public static void checkoutEntry(Repository repo, DirCacheEntry entry, } FileUtils.mkdirs(parentDir, true); FS fs = repo.getFS(); - WorkingTreeOptions opt = repo.getConfig().get(WorkingTreeOptions.KEY); + WorkingTreeOptions opt = options != null ? options + : repo.getConfig().get(WorkingTreeOptions.KEY); if (entry.getFileMode() == FileMode.SYMLINK && opt.getSymLinks() == SymLinks.TRUE) { byte[] bytes = ol.getBytes(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java index f872f9fba..88529ba09 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java @@ -495,7 +495,9 @@ private void checkout() throws NoWorkTreeException, IOException { new File(nonNullNonBareRepo().getWorkTree(), entry.getKey()).mkdirs(); } else { DirCacheCheckout.checkoutEntry( - repo, dirCacheEntry, reader, false, checkoutMetadata.get(entry.getKey())); + repo, dirCacheEntry, reader, false, + checkoutMetadata.get(entry.getKey()), + workingTreeOptions); result.modifiedFiles.add(entry.getKey()); } } @@ -520,7 +522,8 @@ public void revertModifiedFiles() throws IOException { DirCacheEntry entry = dirCache.getEntry(path); if (entry != null) { DirCacheCheckout.checkoutEntry( - repo, entry, reader, false, cleanupMetadata.get(path)); + repo, entry, reader, false, cleanupMetadata.get(path), + workingTreeOptions); } } } @@ -563,7 +566,7 @@ public void updateFileWithContent( try { try (TemporaryBuffer buf = buffer) { DirCacheCheckout.getContent(repo, path, metadata, - resultStreamLoader, null, buf); + resultStreamLoader, workingTreeOptions, buf); } try (InputStream bufIn = buffer.openInputStream()) { Files.copy(bufIn, file.toPath(), @@ -576,7 +579,7 @@ public void updateFileWithContent( } try (OutputStream outputStream = new FileOutputStream(file)) { DirCacheCheckout.getContent(repo, path, metadata, - resultStreamLoader, null, outputStream); + resultStreamLoader, workingTreeOptions, outputStream); } }