-
Notifications
You must be signed in to change notification settings - Fork 188
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use LTK Refactoring when copying (duplicating) a Project.
The Idea is that currently it is not possible to modify a project when it is copied and renamed. This leads to usability issues for example in PDE, where the rename of a project modifies the MANIFEST.MF but a copy does not. This solves this by providing a copy project refactoring that can be extended using a copy participant.
- Loading branch information
Showing
15 changed files
with
841 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
153 changes: 153 additions & 0 deletions
153
...ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/resource/CopyProjectChange.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2024 Vector Informatik GmbH and others. | ||
* | ||
* This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License 2.0 | ||
* which accompanies this distribution, and is available at | ||
* https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Vector Informatik GmbH - initial implementation | ||
*******************************************************************************/ | ||
package org.eclipse.ltk.core.refactoring.resource; | ||
|
||
import org.eclipse.core.runtime.Assert; | ||
import org.eclipse.core.runtime.CoreException; | ||
import org.eclipse.core.runtime.IPath; | ||
import org.eclipse.core.runtime.IProgressMonitor; | ||
import org.eclipse.core.runtime.IStatus; | ||
import org.eclipse.core.runtime.NullProgressMonitor; | ||
import org.eclipse.core.runtime.Platform; | ||
import org.eclipse.core.runtime.Status; | ||
import org.eclipse.core.runtime.SubMonitor; | ||
|
||
import org.eclipse.core.resources.IFile; | ||
import org.eclipse.core.resources.IProject; | ||
import org.eclipse.core.resources.IProjectDescription; | ||
import org.eclipse.core.resources.IResource; | ||
import org.eclipse.core.resources.IResourceVisitor; | ||
|
||
import org.eclipse.core.filebuffers.FileBuffers; | ||
import org.eclipse.core.filebuffers.ITextFileBuffer; | ||
import org.eclipse.core.filebuffers.LocationKind; | ||
|
||
import org.eclipse.ltk.core.refactoring.Change; | ||
import org.eclipse.ltk.core.refactoring.ChangeDescriptor; | ||
import org.eclipse.ltk.internal.core.refactoring.BasicElementLabels; | ||
import org.eclipse.ltk.internal.core.refactoring.Messages; | ||
import org.eclipse.ltk.internal.core.refactoring.RefactoringCoreMessages; | ||
import org.eclipse.ltk.internal.core.refactoring.RefactoringCorePlugin; | ||
|
||
/** | ||
* {@link Change} that copies a project | ||
* | ||
* @since 3.15 | ||
*/ | ||
public class CopyProjectChange extends ResourceChange { | ||
|
||
private final IProject fSourceProject; | ||
|
||
private ChangeDescriptor fDescriptor; | ||
|
||
private String fNewName; | ||
|
||
private IPath fNewLocation; | ||
|
||
/** | ||
* Copy a project. | ||
* | ||
* @param resourcePath the project path | ||
* @param newLocation location of the new project | ||
* @param newName name of the new project | ||
*/ | ||
public CopyProjectChange(IProject resourcePath, IPath newLocation, String newName) { | ||
Assert.isNotNull(resourcePath); | ||
fNewName= newName; | ||
fNewLocation= newLocation; | ||
fSourceProject= resourcePath; | ||
setValidationMethod(SAVE_IF_DIRTY); | ||
} | ||
|
||
@Override | ||
protected IResource getModifiedResource() { | ||
return fSourceProject; | ||
} | ||
|
||
|
||
@Override | ||
public String getName() { | ||
return RefactoringCoreMessages.CopyProjectChange_Name + fSourceProject.getName(); | ||
} | ||
|
||
@Override | ||
public Change perform(IProgressMonitor pm) throws CoreException { | ||
SubMonitor subMonitor= SubMonitor.convert(pm, RefactoringCoreMessages.CopyProjectChange_copying, 10); | ||
|
||
if (fSourceProject == null || !fSourceProject.exists()) { | ||
String message= Messages.format(RefactoringCoreMessages.CopyProjectChange_error_resource_not_exists, | ||
BasicElementLabels.getPathLabel(fSourceProject.getFullPath().makeRelative(), false)); | ||
throw new CoreException(new Status(IStatus.ERROR, RefactoringCorePlugin.getPluginId(), message)); | ||
} | ||
|
||
// make sure all files inside the resource are saved | ||
if (fSourceProject.isAccessible()) { | ||
fSourceProject.accept((IResourceVisitor) curr -> { | ||
try { | ||
if (curr instanceof IFile) { | ||
// progress is covered outside. | ||
saveFileIfNeeded((IFile) curr, new NullProgressMonitor()); | ||
} | ||
} catch (CoreException e) { | ||
// ignore | ||
} | ||
return true; | ||
}, IResource.DEPTH_INFINITE, false); | ||
} | ||
|
||
IProjectDescription description= fSourceProject.getDescription(); | ||
|
||
if (fNewLocation != null && (fNewLocation.equals(Platform.getLocation()) || fNewLocation.isRoot())) { | ||
fNewLocation= null; | ||
} | ||
|
||
description.setName(fNewName); | ||
description.setLocation(fNewLocation); | ||
|
||
fSourceProject.copy(description, IResource.FORCE | IResource.SHALLOW, subMonitor.newChild(10)); | ||
|
||
IProject targetProject= fSourceProject.getWorkspace().getRoot().getProject(fNewName); | ||
|
||
return new DeleteResourceChange(targetProject.getFullPath(), true, true); | ||
|
||
} | ||
|
||
private static void saveFileIfNeeded(IFile file, IProgressMonitor pm) throws CoreException { | ||
ITextFileBuffer buffer= FileBuffers.getTextFileBufferManager().getTextFileBuffer(file.getFullPath(), LocationKind.IFILE); | ||
SubMonitor subMonitor= SubMonitor.convert(pm, 2); | ||
if (buffer != null && buffer.isDirty() && buffer.isStateValidated() && buffer.isSynchronized()) { | ||
buffer.commit(subMonitor.newChild(1), false); | ||
file.refreshLocal(IResource.DEPTH_ONE, subMonitor.newChild(1)); | ||
buffer.commit(subMonitor.newChild(1), false); | ||
file.refreshLocal(IResource.DEPTH_ONE, subMonitor.newChild(1)); | ||
} else { | ||
subMonitor.worked(2); | ||
} | ||
} | ||
|
||
@Override | ||
public ChangeDescriptor getDescriptor() { | ||
return fDescriptor; | ||
} | ||
|
||
/** | ||
* Sets the change descriptor to be returned by {@link Change#getDescriptor()}. | ||
* | ||
* @param descriptor the change descriptor | ||
*/ | ||
public void setDescriptor(ChangeDescriptor descriptor) { | ||
fDescriptor= descriptor; | ||
} | ||
|
||
} |
145 changes: 145 additions & 0 deletions
145
...core.refactoring/src/org/eclipse/ltk/core/refactoring/resource/CopyProjectDescriptor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2024 Vector Informatik GmbH and others. | ||
* | ||
* This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License 2.0 | ||
* which accompanies this distribution, and is available at | ||
* https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Vector Informatik GmbH - initial implementation | ||
*******************************************************************************/ | ||
package org.eclipse.ltk.core.refactoring.resource; | ||
|
||
import org.eclipse.core.runtime.CoreException; | ||
import org.eclipse.core.runtime.IPath; | ||
|
||
import org.eclipse.core.resources.IFile; | ||
import org.eclipse.core.resources.IFolder; | ||
import org.eclipse.core.resources.IProject; | ||
import org.eclipse.core.resources.IResource; | ||
import org.eclipse.core.resources.IWorkspaceRoot; | ||
import org.eclipse.core.resources.ResourcesPlugin; | ||
|
||
import org.eclipse.ltk.core.refactoring.Refactoring; | ||
import org.eclipse.ltk.core.refactoring.RefactoringContribution; | ||
import org.eclipse.ltk.core.refactoring.RefactoringCore; | ||
import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; | ||
import org.eclipse.ltk.core.refactoring.RefactoringStatus; | ||
import org.eclipse.ltk.core.refactoring.participants.CopyRefactoring; | ||
import org.eclipse.ltk.internal.core.refactoring.BasicElementLabels; | ||
import org.eclipse.ltk.internal.core.refactoring.Messages; | ||
import org.eclipse.ltk.internal.core.refactoring.RefactoringCoreMessages; | ||
import org.eclipse.ltk.internal.core.refactoring.resource.CopyProjectProcessor; | ||
|
||
/** | ||
* Refactoring descriptor for the copy project refactoring. | ||
* <p> | ||
* An instance of this refactoring descriptor may be obtained by calling | ||
* {@link RefactoringContribution#createDescriptor()} on a refactoring contribution requested by | ||
* invoking {@link RefactoringCore#getRefactoringContribution(String)} with the refactoring id | ||
* ({@link #ID}). | ||
* </p> | ||
* <p> | ||
* Note: this class is not intended to be subclassed or instantiated by clients. | ||
* </p> | ||
* | ||
* @since 3.15 | ||
* | ||
* @noinstantiate This class is not intended to be instantiated by clients. | ||
* @noextend This class is not intended to be subclassed by clients. | ||
*/ | ||
public class CopyProjectDescriptor extends RefactoringDescriptor { | ||
/** | ||
* Refactoring id of the 'Copy Project' refactoring (value: | ||
* <code>org.eclipse.ltk.core.refactoring.copyproject.resources</code>). | ||
* <p> | ||
* Clients may safely cast the obtained refactoring descriptor to {@link CopyProjectDescriptor}. | ||
* </p> | ||
*/ | ||
public static final String ID= "org.eclipse.ltk.core.refactoring.copyproject.resource"; //$NON-NLS-1$ | ||
|
||
private IPath fSourcePath; | ||
|
||
private String fNewName; | ||
|
||
private IPath fNewLocation; | ||
|
||
/** | ||
* Creates a new refactoring descriptor. | ||
* <p> | ||
* Clients should not instantiated this class but use | ||
* {@link RefactoringCore#getRefactoringContribution(String)} with {@link #ID} to get the | ||
* contribution that can create the descriptor. | ||
* </p> | ||
*/ | ||
public CopyProjectDescriptor() { | ||
super(ID, null, RefactoringCoreMessages.RenameResourceDescriptor_unnamed_descriptor, null, RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE); | ||
} | ||
|
||
/** | ||
* The resource paths to delete. | ||
* | ||
* @return an array of IPaths. | ||
*/ | ||
public IPath getSourcePath() { | ||
return fSourcePath; | ||
} | ||
|
||
public String getNewName() { | ||
return fNewName; | ||
} | ||
|
||
public IPath getNewLocation() { | ||
return fNewLocation; | ||
} | ||
|
||
/** | ||
* The paths to the resources to be deleted. The resources can be {@link IProject} or a mixture | ||
* of {@link IFile} and {@link IFolder}. | ||
* | ||
* @param resourcePath paths of the resources to be deleted | ||
*/ | ||
public void setResourcePath(IPath resourcePath) { | ||
if (resourcePath == null) | ||
throw new IllegalArgumentException(); | ||
fSourcePath= resourcePath; | ||
} | ||
|
||
/** | ||
* The project to be copied. | ||
* | ||
* @param project {@link IProject} to be copied | ||
*/ | ||
public void setProjectToCopy(IProject project) { | ||
if (project == null) | ||
throw new IllegalArgumentException(); | ||
setResourcePath(project.getFullPath()); | ||
} | ||
|
||
@Override | ||
public Refactoring createRefactoring(RefactoringStatus status) throws CoreException { | ||
IWorkspaceRoot wsRoot= ResourcesPlugin.getWorkspace().getRoot(); | ||
IResource resource= wsRoot.findMember(fSourcePath); | ||
if (resource == null || !resource.exists()) { | ||
status.addFatalError(Messages.format(RefactoringCoreMessages.CopyProjectDescriptor_project_copy_does_not_exist, BasicElementLabels.getPathLabel(fSourcePath, false))); | ||
return null; | ||
} | ||
if (resource instanceof IProject project) { | ||
return new CopyRefactoring(new CopyProjectProcessor(project, fNewName, fNewLocation)); | ||
} | ||
return null; | ||
} | ||
|
||
public void setNewName(String newName) { | ||
fNewName= newName; | ||
|
||
} | ||
|
||
public void setNewLocation(IPath newLocation) { | ||
fNewLocation= newLocation; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.