mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Bug 575145 - Importing CMake/Meson Projects
Add API to o.e.tools.templates.ui that hooks into the smart import feature and allows easy implementation of configurators for various CDT project types. Project types that have a IGenerator may use this API to offer smart import functionality by registering their implementation using the org.eclipse.ui.ide.projectConfigurator extension point. This change includes project import implementations for Meson and CMake project types. For these project types users can use the normal project import workflow for their existing non-Eclipse CMake projects instead of using the New Project Wizard. As an additional benefit, users can now also import more than one project at a time, even nested projects. Change also includes SWTBot tests to exercise the feature. Signed-off-by: Mat Booth <mat.booth@gmail.com> Change-Id: I96589e86bee561aa200a4a4487549305765d6409
This commit is contained in:
parent
172d3a25dc
commit
a957e8121d
32 changed files with 586 additions and 69 deletions
1
.gitattributes
vendored
1
.gitattributes
vendored
|
@ -17,6 +17,7 @@ CONTRIBUTING text
|
|||
*.cc text
|
||||
*.cpp text
|
||||
*.h text
|
||||
*.in text
|
||||
*.s text
|
||||
*.S text
|
||||
*.elf binary
|
||||
|
|
|
@ -2,13 +2,13 @@ Manifest-Version: 1.0
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: %Bundle-Name.0
|
||||
Bundle-SymbolicName: org.eclipse.cdt.meson.core;singleton:=true
|
||||
Bundle-Version: 1.1.200.qualifier
|
||||
Bundle-Version: 1.1.300.qualifier
|
||||
Bundle-Activator: org.eclipse.cdt.meson.core.Activator
|
||||
Bundle-Vendor: %provider
|
||||
Require-Bundle: org.eclipse.core.runtime,
|
||||
org.eclipse.core.resources,
|
||||
org.eclipse.cdt.core;bundle-version="6.4.0",
|
||||
org.eclipse.tools.templates.freemarker
|
||||
org.eclipse.tools.templates.freemarker;bundle-version="1.2.200"
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-11
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-Localization: plugin
|
||||
|
|
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: %Bundle-Name.0
|
||||
Bundle-SymbolicName: org.eclipse.cdt.meson.ui;singleton:=true
|
||||
Bundle-Version: 1.1.200.qualifier
|
||||
Bundle-Version: 1.1.300.qualifier
|
||||
Bundle-Vendor: %vendorName
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-11
|
||||
Bundle-Activator: org.eclipse.cdt.meson.ui.Activator
|
||||
|
@ -11,10 +11,9 @@ Bundle-Localization: plugin
|
|||
Require-Bundle: org.eclipse.core.runtime;bundle-version="3.13.0",
|
||||
org.eclipse.ui;bundle-version="3.109.0",
|
||||
org.eclipse.cdt.meson.core;bundle-version="1.0.0",
|
||||
org.eclipse.tools.templates.core;bundle-version="1.1.0",
|
||||
org.eclipse.tools.templates.ui;bundle-version="1.1.1",
|
||||
org.eclipse.tools.templates.ui;bundle-version="1.3.0",
|
||||
org.eclipse.tools.templates.freemarker;bundle-version="1.2.200",
|
||||
org.eclipse.ui.ide;bundle-version="3.13.1",
|
||||
org.eclipse.tools.templates.freemarker;bundle-version="1.0.0",
|
||||
org.eclipse.cdt.core;bundle-version="6.4.0",
|
||||
org.eclipse.core.resources;bundle-version="3.12.0",
|
||||
org.eclipse.debug.core;bundle-version="3.11.0",
|
||||
|
|
|
@ -147,7 +147,12 @@
|
|||
</command>
|
||||
</menuContribution>
|
||||
</extension>
|
||||
|
||||
|
||||
<extension
|
||||
point="org.eclipse.ui.ide.projectConfigurators">
|
||||
<projectConfigurator
|
||||
class="org.eclipse.cdt.internal.meson.ui.MesonProjectConfigurator"
|
||||
label="Meson Project">
|
||||
</projectConfigurator>
|
||||
</extension>
|
||||
|
||||
</plugin>
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2021 Mat Booth 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.meson.ui;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.meson.core.MesonProjectGenerator;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.tools.templates.core.IGenerator;
|
||||
import org.eclipse.tools.templates.ui.ProjectImportConfigurator;
|
||||
|
||||
/**
|
||||
* Smart-import strategy for importing pre-existing Meson projects.
|
||||
*/
|
||||
public class MesonProjectConfigurator extends ProjectImportConfigurator {
|
||||
|
||||
@Override
|
||||
protected List<String> getProjectFileNames() {
|
||||
return List.of("meson.build"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IGenerator getGenerator(IProject project) {
|
||||
// Don't pass any template to the generator, we are importing an existing project
|
||||
MesonProjectGenerator generator = new MesonProjectGenerator(null);
|
||||
generator.setProjectName(project.getName());
|
||||
generator.setLocationURI(project.getLocationURI());
|
||||
return generator;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: %pluginName
|
||||
Bundle-SymbolicName: org.eclipse.cdt.cmake.core;singleton:=true
|
||||
Bundle-Version: 1.4.200.qualifier
|
||||
Bundle-Version: 1.4.300.qualifier
|
||||
Bundle-Activator: org.eclipse.cdt.cmake.core.internal.Activator
|
||||
Bundle-Vendor: %providerName
|
||||
Require-Bundle: org.eclipse.core.runtime,
|
||||
|
@ -10,7 +10,7 @@ Require-Bundle: org.eclipse.core.runtime,
|
|||
org.eclipse.debug.core;bundle-version="3.10.0",
|
||||
org.eclipse.launchbar.core;bundle-version="2.0.0",
|
||||
org.eclipse.cdt.core;bundle-version="5.12.0",
|
||||
org.eclipse.tools.templates.freemarker;bundle-version="1.0.0";visibility:=reexport,
|
||||
org.eclipse.tools.templates.freemarker;bundle-version="1.2.200",
|
||||
com.google.gson,
|
||||
org.eclipse.cdt.jsoncdb.core,
|
||||
org.yaml.snakeyaml;bundle-version="1.14.0"
|
||||
|
|
|
@ -11,3 +11,5 @@ Require-Bundle: org.eclipse.swtbot.go;bundle-version="2.7.0",
|
|||
org.eclipse.cdt.cmake.core;bundle-version="1.2.0"
|
||||
Automatic-Module-Name: org.eclipse.cdt.cmake.ui.tests
|
||||
Bundle-Localization: plugin
|
||||
Import-Package: org.junit.jupiter.api;version="5.8.1",
|
||||
org.junit.jupiter.api.io;version="5.8.1"
|
||||
|
|
|
@ -4,5 +4,7 @@ bin.includes = META-INF/,\
|
|||
.,\
|
||||
plugin.properties,\
|
||||
about.html,\
|
||||
swtbot-test-plugin.properties
|
||||
src.includes = about.html
|
||||
swtbot-test-plugin.properties,\
|
||||
projects/
|
||||
src.includes = about.html,\
|
||||
projects/
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>target-platform-configuration</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<configuration>
|
||||
<dependency-resolution>
|
||||
<extraRequirements>
|
||||
|
@ -50,4 +49,4 @@
|
|||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
# Set the project name and version
|
||||
project(App1 VERSION 1.0)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS "true")
|
||||
|
||||
# Configuration header
|
||||
configure_file(app1.h.in app1.h)
|
||||
|
||||
# Add project executable
|
||||
add_executable(${PROJECT_NAME} app1.c)
|
||||
|
||||
# Include the configuration header
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC "${PROJECT_BINARY_DIR}")
|
|
@ -0,0 +1,8 @@
|
|||
#include <stdio.h>
|
||||
#include "app1.h"
|
||||
|
||||
int main() {
|
||||
printf("Welcome to App1\n");
|
||||
printf("v%d.%d\n", App1_VERSION_MAJOR, App1_VERSION_MINOR);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
#define App1_VERSION_MAJOR @App1_VERSION_MAJOR@
|
||||
#define App1_VERSION_MINOR @App1_VERSION_MINOR@
|
|
@ -0,0 +1,15 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
# Set the project name and version
|
||||
project(App2 VERSION 2.0)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS "true")
|
||||
|
||||
# Configuration header
|
||||
configure_file(app2.h.in app2.h)
|
||||
|
||||
# Add project executable
|
||||
add_executable(${PROJECT_NAME} app2.c)
|
||||
|
||||
# Include the configuration header
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC "${PROJECT_BINARY_DIR}")
|
|
@ -0,0 +1,8 @@
|
|||
#include <stdio.h>
|
||||
#include "app2.h"
|
||||
|
||||
int main() {
|
||||
printf("Welcome to App2\n");
|
||||
printf("v%d.%d\n", App2_VERSION_MAJOR, App2_VERSION_MINOR);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
#define App2_VERSION_MAJOR @App2_VERSION_MAJOR@
|
||||
#define App2_VERSION_MINOR @App2_VERSION_MINOR@
|
|
@ -0,0 +1,18 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
# Set the project name
|
||||
project(NestedProject)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
App1
|
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/App1"
|
||||
PREFIX App1
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
ExternalProject_Add(
|
||||
App2
|
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/App2"
|
||||
PREFIX App2
|
||||
INSTALL_COMMAND ""
|
||||
)
|
|
@ -0,0 +1,15 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
# Set the project name and version
|
||||
project(SimpleProject VERSION 1.0)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS "true")
|
||||
|
||||
# Configuration header
|
||||
configure_file(simple.h.in simple.h)
|
||||
|
||||
# Add project executable
|
||||
add_executable(${PROJECT_NAME} simple.c)
|
||||
|
||||
# Include the configuration header
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC "${PROJECT_BINARY_DIR}")
|
|
@ -0,0 +1,8 @@
|
|||
#include <stdio.h>
|
||||
#include "simple.h"
|
||||
|
||||
int main() {
|
||||
printf("Hello, World!\n");
|
||||
printf("v%d.%d\n", SimpleProject_VERSION_MAJOR, SimpleProject_VERSION_MINOR);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
#define SimpleProject_VERSION_MAJOR @SimpleProject_VERSION_MAJOR@
|
||||
#define SimpleProject_VERSION_MINOR @SimpleProject_VERSION_MINOR@
|
|
@ -1,20 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 QNX Software Systems 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.cmake.ui.internal.tests;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
|
||||
@RunWith(Suite.class)
|
||||
@Suite.SuiteClasses({ NewCMakeProjectTest.class })
|
||||
public class AutomatedIntegrationSuite {
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 QNX Software Systems and others.
|
||||
* Copyright (c) 2017, 2021 QNX Software Systems and others.
|
||||
*
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License 2.0
|
||||
|
@ -11,7 +11,16 @@
|
|||
package org.eclipse.cdt.cmake.ui.internal.tests;
|
||||
|
||||
import static org.eclipse.swtbot.eclipse.finder.matchers.WidgetMatcherFactory.withPartName;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.cdt.cmake.core.CMakeNature;
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
|
@ -19,45 +28,82 @@ import org.eclipse.cdt.core.index.IIndexManager;
|
|||
import org.eclipse.cdt.core.model.CoreModel;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IWorkspace;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.FileLocator;
|
||||
import org.eclipse.core.runtime.ICoreRunnable;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot;
|
||||
import org.eclipse.swtbot.eclipse.finder.waits.Conditions;
|
||||
import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotPerspective;
|
||||
import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView;
|
||||
import org.eclipse.swtbot.swt.finder.utils.SWTBotPreferences;
|
||||
import org.eclipse.swtbot.swt.finder.waits.DefaultCondition;
|
||||
import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell;
|
||||
import org.eclipse.swtbot.swt.finder.widgets.SWTBotTable;
|
||||
import org.eclipse.swtbot.swt.finder.widgets.SWTBotTableItem;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree;
|
||||
import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public class NewCMakeProjectTest {
|
||||
|
||||
private static SWTWorkbenchBot bot;
|
||||
|
||||
@BeforeClass
|
||||
@TempDir
|
||||
public static Path TEMP_DIR;
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
SWTBotPreferences.KEYBOARD_LAYOUT = "EN_US";
|
||||
SWTBotPreferences.TIMEOUT = 10000;
|
||||
bot = new SWTWorkbenchBot();
|
||||
}
|
||||
|
||||
@Before
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
bot.resetWorkbench();
|
||||
|
||||
for (SWTBotView view : bot.views(withPartName("Welcome"))) {
|
||||
view.close();
|
||||
}
|
||||
SWTBotPerspective perspective = bot.perspectiveById("org.eclipse.cdt.ui.CPerspective");
|
||||
perspective.activate();
|
||||
bot.shell().activate();
|
||||
}
|
||||
|
||||
@Test(timeout = 60000)
|
||||
public void createCMakeProject() throws Exception {
|
||||
// open C++ perspective
|
||||
if (!"C/C++".equals(bot.activePerspective().getLabel())) {
|
||||
bot.perspectiveByLabel("C/C++").activate();
|
||||
@AfterEach
|
||||
public void after() {
|
||||
// Delete created projects after we are done with them
|
||||
IWorkspace workspace = ResourcesPlugin.getWorkspace();
|
||||
IProject[] projects = workspace.getRoot().getProjects();
|
||||
ICoreRunnable runnable = new ICoreRunnable() {
|
||||
@Override
|
||||
public void run(IProgressMonitor monitor) throws CoreException {
|
||||
for (IProject project : projects) {
|
||||
project.delete(true, true, null);
|
||||
}
|
||||
}
|
||||
};
|
||||
try {
|
||||
workspace.run(runnable, workspace.getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
|
||||
} catch (CoreException e) {
|
||||
fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Timeout(value = 2, unit = TimeUnit.MINUTES)
|
||||
void createCMakeProject() throws Exception {
|
||||
|
||||
// Activate C/C++ wizard
|
||||
bot.menu("File").menu("New").menu("C/C++ Project").click();
|
||||
|
@ -86,22 +132,113 @@ public class NewCMakeProjectTest {
|
|||
bot.button("Finish").click();
|
||||
bot.waitUntil(Conditions.shellCloses(newProjectShell));
|
||||
|
||||
verifyProjectInExplorer(projectName);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Timeout(value = 2, unit = TimeUnit.MINUTES)
|
||||
void importSimpleCMakeProject() throws Exception {
|
||||
importCMakeProject("SimpleProject", "SimpleProject");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Timeout(value = 2, unit = TimeUnit.MINUTES)
|
||||
void importNestedCMakeProject() throws Exception {
|
||||
importCMakeProject("NestedProject", "NestedProject", "NestedProject/App1", "NestedProject/App2");
|
||||
}
|
||||
|
||||
private void importCMakeProject(String projectDir, String... expectedProjects) throws Exception {
|
||||
// Copy test project out of the bundle to a temp location first
|
||||
Bundle bundle = FrameworkUtil.getBundle(getClass());
|
||||
URL url = FileLocator
|
||||
.toFileURL(FileLocator.find(bundle, new org.eclipse.core.runtime.Path("projects/" + projectDir), null));
|
||||
copyDir(Paths.get(url.getPath()), TEMP_DIR.resolve(projectDir));
|
||||
|
||||
// Activate import wizard
|
||||
bot.menu("File").menu("Import...").click();
|
||||
bot.shell("Import").activate();
|
||||
|
||||
// Open the smart import wizard
|
||||
SWTBotTree wizTree = bot.tree();
|
||||
SWTBotTreeItem generalItem = wizTree.getTreeItem("General").expand();
|
||||
generalItem.getNode("Projects from Folder or Archive").doubleClick();
|
||||
|
||||
// Select path that contains projects to import and check the project type detection works
|
||||
bot.comboBox().setText(TEMP_DIR.resolve(projectDir).toString());
|
||||
SWTBotTree projectProposalTree = bot.tree();
|
||||
assertEquals(expectedProjects.length, projectProposalTree.getAllItems().length);
|
||||
for (SWTBotTreeItem item : projectProposalTree.getAllItems()) {
|
||||
assertEquals("CMake Project", item.cell(1), "Project type was not detected");
|
||||
}
|
||||
|
||||
// Import and verify the project(s)
|
||||
SWTBotShell wizShell = bot.activeShell();
|
||||
bot.button("Finish").click();
|
||||
bot.waitUntil(Conditions.shellCloses(wizShell));
|
||||
for (String expectedProject : expectedProjects) {
|
||||
verifyProjectInExplorer(expectedProject);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyProjectInExplorer(String projectName) throws Exception {
|
||||
// Make sure it shows up in Project Explorer
|
||||
SWTBotView explorer = bot.viewByPartName("Project Explorer");
|
||||
explorer.show();
|
||||
explorer.setFocus();
|
||||
bot.tree().getTreeItem(projectName);
|
||||
|
||||
// Make sure the project indexer completes. At that point we're stable.
|
||||
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
|
||||
ICProject cproject = CoreModel.getDefault().create(project);
|
||||
IIndexManager indexManager = CCorePlugin.getIndexManager();
|
||||
while (!indexManager.isProjectContentSynced(cproject)) {
|
||||
Thread.sleep(1000);
|
||||
// If the project name is a path with >1 segment it was nested, so we need expand the
|
||||
// parent project node to make the child project nodes visible
|
||||
Path path = Paths.get(projectName);
|
||||
SWTBotTreeItem projectNode;
|
||||
if (path.getNameCount() > 1) {
|
||||
SWTBotTreeItem node = explorer.bot().tree().expandNode(path.getName(0).toString());
|
||||
projectNode = node.getNode(path.getFileName().toString());
|
||||
} else {
|
||||
projectNode = explorer.bot().tree().getTreeItem(path.getFileName().toString());
|
||||
}
|
||||
|
||||
// Tests can be unstable if we are too quick, so make sure the project indexer completes
|
||||
// and project natures have been assigned before continuing with post-creation verification.
|
||||
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectNode.getText());
|
||||
bot.waitUntil(new DefaultCondition() {
|
||||
|
||||
@Override
|
||||
public boolean test() throws Exception {
|
||||
int natures = project.getDescription().getNatureIds().length;
|
||||
ICProject cproject = CoreModel.getDefault().create(project);
|
||||
IIndexManager indexManager = CCorePlugin.getIndexManager();
|
||||
return natures > 0 && indexManager.isProjectContentSynced(cproject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFailureMessage() {
|
||||
return "Indexer never finished or natures never assigned for project " + project.getName();
|
||||
}
|
||||
});
|
||||
|
||||
// Make sure it has the right nature
|
||||
assertTrue(project.hasNature(CMakeNature.ID));
|
||||
assertTrue(project.hasNature(CMakeNature.ID), "Project does not have expected nature");
|
||||
|
||||
// Ensure CMakeLists exists
|
||||
assertTrue(project.getFile("CMakeLists.txt").exists(), "Project does not have a build file");
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to perform a depth-first copy of a directory tree.
|
||||
*/
|
||||
private static void copyDir(Path src, Path dest) throws IOException {
|
||||
Files.walk(src).forEach(a -> {
|
||||
if (!a.equals(src)) {
|
||||
Path b = dest.resolve(a.subpath(src.getNameCount(), a.getNameCount()));
|
||||
try {
|
||||
if (!Files.isDirectory(a)) {
|
||||
Files.createDirectories(b.getParent());
|
||||
Files.copy(a, b);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
fail(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: %pluginName
|
||||
Bundle-SymbolicName: org.eclipse.cdt.cmake.ui;singleton:=true
|
||||
Bundle-Version: 1.3.200.qualifier
|
||||
Bundle-Version: 1.3.300.qualifier
|
||||
Bundle-Activator: org.eclipse.cdt.cmake.ui.internal.Activator
|
||||
Bundle-Vendor: %providerName
|
||||
Require-Bundle: org.eclipse.core.runtime,
|
||||
|
@ -10,7 +10,8 @@ Require-Bundle: org.eclipse.core.runtime,
|
|||
org.eclipse.ui,
|
||||
org.eclipse.ui.ide,
|
||||
org.eclipse.cdt.cmake.core,
|
||||
org.eclipse.tools.templates.ui;bundle-version="1.1.0",
|
||||
org.eclipse.tools.templates.ui;bundle-version="1.3.0",
|
||||
org.eclipse.tools.templates.freemarker;bundle-version="1.2.200",
|
||||
org.eclipse.cdt.core;bundle-version="6.1.0",
|
||||
org.eclipse.debug.ui;bundle-version="3.11.200",
|
||||
org.eclipse.cdt.launch;bundle-version="9.1.0",
|
||||
|
|
|
@ -74,5 +74,12 @@
|
|||
tabClass="org.eclipse.cdt.cmake.ui.internal.CMakeBuildTab">
|
||||
</provider>
|
||||
</extension>
|
||||
<extension
|
||||
point="org.eclipse.ui.ide.projectConfigurators">
|
||||
<projectConfigurator
|
||||
class="org.eclipse.cdt.cmake.ui.internal.CMakeProjectConfigurator"
|
||||
label="CMake Project">
|
||||
</projectConfigurator>
|
||||
</extension>
|
||||
|
||||
</plugin>
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2021 Mat Booth 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.cmake.ui.internal;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.cmake.core.CMakeProjectGenerator;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.tools.templates.core.IGenerator;
|
||||
import org.eclipse.tools.templates.ui.ProjectImportConfigurator;
|
||||
|
||||
/**
|
||||
* Smart-import strategy for importing pre-existing CMake projects.
|
||||
*/
|
||||
public class CMakeProjectConfigurator extends ProjectImportConfigurator {
|
||||
|
||||
@Override
|
||||
protected List<String> getProjectFileNames() {
|
||||
return List.of("CMakeLists.txt"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IGenerator getGenerator(IProject project) {
|
||||
// Don't pass any template to the generator, we are importing an existing project
|
||||
CMakeProjectGenerator generator = new CMakeProjectGenerator(null);
|
||||
generator.setProjectName(project.getName());
|
||||
generator.setLocationURI(project.getLocationURI());
|
||||
return generator;
|
||||
}
|
||||
}
|
|
@ -27,8 +27,9 @@
|
|||
|
||||
<modules>
|
||||
<module>org.eclipse.cdt.cmake.core</module>
|
||||
<module>org.eclipse.cdt.cmake.core.tests</module>
|
||||
<module>org.eclipse.cdt.cmake.core.tests</module>
|
||||
<module>org.eclipse.cdt.cmake.ui</module>
|
||||
<module>org.eclipse.cdt.cmake.ui.tests</module>
|
||||
<module>org.eclipse.cdt.cmake-feature</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
|||
Automatic-Module-Name: org.eclipse.tools.templates.freemarker
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-SymbolicName: org.eclipse.tools.templates.freemarker
|
||||
Bundle-Version: 1.2.100.qualifier
|
||||
Bundle-Version: 1.2.200.qualifier
|
||||
Bundle-Name: %pluginName
|
||||
Bundle-Vendor: %providerName
|
||||
Require-Bundle: org.eclipse.core.runtime,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 QNX Software Systems and others.
|
||||
* Copyright (c) 2021 QNX Software Systems and others.
|
||||
*
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License 2.0
|
||||
|
@ -74,6 +74,7 @@ public abstract class FMProjectGenerator extends FMGenerator {
|
|||
|
||||
project = workspace.getRoot().getProject(projectName);
|
||||
if (!project.exists()) {
|
||||
// Create project from scratch
|
||||
IProjectDescription description = workspace.newProjectDescription(projectName);
|
||||
description.setLocationURI(locationURI);
|
||||
if (referencedProjects != null) {
|
||||
|
@ -83,8 +84,11 @@ public abstract class FMProjectGenerator extends FMGenerator {
|
|||
project.create(description, sub);
|
||||
project.open(sub);
|
||||
} else {
|
||||
// TODO make sure it's got all our settings or is this an error
|
||||
// condition?
|
||||
// Project is already created by smart import, so just configure the description
|
||||
IProjectDescription description = project.getDescription();
|
||||
initProjectDescription(description);
|
||||
project.setDescription(description, sub);
|
||||
project.open(sub);
|
||||
}
|
||||
|
||||
sub.worked(1);
|
||||
|
|
|
@ -3,7 +3,7 @@ Automatic-Module-Name: org.eclipse.tools.templates.ui
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: %pluginName
|
||||
Bundle-SymbolicName: org.eclipse.tools.templates.ui;singleton:=true
|
||||
Bundle-Version: 1.2.200.qualifier
|
||||
Bundle-Version: 1.3.0.qualifier
|
||||
Bundle-Activator: org.eclipse.tools.templates.ui.internal.Activator
|
||||
Require-Bundle: org.eclipse.ui,
|
||||
org.eclipse.core.runtime,
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2021 Mat Booth 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tools.templates.ui;
|
||||
|
||||
import org.eclipse.osgi.util.NLS;
|
||||
|
||||
class Messages extends NLS {
|
||||
|
||||
public static String ProjectImportConfigurator_Checking;
|
||||
|
||||
public static String TemplateWizard_CannotBeCreated;
|
||||
public static String TemplateWizard_ErrorCreating;
|
||||
public static String TemplateWizard_FailedToOpen;
|
||||
public static String TemplateWizard_Generating;
|
||||
public static String TemplateWizard_InternalError;
|
||||
|
||||
static {
|
||||
NLS.initializeMessages(Messages.class.getPackageName() + ".messages", Messages.class); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
private Messages() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2021 Mat Booth 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tools.templates.ui;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.PathMatcher;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.core.resources.IContainer;
|
||||
import org.eclipse.core.resources.IFolder;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
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.Status;
|
||||
import org.eclipse.tools.templates.core.IGenerator;
|
||||
import org.eclipse.ui.statushandlers.StatusManager;
|
||||
import org.eclipse.ui.wizards.datatransfer.ProjectConfigurator;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
|
||||
/**
|
||||
* Smart-import strategy for importing pre-existing projects that are not yet
|
||||
* Eclipse projects.
|
||||
*
|
||||
* Project types that have a {@link IGenerator} may extend this to offer smart
|
||||
* import functionality by registering their implementation using the <code>
|
||||
* org.eclipse.ui.ide.projectConfigurator</code> extension point.
|
||||
*
|
||||
* It is important that implementations of this class should be stateless. See
|
||||
* {@link ProjectConfigurator} for more details.
|
||||
*
|
||||
* @since 1.3
|
||||
*/
|
||||
public abstract class ProjectImportConfigurator implements ProjectConfigurator {
|
||||
|
||||
private static class Collector extends SimpleFileVisitor<Path> {
|
||||
private IProgressMonitor monitor;
|
||||
private List<PathMatcher> matchers;
|
||||
|
||||
// LinkedHashSet preserves insertion order so it looks nice in the UI
|
||||
private Set<File> locations = new LinkedHashSet<>();
|
||||
|
||||
private Collector(List<PathMatcher> matchers, IProgressMonitor monitor) {
|
||||
this.monitor = monitor;
|
||||
this.matchers = matchers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
|
||||
// Could be a long operation, so offer opportunity to cancel
|
||||
if (monitor.isCanceled()) {
|
||||
return FileVisitResult.TERMINATE;
|
||||
}
|
||||
monitor.subTask(MessageFormat.format(Messages.ProjectImportConfigurator_Checking, dir));
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
// If file matches any of our patterns, save the location
|
||||
Path name = file.getFileName();
|
||||
boolean match = matchers.stream().anyMatch(p -> p.matches(name));
|
||||
if (match) {
|
||||
locations.add(file.getParent().toFile());
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
public Set<File> getCollected() {
|
||||
return locations;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The presence of any of these files indicates a directory contains a project
|
||||
* of your type. Whole filenames or glob patterns are acceptable, e.g.
|
||||
* ("build.foo", "foo.*")
|
||||
*
|
||||
* @return a list of filenames and/or glob patterns
|
||||
*/
|
||||
protected abstract List<String> getProjectFileNames();
|
||||
|
||||
/**
|
||||
* Returns the project generator implementation to be used to configure your project
|
||||
* type. The base Eclipse project will be created for you, the generator just needs to
|
||||
* know how to configure it. The generator will be run during the smart import batch job.
|
||||
*
|
||||
* @param project the project to be configured
|
||||
* @return a project generator
|
||||
*/
|
||||
protected abstract IGenerator getGenerator(IProject project);
|
||||
|
||||
/**
|
||||
* Utility to create path matchers from glob patterns.
|
||||
*/
|
||||
private List<PathMatcher> createPathMatchers(List<String> globs) {
|
||||
final List<PathMatcher> matchers = new ArrayList<>();
|
||||
for (String glob : globs) {
|
||||
matchers.add(FileSystems.getDefault().getPathMatcher("glob:" + glob)); //$NON-NLS-1$
|
||||
}
|
||||
return matchers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<File> findConfigurableLocations(File root, IProgressMonitor monitor) {
|
||||
List<PathMatcher> matchers = createPathMatchers(getProjectFileNames());
|
||||
Collector c = new Collector(matchers, monitor);
|
||||
try {
|
||||
Files.walkFileTree(root.toPath(), c);
|
||||
} catch (IOException e) {
|
||||
StatusManager.getManager().handle(new Status(IStatus.ERROR,
|
||||
FrameworkUtil.getBundle(getClass()).getSymbolicName(), e.getMessage(), e));
|
||||
}
|
||||
return c.getCollected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldBeAnEclipseProject(IContainer container, IProgressMonitor monitor) {
|
||||
List<PathMatcher> matchers = createPathMatchers(getProjectFileNames());
|
||||
|
||||
// Only if the location contains a file that matches the one of the given patterns
|
||||
File location = container.getLocation().toFile();
|
||||
for (File f : location.listFiles()) {
|
||||
if (f.isFile() && matchers.stream().anyMatch(p -> p.matches(f.toPath().getFileName()))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<IFolder> getFoldersToIgnore(IProject project, IProgressMonitor monitor) {
|
||||
// Default to ignoring nothing
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canConfigure(IProject project, Set<IPath> ignoredPaths, IProgressMonitor monitor) {
|
||||
return shouldBeAnEclipseProject(project, monitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(IProject project, Set<IPath> ignoredPaths, IProgressMonitor monitor) {
|
||||
try {
|
||||
IGenerator generator = getGenerator(project);
|
||||
generator.generate(monitor);
|
||||
} catch (CoreException e) {
|
||||
Status status = new Status(e.getStatus().getSeverity(),
|
||||
FrameworkUtil.getBundle(getClass()).getSymbolicName(), e.getLocalizedMessage(), e);
|
||||
StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.LOG);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 QNX Software Systems and others.
|
||||
* Copyright (c) 2016, 2021 QNX Software Systems and others.
|
||||
*
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License 2.0
|
||||
|
@ -74,7 +74,7 @@ public abstract class TemplateWizard extends BasicNewResourceWizard {
|
|||
IDE.openEditor(activePage, file);
|
||||
}
|
||||
} catch (PartInitException e) {
|
||||
log("Failed to open editor", e); //$NON-NLS-1$
|
||||
log(Messages.TemplateWizard_FailedToOpen, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ public abstract class TemplateWizard extends BasicNewResourceWizard {
|
|||
@Override
|
||||
protected void execute(IProgressMonitor monitor)
|
||||
throws CoreException, InvocationTargetException, InterruptedException {
|
||||
SubMonitor sub = SubMonitor.convert(monitor, "Generating", 1);
|
||||
SubMonitor sub = SubMonitor.convert(monitor, Messages.TemplateWizard_Generating, 1);
|
||||
generator.generate(model, sub);
|
||||
getWorkbench().getDisplay().asyncExec(new Runnable() {
|
||||
@Override
|
||||
|
@ -116,16 +116,16 @@ public abstract class TemplateWizard extends BasicNewResourceWizard {
|
|||
}
|
||||
|
||||
private void handle(Throwable target) {
|
||||
String message = "Project cannot be created";
|
||||
String message = Messages.TemplateWizard_CannotBeCreated;
|
||||
log(message, target);
|
||||
IStatus status;
|
||||
if (target instanceof CoreException) {
|
||||
status = ((CoreException) target).getStatus();
|
||||
} else {
|
||||
status = new Status(IStatus.ERROR, FrameworkUtil.getBundle(getClass()).getSymbolicName(),
|
||||
"Internal Error: ", target);
|
||||
Messages.TemplateWizard_InternalError, target);
|
||||
}
|
||||
ErrorDialog.openError(getShell(), "Error Creating Project", message, status);
|
||||
ErrorDialog.openError(getShell(), Messages.TemplateWizard_ErrorCreating, message, status);
|
||||
}
|
||||
|
||||
private void log(String message, Throwable e) {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
ProjectImportConfigurator_Checking=Checking: {0}
|
||||
TemplateWizard_CannotBeCreated=Project cannot be created
|
||||
TemplateWizard_ErrorCreating=Error Creating Project
|
||||
TemplateWizard_FailedToOpen=Failed to open editor
|
||||
TemplateWizard_Generating=Generating
|
||||
TemplateWizard_InternalError=Internal Error:
|
Loading…
Add table
Reference in a new issue