# This patch file was generated by NetBeans IDE # Following Index: paths are relative to: /data/work/src/netbeans-cdev # This patch can be applied using context Tools: Patch action on respective folder. # It uses platform neutral UTF-8 encoding and \n newlines. # Above lines and this line are ignored by the patching process. Index: versioning/apichanges.xml --- versioning/apichanges.xml Base (BASE) +++ versioning/apichanges.xml Locally Modified (Based On LOCAL) @@ -111,6 +111,21 @@ + beforeCopy(), doCopy() and afterCopy() methods added to VCSInterceptor + + + + + + VCSInterceptor.beforeCopy, VCSInterceptor.doCopy, + and VCSInterceptor.afterCopy allow a version control system + to better control a copy operation on a file. + + + + + + refreshRecursively() method added to VCSInterceptor Index: versioning/nbproject/project.xml --- versioning/nbproject/project.xml Base (BASE) +++ versioning/nbproject/project.xml Locally Modified (Based On LOCAL) @@ -99,7 +99,7 @@ 2 - 2.24 + 2.28 Index: versioning/src/org/netbeans/modules/versioning/FilesystemInterceptor.java --- versioning/src/org/netbeans/modules/versioning/FilesystemInterceptor.java Base (BASE) +++ versioning/src/org/netbeans/modules/versioning/FilesystemInterceptor.java Locally Modified (Based On LOCAL) @@ -302,10 +302,15 @@ private IOHandler getMoveHandlerIntern(File from, File to) { DelegatingInterceptor dic = getInterceptor(from, to, "beforeMove", "doMove"); // NOI18N - return dic.beforeMove() ? dic : null; + return dic.beforeMove() ? dic.getMoveHandler() : null; } @Override + public void moveSuccess(FileObject from, File to) { + getInterceptor(FileUtil.toFile(from), to, "afterMove").afterMove(); + } + + @Override public void fileRenamed(FileRenameEvent fe) { LOG.log(Level.FINE, "fileRenamed {0}", fe.getFile()); removeFromDeletedFiles(fe.getFile()); @@ -318,6 +323,32 @@ // not interested } + // ================================================================================================== + // COPY + // ================================================================================================== + + @Override + public IOHandler getCopyHandler(File from, File to) { + LOG.log(Level.FINE, "getCopyHandler {0}, {1}", new Object[] {from, to}); + return getCopyHandlerIntern(from, to); + } + + private IOHandler getCopyHandlerIntern(File from, File to) { + DelegatingInterceptor dic = getInterceptor(from, to, "beforeCopy", "doCopy"); // NOI18N + return dic.beforeCopy() ? dic.getCopyHandler() : null; + } + + @Override + public void beforeCopy(FileObject from, File to) { } + + @Override + public void copySuccess(FileObject from, File to) { + getInterceptor(FileUtil.toFile(from), to, "afterCopy").afterCopy(); + } + + @Override + public void copyFailure(FileObject from, File to) { } + /** * There is a contract that says that when a file is locked, it is expected to be changed. This is what openide/text * does when it creates a Document. A versioning system is expected to make the file r/w. @@ -407,7 +438,6 @@ public void beforeEdit() { } public void afterChange() { } public void afterMove() { } - public void handle() throws IOException { } public boolean delete(File file) { throw new UnsupportedOperationException(); } }; @@ -418,7 +448,7 @@ */ private final Set deletedFiles = new HashSet(5); - private class DelegatingInterceptor implements IOHandler, DeleteHandler { + private class DelegatingInterceptor implements DeleteHandler { final Collection interceptors; final VCSInterceptor interceptor; @@ -426,6 +456,8 @@ final File file; final File to; private final boolean isDirectory; + private IOHandler moveHandler; + private IOHandler copyHandler; private DelegatingInterceptor() { this((VCSInterceptor) null, null, null, null, false); @@ -488,6 +520,21 @@ interceptor.afterMove(file, to); } + public boolean beforeCopy() { + lhInterceptor.beforeCopy(file, to); + return interceptor.beforeCopy(file, to); + } + + public void doCopy() throws IOException { + lhInterceptor.doCopy(file, to); + interceptor.doCopy(file, to); + } + + public void afterCopy() { + lhInterceptor.afterCopy(file, to); + interceptor.afterCopy(file, to); + } + public boolean beforeCreate() { lhInterceptor.beforeCreate(file, isDirectory); return interceptor.beforeCreate(file, isDirectory); @@ -518,18 +565,30 @@ interceptor.beforeEdit(file); } - /** - * We are doing MOVE here, inspite of the generic name of the method. - * - * @throws IOException - */ + private IOHandler getMoveHandler() { + if(moveHandler == null) { + moveHandler = new IOHandler() { + @Override public void handle() throws IOException { - lhInterceptor.doMove(file, to); - interceptor.doMove(file, to); - lhInterceptor.afterMove(file, to); - interceptor.afterMove(file, to); + doMove(); } + }; + } + return moveHandler; + } + private IOHandler getCopyHandler() { + if(copyHandler == null) { + copyHandler = new IOHandler() { + @Override + public void handle() throws IOException { + doCopy(); + } + }; + } + return copyHandler; + } + /** * This must act EXACTLY like java.io.File.delete(). This means: Index: versioning/src/org/netbeans/modules/versioning/spi/VCSInterceptor.java --- versioning/src/org/netbeans/modules/versioning/spi/VCSInterceptor.java Base (BASE) +++ versioning/src/org/netbeans/modules/versioning/spi/VCSInterceptor.java Locally Modified (Based On LOCAL) @@ -162,6 +162,45 @@ } // ================================================================================================== + // COPY + // ================================================================================================== + + /** + * Notifies the interceptor that the file or folder is about to be copied. The interceptor MUST NOT copy + * the file here. + * + * @param from the file or folder to be copied + * @param to destination of the file being copied + * @return true if this interceptor wants to handle this operation (doCopy will be called), false otherwise + * @since 1.18 + */ + public boolean beforeCopy(File from, File to) { + return false; + } + + /** + * Called if beforeCopy() returns true and delegates the copy operation to this interceptor. + * + * @param from the file or folder to be copied + * @param to destination of the file being copied + * @throws IOException if the copy operation failed + * @since 1.18 + */ + public void doCopy(File from, File to) throws IOException { + } + + /** + * Called after a file or folder has been copied. In case the file was copied outside IDE, this method is not called + * and only afterCreate() is called instead. + * + * @param from original location of the file + * @param to current location of the file + * @since 1.18 + */ + public void afterCopy(File from, File to) { + } + + // ================================================================================================== // CREATE // ================================================================================================== Index: versioning/test/unit/src/org/netbeans/modules/versioning/FSInterceptorTest.java --- versioning/test/unit/src/org/netbeans/modules/versioning/FSInterceptorTest.java Base (BASE) +++ versioning/test/unit/src/org/netbeans/modules/versioning/FSInterceptorTest.java Locally Modified (Based On LOCAL) @@ -59,6 +59,7 @@ import org.openide.filesystems.FileObject; import org.openide.filesystems.FileRenameEvent; import org.openide.filesystems.FileUtil; +import org.openide.util.Exceptions; /** * @@ -224,7 +225,7 @@ } } }; - w.test(new String[] {"doMove", "afterMove"}); + w.test(new String[] {"beforeMove", "doMove"}); // afterMove w = new W() { @@ -232,8 +233,46 @@ fi.fileRenamed(new FileRenameEvent(FileUtil.toFileObject(wFile), "wFile", null)); } }; + w.test(new String[] {"afterMove"}); + w = new W() { + void callInterceptorMethod(FilesystemInterceptor fi) { + fi.moveSuccess(FileUtil.toFileObject(wFile), wFile); + } + }; + w.test(new String[] {"afterMove"}); + + // beforeCopy + w = new W() { + void callInterceptorMethod(FilesystemInterceptor fi) { + try { + fi.getCopyHandler(wFile, wFile).handle(); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + }; w.test(); + // doCopy + w = new W() { + void callInterceptorMethod(FilesystemInterceptor fi) { + try { + fi.getCopyHandler(wFile, wFile).handle(); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + }; + w.test(new String[] {"doCopy", "beforeCopy"}); + + // afterCopy + w = new W() { + void callInterceptorMethod(FilesystemInterceptor fi) { + fi.copySuccess(FileUtil.toFileObject(wFile), wFile); + } + }; + w.test(new String[] {"afterCopy"}); + // fileLocked w = new W() { void callInterceptorMethod(FilesystemInterceptor fi) { @@ -354,6 +393,12 @@ } @Override + public void afterCopy(File from, File to) { + storeMethodName(); + super.afterCopy(from, to); + } + + @Override public void afterMove(File from, File to) { storeMethodName(); super.afterMove(from, to); @@ -384,6 +429,12 @@ } @Override + public boolean beforeCopy(File from, File to) { + storeMethodName(); + return true; + } + + @Override public boolean beforeMove(File from, File to) { storeMethodName(); return true; @@ -402,6 +453,12 @@ } @Override + public void doCopy(File from, File to) throws IOException { + storeMethodName(); + super.doMove(from, to); + } + + @Override public void doMove(File from, File to) throws IOException { storeMethodName(); super.doMove(from, to); Index: versioning/test/unit/src/org/netbeans/modules/versioning/spi/VCSInterceptorTest.java --- versioning/test/unit/src/org/netbeans/modules/versioning/spi/VCSInterceptorTest.java Base (BASE) +++ versioning/test/unit/src/org/netbeans/modules/versioning/spi/VCSInterceptorTest.java Locally Modified (Based On LOCAL) @@ -196,6 +196,22 @@ assertTrue(inteceptor.getDeletedFiles().contains(file2)); } + public void testFileCopied() throws IOException { + File f = new File(dataRootDir, "workdir/root-test-versioned"); + FileObject fo = FileUtil.toFileObject(f); + fo = fo.createData("copyme.txt"); + File from = FileUtil.toFile(fo); + + FileObject fto = fo.copy(fo.getParent(), "copymeto", "txt"); + + assertTrue(inteceptor.getBeforeCopyFiles().contains(from)); + assertTrue(inteceptor.getBeforeCopyFiles().contains(FileUtil.toFile(fo))); + assertTrue(inteceptor.getDoCopyFiles().contains(from)); + assertTrue(inteceptor.getDoCopyFiles().contains(FileUtil.toFile(fo))); + assertTrue(inteceptor.getAfterCopyFiles().contains(from)); + assertTrue(inteceptor.getAfterCopyFiles().contains(FileUtil.toFile(fo))); + } + private void deleteRecursively(File f) { if(f.isFile()) { f.delete(); Index: versioning/test/unit/src/org/netbeans/modules/versioning/spi/testvcs/TestVCSInterceptor.java --- versioning/test/unit/src/org/netbeans/modules/versioning/spi/testvcs/TestVCSInterceptor.java Base (BASE) +++ versioning/test/unit/src/org/netbeans/modules/versioning/spi/testvcs/TestVCSInterceptor.java Locally Modified (Based On LOCAL) @@ -48,6 +48,7 @@ import java.io.File; import java.io.IOException; import java.util.*; +import org.netbeans.modules.versioning.util.FileUtils; /** * @author Maros Sandor @@ -62,6 +63,9 @@ private final List deletedFiles = new ArrayList(); private final List beforeMoveFiles = new ArrayList(); private final List afterMoveFiles = new ArrayList(); + private final List beforeCopyFiles = new ArrayList(); + private final List afterCopyFiles = new ArrayList(); + private final List doCopyFiles = new ArrayList(); private final List beforeEditFiles = new ArrayList(); private final List beforeChangeFiles = new ArrayList(); private final List afterChangeFiles = new ArrayList(); @@ -143,6 +147,23 @@ afterMoveFiles.add(from); } + public boolean beforeCopy(File from, File to) { + beforeCopyFiles.add(from); + beforeCopyFiles.add(to); + return true; + } + + public void doCopy(File from, File to) throws IOException { + doCopyFiles.add(from); + doCopyFiles.add(to); + FileUtils.copyFile(from, to); + } + + public void afterCopy(File from, File to) { + afterCopyFiles.add(from); + afterCopyFiles.add(to); + } + public void beforeEdit(File file) { beforeEditFiles.add(file); } @@ -183,6 +204,18 @@ return afterMoveFiles; } + public List getBeforeCopyFiles() { + return beforeCopyFiles; + } + + public List getDoCopyFiles() { + return doCopyFiles; + } + + public List getAfterCopyFiles() { + return afterCopyFiles; + } + public List getBeforeEditFiles() { return beforeEditFiles; } Index: versioning/work/sys/data/workdir/root-test-versioned/copyme.txt --- versioning/work/sys/data/workdir/root-test-versioned/copyme.txt Base (BASE) +++ versioning/work/sys/data/workdir/root-test-versioned/copyme.txt Locally New Index: versioning/work/sys/data/workdir/root-test-versioned/copymeto.txt --- versioning/work/sys/data/workdir/root-test-versioned/copymeto.txt Base (BASE) +++ versioning/work/sys/data/workdir/root-test-versioned/copymeto.txt Locally New