From 413a4b793b08de3f99f5b2a8561191eccb9e673c Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 13 Aug 2019 11:03:37 +0300 Subject: [PATCH] Extract migration logic into separate class and use in inside maven plugin and main class (#6152) * Make new module and copy initial code there. * Extract mojo functionality to external class and use it from main Java class * Move migration logic to the standalone module * Transfer code from pending PR and add javadocs * Adapt the code for the latest master branch state. * Review fixes. * Add check for faulty migration folder. * Merge branch 'master' into 6095-migration-stand-alone # Conflicts: # flow-migration/src/test/java/com/vaadin/flow/migration/CopyResourcesStepTest.java * Fix sonar issues * Add happy-path test for Migration.migration * Don't use clone. * Remove clone * Clone File arrays to keep them separate from given configuration. * null check * No actuall install. Check executions to be expected command chains --- flow-maven-plugin/pom.xml | 37 +- .../common/AnnotationValuesExtractor.java | 1 + .../common/FlowPluginFrontendUtils.java | 73 +-- .../plugin/common/FrontendDataProvider.java | 1 + .../plugin/common/FrontendToolsManager.java | 4 +- .../plugin/common/ThemedURLTranslator.java | 1 + .../common/WebComponentModulesGenerator.java | 5 +- .../vaadin/flow/plugin/maven/MigrateMojo.java | 362 ++----------- .../production/ProductionModeCopyStep.java | 8 +- .../common/AnnotationValuesExtractorTest.java | 2 +- .../common/FrontendDataProviderTest.java | 1 + .../common/ThemedURLTranslatorTest.java | 3 +- .../WebComponentModulesGeneratorTest.java | 1 + flow-migration/pom.xml | 73 +++ .../migration/AbstractCopyResourcesStep.java | 12 +- .../migration/AnnotationsRewriteStrategy.java | 28 + .../migration}/ClassPathIntrospector.java | 2 +- .../migration/CommandArgumentException.java | 67 +++ .../migration/CopyMigratedResourcesStep.java | 4 +- .../flow}/migration/CopyResourcesStep.java | 8 +- .../migration/CreateMigrationJsonsStep.java | 2 +- .../com/vaadin/flow/migration/Migration.java | 483 ++++++++++++++++++ .../migration/MigrationConfiguration.java | 344 +++++++++++++ .../migration/MigrationFailureException.java | 27 + .../vaadin/flow/migration/MigrationTool.java | 341 +++++++++++++ .../migration/MigrationToolsException.java | 35 ++ .../RewriteLegacyAnnotationsStep.java | 38 +- .../scanner/ReflectionsClassFinder.java | 90 ++++ .../com/vaadin/flow/utils/FlowFileUtils.java | 6 +- .../src/main/resources/migration/bower.json | 0 .../src/main/resources/migration/package.json | 0 .../CopyMigratedResourcesStepTest.java | 4 +- .../migration/CopyResourcesStepTest.java | 8 +- .../CreateMigrationJsonsStepTest.java | 4 +- .../vaadin/flow/migration/MigrationTest.java | 186 +++++++ .../flow/migration/MigrationToolTest.java | 428 ++++++++++++++++ .../RewriteLegacyAnnotationsStepTest.java | 18 +- .../ClassUnitWithNonPublicClass.java | 4 +- .../migration/samplecode/Component1.java | 2 +- .../migration/samplecode/Component2.java | 2 +- .../migration/samplecode/Component3.java | 2 +- .../EnclosingClassWithNestedClass.java | 2 +- .../samplecode/GenericComponent.java | 2 +- .../samplecode/ShouldNotBeRewritten.java | 4 +- .../migration/samplecode/StyledComponent.java | 2 +- pom.xml | 1 + 46 files changed, 2224 insertions(+), 504 deletions(-) create mode 100644 flow-migration/pom.xml rename {flow-maven-plugin/src/main/java/com/vaadin/flow/plugin => flow-migration/src/main/java/com/vaadin/flow}/migration/AbstractCopyResourcesStep.java (95%) create mode 100644 flow-migration/src/main/java/com/vaadin/flow/migration/AnnotationsRewriteStrategy.java rename {flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common => flow-migration/src/main/java/com/vaadin/flow/migration}/ClassPathIntrospector.java (99%) create mode 100644 flow-migration/src/main/java/com/vaadin/flow/migration/CommandArgumentException.java rename {flow-maven-plugin/src/main/java/com/vaadin/flow/plugin => flow-migration/src/main/java/com/vaadin/flow}/migration/CopyMigratedResourcesStep.java (98%) rename {flow-maven-plugin/src/main/java/com/vaadin/flow/plugin => flow-migration/src/main/java/com/vaadin/flow}/migration/CopyResourcesStep.java (96%) rename {flow-maven-plugin/src/main/java/com/vaadin/flow/plugin => flow-migration/src/main/java/com/vaadin/flow}/migration/CreateMigrationJsonsStep.java (98%) create mode 100644 flow-migration/src/main/java/com/vaadin/flow/migration/Migration.java create mode 100644 flow-migration/src/main/java/com/vaadin/flow/migration/MigrationConfiguration.java create mode 100644 flow-migration/src/main/java/com/vaadin/flow/migration/MigrationFailureException.java create mode 100644 flow-migration/src/main/java/com/vaadin/flow/migration/MigrationTool.java create mode 100644 flow-migration/src/main/java/com/vaadin/flow/migration/MigrationToolsException.java rename {flow-maven-plugin/src/main/java/com/vaadin/flow/plugin => flow-migration/src/main/java/com/vaadin/flow}/migration/RewriteLegacyAnnotationsStep.java (92%) create mode 100644 flow-migration/src/main/java/com/vaadin/flow/server/scanner/ReflectionsClassFinder.java rename flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/FlowPluginFileUtils.java => flow-migration/src/main/java/com/vaadin/flow/utils/FlowFileUtils.java (94%) rename {flow-maven-plugin => flow-migration}/src/main/resources/migration/bower.json (100%) rename {flow-maven-plugin => flow-migration}/src/main/resources/migration/package.json (100%) rename {flow-maven-plugin/src/test/java/com/vaadin/flow/plugin => flow-migration/src/test/java/com/vaadin/flow}/migration/CopyMigratedResourcesStepTest.java (98%) rename {flow-maven-plugin/src/test/java/com/vaadin/flow/plugin => flow-migration/src/test/java/com/vaadin/flow}/migration/CopyResourcesStepTest.java (96%) rename {flow-maven-plugin/src/test/java/com/vaadin/flow/plugin => flow-migration/src/test/java/com/vaadin/flow}/migration/CreateMigrationJsonsStepTest.java (96%) create mode 100644 flow-migration/src/test/java/com/vaadin/flow/migration/MigrationTest.java create mode 100644 flow-migration/src/test/java/com/vaadin/flow/migration/MigrationToolTest.java rename {flow-maven-plugin/src/test/java/com/vaadin/flow/plugin => flow-migration/src/test/java/com/vaadin/flow}/migration/RewriteLegacyAnnotationsStepTest.java (94%) rename {flow-maven-plugin/src/test/java/com/vaadin/flow/plugin => flow-migration/src/test/java/com/vaadin/flow}/migration/samplecode/ClassUnitWithNonPublicClass.java (89%) rename {flow-maven-plugin/src/test/java/com/vaadin/flow/plugin => flow-migration/src/test/java/com/vaadin/flow}/migration/samplecode/Component1.java (95%) rename {flow-maven-plugin/src/test/java/com/vaadin/flow/plugin => flow-migration/src/test/java/com/vaadin/flow}/migration/samplecode/Component2.java (93%) rename {flow-maven-plugin/src/test/java/com/vaadin/flow/plugin => flow-migration/src/test/java/com/vaadin/flow}/migration/samplecode/Component3.java (93%) rename {flow-maven-plugin/src/test/java/com/vaadin/flow/plugin => flow-migration/src/test/java/com/vaadin/flow}/migration/samplecode/EnclosingClassWithNestedClass.java (94%) rename {flow-maven-plugin/src/test/java/com/vaadin/flow/plugin => flow-migration/src/test/java/com/vaadin/flow}/migration/samplecode/GenericComponent.java (92%) rename {flow-maven-plugin/src/test/java/com/vaadin/flow/plugin => flow-migration/src/test/java/com/vaadin/flow}/migration/samplecode/ShouldNotBeRewritten.java (86%) rename {flow-maven-plugin/src/test/java/com/vaadin/flow/plugin => flow-migration/src/test/java/com/vaadin/flow}/migration/samplecode/StyledComponent.java (95%) diff --git a/flow-maven-plugin/pom.xml b/flow-maven-plugin/pom.xml index f18a65d28ff..4fbeace9680 100644 --- a/flow-maven-plugin/pom.xml +++ b/flow-maven-plugin/pom.xml @@ -45,22 +45,13 @@ frontend-plugin-core 1.6 - - org.reflections - reflections - 0.9.11 - + com.vaadin - flow-server + flow-migration ${project.version} - - org.slf4j - slf4j-api - - org.apache.maven.plugin-tools maven-plugin-annotations @@ -115,28 +106,6 @@ - - - - org.codehaus.mojo - build-helper-maven-plugin - - - add-resource - generate-resources - - add-test-resource - - - - - src/test/java - - - - - - - + diff --git a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/AnnotationValuesExtractor.java b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/AnnotationValuesExtractor.java index 48d46189db8..eb414a9aa08 100644 --- a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/AnnotationValuesExtractor.java +++ b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/AnnotationValuesExtractor.java @@ -22,6 +22,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import com.vaadin.flow.migration.ClassPathIntrospector; import com.vaadin.flow.server.frontend.scanner.ClassFinder; /** diff --git a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/FlowPluginFrontendUtils.java b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/FlowPluginFrontendUtils.java index 6e411313153..86b775dcaf3 100644 --- a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/FlowPluginFrontendUtils.java +++ b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/FlowPluginFrontendUtils.java @@ -17,88 +17,21 @@ package com.vaadin.flow.plugin.common; import java.io.File; -import java.lang.annotation.Annotation; -import java.lang.annotation.Repeatable; -import java.lang.reflect.AnnotatedElement; import java.net.URL; -import java.net.URLClassLoader; -import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; import org.apache.maven.artifact.DependencyResolutionRequiredException; import org.apache.maven.project.MavenProject; -import org.reflections.Reflections; -import org.reflections.util.ConfigurationBuilder; import com.vaadin.flow.server.frontend.scanner.ClassFinder; +import com.vaadin.flow.server.scanner.ReflectionsClassFinder; +import com.vaadin.flow.utils.FlowFileUtils; /** * Utility methods used by all goals. */ public class FlowPluginFrontendUtils { - /** - * A class finder using org.reflections. - */ - public static class ReflectionsClassFinder implements ClassFinder { - private final transient ClassLoader classLoader; - - private final transient Reflections reflections; - - /** - * Constructor. - * - * @param urls - * the list of urls for finding classes. - */ - public ReflectionsClassFinder(URL... urls) { - classLoader = new URLClassLoader(urls, null); // NOSONAR - reflections = new Reflections( - new ConfigurationBuilder().addClassLoader(classLoader) - .setExpandSuperTypes(false).addUrls(urls)); - } - - @Override - public Set> getAnnotatedClasses( - Class clazz) { - Set> classes = new HashSet<>(); - classes.addAll(reflections.getTypesAnnotatedWith(clazz, true)); - classes.addAll(getAnnotatedByRepeatedAnnotation(clazz)); - return classes; - - } - - private Set> getAnnotatedByRepeatedAnnotation( - AnnotatedElement annotationClass) { - Repeatable repeatableAnnotation = annotationClass - .getAnnotation(Repeatable.class); - if (repeatableAnnotation != null) { - return reflections.getTypesAnnotatedWith( - repeatableAnnotation.value(), true); - } - return Collections.emptySet(); - } - - @Override - public URL getResource(String name) { - return classLoader.getResource(name); - } - - @SuppressWarnings("unchecked") - @Override - public Class loadClass(String name) - throws ClassNotFoundException { - return (Class) classLoader.loadClass(name); - } - - @Override - public Set> getSubTypesOf(Class type) { - return reflections.getSubTypesOf(type); - } - } - private FlowPluginFrontendUtils() { } @@ -120,7 +53,7 @@ public static ClassFinder getClassFinder(MavenProject project) { project), e); } URL[] urls = runtimeClasspathElements.stream().map(File::new) - .map(FlowPluginFileUtils::convertToUrl).toArray(URL[]::new); + .map(FlowFileUtils::convertToUrl).toArray(URL[]::new); return new ReflectionsClassFinder(urls); } diff --git a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/FrontendDataProvider.java b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/FrontendDataProvider.java index b9710a7c91a..6b4ab81e0ea 100644 --- a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/FrontendDataProvider.java +++ b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/FrontendDataProvider.java @@ -39,6 +39,7 @@ import com.vaadin.flow.component.dependency.HtmlImport; import com.vaadin.flow.component.dependency.JavaScript; import com.vaadin.flow.component.dependency.StyleSheet; +import com.vaadin.flow.migration.ClassPathIntrospector; import com.vaadin.flow.server.Constants; import com.vaadin.flow.shared.ApplicationConstants; diff --git a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/FrontendToolsManager.java b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/FrontendToolsManager.java index 70ca4ccf9af..cc411aea080 100644 --- a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/FrontendToolsManager.java +++ b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/FrontendToolsManager.java @@ -35,6 +35,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.vaadin.flow.utils.FlowFileUtils; + /** * Entity to operate frontend tools to transpile files. *

@@ -85,7 +87,7 @@ public FrontendToolsManager(File workingDirectory, String es5OutputDirectoryName, String es6OutputDirectoryName, FrontendDataProvider frontendDataProvider, RunnerManager runnerManager) { - FlowPluginFileUtils + FlowFileUtils .forceMkdir(Objects.requireNonNull(workingDirectory)); this.runnerManager = Objects.requireNonNull(runnerManager); this.workingDirectory = workingDirectory; diff --git a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/ThemedURLTranslator.java b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/ThemedURLTranslator.java index ba6382682bb..83d59dffcea 100644 --- a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/ThemedURLTranslator.java +++ b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/ThemedURLTranslator.java @@ -34,6 +34,7 @@ import org.slf4j.LoggerFactory; import com.vaadin.flow.internal.ReflectTools; +import com.vaadin.flow.migration.ClassPathIntrospector; import com.vaadin.flow.theme.AbstractTheme; import com.vaadin.flow.theme.Theme; diff --git a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/WebComponentModulesGenerator.java b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/WebComponentModulesGenerator.java index 2b14faa1ae5..3dae911a670 100644 --- a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/WebComponentModulesGenerator.java +++ b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/WebComponentModulesGenerator.java @@ -20,6 +20,7 @@ import java.util.stream.Collectors; import com.vaadin.flow.component.WebComponentExporter; +import com.vaadin.flow.migration.ClassPathIntrospector; import com.vaadin.flow.server.webcomponent.WebComponentModulesWriter; /** @@ -29,7 +30,7 @@ * Uses {@link com.vaadin.flow.server.webcomponent.WebComponentModulesWriter} to * generate web component modules files from * {@link com.vaadin.flow.component.WebComponentExporter} implementations found - * by {@link com.vaadin.flow.plugin.common.ClassPathIntrospector}. + * by {@link com.vaadin.flow.migration.ClassPathIntrospector}. * * @author Vaadin Ltd. */ @@ -43,7 +44,7 @@ public class WebComponentModulesGenerator extends ClassPathIntrospector { * {@link com.vaadin.flow.component.WebComponentExporter} classes. * * @param introspector - * {@link com.vaadin.flow.plugin.common.ClassPathIntrospector} + * {@link com.vaadin.flow.migration.ClassPathIntrospector} * implementation to use as a base. */ public WebComponentModulesGenerator(ClassPathIntrospector introspector) { diff --git a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/MigrateMojo.java b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/MigrateMojo.java index 35663db684b..6145ec02290 100644 --- a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/MigrateMojo.java +++ b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/MigrateMojo.java @@ -16,21 +16,7 @@ package com.vaadin.flow.plugin.maven; import java.io.File; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.apache.commons.io.FileUtils; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -42,16 +28,13 @@ import com.vaadin.flow.component.dependency.HtmlImport; import com.vaadin.flow.component.dependency.StyleSheet; +import com.vaadin.flow.migration.AnnotationsRewriteStrategy; +import com.vaadin.flow.migration.MigrationConfiguration; +import com.vaadin.flow.migration.MigrationConfiguration.Builder; +import com.vaadin.flow.migration.Migration; +import com.vaadin.flow.migration.MigrationFailureException; +import com.vaadin.flow.migration.MigrationToolsException; import com.vaadin.flow.plugin.common.FlowPluginFrontendUtils; -import com.vaadin.flow.plugin.migration.CopyMigratedResourcesStep; -import com.vaadin.flow.plugin.migration.CopyResourcesStep; -import com.vaadin.flow.plugin.migration.CreateMigrationJsonsStep; -import com.vaadin.flow.plugin.migration.RewriteLegacyAnnotationsStep; -import com.vaadin.flow.server.frontend.FrontendUtils; - -import elemental.json.Json; -import elemental.json.JsonObject; -import elemental.json.JsonValue; /** * This goal migrates project from compatibility mode to NPM mode. @@ -62,22 +45,11 @@ @Mojo(name = "migrate-to-p3", requiresDependencyResolution = ResolutionScope.COMPILE, defaultPhase = LifecyclePhase.PROCESS_CLASSES) public class MigrateMojo extends AbstractMojo { - private static final String DEPENDENCIES = "dependencies"; - - /** - * The strategy to rewrite {@link HtmlImport}/{@link StyleSheet} - * annotations. - * - */ - public static enum AnnotationsRewriteStrategy { - ALWAYS, SKIP, SKIP_ON_ERROR; - } - /** * A list of directories with files to migrate. */ @Parameter - private String[] resources; + private File[] resources; /** * A temporary directory where migration is performed. @@ -116,11 +88,11 @@ public static enum AnnotationsRewriteStrategy { *

* Three values are available: *

    - *
  • ALWAYS : if chosen then the annotations will be always rewritten + *
  • ALWAYS : if chosen then annotation will be always rewritten * regardless of migration of the import files content *
  • SKIP : if chosen then neither annotation will be rewritten - *
  • SKIP_ON_ERROR : if chosen then the annotations will be rewritten only - * if there are no errors during migration of imported files content + *
  • SKIP_ON_ERROR : if chosen then annotation will be rewritten only if + * there are no errors during migration of imported files content *
*/ @Parameter(defaultValue = "ALWAYS") @@ -128,305 +100,37 @@ public static enum AnnotationsRewriteStrategy { @Override public void execute() throws MojoExecutionException, MojoFailureException { - prepareMigrationDirectory(); - - List bowerCommands = FrontendUtils - .getBowerExecutable(migrateFolder.getPath()); - boolean needInstallBower = bowerCommands.isEmpty(); - if (!ensureTools(needInstallBower)) { - throw new MojoExecutionException( - "Could not install tools required for migration (bower or modulizer)"); - } - if (needInstallBower) { - bowerCommands = FrontendUtils - .getBowerExecutable(migrateFolder.getPath()); - } - - if (bowerCommands.isEmpty()) { - throw new MojoExecutionException( - "Could not locate bower. Install it manually on your system and re-run migration goal."); - } - - Set externalComponents; - CopyResourcesStep copyStep = new CopyResourcesStep(migrateFolder, - getResources()); - Map> paths; - try { - paths = copyStep.copyResources(); - externalComponents = copyStep.getBowerComponents(); - } catch (IOException exception) { - throw new UncheckedIOException( - "Couldn't copy resources from source directories " - + Arrays.asList(getResources()) - + " to the target directory " + migrateFolder, - exception); - } - - Set migratedTopLevelDirs = Stream.of(migrateFolder.listFiles()) - .filter(file -> file.isDirectory()).map(File::getName) - .collect(Collectors.toSet()); - - List allPaths = new ArrayList<>(); - paths.values().stream().forEach(allPaths::addAll); - try { - new CreateMigrationJsonsStep(migrateFolder).createJsons(allPaths); - } catch (IOException exception) { - throw new UncheckedIOException("Couldn't generate json files", - exception); - } - - if (!saveBowerComponents(bowerCommands, externalComponents)) { - throw new MojoFailureException( - "Could not install bower components"); - } - - installNpmPackages(); - - boolean modulizerHasErrors = false; - if (!runModulizer()) { - modulizerHasErrors = true; - if (ignoreModulizerErrors) { - getLog().info("Modulizer has exited with error"); - } else { - throw new MojoFailureException( - "Modulizer has exited with error. Unable to proceed."); - } - } - - // copy the result JS files into "frontend" - if (!frontendDirectory.exists()) { - try { - FileUtils.forceMkdir(frontendDirectory); - } catch (IOException exception) { - throw new UncheckedIOException( - "Unable to create a target folder for migrated files: '" - + frontendDirectory + "'", - exception); - } - } - CopyMigratedResourcesStep copyMigratedStep = new CopyMigratedResourcesStep( - frontendDirectory, migrateFolder, migratedTopLevelDirs); - try { - copyMigratedStep.copyResources(); - } catch (IOException exception) { - throw new UncheckedIOException( - "Couldn't copy migrated resources to the target directory " - + frontendDirectory, - exception); - } - - try { - cleanUp(migrateFolder); - } catch (IOException exception) { - getLog().debug("Couldn't remove " + migrateFolder.getPath(), - exception); - } - - if (!modulizerHasErrors && !keepOriginal) { - removeOriginalResources(paths); - } - - switch (annotationsRewrite) { - case SKIP: - break; - case ALWAYS: - rewrite(); - break; - case SKIP_ON_ERROR: - if (!modulizerHasErrors) { - rewrite(); - } - break; - } - - } - - private void prepareMigrationDirectory() { - if (migrateFolder.exists()) { - try { - cleanUp(migrateFolder); - } catch (IOException exception) { - throw new UncheckedIOException( - "Unable to clean up directory '" + migrateFolder + "'", - exception); - } - } + Builder builder = new Builder(project.getBasedir()); + + builder.setAnnotationRewriteStrategy(annotationsRewrite); + builder.setClassFinder(FlowPluginFrontendUtils.getClassFinder(project)); + builder.setCompiledClassDirectory( + new File(project.getBuild().getOutputDirectory())); + builder.setIgnoreModulizerErrors(ignoreModulizerErrors); + builder.setJavaSourceRoots(project.getCompileSourceRoots().stream() + .map(File::new).toArray(File[]::new)); + builder.setKeepOriginalFiles(keepOriginal); + builder.setResourceDirectories(getResources()); + builder.setTargetDirectory(frontendDirectory); + builder.setTemporaryMigrationFolder(migrateFolder); + + MigrationConfiguration configuration = builder.build(); + Migration migration = new Migration(configuration); try { - FileUtils.forceMkdir(migrateFolder); - } catch (IOException exception) { - throw new UncheckedIOException( - "Unable to create a folder for migration: '" + migrateFolder - + "'", - exception); + migration.migrate(); + } catch (MigrationToolsException exception) { + throw new MojoExecutionException(exception.getMessage(), exception); + } catch (MigrationFailureException exception) { + throw new MojoFailureException(exception.getMessage(), exception); } } - private void removeOriginalResources(Map> paths) { - for (Entry> entry : paths.entrySet()) { - File resourceFolder = new File(entry.getKey()); - entry.getValue() - .forEach(path -> new File(resourceFolder, path).delete()); - } - } - - private void installNpmPackages() throws MojoFailureException { - List npmExec = FrontendUtils - .getNpmExecutable(project.getBasedir().getPath()); - List npmInstall = new ArrayList<>(npmExec.size()); - npmInstall.addAll(npmExec); - npmInstall.add("i"); - - if (!executeProcess(npmInstall, "Couldn't install packages using npm", - "Packages successfully installed", - "Error when running `npm install`")) { - throw new MojoFailureException( - "Error during package installation via npm"); - } - } - - private boolean runModulizer() { - Collection depMapping = makeDependencyMapping(); - - List command = new ArrayList<>(); - command.add(FrontendUtils - .getNodeExecutable(project.getBasedir().getPath())); - command.add("node_modules/polymer-modulizer/bin/modulizer.js"); - command.add("--force"); - command.add("--out"); - command.add("."); - command.add("--import-style=name"); - if (!depMapping.isEmpty()) { - command.add("--dependency-mapping"); - command.addAll(depMapping); - } - - return executeProcess(command, "Migration has finished with errors", - "Modulizer has completed successfully", - "Error when running moulizer"); - } - - private Collection makeDependencyMapping() { - File bower = new File(migrateFolder, "bower.json"); - - try { - Set result = new HashSet<>(); - String content = Files.readAllLines(bower.toPath()).stream() - .collect(Collectors.joining("\n")); - JsonObject object = Json.parse(content); - if (object.hasKey(DEPENDENCIES)) { - JsonObject deps = object.getObject(DEPENDENCIES); - Stream.of(deps.keys()).filter(key -> key.startsWith("vaadin-")) - .forEach(key -> result - .add(makeVaadinDependencyMapping(deps, key))); - } - return result; - } catch (IOException exception) { - throw new UncheckedIOException("Unable to read bower.json", - exception); - } - } - - private String makeVaadinDependencyMapping(JsonObject deps, String key) { - JsonValue version = deps.get(key); - StringBuilder builder = new StringBuilder(key); - builder.append(','); - builder.append("@vaadin/"); - builder.append(key).append(','); - builder.append(version.asString()); - return builder.toString(); - } - - private boolean saveBowerComponents(List bowerCommands, - Collection components) { - List command = new ArrayList<>(); - command.addAll(bowerCommands); - // install - command.add("i"); - // -F option means: Force latest version on conflict - command.add("-F"); - // disable interactive mode - command.add("--config.interactive=false"); - // -S option means: Save installed packages into the project’s - // bower.json dependencies - command.add("-S"); - - // add all extracted bower components to install them and save - - // the latest polymer version which is chosen by bower has only JS - // module file. It won't be resolved from the import properly. So we - // have to force 2.x.x version which is P2 based. - command.add("polymer#2.8.0"); - components.stream().filter(component -> !component.equals("polymer")) - .forEach(command::add); - - return executeProcess(command, - "Couldn't install and save bower components", - "All components are installed and saved successfully", - "Error when running `bower install`"); - } - - private boolean ensureTools(boolean needInstallBower) { - List npmExecutable = FrontendUtils - .getNpmExecutable(project.getBasedir().getPath()); - List command = new ArrayList<>(); - command.addAll(npmExecutable); - command.add("install"); - if (needInstallBower) { - command.add("bower"); - } - command.add("polymer-modulizer"); - - return executeProcess(command, "Couldn't install migration tools", - "Bower is installed successfully", - "Error when running `npm install`"); - } - - private boolean executeProcess(List command, String errorMsg, - String successMsg, String exceptionMsg) { - ProcessBuilder builder = FrontendUtils.createProcessBuilder(command); - builder.directory(migrateFolder); - - Process process = null; - try { - process = builder.inheritIO().start(); - int errorCode = process.waitFor(); - if (errorCode != 0) { - getLog().error(errorMsg); - return false; - } else { - getLog().debug(successMsg); - } - } catch (InterruptedException | IOException e) { - getLog().error(exceptionMsg, e); - return false; - } finally { - if (process != null) { - process.destroyForcibly(); - } - } - - return true; - } - - private void cleanUp(File dir) throws IOException { - FileUtils.forceDelete(dir); - } - - private String[] getResources() { + private File[] getResources() { if (resources == null) { File webApp = new File(project.getBasedir(), "src/main/webapp"); - resources = new String[] { webApp.getPath() }; + resources = new File[] { webApp }; } return resources; } - private void rewrite() { - RewriteLegacyAnnotationsStep step = new RewriteLegacyAnnotationsStep( - new File(project.getBuild().getOutputDirectory()), - FlowPluginFrontendUtils.getClassFinder(project), - project.getCompileSourceRoots().stream().map(File::new) - .collect(Collectors.toList())); - step.rewrite(); - } - } diff --git a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/production/ProductionModeCopyStep.java b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/production/ProductionModeCopyStep.java index b968c132ce4..bb4a4a0eea1 100644 --- a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/production/ProductionModeCopyStep.java +++ b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/production/ProductionModeCopyStep.java @@ -36,9 +36,9 @@ import org.slf4j.LoggerFactory; import com.vaadin.flow.plugin.common.ArtifactData; -import com.vaadin.flow.plugin.common.FlowPluginFileUtils; import com.vaadin.flow.server.Constants; import com.vaadin.flow.server.frontend.JarContentsManager; +import com.vaadin.flow.utils.FlowFileUtils; import elemental.json.Json; import elemental.json.JsonObject; @@ -172,7 +172,7 @@ private String getPackageName(ArtifactData webJar, String nameSourceJarPath) { */ public void copyWebApplicationFiles(File outputDirectory, File frontendWorkingDirectory, String commaSeparatedWildcardPathExclusions) { LOGGER.info("Copying web application files to '{}'", outputDirectory); - FlowPluginFileUtils.forceMkdir(outputDirectory); + FlowFileUtils.forceMkdir(outputDirectory); String[] wildcardExclusions = getWildcardPaths(commaSeparatedWildcardPathExclusions); @@ -188,7 +188,7 @@ public void copyWebApplicationFiles(File outputDirectory, File frontendWorkingDi File bowerComponents = new File(outputDirectory, BOWER_COMPONENTS_DIRECTORY_NAME); webJarNameToPackage.forEach((name, webJarPackage) -> { File webJarDirectory = new File(bowerComponents, name); - FlowPluginFileUtils.forceMkdir(webJarDirectory); + FlowFileUtils.forceMkdir(webJarDirectory); jarContentsManager.copyFilesFromJarTrimmingBasePath(webJarPackage.getWebJar().getFileOrDirectory(), webJarPackage.getPathToPackage(), webJarDirectory, wildcardExclusions); }); } @@ -216,7 +216,7 @@ public void copyFrontendJavaScriptFiles(File frontendDirectory, String commaSeparatedWildcardPathInclusions, String jsResourcePath) { LOGGER.info("Copying frontend '.js' files to '{}'", frontendDirectory); - FlowPluginFileUtils.forceMkdir(frontendDirectory); + FlowFileUtils.forceMkdir(frontendDirectory); String[] wildcardInclusions = getWildcardPaths( commaSeparatedWildcardPathInclusions); diff --git a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/common/AnnotationValuesExtractorTest.java b/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/common/AnnotationValuesExtractorTest.java index fc414261f9e..2514412f7ff 100644 --- a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/common/AnnotationValuesExtractorTest.java +++ b/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/common/AnnotationValuesExtractorTest.java @@ -21,8 +21,8 @@ import java.util.Map; import java.util.Set; -import com.vaadin.flow.plugin.common.FlowPluginFrontendUtils.ReflectionsClassFinder; import com.vaadin.flow.server.frontend.scanner.ClassFinder; +import com.vaadin.flow.server.scanner.ReflectionsClassFinder; import org.apache.maven.plugins.annotations.Mojo; import org.junit.Rule; diff --git a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/common/FrontendDataProviderTest.java b/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/common/FrontendDataProviderTest.java index 58dd569a8fb..ec10112d4c1 100644 --- a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/common/FrontendDataProviderTest.java +++ b/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/common/FrontendDataProviderTest.java @@ -52,6 +52,7 @@ import com.vaadin.flow.component.dependency.JavaScript; import com.vaadin.flow.component.dependency.StyleSheet; import com.vaadin.flow.component.webcomponent.WebComponent; +import com.vaadin.flow.migration.ClassPathIntrospector; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; diff --git a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/common/ThemedURLTranslatorTest.java b/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/common/ThemedURLTranslatorTest.java index a87e751c5ee..20f12d18f01 100644 --- a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/common/ThemedURLTranslatorTest.java +++ b/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/common/ThemedURLTranslatorTest.java @@ -23,9 +23,10 @@ import java.util.Set; import java.util.function.Function; +import com.vaadin.flow.migration.ClassPathIntrospector; import com.vaadin.flow.plugin.TestUtils; -import com.vaadin.flow.plugin.common.FlowPluginFrontendUtils.ReflectionsClassFinder; import com.vaadin.flow.server.frontend.scanner.ClassFinder; +import com.vaadin.flow.server.scanner.ReflectionsClassFinder; import org.hamcrest.CoreMatchers; import org.junit.Assert; diff --git a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/common/WebComponentModulesGeneratorTest.java b/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/common/WebComponentModulesGeneratorTest.java index 71f85b85cdb..84c0774bdcf 100644 --- a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/common/WebComponentModulesGeneratorTest.java +++ b/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/common/WebComponentModulesGeneratorTest.java @@ -37,6 +37,7 @@ import org.mockito.Mockito; import com.vaadin.flow.component.WebComponentExporter; +import com.vaadin.flow.migration.ClassPathIntrospector; import com.vaadin.flow.plugin.samplecode.AbstractExporter; import com.vaadin.flow.plugin.samplecode.BarExporter; import com.vaadin.flow.plugin.samplecode.FooExporter; diff --git a/flow-migration/pom.xml b/flow-migration/pom.xml new file mode 100644 index 00000000000..fdcfacd6a3a --- /dev/null +++ b/flow-migration/pom.xml @@ -0,0 +1,73 @@ + + + 4.0.0 + + com.vaadin + flow-project + 2.0-SNAPSHOT + + flow-migration + Flow Migration Tool + jar + + + + + org.reflections + reflections + 0.9.11 + + + + com.vaadin + flow-server + ${project.version} + + + + org.slf4j + slf4j-api + + + + org.slf4j + slf4j-simple + test + + + + commons-cli + commons-cli + 1.4 + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-resource + generate-resources + + add-test-resource + + + + + src/test/java + + + + + + + + + + diff --git a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/migration/AbstractCopyResourcesStep.java b/flow-migration/src/main/java/com/vaadin/flow/migration/AbstractCopyResourcesStep.java similarity index 95% rename from flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/migration/AbstractCopyResourcesStep.java rename to flow-migration/src/main/java/com/vaadin/flow/migration/AbstractCopyResourcesStep.java index 0bb06e7ec12..6324ebaeb6f 100644 --- a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/migration/AbstractCopyResourcesStep.java +++ b/flow-migration/src/main/java/com/vaadin/flow/migration/AbstractCopyResourcesStep.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration; +package com.vaadin.flow.migration; import java.io.File; import java.io.IOException; @@ -129,7 +129,7 @@ private Path getTarget(Path source) { } private final File target; - private final List resources; + private final List resources; private final FileTreeHandler handler; /** @@ -142,7 +142,7 @@ private Path getTarget(Path source) { * @param handler * a strategy which handles the files in the source directories */ - public AbstractCopyResourcesStep(File target, String[] sourceFolders, + public AbstractCopyResourcesStep(File target, File[] sourceFolders, FileTreeHandler handler) { this.target = target; resources = Arrays.asList(sourceFolders); @@ -171,11 +171,11 @@ public Map> copyResources() throws IOException { getLogger().debug("Use {} as source folders to copy", resources); Map> allResources = new HashMap<>(); - for (String resourceFolder : resources) { + for (File resourceFolder : resources) { getLogger().debug("Copy resources from {} to {}", resourceFolder, target.getPath()); - allResources.put(resourceFolder, - doCopyResources(new File(resourceFolder))); + allResources.put(resourceFolder.getPath(), + doCopyResources(resourceFolder)); } return allResources; } diff --git a/flow-migration/src/main/java/com/vaadin/flow/migration/AnnotationsRewriteStrategy.java b/flow-migration/src/main/java/com/vaadin/flow/migration/AnnotationsRewriteStrategy.java new file mode 100644 index 00000000000..13e22c9aa33 --- /dev/null +++ b/flow-migration/src/main/java/com/vaadin/flow/migration/AnnotationsRewriteStrategy.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2018 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.migration; + +import com.vaadin.flow.component.dependency.HtmlImport; +import com.vaadin.flow.component.dependency.StyleSheet; + +/** + * The strategy to rewrite {@link HtmlImport}/{@link StyleSheet} + * annotations. + * + */ +public enum AnnotationsRewriteStrategy { + ALWAYS, SKIP, SKIP_ON_ERROR; +} diff --git a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/ClassPathIntrospector.java b/flow-migration/src/main/java/com/vaadin/flow/migration/ClassPathIntrospector.java similarity index 99% rename from flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/ClassPathIntrospector.java rename to flow-migration/src/main/java/com/vaadin/flow/migration/ClassPathIntrospector.java index e588519bf75..43f95926fa6 100644 --- a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/ClassPathIntrospector.java +++ b/flow-migration/src/main/java/com/vaadin/flow/migration/ClassPathIntrospector.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.common; +package com.vaadin.flow.migration; import java.io.Serializable; import java.lang.annotation.Annotation; diff --git a/flow-migration/src/main/java/com/vaadin/flow/migration/CommandArgumentException.java b/flow-migration/src/main/java/com/vaadin/flow/migration/CommandArgumentException.java new file mode 100644 index 00000000000..199d2f34370 --- /dev/null +++ b/flow-migration/src/main/java/com/vaadin/flow/migration/CommandArgumentException.java @@ -0,0 +1,67 @@ +/* + * Copyright 2000-2018 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.migration; + +import java.util.Optional; + +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + +/** + * An exception is thrown if there is an error in command line arguments. + * + * @author Vaadin Ltd + * + */ +class CommandArgumentException extends Exception { + + private final Options options; + + /** + * Creates a new exception instance using provided command line + * {@code options} and the parse exception {@code cause}. + * + * @param options + * command line options + * @param cause + * the parse exception cause + */ + CommandArgumentException(Options options, ParseException cause) { + super(cause); + this.options = options; + } + + /** + * Creates a new exception instance using a {@code cause}. + * + * @param cause + * the intitial exception cause + */ + public CommandArgumentException(Exception cause) { + super(cause); + options = null; + } + + /** + * Returns the command line options. + * + * @return an optional options, or an empty optional if the instance is + * created with a cause only + */ + Optional getOptions() { + return Optional.ofNullable(options); + } +} diff --git a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/migration/CopyMigratedResourcesStep.java b/flow-migration/src/main/java/com/vaadin/flow/migration/CopyMigratedResourcesStep.java similarity index 98% rename from flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/migration/CopyMigratedResourcesStep.java rename to flow-migration/src/main/java/com/vaadin/flow/migration/CopyMigratedResourcesStep.java index dbb66979edb..f113254732b 100644 --- a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/migration/CopyMigratedResourcesStep.java +++ b/flow-migration/src/main/java/com/vaadin/flow/migration/CopyMigratedResourcesStep.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration; +package com.vaadin.flow.migration; import java.io.File; import java.io.IOException; @@ -141,7 +141,7 @@ private String rewriteImport(String line) { */ public CopyMigratedResourcesStep(File target, File source, Set allowedDirectoryNames) { - super(target, new String[] { source.getPath() }, + super(target, new File[] { source }, new CopyMigratedFiles(source.toPath(), allowedDirectoryNames)); } diff --git a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/migration/CopyResourcesStep.java b/flow-migration/src/main/java/com/vaadin/flow/migration/CopyResourcesStep.java similarity index 96% rename from flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/migration/CopyResourcesStep.java rename to flow-migration/src/main/java/com/vaadin/flow/migration/CopyResourcesStep.java index 167a13f597c..012be82be1e 100644 --- a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/migration/CopyResourcesStep.java +++ b/flow-migration/src/main/java/com/vaadin/flow/migration/CopyResourcesStep.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration; +package com.vaadin.flow.migration; import java.io.File; import java.io.IOException; @@ -40,7 +40,7 @@ * Step which copies resources from provided collection of directories to the * target folder. It keeps the files hierarchical structure. *

- * The content of copied file is modified to correct URIs in the imports and + * The content of copied file is modified to correct URI in the imports and * remove the comments. * * @author Vaadin Ltd @@ -174,11 +174,11 @@ private void addBowerComponent(String uri) { * @param resourceFolders * an array of source folders */ - public CopyResourcesStep(File target, String[] resourceFolders) { + public CopyResourcesStep(File target, File[] resourceFolders) { this(target, resourceFolders, new HashSet<>()); } - private CopyResourcesStep(File target, String[] resourceFolders, + private CopyResourcesStep(File target, File[] resourceFolders, Set bowerComponents) { super(target, resourceFolders, new HtmlImportRewriter(target, bowerComponents)); diff --git a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/migration/CreateMigrationJsonsStep.java b/flow-migration/src/main/java/com/vaadin/flow/migration/CreateMigrationJsonsStep.java similarity index 98% rename from flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/migration/CreateMigrationJsonsStep.java rename to flow-migration/src/main/java/com/vaadin/flow/migration/CreateMigrationJsonsStep.java index 359bf3473f7..cc4947e5a7e 100644 --- a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/migration/CreateMigrationJsonsStep.java +++ b/flow-migration/src/main/java/com/vaadin/flow/migration/CreateMigrationJsonsStep.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration; +package com.vaadin.flow.migration; import java.io.BufferedReader; import java.io.File; diff --git a/flow-migration/src/main/java/com/vaadin/flow/migration/Migration.java b/flow-migration/src/main/java/com/vaadin/flow/migration/Migration.java new file mode 100644 index 00000000000..e08b4bfe065 --- /dev/null +++ b/flow-migration/src/main/java/com/vaadin/flow/migration/Migration.java @@ -0,0 +1,483 @@ +/* + * Copyright 2000-2018 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.migration; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.vaadin.flow.server.frontend.FrontendUtils; + +import elemental.json.Json; +import elemental.json.JsonObject; +import elemental.json.JsonValue; + +/** + * Migrates resource (template and CSS) files from provided directories and Java + * source files from V13 to V14. + * + * @author Vaadin Ltd + * + */ +public class Migration { + + private static final String DEPENDENCIES = "dependencies"; + + private final File tempMigrationFolder; + + private final File targetDirectory; + + private final File[] resourceDirectories; + + private final MigrationConfiguration configuration; + + /** + * Creates an instance with given {@code configuration} to migrate. + * + * @param configuration + * configuration to do migration + */ + public Migration(MigrationConfiguration configuration) { + this.configuration = configuration; + if (getTempMigrationFolder() == null) { + if(configuration.getTempMigrationFolder() != null) { + tempMigrationFolder = configuration.getTempMigrationFolder(); + } else { + try { + tempMigrationFolder = Files.createTempDirectory("migration") + .toFile(); + } catch (IOException e) { + throw new RuntimeException("Could not create a new " + + "temporary folder for migration. You may specify it manually"); + } + } + } else { + if (!getTempMigrationFolder().isDirectory()) { + String message = String + .format("Received temp migration folder value '%s' is not a directory.", + getTempMigrationFolder()); + throw new IllegalArgumentException(message); + } else if (getTempMigrationFolder().list().length > 0) { + String message = String + .format("Received non empty directory '%s' for use as the temporary migration folder.", + getTempMigrationFolder()); + throw new IllegalArgumentException(message); + } + tempMigrationFolder = getTempMigrationFolder(); + } + + if (configuration.getBaseDirectory() == null) { + throw new IllegalArgumentException( + "Configuration does not provide a base directory"); + } + + if (configuration.getResourceDirectories() != null + && configuration.getResourceDirectories().length == 0) { + throw new IllegalArgumentException( + "Configuration does not provide any resource directories"); + } else if (configuration.getResourceDirectories() == null) { + resourceDirectories = new File[] { new File( + configuration.getBaseDirectory(), "src/main/webapp") }; + } else { + resourceDirectories = configuration.getResourceDirectories(); + } + + if (configuration.getTargetDirectory() == null) { + targetDirectory = new File(configuration.getBaseDirectory(), + "frontend"); + } else { + targetDirectory = configuration.getBaseDirectory(); + } + + if (configuration.getClassFinder() == null) { + throw new IllegalArgumentException( + "Configuration does not provide a class finder"); + } + + if (configuration.getJavaSourceDirectories() == null + || configuration.getJavaSourceDirectories().length == 0) { + throw new IllegalArgumentException( + "Configuration does not provide any java source directories"); + } + + if (configuration.getCompiledClassDirectory() == null) { + throw new IllegalArgumentException( + "Configuration does not provide a compiled class directory"); + } + } + + /** + * Performs the migration. + * + * @throws MigrationToolsException + * Thrown when migration tools are missing + * @throws MigrationFailureException + * Thrown for an exception during migration + */ + public void migrate() + throws MigrationToolsException, MigrationFailureException { + prepareMigrationDirectory(); + + List bowerCommands = FrontendUtils + .getBowerExecutable(getTempMigrationFolder().getPath()); + boolean needInstallBower = bowerCommands.isEmpty(); + if (!ensureTools(needInstallBower)) { + throw new MigrationToolsException( + "Could not install tools required for migration (bower or modulizer)"); + } + if (needInstallBower) { + bowerCommands = FrontendUtils + .getBowerExecutable(getTempMigrationFolder().getPath()); + } + + if (bowerCommands.isEmpty()) { + throw new MigrationToolsException( + "Could not locate bower. Install it manually on your system and re-run migration goal."); + } + + Set externalComponents; + CopyResourcesStep copyStep = new CopyResourcesStep( + getTempMigrationFolder(), getResources()); + Map> paths; + try { + paths = copyStep.copyResources(); + externalComponents = copyStep.getBowerComponents(); + } catch (IOException exception) { + throw new UncheckedIOException( + "Couldn't copy resources from source directories " + + Arrays.asList(getResources()) + + " to the target directory " + + getTempMigrationFolder(), + exception); + } + + Set migratedTopLevelDirs = Stream + .of(getTempMigrationFolder().listFiles()) + .filter(File::isDirectory).map(File::getName) + .collect(Collectors.toSet()); + + List allPaths = new ArrayList<>(); + paths.values().stream().forEach(allPaths::addAll); + try { + new CreateMigrationJsonsStep(getTempMigrationFolder()) + .createJsons(allPaths); + } catch (IOException exception) { + throw new UncheckedIOException("Couldn't generate json files", + exception); + } + + if (!saveBowerComponents(bowerCommands, externalComponents)) { + throw new MigrationFailureException( + "Could not install bower components"); + } + + installNpmPackages(); + + boolean modulizerHasErrors = false; + if (!runModulizer()) { + modulizerHasErrors = true; + if (configuration.isIgnoreModulizerErrors()) { + getLogger().info("Modulizer has exited with error"); + } else { + throw new MigrationFailureException( + "Modulizer has exited with error. Unable to proceed."); + } + } + + // copy the result JS files into target dir ("frontend") + if (!getTargetDirectory().exists()) { + try { + FileUtils.forceMkdir(getTargetDirectory()); + } catch (IOException exception) { + throw new UncheckedIOException( + "Unable to create a target folder for migrated files: '" + + getTargetDirectory() + "'", + exception); + } + } + CopyMigratedResourcesStep copyMigratedStep = new CopyMigratedResourcesStep( + getTargetDirectory(), getTempMigrationFolder(), + migratedTopLevelDirs); + try { + copyMigratedStep.copyResources(); + } catch (IOException exception) { + throw new UncheckedIOException( + "Couldn't copy migrated resources to the target directory " + + getTargetDirectory(), + exception); + } + + try { + cleanUp(getTempMigrationFolder()); + } catch (IOException exception) { + getLogger().debug( + "Couldn't remove " + getTempMigrationFolder().getPath(), + exception); + } + + if (!modulizerHasErrors && !configuration.isKeepOriginalFiles()) { + removeOriginalResources(paths); + } + + switch (configuration.getAnnotationRewriteStrategy()) { + case SKIP: + break; + case ALWAYS: + rewrite(); + break; + case SKIP_ON_ERROR: + if (!modulizerHasErrors) { + rewrite(); + } + break; + } + } + + /** + * Prepare migration by cleaning everything, except if only node_modules + * exists in the target directory. + */ + private void prepareMigrationDirectory() { + if (getTempMigrationFolder().exists()) { + String[] list = getTempMigrationFolder().list(); + if (list.length == 1 && list[0].equals("node_modules")) { + return; + } else if (list.length == 2 && + Stream.of(list).filter(file -> file.startsWith("node")) + .count() == 2) { + return; + } + try { + cleanUp(getTempMigrationFolder()); + } catch (IOException exception) { + String message = String + .format("Unable to clean up directory '%s'", + getTempMigrationFolder()); + throw new UncheckedIOException(message, exception); + } + } else { + try { + FileUtils.forceMkdir(getTempMigrationFolder()); + } catch (IOException exception) { + String message = String + .format("Failed in creating migration folder '%s'", + getTempMigrationFolder()); + throw new UncheckedIOException(message, exception); + } + } + } + + private void removeOriginalResources(Map> paths) { + for (Entry> entry : paths.entrySet()) { + File resourceFolder = new File(entry.getKey()); + entry.getValue() + .forEach(path -> new File(resourceFolder, path).delete()); + } + } + + private void installNpmPackages() throws MigrationFailureException { + List npmExec = FrontendUtils + .getNpmExecutable(configuration.getBaseDirectory().getPath()); + List npmInstall = new ArrayList<>(npmExec.size()); + npmInstall.addAll(npmExec); + npmInstall.add("i"); + + if (!executeProcess(npmInstall, "Couldn't install packages using npm", + "Packages successfully installed", + "Error when running `npm install`")) { + throw new MigrationFailureException( + "Error during package installation via npm"); + } + } + + private boolean runModulizer() { + Collection depMapping = makeDependencyMapping(); + + List command = new ArrayList<>(); + command.add(FrontendUtils + .getNodeExecutable(configuration.getBaseDirectory().getPath())); + command.add("node_modules/polymer-modulizer/bin/modulizer.js"); + command.add("--force"); + command.add("--out"); + command.add("."); + command.add("--import-style=name"); + if (!depMapping.isEmpty()) { + command.add("--dependency-mapping"); + command.addAll(depMapping); + } + + return executeProcess(command, "Migration has finished with errors", + "Modulizer has completed successfully", + "Error when running moulizer"); + } + + private Collection makeDependencyMapping() { + File bower = new File(getTempMigrationFolder(), "bower.json"); + + try { + Set result = new HashSet<>(); + String content = Files.readAllLines(bower.toPath()).stream() + .collect(Collectors.joining("\n")); + JsonObject object = Json.parse(content); + if (object.hasKey(DEPENDENCIES)) { + JsonObject deps = object.getObject(DEPENDENCIES); + Stream.of(deps.keys()).filter(key -> key.startsWith("vaadin-")) + .forEach(key -> result + .add(makeVaadinDependencyMapping(deps, key))); + } + return result; + } catch (IOException exception) { + throw new UncheckedIOException("Unable to read bower.json", + exception); + } + } + + private String makeVaadinDependencyMapping(JsonObject deps, String key) { + JsonValue version = deps.get(key); + StringBuilder builder = new StringBuilder(key); + builder.append(','); + builder.append("@vaadin/"); + builder.append(key).append(','); + builder.append(version.asString()); + return builder.toString(); + } + + private boolean saveBowerComponents(List bowerCommands, + Collection components) { + List command = new ArrayList<>(); + command.addAll(bowerCommands); + // install + command.add("i"); + // -F option means: Force latest version on conflict + command.add("-F"); + // disable interactive mode + command.add("--config.interactive=false"); + // -S option means: Save installed packages into the project’s + // bower.json dependencies + command.add("-S"); + + // add all extracted bower components to install them and save + + // the latest polymer version which is chosen by bower has only JS + // module file. It won't be resolved from the import properly. So we + // have to force 2.x.x version which is P2 based. + command.add("polymer#2.8.0"); + components.stream().filter(component -> !"polymer".equals(component)) + .forEach(command::add); + + return executeProcess(command, + "Couldn't install and save bower components", + "All components are installed and saved successfully", + "Error when running `bower install`"); + } + + private boolean ensureTools(boolean needInstallBower) { + List npmExecutable = FrontendUtils + .getNpmExecutable(configuration.getBaseDirectory().getPath()); + List command = new ArrayList<>(); + command.addAll(npmExecutable); + command.add("install"); + if (needInstallBower) { + command.add("bower"); + } + command.add("polymer-modulizer"); + + return executeProcess(command, "Couldn't install migration tools", + "Bower is installed successfully", + "Error when running `npm install`"); + } + + protected boolean executeProcess(List command, String errorMsg, + String successMsg, String exceptionMsg) { + ProcessBuilder builder = FrontendUtils.createProcessBuilder(command); + builder.directory(getTempMigrationFolder()); + + Process process = null; + try { + process = builder.inheritIO().start(); + int errorCode = process.waitFor(); + if (errorCode != 0) { + getLogger().error(errorMsg); + return false; + } else { + getLogger().debug(successMsg); + } + } catch (InterruptedException | IOException e) { + getLogger().error(exceptionMsg, e); + return false; + } finally { + if (process != null) { + process.destroyForcibly(); + } + } + + return true; + } + + private Logger getLogger() { + return LoggerFactory.getLogger(Migration.class); + } + + private void cleanUp(File dir) throws IOException { + FileUtils.forceDelete(dir); + } + + private File[] getResources() { + if (getResourceDirectories() == null) { + File webApp = new File(configuration.getBaseDirectory(), + "src/main/webapp"); + return new File[] { webApp }; + } + return getResourceDirectories(); + } + + private void rewrite() { + RewriteLegacyAnnotationsStep step = new RewriteLegacyAnnotationsStep( + configuration.getCompiledClassDirectory(), + configuration.getClassFinder(), + Stream.of(configuration.getJavaSourceDirectories()) + .collect(Collectors.toList())); + step.rewrite(); + } + + private File getTempMigrationFolder() { + return tempMigrationFolder; + } + + private File getTargetDirectory() { + return targetDirectory; + } + + private File[] getResourceDirectories() { + return resourceDirectories; + } + +} diff --git a/flow-migration/src/main/java/com/vaadin/flow/migration/MigrationConfiguration.java b/flow-migration/src/main/java/com/vaadin/flow/migration/MigrationConfiguration.java new file mode 100644 index 00000000000..58063b32156 --- /dev/null +++ b/flow-migration/src/main/java/com/vaadin/flow/migration/MigrationConfiguration.java @@ -0,0 +1,344 @@ +/* + * Copyright 2000-2018 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.migration; + +import java.io.File; +import java.util.Objects; + +import com.vaadin.flow.component.dependency.HtmlImport; +import com.vaadin.flow.component.dependency.JsModule; +import com.vaadin.flow.component.dependency.StyleSheet; +import com.vaadin.flow.server.frontend.scanner.ClassFinder; + +/** + * Configuration for migration. + * + * @author Vaadin Ltd + * + */ +public class MigrationConfiguration { + + private File tempMigrationFolder; + + private File[] resourceDirectories; + + private File targetDirectory; + + private boolean keepOriginalFiles; + + private boolean ignoreModulizerErrors = true; + + private AnnotationsRewriteStrategy annotationRewriteStrategy = AnnotationsRewriteStrategy.ALWAYS; + + private final File baseDirectory; + + private ClassFinder classFinder; + + private File[] javaSourceDirectories; + + private File compiledClassDirectory; + + private MigrationConfiguration(File baseDir) { + baseDirectory = baseDir; + } + + private MigrationConfiguration(MigrationConfiguration configuration) { + this.tempMigrationFolder = configuration.getTempMigrationFolder(); + if (configuration.getResourceDirectories() != null) { + this.resourceDirectories = configuration.getResourceDirectories() + .clone(); + } + this.targetDirectory = configuration.getTargetDirectory(); + this.keepOriginalFiles = configuration.isKeepOriginalFiles(); + this.ignoreModulizerErrors = configuration.isIgnoreModulizerErrors(); + this.annotationRewriteStrategy = configuration + .getAnnotationRewriteStrategy(); + this.baseDirectory = configuration.getBaseDirectory(); + this.classFinder = configuration.getClassFinder(); + if (configuration.getJavaSourceDirectories() != null) { + this.javaSourceDirectories = configuration + .getJavaSourceDirectories().clone(); + } + this.compiledClassDirectory = configuration.getCompiledClassDirectory(); + } + + /** + * Gets the migration folder. + * + * @return the migration folder + */ + public File getTempMigrationFolder() { + return tempMigrationFolder; + } + + /** + * Gets the resource directories. + * + * @return the resource directories + */ + public File[] getResourceDirectories() { + return resourceDirectories; + } + + /** + * Gets the target directory. + * + * @return the target directory + */ + public File getTargetDirectory() { + return targetDirectory; + } + + /** + * Checks whether the original resource files should be preserved. + * + * @return whether the original resource files should be preserved + */ + public boolean isKeepOriginalFiles() { + return keepOriginalFiles; + } + + /** + * Checks whether Modulizer errors should be ignored. + * + * @return whether Modulizer errors should be ignored + */ + public boolean isIgnoreModulizerErrors() { + return ignoreModulizerErrors; + } + + /** + * Gets the base directory + * + * @return the base directory + */ + public File getBaseDirectory() { + return baseDirectory; + } + + /** + * Gets the compiled classes directory. + * + * @return the compiled classes directory + */ + public File getCompiledClassDirectory() { + return compiledClassDirectory; + } + + /** + * Gets the class finder. + * + * @return the class finder + */ + public ClassFinder getClassFinder() { + return classFinder; + } + + /** + * Gets the java source roots. + * + * @return the java source roots + */ + public File[] getJavaSourceDirectories() { + return javaSourceDirectories; + } + + /** + * Gets the annotation rewrite strategy. + * + * @return the annotation rewrite strategy + */ + public AnnotationsRewriteStrategy getAnnotationRewriteStrategy() { + return annotationRewriteStrategy; + } + + /** + * A builder for {@link MigrationConfiguration}. Allows to set all required + * parameters via setters fluent API. + * + * @author Vaadin Ltd + * + */ + public static class Builder { + + private final MigrationConfiguration config; + + /** + * Creates a new instance of the builded with provided {@code baseDir}. + * + * @param baseDir + * base project directory + */ + public Builder(File baseDir) { + config = new MigrationConfiguration(baseDir); + } + + /** + * Sets temporary migration folder where the migration happens. + *

+ * The folder value is not required. It it's not set then temporary + * folder will be used. This folder will be removed once the migration + * happens regardless of result. + * + * @param file + * the migration folder + * @return this builder + */ + public Builder setTemporaryMigrationFolder(File file) { + config.tempMigrationFolder = Objects.requireNonNull(file); + return this; + } + + /** + * Sets the resource files directories. + *

+ * There can be several resource roots. They contains HTML tempate files + * and stylesheet files. The hierarchical structure will be transfered + * into the target directory (see {@link #setTargetDirectory(File)} as + * is (except "frontend" directory whose files and subdirs are moved + * ignoring the "frontend" dir). + * + * @param resourceDirs + * resource roots + * @return this builder + */ + public Builder setResourceDirectories(File[] resourceDirs) { + config.resourceDirectories = Objects.requireNonNull(resourceDirs); + return this; + } + + /** + * Sets the target directory where the resource files will be stored + * after the migration. + *

+ * This directory is usually is "frontend" folder inside base dir + * + * @param targetDir + * the target directory + * @return this builder + */ + public Builder setTargetDirectory(File targetDir) { + config.targetDirectory = Objects.requireNonNull(targetDir); + return this; + } + + /** + * Sets whether the original resources should be preserved. + *

+ * By default the original resources are removed if there were no errors + * during migration. + * + * @param keepOriginal + * whether the original resources should be preserved + * @return this builder + */ + public Builder setKeepOriginalFiles(boolean keepOriginal) { + config.keepOriginalFiles = keepOriginal; + return this; + } + + /** + * Sets whether the build should be considered successful even if there + * are Modulizer errors. + *

+ * Modulizer is an external tool which is used internally for converting + * resource files. Modulizer process exit status may be non zero even if + * all files have been converted correctly. By default the exit status + * code is ignored. + * + * @param ignoreModulizerErrors + * whether the tool should fail is Modulizer fails + * @return this builder + */ + public Builder setIgnoreModulizerErrors(boolean ignoreModulizerErrors) { + config.ignoreModulizerErrors = ignoreModulizerErrors; + return this; + } + + /** + * Sets the class finder instance. + * + * @param finder + * a class finder + * @return this builder + */ + public Builder setClassFinder(ClassFinder finder) { + config.classFinder = Objects.requireNonNull(finder); + return this; + } + + /** + * Sets java source roots. + *

+ * Java source roots contain java files which should be rewritten to use + * {@link JsModule} annotation instead of {@link HtmlImport} and + * {@link StyleSheet}. + * + * @param sourceRoots + * java source roots + * @return this builder + */ + public Builder setJavaSourceRoots(File[] sourceRoots) { + config.javaSourceDirectories = Objects.requireNonNull(sourceRoots); + return this; + } + + /** + * Sets java binary (compiled) classes directory. + *

+ * The java files from source roots ({@link #setJavaSourceRoots(File[])} + * must be compiled when the migration is done into this directory. + * + * @param classDirectory + * compiled java classes directory + * @return this builder + */ + public Builder setCompiledClassDirectory(File classDirectory) { + config.compiledClassDirectory = Objects + .requireNonNull(classDirectory); + return this; + } + + /** + * Sets the annotation rewrite strategy. + *

+ * This strategy is used to control annotation ( {@link HtmlImport} and + * {@link StyleSheet} rewrite logic. By default the annotation are + * always rewritten regardless of conversation status. + * + * @param strategy + * the annotation rewrite strategy + * @return this builder + */ + public Builder setAnnotationRewriteStrategy( + AnnotationsRewriteStrategy strategy) { + config.annotationRewriteStrategy = Objects.requireNonNull(strategy); + return this; + + } + + /** + * Builds the immutable configuration based on the builder. + * + * @return the resulting configuration + */ + public MigrationConfiguration build() { + // return an immutable instance + return new MigrationConfiguration(config); + } + } + +} diff --git a/flow-migration/src/main/java/com/vaadin/flow/migration/MigrationFailureException.java b/flow-migration/src/main/java/com/vaadin/flow/migration/MigrationFailureException.java new file mode 100644 index 00000000000..dd2660b2bbc --- /dev/null +++ b/flow-migration/src/main/java/com/vaadin/flow/migration/MigrationFailureException.java @@ -0,0 +1,27 @@ +/* + * Copyright 2000-2018 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.migration; + +/** + * @author Vaadin Ltd + * + */ +public class MigrationFailureException extends Exception { + + public MigrationFailureException(String message) { + super(message); + } +} diff --git a/flow-migration/src/main/java/com/vaadin/flow/migration/MigrationTool.java b/flow-migration/src/main/java/com/vaadin/flow/migration/MigrationTool.java new file mode 100644 index 00000000000..5575f16a2db --- /dev/null +++ b/flow-migration/src/main/java/com/vaadin/flow/migration/MigrationTool.java @@ -0,0 +1,341 @@ +/* + * Copyright 2000-2018 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.migration; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.vaadin.flow.migration.MigrationConfiguration.Builder; +import com.vaadin.flow.server.scanner.ReflectionsClassFinder; + +/** + * Main class which allow to call migration from the command line using + * arguments. + * + * @author Vaadin Ltd + * + */ +public class MigrationTool { + + private static final String DEP_URLS = "depUrls"; + private static final String SOURCE_DIRS = "sourceDirs"; + private static final String TARGET_DIR = "targetDir"; + private static final String KEEP_ORIGINAL = "keepOriginal"; + private static final String MIGRATION_DIR = "migrationDir"; + private static final String RESOURCES_DIRS = "resourcesDirs"; + private static final String STOP_ON_ERROR = "stopOnError"; + private static final String CLASSES_DIR = "classesDir"; + private static final String BASE_DIR = "baseDir"; + private static final String ANNOTATION_REWRITE = "annRewrite"; + + /** + * Runs migration tool using command line {@code args}. + * + * @param args + * command line arguments + * @throws MigrationFailureException + * if migration failed because of errors during execution + * @throws MigrationToolsException + * if migration failed because some necessary tools installation + * failed + * + * @see #runMigration(String[]) + */ + public static void main(String[] args) + throws MigrationToolsException, MigrationFailureException { + MigrationTool tool = new MigrationTool(); + + HelpFormatter formatter = new HelpFormatter(); + try { + tool.runMigration(args); + } catch (CommandArgumentException exception) { + System.out.println(exception.getCause().getMessage()); + if (exception.getOptions().isPresent()) { + formatter.printHelp("migration tool", + exception.getOptions().get()); + } + + System.exit(1); + } + + } + + /** + * Runs migration tool using command line {@code args}. + * + * @param args + * command line arguments + * @throws MigrationFailureException + * if migration failed because of errors during execution + * @throws MigrationToolsException + * if migration failed because some necessary tools installation + * failed + */ + protected void runMigration(String[] args) throws CommandArgumentException, + MigrationToolsException, MigrationFailureException { + Options options = makeOptions(); + + CommandLineParser parser = new DefaultParser(); + + CommandLine command = null; + + try { + command = parser.parse(options, args); + } catch (ParseException exception) { + throw new CommandArgumentException(options, exception); + } + + File baseDirValue = new File(command.getOptionValue(BASE_DIR)); + Builder builder = new Builder(baseDirValue); + + getLogger().debug("The base dir is {}", + command.getOptionValue(BASE_DIR)); + + File compiledClasses = setCompiledClasses(command, builder); + + setIgnoreModulizerErrors(command, builder); + + setResourcesDirs(command, baseDirValue, builder); + + setMigrationDir(command, builder); + + setTargetDir(command, baseDirValue, builder); + + setKeepOriginal(command, builder); + + setSourceDirs(command, builder); + + setClassFinder(command, builder, compiledClasses); + + setAnnotationRewriteStrategy(command, builder); + + doMigration(builder.build()); + } + + /** + * Runs migration using the provided {@code configuration}. + * + * @param configuration + * the configuration + * @throws MigrationFailureException + * if migration failed because of errors during execution + * @throws MigrationToolsException + * if migration failed because some necessary tools installation + * failed + */ + protected void doMigration(MigrationConfiguration configuration) + throws MigrationToolsException, MigrationFailureException { + Migration migration = new Migration(configuration); + migration.migrate(); + } + + private void setAnnotationRewriteStrategy(CommandLine command, + Builder builder) throws CommandArgumentException { + String annotationRewrite = command.getOptionValue(ANNOTATION_REWRITE); + if (annotationRewrite != null) { + try { + AnnotationsRewriteStrategy strategy = AnnotationsRewriteStrategy + .valueOf(annotationRewrite); + builder.setAnnotationRewriteStrategy(strategy); + getLogger().debug( + "Annotation rewrite strategy is set to " + strategy); + } catch (IllegalArgumentException exception) { + throw new CommandArgumentException(exception); + } + } else { + getLogger().debug( + "Annotation rewrite strategy is not explicitly set"); + } + } + + private void setClassFinder(CommandLine command, Builder builder, + File compiledClasses) throws CommandArgumentException { + URL compiledClassesURL; + try { + compiledClassesURL = compiledClasses.toURI().toURL(); + } catch (MalformedURLException exception) { + throw new CommandArgumentException(exception); + } + String[] urls = command.getOptionValues(DEP_URLS); + URL[] depUrls = new URL[urls.length + 1]; + depUrls[0] = compiledClassesURL; + for (int i = 0; i < urls.length; i++) { + try { + depUrls[i + 1] = new URL(urls[i]); + } catch (MalformedURLException exception) { + throw new CommandArgumentException(exception); + } + } + + builder.setClassFinder(new ReflectionsClassFinder(depUrls)); + } + + private void setSourceDirs(CommandLine command, Builder builder) { + String[] sourceDirs = command.getOptionValues(SOURCE_DIRS); + List sourceRoots = Stream.of(sourceDirs).map(File::new) + .collect(Collectors.toList()); + builder.setJavaSourceRoots( + sourceRoots.toArray(new File[sourceRoots.size()])); + getLogger().debug("The java source directories are {}", sourceRoots); + } + + private void setKeepOriginal(CommandLine command, Builder builder) { + if (command.hasOption(KEEP_ORIGINAL)) { + builder.setKeepOriginalFiles(true); + getLogger().debug("Keep original resources value is true"); + } else { + getLogger().debug("Keep original resources value is false"); + } + } + + private void setTargetDir(CommandLine command, File baseDirValue, + Builder builder) { + String targetDir = command.getOptionValue(TARGET_DIR); + if (targetDir != null) { + builder.setTargetDirectory(new File(targetDir)); + getLogger().debug("The target directory is {}", targetDir); + } else { + getLogger().debug( + "The target directory is not set explicitly. " + + "The value is implicitly set to {}", + new File(baseDirValue, "frontend")); + } + } + + private void setMigrationDir(CommandLine command, Builder builder) { + String tempMigrationFolder = command.getOptionValue(MIGRATION_DIR); + if (tempMigrationFolder != null) { + builder.setTemporaryMigrationFolder(new File(tempMigrationFolder)); + getLogger().debug("The temporary migration directory is {}", + tempMigrationFolder); + } else { + getLogger().debug( + "The temporary migration directory is not set explicitely"); + } + } + + private void setResourcesDirs(CommandLine command, File baseDirValue, + Builder builder) { + String[] resourceDirs = command.getOptionValues(RESOURCES_DIRS); + if (resourceDirs != null) { + List folders = Stream.of(resourceDirs).map(File::new) + .collect(Collectors.toList()); + builder.setResourceDirectories( + folders.toArray(new File[folders.size()])); + getLogger().debug("The resource directories are {}", folders); + } else { + getLogger().debug( + "The resource directories is not set explicitely. " + + "The value is implicitely set to {}", + new File(baseDirValue, "src/main/webapp")); + } + } + + private void setIgnoreModulizerErrors(CommandLine command, + Builder builder) { + if (command.hasOption(STOP_ON_ERROR)) { + builder.setIgnoreModulizerErrors(false); + getLogger().debug("Ignore modulizer errors value is false"); + } else { + getLogger().debug("Ignore modulizer errors value is true"); + } + } + + private File setCompiledClasses(CommandLine command, Builder builder) { + File compiledClasses = new File(command.getOptionValue(CLASSES_DIR)); + builder.setCompiledClassDirectory(compiledClasses); + + getLogger().debug("The classes directory is {}", + command.getOptionValue(CLASSES_DIR)); + return compiledClasses; + } + + private Options makeOptions() { + Options options = new Options(); + + // Not required + Option migrationDir = new Option("md", MIGRATION_DIR, true, + "temporary migration directory"); + options.addOption(migrationDir); + + Option baseDir = new Option("b", BASE_DIR, true, + "base project directory. Normally it is the root of the files to migrate. " + + "The directory will be used to search and install " + + "(if necessary) external tools like node, npm, etc.."); + baseDir.setRequired(true); + options.addOption(baseDir); + + Option resourceDirectories = new Option("res", RESOURCES_DIRS, true, + "comma separated resource directories relative to the baseDir, by default the value is one path 'src/main/webapp' inside base directory"); + options.addOption(resourceDirectories); + + Option target = new Option("t", TARGET_DIR, true, + "target directory for converted resource files. " + + "By default it's the path 'frontend' inside the base directory"); + options.addOption(target); + + Option stopOnError = new Option("se", STOP_ON_ERROR, false, + "whether migration should " + + "stop execution with error if modulizer has exited with not 0 status"); + options.addOption(stopOnError); + + Option javaSourceDirectories = new Option("src", SOURCE_DIRS, true, + "comma separated java source directories"); + javaSourceDirectories.setRequired(true); + options.addOption(javaSourceDirectories); + + Option compiledClassesDir = new Option("c", CLASSES_DIR, true, + "compiled classes directory. Java classes have to be compiled into " + + "this directory to be able to apply migration"); + compiledClassesDir.setRequired(true); + options.addOption(compiledClassesDir); + + Option dependenciesUrls = new Option("d", DEP_URLS, true, + "comma separated classpath URLs. The URLs should include all dependencies for " + + "the project such as Jars or filesystem paths to binary classes"); + dependenciesUrls.setRequired(true); + options.addOption(dependenciesUrls); + + Option keepOriginal = new Option("ko", KEEP_ORIGINAL, false, + "whether the original " + + "resource files should be preserved. By default the migrated files are removed."); + options.addOption(keepOriginal); + + Option annotationRewrite = new Option("ars", ANNOTATION_REWRITE, true, + "annotation rewrite strategy. By default the value is ALWAYS. Other choices are SKIP, SKIP_ON_ERROR"); + options.addOption(annotationRewrite); + return options; + } + + private Logger getLogger() { + return LoggerFactory.getLogger(MigrationTool.class); + } + +} diff --git a/flow-migration/src/main/java/com/vaadin/flow/migration/MigrationToolsException.java b/flow-migration/src/main/java/com/vaadin/flow/migration/MigrationToolsException.java new file mode 100644 index 00000000000..330644e26dd --- /dev/null +++ b/flow-migration/src/main/java/com/vaadin/flow/migration/MigrationToolsException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2018 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.migration; + +/** + * Exception thrown for missing migration tools. + * + * @author Vaadin Ltd + */ +public class MigrationToolsException extends Exception { + + /** + * Migration tool exception constructor. + * + * @param message + * message on why this exception was thrown + */ + public MigrationToolsException(String message) { + super(message); + } + +} diff --git a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/migration/RewriteLegacyAnnotationsStep.java b/flow-migration/src/main/java/com/vaadin/flow/migration/RewriteLegacyAnnotationsStep.java similarity index 92% rename from flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/migration/RewriteLegacyAnnotationsStep.java rename to flow-migration/src/main/java/com/vaadin/flow/migration/RewriteLegacyAnnotationsStep.java index 6f4d73313a8..43734732d4b 100644 --- a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/migration/RewriteLegacyAnnotationsStep.java +++ b/flow-migration/src/main/java/com/vaadin/flow/migration/RewriteLegacyAnnotationsStep.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration; +package com.vaadin.flow.migration; import java.io.File; import java.io.IOException; @@ -36,14 +36,13 @@ import com.vaadin.flow.component.dependency.HtmlImport; import com.vaadin.flow.component.dependency.JsModule; import com.vaadin.flow.component.dependency.StyleSheet; -import com.vaadin.flow.plugin.common.ClassPathIntrospector; -import com.vaadin.flow.plugin.common.FlowPluginFileUtils; import com.vaadin.flow.server.frontend.scanner.ClassFinder; import com.vaadin.flow.shared.ApplicationConstants; +import com.vaadin.flow.utils.FlowFileUtils; /** - * Rewrites {@link HtmlImport} annotation to corresponding {@link JsModule} - * annotation. + * Rewrites {@link HtmlImport}/{@link StyleSheet} annotation to corresponding + * {@link JsModule} annotation. * * @author Vaadin Ltd * @@ -52,7 +51,6 @@ public class RewriteLegacyAnnotationsStep extends ClassPathIntrospector { private static final String HTML_EXTENSION = ".html"; private static final String CSS_EXTENSION = ".css"; - private final URL compiledClassesURL; private final Collection sourceRoots; @@ -78,27 +76,25 @@ public class RewriteLegacyAnnotationsStep extends ClassPathIntrospector { public RewriteLegacyAnnotationsStep(File compiledClassesDir, ClassFinder finder, Collection sourceRoots) { super(finder); - compiledClassesURL = FlowPluginFileUtils - .convertToUrl(compiledClassesDir); + compiledClassesURL = FlowFileUtils.convertToUrl(compiledClassesDir); this.sourceRoots = sourceRoots; } /** - * Search for java files in the project and replace - * {@link HtmlImport}/{@link StyleSheet} annotations to {@link JsModule} - * annotation with updated value. + * Search for java files in the project and replace {@link HtmlImport} to + * {@link JsModule} annotation with updated value. */ public void rewrite() { - Map, Map, Collection>> annotationsPerClass = new HashMap<>(); + Map, Map, Collection>> annotationPerClass = new HashMap<>(); collectAnnotatedClasses( loadClassInProjectClassLoader(HtmlImport.class.getName()), - annotationsPerClass); + annotationPerClass); collectAnnotatedClasses( loadClassInProjectClassLoader(StyleSheet.class.getName()), - annotationsPerClass); + annotationPerClass); - annotationsPerClass.forEach(this::rewriteAnnotations); + annotationPerClass.forEach(this::rewriteAnnotations); } private void collectAnnotatedClasses(Class annotation, @@ -135,6 +131,7 @@ private Collection collectAnnotationValues(Class clazz, String path = invokeAnnotationMethod(annotation, "value") .toString(); result.add(path); + } return result; } @@ -234,8 +231,10 @@ private void rewrite(File javaFile, Class clazz, String beforeClassDeclaration = content.substring(0, classDeclarationStart); + for (Entry, Collection> entry : annotations .entrySet()) { + beforeClassDeclaration = rewrite(beforeClassDeclaration, entry.getKey(), entry.getValue()); } @@ -247,7 +246,7 @@ private void rewrite(File javaFile, Class clazz, StandardCharsets.UTF_8); } catch (IOException e) { getLogger().warn("Could not write source code back to file '{}'", - javaFile, e); + javaFile); } } @@ -255,7 +254,8 @@ private String rewrite(String content, Class annotation, Collection paths) { String result = content; // replace FQN first - result = replace(annotation.getName(), result, "\\b" + annotation.getName().replace(".", "\\.") + "\\b", + result = replace(annotation.getName(), result, + "\\b" + annotation.getName().replace(".", "\\.") + "\\b", JsModule.class.getName()); // replace annotation attached to the class with @ sign @@ -274,8 +274,8 @@ private String rewrite(String content, * Does the same as {@link String#replaceAll(String, String)} but caches the * compiled pattern */ - private String replace(String patternKey, String content, - String regexp, String replacement) { + private String replace(String patternKey, String content, String regexp, + String replacement) { Pattern pattern = compiledReplacePatterns.computeIfAbsent(patternKey, key -> Pattern.compile(regexp)); return pattern.matcher(content).replaceAll(replacement); diff --git a/flow-migration/src/main/java/com/vaadin/flow/server/scanner/ReflectionsClassFinder.java b/flow-migration/src/main/java/com/vaadin/flow/server/scanner/ReflectionsClassFinder.java new file mode 100644 index 00000000000..2c55ac1b544 --- /dev/null +++ b/flow-migration/src/main/java/com/vaadin/flow/server/scanner/ReflectionsClassFinder.java @@ -0,0 +1,90 @@ +/* + * Copyright 2000-2018 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.server.scanner; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Repeatable; +import java.lang.reflect.AnnotatedElement; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.reflections.Reflections; +import org.reflections.util.ConfigurationBuilder; + +import com.vaadin.flow.server.frontend.scanner.ClassFinder; + +/** + * A class finder using org.reflections. + */ +public class ReflectionsClassFinder implements ClassFinder { + private final transient ClassLoader classLoader; + + private final transient Reflections reflections; + + /** + * Constructor. + * + * @param urls + * the list of urls for finding classes. + */ + public ReflectionsClassFinder(URL... urls) { + classLoader = new URLClassLoader(urls, null); // NOSONAR + reflections = new Reflections( + new ConfigurationBuilder().addClassLoader(classLoader) + .setExpandSuperTypes(false).addUrls(urls)); + } + + @Override + public Set> getAnnotatedClasses( + Class clazz) { + Set> classes = new HashSet<>(); + classes.addAll(reflections.getTypesAnnotatedWith(clazz, true)); + classes.addAll(getAnnotatedByRepeatedAnnotation(clazz)); + return classes; + + } + + private Set> getAnnotatedByRepeatedAnnotation( + AnnotatedElement annotationClass) { + Repeatable repeatableAnnotation = annotationClass + .getAnnotation(Repeatable.class); + if (repeatableAnnotation != null) { + return reflections.getTypesAnnotatedWith( + repeatableAnnotation.value(), true); + } + return Collections.emptySet(); + } + + @Override + public URL getResource(String name) { + return classLoader.getResource(name); + } + + @SuppressWarnings("unchecked") + @Override + public Class loadClass(String name) + throws ClassNotFoundException { + return (Class) classLoader.loadClass(name); + } + + @Override + public Set> getSubTypesOf(Class type) { + return reflections.getSubTypesOf(type); + } +} diff --git a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/FlowPluginFileUtils.java b/flow-migration/src/main/java/com/vaadin/flow/utils/FlowFileUtils.java similarity index 94% rename from flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/FlowPluginFileUtils.java rename to flow-migration/src/main/java/com/vaadin/flow/utils/FlowFileUtils.java index ca433b657c8..070a21ad756 100644 --- a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/common/FlowPluginFileUtils.java +++ b/flow-migration/src/main/java/com/vaadin/flow/utils/FlowFileUtils.java @@ -14,7 +14,7 @@ * the License. */ -package com.vaadin.flow.plugin.common; +package com.vaadin.flow.utils; import java.io.File; import java.io.IOException; @@ -31,8 +31,8 @@ * @author Vaadin Ltd * @since 1.0. */ -public final class FlowPluginFileUtils { - private FlowPluginFileUtils() { +public final class FlowFileUtils { + private FlowFileUtils() { } /** diff --git a/flow-maven-plugin/src/main/resources/migration/bower.json b/flow-migration/src/main/resources/migration/bower.json similarity index 100% rename from flow-maven-plugin/src/main/resources/migration/bower.json rename to flow-migration/src/main/resources/migration/bower.json diff --git a/flow-maven-plugin/src/main/resources/migration/package.json b/flow-migration/src/main/resources/migration/package.json similarity index 100% rename from flow-maven-plugin/src/main/resources/migration/package.json rename to flow-migration/src/main/resources/migration/package.json diff --git a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/CopyMigratedResourcesStepTest.java b/flow-migration/src/test/java/com/vaadin/flow/migration/CopyMigratedResourcesStepTest.java similarity index 98% rename from flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/CopyMigratedResourcesStepTest.java rename to flow-migration/src/test/java/com/vaadin/flow/migration/CopyMigratedResourcesStepTest.java index 8d2fc43de17..0a6804e966b 100644 --- a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/CopyMigratedResourcesStepTest.java +++ b/flow-migration/src/test/java/com/vaadin/flow/migration/CopyMigratedResourcesStepTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration; +package com.vaadin.flow.migration; import java.io.File; import java.io.IOException; @@ -33,6 +33,8 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; +import com.vaadin.flow.migration.CopyMigratedResourcesStep; + public class CopyMigratedResourcesStepTest { @Rule diff --git a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/CopyResourcesStepTest.java b/flow-migration/src/test/java/com/vaadin/flow/migration/CopyResourcesStepTest.java similarity index 96% rename from flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/CopyResourcesStepTest.java rename to flow-migration/src/test/java/com/vaadin/flow/migration/CopyResourcesStepTest.java index d53621d5aef..992f7f3257d 100644 --- a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/CopyResourcesStepTest.java +++ b/flow-migration/src/test/java/com/vaadin/flow/migration/CopyResourcesStepTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration; +package com.vaadin.flow.migration; import java.io.File; import java.io.IOException; @@ -48,8 +48,7 @@ public void setUp() throws IOException { target = temporaryFolder.newFolder(); source1 = temporaryFolder.newFolder(); source2 = temporaryFolder.newFolder(); - step = new CopyResourcesStep(target, - new String[] { source1.getPath(), source2.getPath() }); + step = new CopyResourcesStep(target, new File[] { source1, source2 }); } @Test @@ -219,8 +218,7 @@ private void assertCopiedResources(Map> copied, List list = copied.get(source.getPath()); Assert.assertEquals(path.length, list.size()); for (int i = 0; i < path.length; i++) { - Assert.assertTrue(String.format("copied files %s did not contain expected file '%s'", list.toString(), path[i]), - list.contains(path[i])); + Assert.assertTrue("Copied resources didn't contain: " + path[i], list.contains(path[i])); } } } diff --git a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/CreateMigrationJsonsStepTest.java b/flow-migration/src/test/java/com/vaadin/flow/migration/CreateMigrationJsonsStepTest.java similarity index 96% rename from flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/CreateMigrationJsonsStepTest.java rename to flow-migration/src/test/java/com/vaadin/flow/migration/CreateMigrationJsonsStepTest.java index 0bcbf425615..e216979fe56 100644 --- a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/CreateMigrationJsonsStepTest.java +++ b/flow-migration/src/test/java/com/vaadin/flow/migration/CreateMigrationJsonsStepTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration; +package com.vaadin.flow.migration; import java.io.File; import java.io.IOException; @@ -27,6 +27,8 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; +import com.vaadin.flow.migration.CreateMigrationJsonsStep; + import elemental.json.Json; import elemental.json.JsonArray; import elemental.json.JsonObject; diff --git a/flow-migration/src/test/java/com/vaadin/flow/migration/MigrationTest.java b/flow-migration/src/test/java/com/vaadin/flow/migration/MigrationTest.java new file mode 100644 index 00000000000..c4f9de75a4c --- /dev/null +++ b/flow-migration/src/test/java/com/vaadin/flow/migration/MigrationTest.java @@ -0,0 +1,186 @@ +/* + * Copyright 2000-2018 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.migration; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.commons.io.FileUtils; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.mockito.Mockito; + +import com.vaadin.flow.server.frontend.scanner.ClassFinder; + +public class MigrationTest { + + @Rule + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); + + private MigrationConfiguration configuration = Mockito.mock(MigrationConfiguration.class); + + @Test(expected = IllegalArgumentException.class) + public void createMigration_noBaseDir_throw() { + new Migration(configuration); + } + + @Test(expected = IllegalArgumentException.class) + public void createMigration_baseDirIsSet_noClassFinder_throw() { + Mockito.when(configuration.getClassFinder()) + .thenReturn(Mockito.mock(ClassFinder.class)); + Mockito.when(configuration.getJavaSourceDirectories()) + .thenReturn(new File[] { new File("bar") }); + Mockito.when(configuration.getCompiledClassDirectory()) + .thenReturn(new File("foobar")); + new Migration(configuration); + } + + @Test(expected = IllegalArgumentException.class) + public void createMigration_noJavaSourceDirs_throw() { + Mockito.when(configuration.getBaseDirectory()) + .thenReturn(new File("foo")); + Mockito.when(configuration.getClassFinder()) + .thenReturn(Mockito.mock(ClassFinder.class)); + Mockito.when(configuration.getCompiledClassDirectory()) + .thenReturn(new File("foobar")); + new Migration(configuration); + } + + @Test(expected = IllegalArgumentException.class) + public void createMigration_emptyJavaSourceDirs_throw() { + Mockito.when(configuration.getBaseDirectory()) + .thenReturn(new File("foo")); + Mockito.when(configuration.getClassFinder()) + .thenReturn(Mockito.mock(ClassFinder.class)); + Mockito.when(configuration.getCompiledClassDirectory()) + .thenReturn(new File("foobar")); + Mockito.when(configuration.getJavaSourceDirectories()) + .thenReturn(new File[] {}); + new Migration(configuration); + } + + @Test(expected = IllegalArgumentException.class) + public void createMigration_noCompiledClassDir_throw() { + Mockito.when(configuration.getBaseDirectory()) + .thenReturn(new File("foo")); + Mockito.when(configuration.getClassFinder()) + .thenReturn(Mockito.mock(ClassFinder.class)); + Mockito.when(configuration.getJavaSourceDirectories()) + .thenReturn(new File[] { new File("bar") }); + new Migration(configuration); + } + + @Test + public void createMigration_allRequiredConfigParamsAreSet_doesnThrow() { + Mockito.when(configuration.getBaseDirectory()) + .thenReturn(new File("foo")); + Mockito.when(configuration.getClassFinder()) + .thenReturn(Mockito.mock(ClassFinder.class)); + Mockito.when(configuration.getJavaSourceDirectories()) + .thenReturn(new File[] { new File("bar") }); + Mockito.when(configuration.getCompiledClassDirectory()) + .thenReturn(new File("foobar")); + + new Migration(configuration); + } + + @Test + public void migratePassesHappyPath() + throws MigrationFailureException, MigrationToolsException, + IOException { + File sourcesFolder = makeTempDirectoryStructure(); + File targetFolder = populateTargetWithApplications(); + + Mockito.when(configuration.getBaseDirectory()) + .thenReturn(Paths.get(sourcesFolder.getPath(), "foo").toFile()); + Mockito.when(configuration.getTempMigrationFolder()). + thenReturn(targetFolder); + Mockito.when(configuration.getAnnotationRewriteStrategy()) + .thenReturn(AnnotationsRewriteStrategy.SKIP); + Mockito.when(configuration.isKeepOriginalFiles()).thenReturn(true); + Mockito.when(configuration.getClassFinder()) + .thenReturn(Mockito.mock(ClassFinder.class)); + Mockito.when(configuration.getJavaSourceDirectories()).thenReturn( + new File[] { + Paths.get(sourcesFolder.getPath(), "bar").toFile() }); + Mockito.when(configuration.getCompiledClassDirectory()).thenReturn( + Paths.get(sourcesFolder.getPath(), "foobar").toFile()); + + // Expected execution calls: + // 1 - npm install polymer-modulizer + // 2 - node {tempFolder} i -F --confid.interactive=false -S polymer#2.8.0 + // 3 - npm i + // 4 - node node_modules/polymer-modulizer/bin/modulizer.js --force --out , --import-style=name + + LinkedList excecuteExpectations = Stream.of(3, 7, 2, 6) + .collect(Collectors.toCollection(LinkedList::new)); + + Migration migration = new Migration(configuration) { + @Override + protected boolean executeProcess(List command, + String errorMsg, String successMsg, String exceptionMsg) { + Assert.assertEquals("Unexpected command", (int)excecuteExpectations.pop(), command.size()); + // Skip actual execution of commands. + return true; + } + }; + migration.migrate(); + } + + private File populateTargetWithApplications() throws IOException { + File targetFolder = temporaryFolder.newFolder(); + targetFolder.mkdirs(); + Path bowerBin = Files.createDirectories( + Paths.get(targetFolder.getAbsolutePath(), "node_modules", + "bower", "bin")); + new File(bowerBin.toFile(), "bower").createNewFile(); + + // Add stub node for test. !note! will not work on windows which will + // need to have node installed + Path nodeDirectory = Files.createDirectories( + Paths.get(targetFolder.getAbsolutePath(), "node")); + File node = new File(nodeDirectory.toFile(),"node"); + node.createNewFile(); + node.setExecutable(true); + FileUtils.write(node, + "#!/bin/sh\n[ \"$1\" = -v ] && echo 8.0.0 || sleep 1\n", + "UTF-8"); + + return targetFolder; + } + + private File makeTempDirectoryStructure() throws IOException { + File folder = temporaryFolder.newFolder(); + folder.mkdirs(); + Files.createDirectories( + Paths.get(folder.getAbsolutePath(), "foo", "src", "main", + "webapp")); + Files.createDirectories( + Paths.get(folder.getAbsolutePath(), "bar", "src", "main", + "java")); + Files.createDirectories(Paths.get(folder.getAbsolutePath(), "foobar")); + return folder; + } +} diff --git a/flow-migration/src/test/java/com/vaadin/flow/migration/MigrationToolTest.java b/flow-migration/src/test/java/com/vaadin/flow/migration/MigrationToolTest.java new file mode 100644 index 00000000000..a2c27141dcd --- /dev/null +++ b/flow-migration/src/test/java/com/vaadin/flow/migration/MigrationToolTest.java @@ -0,0 +1,428 @@ +/* + * Copyright 2000-2018 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.migration; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; + +import org.apache.commons.cli.ParseException; +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; + +import com.vaadin.flow.server.frontend.scanner.ClassFinder; + +public class MigrationToolTest { + + @Rule + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public ExpectedException exception = ExpectedException.none(); + + private static class TestMigrationTool extends MigrationTool { + + private MigrationConfiguration conf; + + @Override + protected void doMigration(MigrationConfiguration configuration) { + conf = configuration; + } + } + + private TestMigrationTool tool = new TestMigrationTool(); + + @Test + public void passRequiredArguments_configurationIsPassed() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + tool.runMigration(new String[] { "-b", "fooBaseDir", "-src", "barSrcs", + "-c", makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + } + + @Test + public void noBaseDir_throw() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + exception.expect(CommandArgumentException.class); + exception.expectCause(Matchers.any(ParseException.class)); + tool.runMigration(new String[] { "-src", "barSrcs", "-c", + makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + } + + @Test + public void noSourceRoot_throw() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + exception.expect(CommandArgumentException.class); + exception.expectCause(Matchers.any(ParseException.class)); + tool.runMigration(new String[] { "-b", "fooBaseDir", "-c", + makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + } + + @Test + public void noClassesDir_throw() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + exception.expect(CommandArgumentException.class); + exception.expectCause(Matchers.any(ParseException.class)); + tool.runMigration(new String[] { "-b", "fooBaseDir", "-src", "barSrcs", + "-d", makeSomeFolder().toURI().toURL().toExternalForm() }); + } + + @Test + public void noDependeciesUrls_throw() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + exception.expect(CommandArgumentException.class); + exception.expectCause(Matchers.any(ParseException.class)); + tool.runMigration(new String[] { "-b", "fooBaseDir", "-src", "barSrcs", + "-c", makeSomeFolder().getPath(), }); + } + + @Test + public void passBadDependencyUrl_throw() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + exception.expect(CommandArgumentException.class); + exception.expectCause(Matchers.any(MalformedURLException.class)); + tool.runMigration(new String[] { "-b", "fooBaseDir", "-src", "barSrcs", + "-c", makeSomeFolder().getPath(), "-d", "foo" }); + } + + @Test + public void passBaseDir_baseDirIsConfigured() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + tool.runMigration(new String[] { "-b", "fooBaseDir", "-src", "barSrcs", + "-c", makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertEquals("fooBaseDir", + tool.conf.getBaseDirectory().getPath()); + + tool.conf = null; + + tool.runMigration(new String[] { "--baseDir", "barBaseDir", "-src", + "barSrcs", "-c", makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertEquals("barBaseDir", + tool.conf.getBaseDirectory().getPath()); + } + + @Test + public void passCompiledClassesDir_compiledClassesDirIsConfigured() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + File compileClasessDir = makeSomeFolder(); + tool.runMigration(new String[] { "-b", "fooBaseDir", "-src", "barSrcs", + "-c", compileClasessDir.getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertEquals(compileClasessDir, + tool.conf.getCompiledClassDirectory()); + + tool.conf = null; + + compileClasessDir = makeSomeFolder(); + + tool.runMigration(new String[] { "-b", "fooBaseDir", "-src", "barSrcs", + "--classesDir", compileClasessDir.getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertEquals(compileClasessDir, + tool.conf.getCompiledClassDirectory()); + } + + @Test + public void passIgnoreModulizerError_theValueIsConfigured() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + tool.runMigration(new String[] { "-stopOnError", "-b", "fooBaseDir", + "-src", "barSrcs", "-c", makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertFalse(tool.conf.isIgnoreModulizerErrors()); + + tool.conf = null; + + tool.runMigration(new String[] { "-b", "fooBaseDir", "-src", "barSrcs", + "-c", makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertTrue(tool.conf.isIgnoreModulizerErrors()); + + tool.conf = null; + + tool.runMigration(new String[] { "-se", "-b", "fooBaseDir", "-src", + "barSrcs", "-c", makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertFalse(tool.conf.isIgnoreModulizerErrors()); + } + + @Test + public void passKeepOriginal_theValueIsConfigured() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + tool.runMigration(new String[] { "-keepOriginal", "-b", "fooBaseDir", + "-src", "barSrcs", "-c", makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertTrue(tool.conf.isKeepOriginalFiles()); + + tool.conf = null; + + tool.runMigration(new String[] { "-b", "fooBaseDir", "-src", "barSrcs", + "-c", makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertFalse(tool.conf.isKeepOriginalFiles()); + + tool.conf = null; + + tool.runMigration(new String[] { "-ko", "-b", "fooBaseDir", "-src", + "barSrcs", "-c", makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertTrue(tool.conf.isKeepOriginalFiles()); + } + + @Test + public void passResourcesDirs_resourcesDirsAreConfigured() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + tool.runMigration( + new String[] { "-res", "fooBarRes", "-b", "fooBaseDir", "-src", + "barSrcs", "-c", makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertEquals(1, tool.conf.getResourceDirectories().length); + Assert.assertEquals("fooBarRes", + tool.conf.getResourceDirectories()[0].getPath()); + + tool.conf = null; + + tool.runMigration(new String[] { "--resourcesDirs", "barFooRes", "-res", + "baz", "-b", "fooBaseDir", "-src", "barSrcs", "-c", + makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertEquals(2, tool.conf.getResourceDirectories().length); + Assert.assertEquals("barFooRes", + tool.conf.getResourceDirectories()[0].getPath()); + Assert.assertEquals("baz", + tool.conf.getResourceDirectories()[1].getPath()); + } + + @Test + public void dontPassResourcesDir_resourcesDirIsNotConfigured_noException() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + tool.runMigration(new String[] { "-b", "fooBaseDir", "-src", "barSrcs", + "-c", makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertNull(tool.conf.getResourceDirectories()); + } + + @Test + public void passMigrationDir_migrationDirIsConfigured() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + tool.runMigration(new String[] { "-md", "migrationFoo", "-b", + "fooBaseDir", "-src", "barSrcs", "-c", + makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertEquals("migrationFoo", + tool.conf.getTempMigrationFolder().getPath()); + + tool.conf = null; + + tool.runMigration(new String[] { "--migrationDir", "fooMigration", "-b", + "fooBaseDir", "-src", "barSrcs", "-c", + makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertEquals("fooMigration", + tool.conf.getTempMigrationFolder().getPath()); + + } + + @Test + public void dontPassMigrationDir_MigrationDirIsNotConfigured_noException() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + tool.runMigration(new String[] { "-b", "fooBaseDir", "-src", "barSrcs", + "-c", makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertNull(tool.conf.getTempMigrationFolder()); + } + + @Test + public void passTargetDir_migrationTargetIsConfigured() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + tool.runMigration(new String[] { "-t", "targetFoo", "-b", "fooBaseDir", + "-src", "barSrcs", "-c", makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertEquals("targetFoo", + tool.conf.getTargetDirectory().getPath()); + + tool.conf = null; + + tool.runMigration(new String[] { "--targetDir", "fooTarget", "-b", + "fooBaseDir", "-src", "barSrcs", "-c", + makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertEquals("fooTarget", + tool.conf.getTargetDirectory().getPath()); + + } + + @Test + public void dontPassTargetnDir_MigrationDirIsNotConfigured_noException() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + tool.runMigration(new String[] { "-b", "fooBaseDir", "-src", "barSrcs", + "-c", makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertNull(tool.conf.getTargetDirectory()); + } + + @Test + public void passJavaSourceDirs_sourceDirsAreConfigured() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + tool.runMigration(new String[] { "-b", "fooBaseDir", "-src", "barSrcs", + "-c", makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertEquals(1, tool.conf.getJavaSourceDirectories().length); + Assert.assertEquals("barSrcs", + tool.conf.getJavaSourceDirectories()[0].getPath()); + + tool.conf = null; + + tool.runMigration(new String[] { "--sourceDirs", "fooSrc", "-b", + "fooBaseDir", "-src", "barSrcs", "-c", + makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertEquals(2, tool.conf.getJavaSourceDirectories().length); + Assert.assertEquals("fooSrc", + tool.conf.getJavaSourceDirectories()[0].getPath()); + Assert.assertEquals("barSrcs", + tool.conf.getJavaSourceDirectories()[1].getPath()); + } + + @Test + public void passDpeUrls_classFinderIsConfigured() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException, + URISyntaxException { + File depDir = makeSomeFolder(); + File file = new File(depDir, "foo"); + file.createNewFile(); + + tool.runMigration(new String[] { "-b", "fooBaseDir", "-src", "barSrcs", + "-c", makeSomeFolder().getPath(), "-d", + depDir.toURI().toURL().toExternalForm() }); + + ClassFinder classFinder = tool.conf.getClassFinder(); + Assert.assertNotNull(classFinder); + + Assert.assertEquals(file, + new File(classFinder.getResource("foo").toURI())); + + tool.conf = null; + + tool.runMigration(new String[] { "-b", "fooBaseDir", "-src", "barSrcs", + "-c", makeSomeFolder().getPath(), "-depUrls", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertNotNull(tool.conf.getClassFinder()); + + } + + @Test + public void passAnnotationRewriteStrategy_strategyIsConfigured() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + tool.runMigration(new String[] { "-ars", "SKIP", "-t", "targetFoo", + "-b", "fooBaseDir", "-src", "barSrcs", "-c", + makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertEquals(AnnotationsRewriteStrategy.SKIP, + tool.conf.getAnnotationRewriteStrategy()); + + tool.conf = null; + + tool.runMigration(new String[] { "--annRewrite", "SKIP_ON_ERROR", "-t", + "targetFoo", "-b", "fooBaseDir", "-src", "barSrcs", "-c", + makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertEquals(AnnotationsRewriteStrategy.SKIP_ON_ERROR, + tool.conf.getAnnotationRewriteStrategy()); + + } + + @Test + public void passBadAnnotationRewriteStrategy_throw() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + exception.expect(CommandArgumentException.class); + exception.expectCause(Matchers.any(IllegalArgumentException.class)); + tool.runMigration(new String[] { "-ars", "bar", "-t", "targetFoo", "-b", + "fooBaseDir", "-src", "barSrcs", "-c", + makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + } + + @Test + public void dontPassAnnotationRewriteStrategy_defaultStrategyIsInConfiguration() + throws CommandArgumentException, MigrationToolsException, + MigrationFailureException, IOException { + tool.runMigration(new String[] { "-t", "targetFoo", "-b", "fooBaseDir", + "-src", "barSrcs", "-c", makeSomeFolder().getPath(), "-d", + makeSomeFolder().toURI().toURL().toExternalForm() }); + + Assert.assertEquals(AnnotationsRewriteStrategy.ALWAYS, + tool.conf.getAnnotationRewriteStrategy()); + } + + private File makeSomeFolder() throws IOException { + File folder = temporaryFolder.newFolder(); + folder.mkdirs(); + return folder; + } +} diff --git a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/RewriteLegacyAnnotationsStepTest.java b/flow-migration/src/test/java/com/vaadin/flow/migration/RewriteLegacyAnnotationsStepTest.java similarity index 94% rename from flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/RewriteLegacyAnnotationsStepTest.java rename to flow-migration/src/test/java/com/vaadin/flow/migration/RewriteLegacyAnnotationsStepTest.java index 1528bc050ef..24d47828cfe 100644 --- a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/RewriteLegacyAnnotationsStepTest.java +++ b/flow-migration/src/test/java/com/vaadin/flow/migration/RewriteLegacyAnnotationsStepTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration; +package com.vaadin.flow.migration; import java.io.File; import java.io.IOException; @@ -37,14 +37,14 @@ import com.vaadin.flow.component.dependency.HtmlImport; import com.vaadin.flow.component.dependency.StyleSheet; -import com.vaadin.flow.plugin.migration.samplecode.ClassUnitWithNonPublicClass; -import com.vaadin.flow.plugin.migration.samplecode.Component1; -import com.vaadin.flow.plugin.migration.samplecode.Component2; -import com.vaadin.flow.plugin.migration.samplecode.Component3; -import com.vaadin.flow.plugin.migration.samplecode.EnclosingClassWithNestedClass; -import com.vaadin.flow.plugin.migration.samplecode.EnclosingClassWithNestedClass.NestedComponent; -import com.vaadin.flow.plugin.migration.samplecode.ShouldNotBeRewritten; -import com.vaadin.flow.plugin.migration.samplecode.StyledComponent; +import com.vaadin.flow.migration.samplecode.ClassUnitWithNonPublicClass; +import com.vaadin.flow.migration.samplecode.Component1; +import com.vaadin.flow.migration.samplecode.Component2; +import com.vaadin.flow.migration.samplecode.Component3; +import com.vaadin.flow.migration.samplecode.EnclosingClassWithNestedClass; +import com.vaadin.flow.migration.samplecode.EnclosingClassWithNestedClass.NestedComponent; +import com.vaadin.flow.migration.samplecode.ShouldNotBeRewritten; +import com.vaadin.flow.migration.samplecode.StyledComponent; import com.vaadin.flow.server.frontend.scanner.ClassFinder; public class RewriteLegacyAnnotationsStepTest { diff --git a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/ClassUnitWithNonPublicClass.java b/flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/ClassUnitWithNonPublicClass.java similarity index 89% rename from flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/ClassUnitWithNonPublicClass.java rename to flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/ClassUnitWithNonPublicClass.java index ec09154d6d3..f96b64012f1 100644 --- a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/ClassUnitWithNonPublicClass.java +++ b/flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/ClassUnitWithNonPublicClass.java @@ -13,14 +13,14 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration.samplecode; +package com.vaadin.flow.migration.samplecode; import java.io.Serializable; import java.util.List; import com.vaadin.flow.component.Component; import com.vaadin.flow.component.dependency.HtmlImport; -import com.vaadin.flow.plugin.migration.samplecode.NonPublicClassWithNestedClass.NestedClassInsideNonPublicClass; +import com.vaadin.flow.migration.samplecode.NonPublicClassWithNestedClass.NestedClassInsideNonPublicClass; public class ClassUnitWithNonPublicClass { diff --git a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/Component1.java b/flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/Component1.java similarity index 95% rename from flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/Component1.java rename to flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/Component1.java index 7b3329e9cb0..dcb322f4ece 100644 --- a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/Component1.java +++ b/flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/Component1.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration.samplecode; +package com.vaadin.flow.migration.samplecode; import java.io.Serializable; import java.util.List; diff --git a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/Component2.java b/flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/Component2.java similarity index 93% rename from flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/Component2.java rename to flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/Component2.java index 4b40df69eeb..4740781aea7 100644 --- a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/Component2.java +++ b/flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/Component2.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration.samplecode; +package com.vaadin.flow.migration.samplecode; import com.vaadin.flow.component.Component; import com.vaadin.flow.component.dependency.HtmlImport; diff --git a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/Component3.java b/flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/Component3.java similarity index 93% rename from flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/Component3.java rename to flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/Component3.java index cf0ab628fab..7eac3807547 100644 --- a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/Component3.java +++ b/flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/Component3.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration.samplecode; +package com.vaadin.flow.migration.samplecode; import com.vaadin.flow.component.Component; import com.vaadin.flow.component.dependency.HtmlImport; diff --git a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/EnclosingClassWithNestedClass.java b/flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/EnclosingClassWithNestedClass.java similarity index 94% rename from flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/EnclosingClassWithNestedClass.java rename to flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/EnclosingClassWithNestedClass.java index f1e8627a64c..7e2f60f2e42 100644 --- a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/EnclosingClassWithNestedClass.java +++ b/flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/EnclosingClassWithNestedClass.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration.samplecode; +package com.vaadin.flow.migration.samplecode; import java.io.Serializable; import java.util.List; diff --git a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/GenericComponent.java b/flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/GenericComponent.java similarity index 92% rename from flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/GenericComponent.java rename to flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/GenericComponent.java index bdf884a04ff..f71d8ea3c95 100644 --- a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/GenericComponent.java +++ b/flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/GenericComponent.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration.samplecode; +package com.vaadin.flow.migration.samplecode; import com.vaadin.flow.component.Component; diff --git a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/ShouldNotBeRewritten.java b/flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/ShouldNotBeRewritten.java similarity index 86% rename from flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/ShouldNotBeRewritten.java rename to flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/ShouldNotBeRewritten.java index b0a41fc28f3..278e5fe786b 100644 --- a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/ShouldNotBeRewritten.java +++ b/flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/ShouldNotBeRewritten.java @@ -13,10 +13,10 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration.samplecode; +package com.vaadin.flow.migration.samplecode; import com.vaadin.flow.component.Component; -import com.vaadin.flow.plugin.migration.samplecode.ShouldNotBeRewritten.MyStyleSheet; +import com.vaadin.flow.migration.samplecode.ShouldNotBeRewritten.MyStyleSheet; @MyStyleSheet public class ShouldNotBeRewritten extends Component { diff --git a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/StyledComponent.java b/flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/StyledComponent.java similarity index 95% rename from flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/StyledComponent.java rename to flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/StyledComponent.java index a8f785c6254..16dc6fe6237 100644 --- a/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/migration/samplecode/StyledComponent.java +++ b/flow-migration/src/test/java/com/vaadin/flow/migration/samplecode/StyledComponent.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.plugin.migration.samplecode; +package com.vaadin.flow.migration.samplecode; import java.io.Serializable; import java.util.List; diff --git a/pom.xml b/pom.xml index e050e1bc852..b3abec0b932 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,7 @@ flow-server-production-mode flow-server-compatibility-mode flow-components-parent + flow-migration flow-maven-plugin flow-test-generic flow-bom