Commit 8ae46755 authored by Romain Bioteau's avatar Romain Bioteau Committed by GitHub
Browse files

feat(import) Import from another workspace (#538)

Closes [BS-16686](https://bonitasoft.atlassian.net/browse/BS-16686)
parent 6b381ad2
......@@ -125,6 +125,10 @@
icon="icons/menuIcons/import.png"
style="push">
</command>
<command
commandId="org.bonitasoft.studio.importer.workspace.command"
style="push">
</command>
<command
commandId="org.bonitasoft.studio.importer.other.command"
style="push">
......
......@@ -499,23 +499,18 @@ public class Repository implements IRepository, IJavaContainer {
}
@Override
public void exportToArchive(final String fileName) {
public IStatus exportToArchive(final String fileName) {
final ExportBosArchiveOperation operation = new ExportBosArchiveOperation();
operation.setDestinationPath(fileName);
final Set<IResource> allResources = new HashSet<>();
final Set<IRepositoryFileStore> fileStores = new HashSet<>();
for (final IRepositoryStore<?> store : getAllExportableStores()) {
for (final IRepositoryFileStore fs : store.getChildren()) {
if (fs.canBeExported()) {
allResources.add(fs.getResource());
for (final IRepositoryFileStore relatedFs : fs.getRelatedFileStore()) {
if (relatedFs.canBeExported()) {
allResources.add(relatedFs.getResource());
}
}
fileStores.add(fs);
}
}
}
operation.setResources(allResources);
operation.setFileStores(fileStores);
final IStatus status = operation.run(NULL_PROGRESS_MONITOR);
if (!status.isOK()) {
logErrorStatus(status);
......@@ -523,6 +518,7 @@ public class Repository implements IRepository, IJavaContainer {
BonitaStudioLog.info(String.format("%s archive exported successfully.", fileName),
CommonRepositoryPlugin.PLUGIN_ID);
}
return status;
}
protected void logErrorStatus(final IStatus status) {
......
......@@ -86,6 +86,10 @@ public class RepositoryAccessor {
return repositoryManagerInstance.getRepository(targetRepository);
}
public void setRepository(final String repositoryName) {
repositoryManagerInstance.setRepository(repositoryName, false, Repository.NULL_PROGRESS_MONITOR);
}
public List<IRepository> getAllRepositories() {
return repositoryManagerInstance.getAllRepositories();
}
......
......@@ -25,6 +25,7 @@ import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.edapt.migration.MigrationException;
import org.eclipse.swt.graphics.Image;
......@@ -65,7 +66,7 @@ public interface IRepository extends IFileStoreChangeListener {
Image getIcon();
void exportToArchive(String file);
IStatus exportToArchive(String file);
IRepositoryFileStore getFileStore(IResource resource);
......
......@@ -5,14 +5,12 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2.0 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.bonitasoft.studio.common.repository.operation;
......@@ -24,8 +22,10 @@ import java.io.InputStream;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Pattern;
import org.bonitasoft.studio.common.ProductVersion;
import org.bonitasoft.studio.common.jface.FileActionDialog;
......@@ -34,7 +34,9 @@ import org.bonitasoft.studio.common.platform.tools.PlatformUtil;
import org.bonitasoft.studio.common.repository.CommonRepositoryPlugin;
import org.bonitasoft.studio.common.repository.Repository;
import org.bonitasoft.studio.common.repository.RepositoryManager;
import org.bonitasoft.studio.common.repository.model.IRepositoryFileStore;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
......@@ -45,125 +47,161 @@ import org.eclipse.ui.internal.wizards.datatransfer.ArchiveFileExportOperation;
/**
* @author Romain Bioteau
*
*/
public class ExportBosArchiveOperation {
public static final String VERSION = "version";
private static final String BOS_MANIFEST_COMMENT = "Generated with BOS";
public static final String BOS_ARCHIVE_MANIFEST = "MANIFEST";
public static final String TO_OPEN = "toOpen";
public static final String NONE = "<NONE>";
private Set<IResource> resources;
private IStatus status;
private String destPath;
private IFile manifestFile;
private Set<IResource> resourcesToReOpen;
public IStatus run(final IProgressMonitor monitor) {
status = Status.OK_STATUS;
Assert.isNotNull(destPath);
Assert.isNotNull(resources);
final File destFile = new File(destPath);
if (destFile.exists()) {
if (FileActionDialog.overwriteQuestion(destFile.getName())) {
PlatformUtil.delete(destFile, monitor);
} else {
status = Status.CANCEL_STATUS;
return status;
}
}
if (!destFile.getParentFile().exists()) {
destFile.getParentFile().mkdirs();
}
status = addManifest();
if (!status.isOK()) {
return status;
}
final ArchiveFileExportOperation op = new ArchiveFileExportOperation(null, new ArrayList<IResource>(resources),
destPath);
op.setCreateLeadupStructure(true);
op.setUseCompression(true);
op.setUseTarFormat(false);
try {
op.run(monitor);
if (manifestFile != null && manifestFile.exists()) {
manifestFile.delete(true, Repository.NULL_PROGRESS_MONITOR);
}
} catch (final CoreException | InterruptedException | InvocationTargetException e) {
status = new Status(IStatus.ERROR, CommonRepositoryPlugin.PLUGIN_ID, e.getMessage(), e);
return status;
}
status = op.getStatus();
return status;
}
protected IStatus addManifest() {
manifestFile = RepositoryManager.getInstance().getCurrentRepository().getProject()
.getFile(BOS_ARCHIVE_MANIFEST);
if (manifestFile.exists()) {
try {
manifestFile.delete(true, Repository.NULL_PROGRESS_MONITOR);
} catch (final CoreException e) {
BonitaStudioLog.error(e);
return new Status(IStatus.ERROR, CommonRepositoryPlugin.PLUGIN_ID, e.getMessage(), e);
}
}
final Properties prop = new Properties();
prop.put(VERSION, ProductVersion.CURRENT_VERSION);
if (resourcesToReOpen != null && !resourcesToReOpen.isEmpty()) {
final StringBuilder sb = new StringBuilder();
for (final IResource r : resourcesToReOpen) {
sb.append(r.getName());
sb.append(",");
}
if (sb.length() > 0) {
sb.delete(sb.length() - 1, sb.length());
}
prop.put(TO_OPEN, sb.toString());
} else {
prop.put(TO_OPEN, NONE);
}
final Writer w = new CharArrayWriter();
try {
prop.store(w, BOS_MANIFEST_COMMENT);
} catch (final IOException e) {
BonitaStudioLog.error(e);
return new Status(IStatus.ERROR, CommonRepositoryPlugin.PLUGIN_ID, e.getMessage(), e);
}
final InputStream source = new ByteArrayInputStream(w.toString().getBytes());
try {
manifestFile.create(source, IResource.FORCE, Repository.NULL_PROGRESS_MONITOR);
} catch (final CoreException e1) {
return new Status(IStatus.ERROR, CommonRepositoryPlugin.PLUGIN_ID, e1.getMessage(), e1);
}
resources.add(manifestFile);
return Status.OK_STATUS;
}
public IStatus getStatus() {
return status;
}
public void setResources(final Set<IResource> resourcesToExport) {
resources = resourcesToExport;
}
public void setResourcesToOpen(final Set<IResource> resourcesToReopenAtImport) {
resourcesToReOpen = resourcesToReopenAtImport;
}
public void setDestinationPath(final String destPath) {
this.destPath = destPath;
}
public static final String VERSION = "version";
private static final String BOS_MANIFEST_COMMENT = "Generated with BOS";
public static final String BOS_ARCHIVE_MANIFEST = "MANIFEST";
public static final String TO_OPEN = "toOpen";
public static final String NONE = "<NONE>";
private Set<IResource> resources;
private IStatus status;
private String destPath;
private IFile manifestFile;
private Set<IResource> resourcesToReOpen;
public IStatus run(final IProgressMonitor monitor) {
status = Status.OK_STATUS;
Assert.isNotNull(destPath);
final File destFile = new File(destPath);
if (destFile.exists()) {
if (FileActionDialog.overwriteQuestion(destFile.getName())) {
PlatformUtil.delete(destFile, monitor);
} else {
status = Status.CANCEL_STATUS;
return status;
}
}
if (!destFile.getParentFile().exists()) {
destFile.getParentFile().mkdirs();
}
status = addManifest();
if (!status.isOK()) {
return status;
}
final ArchiveFileExportOperation op = new ArchiveFileExportOperation(null, new ArrayList<>(resources),
destPath);
op.setCreateLeadupStructure(true);
op.setUseCompression(true);
op.setUseTarFormat(false);
try {
op.run(monitor);
if (manifestFile != null && manifestFile.exists()) {
manifestFile.delete(true, Repository.NULL_PROGRESS_MONITOR);
}
} catch (final CoreException | InterruptedException | InvocationTargetException e) {
status = new Status(IStatus.ERROR, CommonRepositoryPlugin.PLUGIN_ID, e.getMessage(), e);
return status;
}
status = op.getStatus();
return status;
}
protected IStatus addManifest() {
manifestFile = RepositoryManager.getInstance().getCurrentRepository().getProject()
.getFile(BOS_ARCHIVE_MANIFEST);
if (manifestFile.exists()) {
try {
manifestFile.delete(true, Repository.NULL_PROGRESS_MONITOR);
} catch (final CoreException e) {
BonitaStudioLog.error(e);
return new Status(IStatus.ERROR, CommonRepositoryPlugin.PLUGIN_ID, e.getMessage(), e);
}
}
final Properties prop = new Properties();
prop.put(VERSION, ProductVersion.CURRENT_VERSION);
if (resourcesToReOpen != null && !resourcesToReOpen.isEmpty()) {
final StringBuilder sb = new StringBuilder();
for (final IResource r : resourcesToReOpen) {
sb.append(r.getName());
sb.append(",");
}
if (sb.length() > 0) {
sb.delete(sb.length() - 1, sb.length());
}
prop.put(TO_OPEN, sb.toString());
} else {
prop.put(TO_OPEN, NONE);
}
final Writer w = new CharArrayWriter();
try {
prop.store(w, BOS_MANIFEST_COMMENT);
} catch (final IOException e) {
BonitaStudioLog.error(e);
return new Status(IStatus.ERROR, CommonRepositoryPlugin.PLUGIN_ID, e.getMessage(), e);
}
final InputStream source = new ByteArrayInputStream(w.toString().getBytes());
try {
manifestFile.create(source, IResource.FORCE, Repository.NULL_PROGRESS_MONITOR);
} catch (final CoreException e1) {
return new Status(IStatus.ERROR, CommonRepositoryPlugin.PLUGIN_ID, e1.getMessage(), e1);
}
resources.add(manifestFile);
return Status.OK_STATUS;
}
public IStatus getStatus() {
return status;
}
public void setResourcesToOpen(final Set<IResource> resourcesToReopenAtImport) {
resourcesToReOpen = resourcesToReopenAtImport;
}
public void setDestinationPath(final String destPath) {
this.destPath = destPath;
}
protected Set<IResource> computeResourcesToExport(Set<IRepositoryFileStore> fileStores) {
final Set<IResource> resourcesToExport = new HashSet<>();
for (final IRepositoryFileStore file : fileStores) {
final IResource resource = file.getResource();
if (resource != null && resource.exists()) {
try {
addChildrenFile(resource, resourcesToExport);
} catch (final CoreException e) {
BonitaStudioLog.error(e);
}
resourcesToExport.addAll(file.getRelatedResources());
}
}
return resourcesToExport;
}
private void addChildrenFile(IResource resource, Set<IResource> resourcesToExport) throws CoreException {
if (resource instanceof IFile) {
resourcesToExport.add(resource);
} else if (resource instanceof IFolder && !isMetadataFolder(resource) && !isTargetFolder(resource)) {
for (final IResource r : ((IFolder) resource).members()) {
addChildrenFile(r, resourcesToExport);
}
}
}
private boolean isTargetFolder(IResource resource) {
return Pattern.matches("target", resource.getName());
}
private boolean isMetadataFolder(IResource resource) {
return Pattern.matches(".metadata", resource.getName());
}
public void setFileStores(Set<IRepositoryFileStore> fileStores) {
resources = computeResourcesToExport(fileStores);
}
public Set<IResource> getResources() {
return resources;
}
}
......@@ -304,7 +304,7 @@ public abstract class AbstractRepositoryStore<T extends IRepositoryFileStore> im
return result;
} catch (final CoreException e1) {
BonitaStudioLog.error("Failed to retrieve store children", e1);
return Collections.emptyList();
return newArrayList();
}
}
......
......@@ -30,7 +30,7 @@ import org.eclipse.core.runtime.CoreException;
*/
public class FileStoreCollector implements IResourceVisitor {
private final List<IResource> collectedResources = new ArrayList<IResource>();
private final List<IResource> collectedResources = new ArrayList<>();
private final Set<String> fileExtensions;
private final IResource root;
......
......@@ -21,7 +21,6 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import org.bonitasoft.studio.common.editor.EditorUtil;
import org.bonitasoft.studio.common.jface.databinding.validator.EmptyInputValidator;
......@@ -38,9 +37,7 @@ import org.eclipse.core.databinding.observable.set.IObservableSet;
import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.databinding.validation.ValidationStatus;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.databinding.swt.SWTObservables;
......@@ -294,13 +291,13 @@ public class ExportRepositoryWizardPage extends WizardPage {
protected ExportBosArchiveOperation createExportBOSOperation() {
final ExportBosArchiveOperation operation = new ExportBosArchiveOperation();
operation.setDestinationPath(getDetinationPath());
final Set<IResource> resourcesToExport = computeResourcesToExport();
operation.setFileStores(getSelectedFileStores());
try {
final Set<IResource> toOpen = new HashSet<>();
for (final IEditorReference ref : PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.getEditorReferences()) {
final IFile file = (IFile) EditorUtil.retrieveResourceFromEditorInput(ref.getEditorInput());
if (resourcesToExport.contains(file)) {
if (operation.getResources().contains(file)) {
toOpen.add(file);
}
}
......@@ -309,44 +306,9 @@ public class ExportRepositoryWizardPage extends WizardPage {
BonitaStudioLog.error(e);
}
operation.setResources(resourcesToExport);
return operation;
}
protected Set<IResource> computeResourcesToExport() {
final Set<IResource> resourcesToExport = new HashSet<>();
for (final IRepositoryFileStore file : getSelectedFileStores()) {
final IResource resource = file.getResource();
if (resource != null && resource.exists()) {
try {
addChildrenFile(resource, resourcesToExport);
} catch (final CoreException e) {
BonitaStudioLog.error(e);
}
resourcesToExport.addAll(file.getRelatedResources());
}
}
return resourcesToExport;
}
private void addChildrenFile(IResource resource, Set<IResource> resourcesToExport) throws CoreException {
if (resource instanceof IFile) {
resourcesToExport.add(resource);
} else if (resource instanceof IFolder && !isMetadataFolder(resource) && !isTargetFolder(resource)) {
for (final IResource r : ((IFolder) resource).members()) {
addChildrenFile(r, resourcesToExport);
}
}
}
private boolean isTargetFolder(IResource resource) {
return Pattern.matches("target", resource.getName());
}
private boolean isMetadataFolder(IResource resource) {
return Pattern.matches(".metadata", resource.getName());
}
protected void createDestination(final Composite group) {
final Label destPath = new Label(group, SWT.NONE);
destPath.setText(Messages.destinationPath + " *");
......
......@@ -48,4 +48,10 @@ public class ProductVersionTest {
final String currentYear = new SimpleDateFormat("yyyy").format(new Date());
assertThat(ProductVersion.CURRENT_YEAR).isEqualTo(currentYear);
}
@Test
public void should_not_import_version_below_6_0_0() throws Exception {
assertThat(ProductVersion.canBeImported("5.10.0")).isFalse();
assertThat(ProductVersion.canBeImported("6.0.0")).isTrue();
}
}
......@@ -63,6 +63,7 @@ public class ProductVersion {
if (version == null) {
return true;
}
final Version initialVersion = new Version("6.0.0");
Version current = new Version("0.0.0");
try {
current = Version.parseVersion(version);
......@@ -70,7 +71,7 @@ public class ProductVersion {
return false;
}
final Version productVersion = new Version(CURRENT_VERSION);
return current.compareTo(productVersion) <= 0;
return current.compareTo(productVersion) <= 0 && current.compareTo(initialVersion) >= 0;
}
public static String majorVersion() {
......
......@@ -39,7 +39,13 @@ Require-Bundle: org.eclipse.ui,
org.eclipse.e4.core.di,
org.json,
org.eclipse.jface.databinding,
org.bonitasoft.studio.connectors
org.bonitasoft.studio.connectors,
org.eclipse.debug.core,
org.eclipse.pde.launching;bundle-version="3.6.200",
org.bonitasoft.studio.connectors.model.edit,