mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[lvcs]: implement rollback to Label from local history
* add label ID to identify label change; * create a local history model; * implement revert method by label; * inform if failed; * tests added;
This commit is contained in:
@@ -18,10 +18,18 @@ package com.intellij.history;
|
||||
|
||||
public interface Label {
|
||||
Label NULL_INSTANCE = new Label() {
|
||||
|
||||
@Override
|
||||
public long getLabelChangeId() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public ByteContent getByteContent(String path) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
long getLabelChangeId();
|
||||
|
||||
ByteContent getByteContent(String path);
|
||||
}
|
||||
|
||||
@@ -19,5 +19,7 @@ import com.intellij.history.ByteContent;
|
||||
import com.intellij.history.core.tree.RootEntry;
|
||||
|
||||
public interface LabelImpl {
|
||||
long getLabelChangeId();
|
||||
|
||||
ByteContent getByteContent(RootEntry root, String path);
|
||||
}
|
||||
|
||||
@@ -105,6 +105,12 @@ public class LocalHistoryFacade {
|
||||
private LabelImpl putLabel(@NotNull final PutLabelChange c) {
|
||||
addChange(c);
|
||||
return new LabelImpl() {
|
||||
|
||||
@Override
|
||||
public long getLabelChangeId() {
|
||||
return c.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteContent getByteContent(RootEntry root, String path) {
|
||||
return getByteContentBefore(root, path, c);
|
||||
|
||||
@@ -108,4 +108,8 @@ public class ChangeRevision extends Revision {
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + ": " + myChangeToRevert;
|
||||
}
|
||||
|
||||
public boolean containsChangeWithId(long id) {
|
||||
return myChangeToRevert.getId() == id;
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,9 @@ package com.intellij.history.integration;
|
||||
import com.intellij.history.*;
|
||||
import com.intellij.history.core.*;
|
||||
import com.intellij.history.core.tree.RootEntry;
|
||||
import com.intellij.history.integration.ui.models.DirectoryHistoryDialogModel;
|
||||
import com.intellij.history.integration.ui.models.EntireFileHistoryDialogModel;
|
||||
import com.intellij.history.integration.ui.models.HistoryDialogModel;
|
||||
import com.intellij.history.utils.LocalHistoryLog;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
@@ -38,8 +41,11 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static com.intellij.history.integration.LocalHistoryUtil.findRevisionIndexToRevert;
|
||||
|
||||
public class LocalHistoryImpl extends LocalHistory implements ApplicationComponent {
|
||||
private ChangeList myChangeList;
|
||||
private LocalHistoryFacade myVcs;
|
||||
@@ -183,6 +189,11 @@ public class LocalHistoryImpl extends LocalHistory implements ApplicationCompone
|
||||
|
||||
private Label label(final LabelImpl impl) {
|
||||
return new Label() {
|
||||
@Override
|
||||
public long getLabelChangeId() {
|
||||
return impl.getLabelChangeId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteContent getByteContent(final String path) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<ByteContent>() {
|
||||
@@ -237,5 +248,21 @@ public class LocalHistoryImpl extends LocalHistory implements ApplicationCompone
|
||||
|
||||
@Override
|
||||
public void revertToLabel(@NotNull Project project, @NotNull VirtualFile f, @NotNull Label label) {
|
||||
HistoryDialogModel dirHistoryModel = f.isDirectory()
|
||||
? new DirectoryHistoryDialogModel(project, myGateway, myVcs, f)
|
||||
: new EntireFileHistoryDialogModel(project, myGateway, myVcs, f);
|
||||
int leftRev = findRevisionIndexToRevert(dirHistoryModel, label);
|
||||
if (leftRev < 0) {
|
||||
LocalHistoryLog.LOG.warn(
|
||||
String.format("Couldn't find label revision. try to Use local history dialog for %s and perform revert manually.", f.getName()));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
dirHistoryModel.selectRevisions(-1, leftRev - 1); //-1 because we should revert all changes up to previous one, but not label-related.
|
||||
dirHistoryModel.createReverter().revert();
|
||||
}
|
||||
catch (IOException e) {
|
||||
LocalHistoryLog.LOG.error(String.format("Couldn't revert %s to local history label.", f.getName()), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.history.integration;
|
||||
|
||||
import com.intellij.history.Label;
|
||||
import com.intellij.history.core.revisions.ChangeRevision;
|
||||
import com.intellij.history.core.revisions.Revision;
|
||||
import com.intellij.history.integration.ui.models.HistoryDialogModel;
|
||||
import com.intellij.history.integration.ui.models.RevisionItem;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LocalHistoryUtil {
|
||||
|
||||
static int findRevisionIndexToRevert(@NotNull HistoryDialogModel dirHistoryModel, @NotNull Label label) {
|
||||
List<RevisionItem> revs = dirHistoryModel.getRevisions();
|
||||
for (int i = 0; i < revs.size(); i++) {
|
||||
final RevisionItem rev = revs.get(i);
|
||||
if (isLabelRevision(rev, label)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static boolean isLabelRevision(@NotNull RevisionItem rev, @NotNull Label label) {
|
||||
final long targetChangeId = label.getLabelChangeId();
|
||||
return ContainerUtil.exists(rev.labels, new Condition<Revision>() {
|
||||
@Override
|
||||
public boolean value(Revision revision) {
|
||||
return revision instanceof ChangeRevision && ((ChangeRevision)revision).containsChangeWithId(targetChangeId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.history.integration.revertion;
|
||||
|
||||
import com.intellij.history.Label;
|
||||
import com.intellij.history.LocalHistory;
|
||||
import com.intellij.history.integration.IntegrationTestCase;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
|
||||
public class HistoryReverterToLabelTest extends IntegrationTestCase {
|
||||
|
||||
public void testFileCreation() throws Exception {
|
||||
createChildData(myRoot, "first.txt");
|
||||
final LocalHistory localHistory = LocalHistory.getInstance();
|
||||
final Label testLabel = localHistory.putSystemLabel(myProject, "testLabel");
|
||||
createChildData(myRoot, "foo.txt");
|
||||
localHistory.revertToLabel(myProject, myRoot, testLabel);
|
||||
assertNull(myRoot.findChild("foo.txt"));
|
||||
assertNotNull(myRoot.findChild("first.txt"));
|
||||
}
|
||||
|
||||
public void testFileDeletion() throws Exception {
|
||||
VirtualFile f = createChildData(myRoot, "foo.txt");
|
||||
setBinaryContent(f, new byte[]{123}, -1, 4000, this);
|
||||
final LocalHistory localHistory = LocalHistory.getInstance();
|
||||
final Label testLabel = localHistory.putSystemLabel(myProject, "testLabel");
|
||||
delete(f);
|
||||
localHistory.revertToLabel(myProject, myRoot, testLabel);
|
||||
f = myRoot.findChild("foo.txt");
|
||||
assertNotNull(f);
|
||||
assertEquals(123, f.contentsToByteArray()[0]);
|
||||
assertEquals(4000, f.getTimeStamp());
|
||||
}
|
||||
|
||||
public void testFileDeletionWithContent() throws Exception {
|
||||
VirtualFile f = createChildData(myRoot, "foo.txt");
|
||||
final LocalHistory localHistory = LocalHistory.getInstance();
|
||||
final Label testLabel = localHistory.putSystemLabel(myProject, "testLabel");
|
||||
setBinaryContent(f, new byte[]{123}, -1, 4000, this);
|
||||
delete(f);
|
||||
localHistory.revertToLabel(myProject, myRoot, testLabel);
|
||||
f = myRoot.findChild("foo.txt");
|
||||
assertNotNull(f);
|
||||
assertEquals(0, f.contentsToByteArray().length);
|
||||
}
|
||||
|
||||
public void testParentAndChildRename() throws Exception {
|
||||
VirtualFile dir = createChildDirectory(myRoot, "dir");
|
||||
VirtualFile f = createChildData(dir, "foo.txt");
|
||||
int modificationStamp = -1;
|
||||
setBinaryContent(f, new byte[]{123}, modificationStamp, 4000, this);
|
||||
final LocalHistory localHistory = LocalHistory.getInstance();
|
||||
final Label testLabel1 = localHistory.putSystemLabel(myProject, "testLabel");
|
||||
rename(dir, "dir2");
|
||||
final Label testLabel2 = localHistory.putSystemLabel(myProject, "testLabel");
|
||||
rename(f, "bar.txt");
|
||||
|
||||
localHistory.revertToLabel(myProject, myRoot, testLabel2);
|
||||
|
||||
assertNotNull(myRoot.findChild("dir2"));
|
||||
dir = myRoot.findChild("dir2");
|
||||
|
||||
assert dir != null;
|
||||
assertNull(dir.findChild("bar.txt"));
|
||||
f = dir.findChild("foo.txt");
|
||||
assertNotNull(f);
|
||||
assertEquals(123, f.contentsToByteArray()[0]);
|
||||
assertEquals(4000, f.getTimeStamp());
|
||||
|
||||
localHistory.revertToLabel(myProject, myRoot, testLabel1);
|
||||
assertNull(myRoot.findChild("dir2"));
|
||||
dir = myRoot.findChild("dir");
|
||||
|
||||
assert dir != null;
|
||||
assertNull(dir.findChild("bar.txt"));
|
||||
f = dir.findChild("foo.txt");
|
||||
assertNotNull(f);
|
||||
assertEquals(123, f.contentsToByteArray()[0]);
|
||||
assertEquals(4000, f.getTimeStamp());
|
||||
}
|
||||
|
||||
public void testRevertContentChange() throws Exception {
|
||||
VirtualFile f = createChildData(myRoot, "foo.txt");
|
||||
int modificationStamp1 = -1;
|
||||
setBinaryContent(f, new byte[]{1}, modificationStamp1, 1000, this);
|
||||
final LocalHistory localHistory = LocalHistory.getInstance();
|
||||
final Label testLabel = localHistory.putSystemLabel(myProject, "testLabel");
|
||||
int modificationStamp = -1;
|
||||
setBinaryContent(f, new byte[]{2}, modificationStamp, 2000, this);
|
||||
setBinaryContent(f, new byte[]{3}, modificationStamp, 3000, this);
|
||||
localHistory.revertToLabel(myProject, myRoot, testLabel);
|
||||
f = myRoot.findChild("foo.txt");
|
||||
assertNotNull(f);
|
||||
assertEquals(1, f.contentsToByteArray()[0]);
|
||||
assertEquals(1000, f.getTimeStamp());
|
||||
}
|
||||
}
|
||||
+2
@@ -16,6 +16,7 @@
|
||||
package com.intellij.openapi.diff.impl.patch.formove;
|
||||
|
||||
import com.intellij.history.Label;
|
||||
import com.intellij.history.LocalHistory;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -70,6 +71,7 @@ class UndoApplyPatchDialog extends DialogWrapper {
|
||||
@Override
|
||||
protected void doOKAction() {
|
||||
super.doOKAction();
|
||||
LocalHistory.getInstance().revertToLabel(myProject, myProject.getBaseDir(), myBeforeLabel);
|
||||
}
|
||||
|
||||
static void rollbackApplyPatch(@NotNull Project project, @NotNull List<FilePath> filePaths,
|
||||
|
||||
Reference in New Issue
Block a user