From a957e8121df1937ae27243389bb7286fcd933c6b Mon Sep 17 00:00:00 2001 From: Mat Booth Date: Sat, 31 Jul 2021 15:39:24 +0100 Subject: [PATCH] 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 Change-Id: I96589e86bee561aa200a4a4487549305765d6409 --- .gitattributes | 1 + .../META-INF/MANIFEST.MF | 4 +- .../META-INF/MANIFEST.MF | 7 +- build/org.eclipse.cdt.meson.ui/plugin.xml | 9 +- .../meson/ui/MesonProjectConfigurator.java | 38 ++++ .../META-INF/MANIFEST.MF | 4 +- .../META-INF/MANIFEST.MF | 2 + .../build.properties | 6 +- cmake/org.eclipse.cdt.cmake.ui.tests/pom.xml | 3 +- .../NestedProject/App1/CMakeLists.txt | 15 ++ .../projects/NestedProject/App1/app1.c | 8 + .../projects/NestedProject/App1/app1.h.in | 2 + .../NestedProject/App2/CMakeLists.txt | 15 ++ .../projects/NestedProject/App2/app2.c | 8 + .../projects/NestedProject/App2/app2.h.in | 2 + .../projects/NestedProject/CMakeLists.txt | 18 ++ .../projects/SimpleProject/CMakeLists.txt | 15 ++ .../projects/SimpleProject/simple.c | 8 + .../projects/SimpleProject/simple.h.in | 2 + .../tests/AutomatedIntegrationSuite.java | 20 -- .../internal/tests/NewCMakeProjectTest.java | 179 ++++++++++++++++-- .../META-INF/MANIFEST.MF | 5 +- cmake/org.eclipse.cdt.cmake.ui/plugin.xml | 7 + .../ui/internal/CMakeProjectConfigurator.java | 38 ++++ cmake/pom.xml | 3 +- .../META-INF/MANIFEST.MF | 2 +- .../freemarker/FMProjectGenerator.java | 10 +- .../META-INF/MANIFEST.MF | 2 +- .../eclipse/tools/templates/ui/Messages.java | 31 +++ .../ui/ProjectImportConfigurator.java | 173 +++++++++++++++++ .../tools/templates/ui/TemplateWizard.java | 12 +- .../tools/templates/ui/messages.properties | 6 + 32 files changed, 586 insertions(+), 69 deletions(-) create mode 100644 build/org.eclipse.cdt.meson.ui/src/org/eclipse/cdt/internal/meson/ui/MesonProjectConfigurator.java create mode 100644 cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App1/CMakeLists.txt create mode 100644 cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App1/app1.c create mode 100644 cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App1/app1.h.in create mode 100644 cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App2/CMakeLists.txt create mode 100644 cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App2/app2.c create mode 100644 cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App2/app2.h.in create mode 100644 cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/CMakeLists.txt create mode 100644 cmake/org.eclipse.cdt.cmake.ui.tests/projects/SimpleProject/CMakeLists.txt create mode 100644 cmake/org.eclipse.cdt.cmake.ui.tests/projects/SimpleProject/simple.c create mode 100644 cmake/org.eclipse.cdt.cmake.ui.tests/projects/SimpleProject/simple.h.in delete mode 100644 cmake/org.eclipse.cdt.cmake.ui.tests/src/org/eclipse/cdt/cmake/ui/internal/tests/AutomatedIntegrationSuite.java create mode 100644 cmake/org.eclipse.cdt.cmake.ui/src/org/eclipse/cdt/cmake/ui/internal/CMakeProjectConfigurator.java create mode 100644 tools.templates/org.eclipse.tools.templates.ui/src/org/eclipse/tools/templates/ui/Messages.java create mode 100644 tools.templates/org.eclipse.tools.templates.ui/src/org/eclipse/tools/templates/ui/ProjectImportConfigurator.java create mode 100644 tools.templates/org.eclipse.tools.templates.ui/src/org/eclipse/tools/templates/ui/messages.properties diff --git a/.gitattributes b/.gitattributes index 329a3eecb3c..784d85d78db 100644 --- a/.gitattributes +++ b/.gitattributes @@ -17,6 +17,7 @@ CONTRIBUTING text *.cc text *.cpp text *.h text +*.in text *.s text *.S text *.elf binary diff --git a/build/org.eclipse.cdt.meson.core/META-INF/MANIFEST.MF b/build/org.eclipse.cdt.meson.core/META-INF/MANIFEST.MF index e270f1be98d..dd52385cbff 100644 --- a/build/org.eclipse.cdt.meson.core/META-INF/MANIFEST.MF +++ b/build/org.eclipse.cdt.meson.core/META-INF/MANIFEST.MF @@ -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 diff --git a/build/org.eclipse.cdt.meson.ui/META-INF/MANIFEST.MF b/build/org.eclipse.cdt.meson.ui/META-INF/MANIFEST.MF index 430cae96a31..80ac92825d8 100644 --- a/build/org.eclipse.cdt.meson.ui/META-INF/MANIFEST.MF +++ b/build/org.eclipse.cdt.meson.ui/META-INF/MANIFEST.MF @@ -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", diff --git a/build/org.eclipse.cdt.meson.ui/plugin.xml b/build/org.eclipse.cdt.meson.ui/plugin.xml index a517f8ec1cf..9c788aaff3c 100644 --- a/build/org.eclipse.cdt.meson.ui/plugin.xml +++ b/build/org.eclipse.cdt.meson.ui/plugin.xml @@ -147,7 +147,12 @@ - - + + + + diff --git a/build/org.eclipse.cdt.meson.ui/src/org/eclipse/cdt/internal/meson/ui/MesonProjectConfigurator.java b/build/org.eclipse.cdt.meson.ui/src/org/eclipse/cdt/internal/meson/ui/MesonProjectConfigurator.java new file mode 100644 index 00000000000..3c38675aa16 --- /dev/null +++ b/build/org.eclipse.cdt.meson.ui/src/org/eclipse/cdt/internal/meson/ui/MesonProjectConfigurator.java @@ -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 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; + } +} diff --git a/cmake/org.eclipse.cdt.cmake.core/META-INF/MANIFEST.MF b/cmake/org.eclipse.cdt.cmake.core/META-INF/MANIFEST.MF index a39ba297e2b..b53aecc42ae 100644 --- a/cmake/org.eclipse.cdt.cmake.core/META-INF/MANIFEST.MF +++ b/cmake/org.eclipse.cdt.cmake.core/META-INF/MANIFEST.MF @@ -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" diff --git a/cmake/org.eclipse.cdt.cmake.ui.tests/META-INF/MANIFEST.MF b/cmake/org.eclipse.cdt.cmake.ui.tests/META-INF/MANIFEST.MF index c7e426c65d2..0e122f34b15 100644 --- a/cmake/org.eclipse.cdt.cmake.ui.tests/META-INF/MANIFEST.MF +++ b/cmake/org.eclipse.cdt.cmake.ui.tests/META-INF/MANIFEST.MF @@ -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" diff --git a/cmake/org.eclipse.cdt.cmake.ui.tests/build.properties b/cmake/org.eclipse.cdt.cmake.ui.tests/build.properties index 4d08392689a..132ade6351a 100644 --- a/cmake/org.eclipse.cdt.cmake.ui.tests/build.properties +++ b/cmake/org.eclipse.cdt.cmake.ui.tests/build.properties @@ -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/ diff --git a/cmake/org.eclipse.cdt.cmake.ui.tests/pom.xml b/cmake/org.eclipse.cdt.cmake.ui.tests/pom.xml index f2bec5f1152..3ff99b7ad34 100644 --- a/cmake/org.eclipse.cdt.cmake.ui.tests/pom.xml +++ b/cmake/org.eclipse.cdt.cmake.ui.tests/pom.xml @@ -30,7 +30,6 @@ org.eclipse.tycho target-platform-configuration - ${tycho-version} @@ -50,4 +49,4 @@ - \ No newline at end of file + diff --git a/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App1/CMakeLists.txt b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App1/CMakeLists.txt new file mode 100644 index 00000000000..9cdcf22c485 --- /dev/null +++ b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App1/CMakeLists.txt @@ -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}") diff --git a/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App1/app1.c b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App1/app1.c new file mode 100644 index 00000000000..3c835fdd007 --- /dev/null +++ b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App1/app1.c @@ -0,0 +1,8 @@ +#include +#include "app1.h" + +int main() { + printf("Welcome to App1\n"); + printf("v%d.%d\n", App1_VERSION_MAJOR, App1_VERSION_MINOR); + return 0; +} diff --git a/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App1/app1.h.in b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App1/app1.h.in new file mode 100644 index 00000000000..fd3a262863f --- /dev/null +++ b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App1/app1.h.in @@ -0,0 +1,2 @@ +#define App1_VERSION_MAJOR @App1_VERSION_MAJOR@ +#define App1_VERSION_MINOR @App1_VERSION_MINOR@ diff --git a/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App2/CMakeLists.txt b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App2/CMakeLists.txt new file mode 100644 index 00000000000..09be2e33ff1 --- /dev/null +++ b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App2/CMakeLists.txt @@ -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}") diff --git a/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App2/app2.c b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App2/app2.c new file mode 100644 index 00000000000..7657f365c00 --- /dev/null +++ b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App2/app2.c @@ -0,0 +1,8 @@ +#include +#include "app2.h" + +int main() { + printf("Welcome to App2\n"); + printf("v%d.%d\n", App2_VERSION_MAJOR, App2_VERSION_MINOR); + return 0; +} diff --git a/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App2/app2.h.in b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App2/app2.h.in new file mode 100644 index 00000000000..48cbed16ac5 --- /dev/null +++ b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/App2/app2.h.in @@ -0,0 +1,2 @@ +#define App2_VERSION_MAJOR @App2_VERSION_MAJOR@ +#define App2_VERSION_MINOR @App2_VERSION_MINOR@ diff --git a/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/CMakeLists.txt b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/CMakeLists.txt new file mode 100644 index 00000000000..2f985a02c20 --- /dev/null +++ b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/NestedProject/CMakeLists.txt @@ -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 "" +) diff --git a/cmake/org.eclipse.cdt.cmake.ui.tests/projects/SimpleProject/CMakeLists.txt b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/SimpleProject/CMakeLists.txt new file mode 100644 index 00000000000..33079324d57 --- /dev/null +++ b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/SimpleProject/CMakeLists.txt @@ -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}") diff --git a/cmake/org.eclipse.cdt.cmake.ui.tests/projects/SimpleProject/simple.c b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/SimpleProject/simple.c new file mode 100644 index 00000000000..88de1dcd6f4 --- /dev/null +++ b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/SimpleProject/simple.c @@ -0,0 +1,8 @@ +#include +#include "simple.h" + +int main() { + printf("Hello, World!\n"); + printf("v%d.%d\n", SimpleProject_VERSION_MAJOR, SimpleProject_VERSION_MINOR); + return 0; +} diff --git a/cmake/org.eclipse.cdt.cmake.ui.tests/projects/SimpleProject/simple.h.in b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/SimpleProject/simple.h.in new file mode 100644 index 00000000000..6b3ff6931d3 --- /dev/null +++ b/cmake/org.eclipse.cdt.cmake.ui.tests/projects/SimpleProject/simple.h.in @@ -0,0 +1,2 @@ +#define SimpleProject_VERSION_MAJOR @SimpleProject_VERSION_MAJOR@ +#define SimpleProject_VERSION_MINOR @SimpleProject_VERSION_MINOR@ diff --git a/cmake/org.eclipse.cdt.cmake.ui.tests/src/org/eclipse/cdt/cmake/ui/internal/tests/AutomatedIntegrationSuite.java b/cmake/org.eclipse.cdt.cmake.ui.tests/src/org/eclipse/cdt/cmake/ui/internal/tests/AutomatedIntegrationSuite.java deleted file mode 100644 index 35460381c2f..00000000000 --- a/cmake/org.eclipse.cdt.cmake.ui.tests/src/org/eclipse/cdt/cmake/ui/internal/tests/AutomatedIntegrationSuite.java +++ /dev/null @@ -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 { - -} diff --git a/cmake/org.eclipse.cdt.cmake.ui.tests/src/org/eclipse/cdt/cmake/ui/internal/tests/NewCMakeProjectTest.java b/cmake/org.eclipse.cdt.cmake.ui.tests/src/org/eclipse/cdt/cmake/ui/internal/tests/NewCMakeProjectTest.java index 0f18d9b54ec..d53ceb8f112 100644 --- a/cmake/org.eclipse.cdt.cmake.ui.tests/src/org/eclipse/cdt/cmake/ui/internal/tests/NewCMakeProjectTest.java +++ b/cmake/org.eclipse.cdt.cmake.ui.tests/src/org/eclipse/cdt/cmake/ui/internal/tests/NewCMakeProjectTest.java @@ -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); + } + } + }); + } } diff --git a/cmake/org.eclipse.cdt.cmake.ui/META-INF/MANIFEST.MF b/cmake/org.eclipse.cdt.cmake.ui/META-INF/MANIFEST.MF index 2d4887a339d..ed14892d7ef 100644 --- a/cmake/org.eclipse.cdt.cmake.ui/META-INF/MANIFEST.MF +++ b/cmake/org.eclipse.cdt.cmake.ui/META-INF/MANIFEST.MF @@ -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", diff --git a/cmake/org.eclipse.cdt.cmake.ui/plugin.xml b/cmake/org.eclipse.cdt.cmake.ui/plugin.xml index 7c8cd4b1e0b..24251a4843b 100644 --- a/cmake/org.eclipse.cdt.cmake.ui/plugin.xml +++ b/cmake/org.eclipse.cdt.cmake.ui/plugin.xml @@ -74,5 +74,12 @@ tabClass="org.eclipse.cdt.cmake.ui.internal.CMakeBuildTab"> + + + + diff --git a/cmake/org.eclipse.cdt.cmake.ui/src/org/eclipse/cdt/cmake/ui/internal/CMakeProjectConfigurator.java b/cmake/org.eclipse.cdt.cmake.ui/src/org/eclipse/cdt/cmake/ui/internal/CMakeProjectConfigurator.java new file mode 100644 index 00000000000..ed704582c5b --- /dev/null +++ b/cmake/org.eclipse.cdt.cmake.ui/src/org/eclipse/cdt/cmake/ui/internal/CMakeProjectConfigurator.java @@ -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 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; + } +} diff --git a/cmake/pom.xml b/cmake/pom.xml index 04bb3aeb26c..bee2c53cbe9 100644 --- a/cmake/pom.xml +++ b/cmake/pom.xml @@ -27,8 +27,9 @@ org.eclipse.cdt.cmake.core - org.eclipse.cdt.cmake.core.tests + org.eclipse.cdt.cmake.core.tests org.eclipse.cdt.cmake.ui + org.eclipse.cdt.cmake.ui.tests org.eclipse.cdt.cmake-feature diff --git a/tools.templates/org.eclipse.tools.templates.freemarker/META-INF/MANIFEST.MF b/tools.templates/org.eclipse.tools.templates.freemarker/META-INF/MANIFEST.MF index bb2b7622203..34cbb9e9ed2 100644 --- a/tools.templates/org.eclipse.tools.templates.freemarker/META-INF/MANIFEST.MF +++ b/tools.templates/org.eclipse.tools.templates.freemarker/META-INF/MANIFEST.MF @@ -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, diff --git a/tools.templates/org.eclipse.tools.templates.freemarker/src/org/eclipse/tools/templates/freemarker/FMProjectGenerator.java b/tools.templates/org.eclipse.tools.templates.freemarker/src/org/eclipse/tools/templates/freemarker/FMProjectGenerator.java index 008e4821471..cc0de554c85 100644 --- a/tools.templates/org.eclipse.tools.templates.freemarker/src/org/eclipse/tools/templates/freemarker/FMProjectGenerator.java +++ b/tools.templates/org.eclipse.tools.templates.freemarker/src/org/eclipse/tools/templates/freemarker/FMProjectGenerator.java @@ -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); diff --git a/tools.templates/org.eclipse.tools.templates.ui/META-INF/MANIFEST.MF b/tools.templates/org.eclipse.tools.templates.ui/META-INF/MANIFEST.MF index a0ab5a6c7fd..1334462acd9 100644 --- a/tools.templates/org.eclipse.tools.templates.ui/META-INF/MANIFEST.MF +++ b/tools.templates/org.eclipse.tools.templates.ui/META-INF/MANIFEST.MF @@ -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, diff --git a/tools.templates/org.eclipse.tools.templates.ui/src/org/eclipse/tools/templates/ui/Messages.java b/tools.templates/org.eclipse.tools.templates.ui/src/org/eclipse/tools/templates/ui/Messages.java new file mode 100644 index 00000000000..52c52c9422e --- /dev/null +++ b/tools.templates/org.eclipse.tools.templates.ui/src/org/eclipse/tools/templates/ui/Messages.java @@ -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() { + } +} diff --git a/tools.templates/org.eclipse.tools.templates.ui/src/org/eclipse/tools/templates/ui/ProjectImportConfigurator.java b/tools.templates/org.eclipse.tools.templates.ui/src/org/eclipse/tools/templates/ui/ProjectImportConfigurator.java new file mode 100644 index 00000000000..1873d5cac1c --- /dev/null +++ b/tools.templates/org.eclipse.tools.templates.ui/src/org/eclipse/tools/templates/ui/ProjectImportConfigurator.java @@ -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 + * org.eclipse.ui.ide.projectConfigurator 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 { + private IProgressMonitor monitor; + private List matchers; + + // LinkedHashSet preserves insertion order so it looks nice in the UI + private Set locations = new LinkedHashSet<>(); + + private Collector(List 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 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 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 createPathMatchers(List globs) { + final List matchers = new ArrayList<>(); + for (String glob : globs) { + matchers.add(FileSystems.getDefault().getPathMatcher("glob:" + glob)); //$NON-NLS-1$ + } + return matchers; + } + + @Override + public Set findConfigurableLocations(File root, IProgressMonitor monitor) { + List 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 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 getFoldersToIgnore(IProject project, IProgressMonitor monitor) { + // Default to ignoring nothing + return Set.of(); + } + + @Override + public boolean canConfigure(IProject project, Set ignoredPaths, IProgressMonitor monitor) { + return shouldBeAnEclipseProject(project, monitor); + } + + @Override + public void configure(IProject project, Set 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); + } + } +} diff --git a/tools.templates/org.eclipse.tools.templates.ui/src/org/eclipse/tools/templates/ui/TemplateWizard.java b/tools.templates/org.eclipse.tools.templates.ui/src/org/eclipse/tools/templates/ui/TemplateWizard.java index 2ff629f4e2a..b2ff1c8b5a5 100644 --- a/tools.templates/org.eclipse.tools.templates.ui/src/org/eclipse/tools/templates/ui/TemplateWizard.java +++ b/tools.templates/org.eclipse.tools.templates.ui/src/org/eclipse/tools/templates/ui/TemplateWizard.java @@ -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) { diff --git a/tools.templates/org.eclipse.tools.templates.ui/src/org/eclipse/tools/templates/ui/messages.properties b/tools.templates/org.eclipse.tools.templates.ui/src/org/eclipse/tools/templates/ui/messages.properties new file mode 100644 index 00000000000..20316146107 --- /dev/null +++ b/tools.templates/org.eclipse.tools.templates.ui/src/org/eclipse/tools/templates/ui/messages.properties @@ -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: