RefactoringFSandVCS

Contents

Problems in VCS when refactoring

Status in Issue 187485

There are several scenarios in which an explicit move/rename/copy user action is broken down to a bunch of create and delete events. The outcome in such a case is that there is no way for VCS to find out that an incoming create and delete combination actually represents a file rename/move a relevant vcs move command isn't called and changes in a files history are lost.

copy

Copy is exclusively handled as create. A relevant VCS command isn't called at all. History gets lost.

move/rename a folder with a file in it

Nr. Action Event
1 Select a package in Projects View and invoke rename (Menu>Refactor>Rename or Doubleclick) Folder handled via create/delete. File in folder moved via getMoveHandler. This is of course caused by the fact that a package is handled as a flat folder and the underlying folder structure is supposed to remain untouched. One more ugly side effect in case of e.g. svn is that no delete event comes because svn prevents a folders metadata from being deleted and refactoring decides not to delete the folder in case it's not empty - covered by issue #156529
2 Select in Files View and invoke rename (Menu>Refactor>Rename or Doubleclick) folder handled via getRenameHandler which is ok, but metadata handled via create. Should not happen! FS occasionally gets out of sync:
java.lang.AssertionError: childName: /Users/tomas/NetBeansProjects/JavaApplication2/src/javaapplication4/.svn/text-base/Main.java.svn-base folderName: /Users/tomas/NetBeansProjects/JavaApplication2/src/javaapplication4/.svn/text-base at org.netbeans.modules.masterfs.filebasedfs.children.ChildrenSupport.addChild(ChildrenSupport.java:125)
3 Select in Favorites View and rename via Menu>Refactor>Rename N/A
4 Select in Favorites View and Doubleclick to rename getMoveHandler, followed by file created and deleted events from FileChangeListener
5 Select in Projects View and Menu > Refactor > Move N/A
6 Select in Files View and Menu > Refactor > Move N/A
7 Select in Favorites View and Menu > Refactor > Move N/A
8 D&D in Projects View N/A
9 D&D in Files View no event for rename. folder handled via create/delete. File in folder moved via getMoveHandler.
10 D&D in Files View N/A

move/rename 1 file

In general - simple file refactoring works fine. Listed for completeness sake.

Nr. Action Event
1 Select in Projects View and Menu > Refactor > Rename or Doubleclick to rename getMoveHandler etc
2 Select in Files View and Menu > Refactor > Rename or Doubleclick to rename getMoveHandler etc
3 Select in Favorites View and Menu > Refactor > Rename or Doubleclick to rename N/A
4 Select in Projects View and Menu > Refactor > Move getMoveHandler, followed by file created and deleted events from FileChangeListener
5 Select in Files View and Menu > Refactor > Move getMoveHandler, followed by file created and deleted events from FileChangeListener
6 Select in Favorites View and Menu > Refactor > Move N/A
7 D&D in Project View getMoveHandler, followed by file created and deleted events from FileChangeListener
8 D&D in Files View getMoveHandler, followed by file created and deleted events from FileChangeListener
9 D&D in Favorites View getMoveHandler, followed by file created and deleted events from FileChangeListener

Problem Description

The base problem is that the initiator of the operation, e.g. refactoring or data systems (in case of files view), disassemble one logical operation into series of individual, illogical actions. The version control system then sees only these small actions and is not capable to assemble them back into the original intention.

-1: Possible way to address the problems is to improve the assembling logic of version control system. E.g. recognize that creation of a file, deletion of another file in different directory with the same name is in fact a move refactoring. This is not sustainable solution. It requires version control to understand all refactorings, including those created by 3rd party, and this will not scale.

Conclusion: We want dummy version control system with as little refactoring logic as possible. We want refactoring & co. to give version control enough information about the logical action which is happening.

The situation is complicated by two factors. The APIs (filesystems, data systems) between the logical action initiator and version control system are not necessarily flexible enough to carry the information about the logical action. There are two options. Either the APIs can be enhanced, or we can bypass them.


Proposed Fix

Let's fix at least something for 6.10. Let's improve copy, let's deal with rename a bit. This is the enhancing path, limited to improving currently existing APIs:

Masterfs needs new method copy that will be called from overriden FileObj.copy:

IOHandler ProvidedExtensions.copy(File,File) { return null; }

Is VCS correctly implementing move(File,File)?

We need to verify that all important DataObject implementations use the copy and move methods. Even if they do:

newFo = fo.copy(...);
String txt = newFo.asText().replace(...)
newFo.getOutputStream().write(txt.getBytes());

Let's eliminate most of the rename/move folder problems by preventing creation of DataObject for .svn folders. This makes these folders invisible to all DataObject related operations (including refactoring). As a result .svn folders will stay untouched where they are during all data object based operations.

Rejected Ideas

Enhancing: For example for move and copy refactorings it would be handy to have (btw. related to Issue 40739):

FileObject folder = ...;
FileObject originalFile = ...;
boolean deleteOriginal = ...;
FileObject res = folder.createCopy(originalFile, outputStream, deleteOriginal);

the masterfs would tell the versioning system before the copy/move started to transfer necessary versioning metadata and only then it would write the content of the new file. The datasystems API has to use this new method instead of the current create/delete pair.

Bypassing -1: Indeed refactoring can talk directly to some versioning API. However if there is a way to enhance filesystem API, let's try that.

Bypassing +1: When starting FileSystem.AtomicAction, one could specify a logical plan:

FileSystem.Plan plan = FileSystem.createPlan(rootFileObject);
plan.move(pathToFileObject, toNewLocation);
plan.copy(pathElseWhere, anotherLocation);
FileUtil.runAtomicAction(runnable, plan);

The plan would be passed to versioning before operations happen, so the system can prepare whatever metadata are needed in advance, and later, when individual actions on files are requested, it can assign them proper meaning. Good thing on this proposal is that it does not require general changes in filesystems and datasystems API. It just adds new way to express the intention and it is up to refactoring and co. to use it when appropriate.

Transactional: Last way to solve this problem that comes to my mind is to defer the actual changes on disk for later and reply them in a batch, when they are finished. The refactoring would use the regular APIs. The requested changes would be stored and remembered. When everything is done, the refactoring could commit the changes. At that time the version control system would be get information about the whole batch, could set things up, and only then the files would be shuffled on the disk. While tempting, this alternative is probably too fragile to be implemented correctly.

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo