Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use LTK Refactoring when copying (duplicating) a Project. #2262

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Automatic-Module-Name: org.eclipse.ltk.core.refactoring
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.ltk.core.refactoring; singleton:=true
Bundle-Version: 3.14.600.qualifier
Bundle-Version: 3.15.0.qualifier
Bundle-Activator: org.eclipse.ltk.internal.core.refactoring.RefactoringCorePlugin
Bundle-ActivationPolicy: lazy
Bundle-Vendor: %providerName
Expand Down
4 changes: 4 additions & 0 deletions bundles/org.eclipse.ltk.core.refactoring/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,9 @@
<contribution
class="org.eclipse.ltk.internal.core.refactoring.resource.MoveRenameResourceRefactoringContribution"
id="org.eclipse.ltk.core.refactoring.moverename.resource"/>
<contribution
class="org.eclipse.ltk.internal.core.refactoring.resource.CopyProjectRefactoringContribution"
id="org.eclipse.ltk.core.refactoring.copyproject.resource">
</contribution>
</extension>
</plugin>
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;
}

}
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;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ public final class RefactoringCoreMessages extends NLS {

public static String CompositeChange_performingChangesTask_name;

public static String CopyProjectChange_copying;

public static String CopyProjectChange_error_resource_not_exists;

public static String CopyProjectChange_Name;

public static String CopyProjectDescriptor_project_copy_does_not_exist;

public static String CopyProjectProcessor_description;

public static String CopyProjectProcessor_error_project_exists;

public static String CopyProjectProcessor_name;

public static String CreateChangeOperation_unknown_Refactoring;

public static String DefaultRefactoringDescriptor_cannot_create_refactoring;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ BufferValidationState_character_encoding_changed=The character encoding of ''{0}
CheckConditionContext_error_checker_exists= A checker of type ''{0}'' already exists.

CompositeChange_performingChangesTask_name=Performing changes...
CopyProjectChange_copying=Copying...
CopyProjectChange_error_resource_not_exists=Can not copy Project ''{0}''. Project does not exist.
CopyProjectChange_Name=Copy Project
CopyProjectDescriptor_project_copy_does_not_exist=The Project ''{0}'' to copy does not exist.
CopyProjectProcessor_description=Copy Project ''{0}''
CopyProjectProcessor_error_project_exists=There is already a Project with the name ''{0}''
CopyProjectProcessor_name=Copy Project

ProcessorBasedRefactoring_initial_conditions=Checking preconditions...
ProcessorBasedRefactoring_check_condition_participant_failed=The participant ''{0}'' caused an internal error and has been disabled for this refactoring. See the error log for more details.
Expand Down
Loading
Loading