Bug 7182 related: yang-maven-plugin no hard-coded target/ (target-ide/)
[yangtools.git] / yang / yang-maven-plugin / src / main / java / org / opendaylight / yangtools / yang2sources / plugin / YangToSourcesProcessor.java
index 9d8c0095f881eaf9ea54763241cb798751ba5133..3389404a8071de1c4dccf474849f056e21d2c4c2 100644 (file)
@@ -10,23 +10,26 @@ package org.opendaylight.yangtools.yang2sources.plugin;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.io.CharStreams;
 import java.io.Closeable;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import org.apache.commons.io.IOUtils;
-import org.apache.maven.model.Resource;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.FileUtils;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaContextResolver;
@@ -52,7 +55,7 @@ class YangToSourcesProcessor {
     static final String META_INF_YANG_SERVICES_STRING_JAR = "META-INF" + "/" + "services";
 
     private final File yangFilesRootDir;
-    private final File[] excludedFiles;
+    private final Set<File> excludedFiles;
     private final List<CodeGeneratorArg> codeGenerators;
     private final MavenProject project;
     private final boolean inspectDependencies;
@@ -61,31 +64,29 @@ class YangToSourcesProcessor {
     private final YangTextSchemaContextResolver resolver;
 
     @VisibleForTesting
-    YangToSourcesProcessor(final File yangFilesRootDir, final File[] excludedFiles, final List<CodeGeneratorArg> codeGenerators,
-            final MavenProject project, final boolean inspectDependencies, final YangProvider yangProvider) {
+    YangToSourcesProcessor(final File yangFilesRootDir, final Collection<File> excludedFiles,
+            final List<CodeGeneratorArg> codeGenerators, final MavenProject project, final boolean inspectDependencies,
+            final YangProvider yangProvider) {
         this(new DefaultBuildContext(), yangFilesRootDir, excludedFiles, codeGenerators, project,
                 inspectDependencies, yangProvider);
     }
 
-    private YangToSourcesProcessor(final BuildContext buildContext, final File yangFilesRootDir, final File[] excludedFiles,
-            final List<CodeGeneratorArg> codeGenerators, final MavenProject project, final boolean inspectDependencies, final YangProvider
-                                           yangProvider) {
-        this.buildContext = Util.checkNotNull(buildContext, "buildContext");
-        this.yangFilesRootDir = Util.checkNotNull(yangFilesRootDir, "yangFilesRootDir");
-        this.excludedFiles = new File[excludedFiles.length];
-        int i = 0;
-        for (File file : excludedFiles) {
-            this.excludedFiles[i++] = new File(file.getPath());
-        }
-        this.codeGenerators = Collections.unmodifiableList(Util.checkNotNull(codeGenerators, "codeGenerators"));
-        this.project = Util.checkNotNull(project, "project");
+    private YangToSourcesProcessor(final BuildContext buildContext, final File yangFilesRootDir,
+            final Collection<File> excludedFiles, final List<CodeGeneratorArg> codeGenerators,
+            final MavenProject project, final boolean inspectDependencies, final YangProvider yangProvider) {
+        this.buildContext = Preconditions.checkNotNull(buildContext, "buildContext");
+        this.yangFilesRootDir = Preconditions.checkNotNull(yangFilesRootDir, "yangFilesRootDir");
+        this.excludedFiles = ImmutableSet.copyOf(excludedFiles);
+        this.codeGenerators = ImmutableList.copyOf(codeGenerators);
+        this.project = Preconditions.checkNotNull(project);
         this.inspectDependencies = inspectDependencies;
         this.yangProvider = yangProvider;
         this.resolver = YangTextSchemaContextResolver.create("maven-plugin");
     }
 
-    YangToSourcesProcessor(final BuildContext buildContext, final File yangFilesRootDir, final File[] excludedFiles,
-                           final List<CodeGeneratorArg> codeGenerators, final MavenProject project, final boolean inspectDependencies) {
+    YangToSourcesProcessor(final BuildContext buildContext, final File yangFilesRootDir,
+                final Collection<File> excludedFiles, final List<CodeGeneratorArg> codeGenerators,
+                final MavenProject project, final boolean inspectDependencies) {
         this(yangFilesRootDir, excludedFiles, codeGenerators, project, inspectDependencies, new YangProvider());
     }
 
@@ -106,7 +107,7 @@ class YangToSourcesProcessor {
             yangProvider.addYangsToMetaInf(project, yangFilesRootDir, excludedFiles);
 
             // add META_INF/services
-            File generatedServicesDir = new File(project.getBasedir(), CodeGeneratorArg.YANG_SERVICES_GENERATED_DIR);
+            File generatedServicesDir = new GeneratedDirectories(project).getYangServicesDir();
             YangProvider.setResource(generatedServicesDir, project);
             LOG.debug("{} Yang services files from: {} marked as resources: {}", LOG_PREFIX, generatedServicesDir,
                     META_INF_YANG_SERVICES_STRING_JAR);
@@ -129,7 +130,6 @@ class YangToSourcesProcessor {
              */
             final Collection<File> yangFilesInProject = Util.listFiles(yangFilesRootDir, excludedFiles);
 
-
             final Collection<File> allFiles = new ArrayList<>(yangFilesInProject);
             if (inspectDependencies) {
                 allFiles.addAll(Util.findYangFilesInDependencies(project));
@@ -174,7 +174,8 @@ class YangToSourcesProcessor {
              * (parsed submodule's data are added to its parent module). Set
              * cannot contains null values.
              */
-            Set<Module> projectYangModules;
+            final Set<Module> projectYangModules = new HashSet<>();
+            final Set<Module> projectYangFiles = new HashSet<>();
             try {
                 if (inspectDependencies) {
                     YangsInZipsResult dependentYangResult = Util.findYangFilesInDependenciesAsStream(project);
@@ -188,17 +189,18 @@ class YangToSourcesProcessor {
                 resolveSchemaContext = YangParserTestUtils.parseYangStreams(all);
 
                 Set<Module> parsedAllYangModules = resolveSchemaContext.getModules();
-                projectYangModules = new HashSet<>();
                 for (Module module : parsedAllYangModules) {
-                    final String path = module.getModuleSourcePath();
-                    if (path != null) {
-                        LOG.debug("Looking for source {}", path);
-                        for (NamedFileInputStream is : yangsInProject) {
-                            LOG.debug("In project destination {}", is.getFileDestination());
-                            if (path.equals(is.getFileDestination())) {
-                                LOG.debug("Module {} belongs to current project", module);
-                                projectYangModules.add(module);
-                                break;
+                    if (containedInFiles(yangsInProject, module)) {
+                        LOG.debug("Module {} belongs to current project", module);
+                        projectYangModules.add(module);
+                        projectYangFiles.add(module);
+
+                        for (Module sub : module.getSubmodules()) {
+                            if (containedInFiles(yangsInProject, sub)) {
+                                LOG.debug("Submodule {} belongs to current project", sub);
+                                projectYangFiles.add(sub);
+                            } else {
+                                LOG.warn("Submodule {} not found in input files", sub);
                             }
                         }
                     }
@@ -210,7 +212,9 @@ class YangToSourcesProcessor {
             }
 
             LOG.info("{} {} files parsed from {}", LOG_PREFIX, Util.YANG_SUFFIX.toUpperCase(), yangsInProject);
-            return new ContextHolder(resolveSchemaContext, projectYangModules);
+            LOG.debug("Project YANG files: {}", projectYangFiles);
+
+            return new ContextHolder(resolveSchemaContext, projectYangModules, projectYangFiles);
 
             // MojoExecutionException is thrown since execution cannot continue
         } catch (Exception e) {
@@ -221,12 +225,28 @@ class YangToSourcesProcessor {
         }
     }
 
-    private static List<InputStream> toStreamsWithoutDuplicates(final List<YangSourceFromDependency> list) throws IOException {
+    private static boolean containedInFiles(final List<NamedFileInputStream> files, final Module module) {
+        final String path = module.getModuleSourcePath();
+        if (path != null) {
+            LOG.debug("Looking for source {}", path);
+            for (NamedFileInputStream is : files) {
+                LOG.debug("In project destination {}", is.getFileDestination());
+                if (path.equals(is.getFileDestination())) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    private static List<InputStream> toStreamsWithoutDuplicates(final List<YangSourceFromDependency> list)
+            throws IOException {
         final Map<String, YangSourceFromDependency> byContent = new HashMap<>();
 
         for (YangSourceFromDependency yangFromDependency : list) {
-            try (InputStream dataStream = yangFromDependency.openStream()) {
-                String contents = IOUtils.toString(dataStream);
+            try (Reader reader = yangFromDependency.asCharSource(StandardCharsets.UTF_8).openStream()) {
+                final String contents = CharStreams.toString(reader);
                 byContent.putIfAbsent(contents, yangFromDependency);
             } catch (IOException e) {
                 throw new IOException("Exception when reading from: " + yangFromDependency.getDescription(), e);
@@ -240,56 +260,6 @@ class YangToSourcesProcessor {
         return inputs;
     }
 
-    static class YangProvider {
-        private static final Logger LOG = LoggerFactory.getLogger(YangProvider.class);
-
-        void addYangsToMetaInf(final MavenProject project, final File yangFilesRootDir, final File[] excludedFiles)
-                throws MojoFailureException {
-
-            // copy project's src/main/yang/*.yang to target/generated-sources/yang/META-INF/yang/*.yang
-
-            File generatedYangDir = new File(project.getBasedir(), CodeGeneratorArg.YANG_GENERATED_DIR);
-            addYangsToMetaInf(project, yangFilesRootDir, excludedFiles, generatedYangDir);
-
-            // Also copy to the actual build output dir if different than "target". When running in
-            // Eclipse this can differ (eg "target-ide").
-
-            File actualGeneratedYangDir = new File(project.getBuild().getDirectory(),
-                    CodeGeneratorArg.YANG_GENERATED_DIR.replace("target" + File.separator, ""));
-            if (!actualGeneratedYangDir.equals(generatedYangDir)) {
-                addYangsToMetaInf(project, yangFilesRootDir, excludedFiles, actualGeneratedYangDir);
-            }
-        }
-
-        private static void addYangsToMetaInf(final MavenProject project, final File yangFilesRootDir,
-                final File[] excludedFiles, final File generatedYangDir) throws MojoFailureException {
-
-            File withMetaInf = new File(generatedYangDir, META_INF_YANG_STRING);
-            withMetaInf.mkdirs();
-
-            try {
-                Collection<File> files = Util.listFiles(yangFilesRootDir, excludedFiles);
-                for (File file : files) {
-                    org.apache.commons.io.FileUtils.copyFile(file, new File(withMetaInf, file.getName()));
-                }
-            } catch (IOException e) {
-                LOG.warn("Failed to generate files into root {}", yangFilesRootDir, e);
-                throw new MojoFailureException("Unable to list yang files into resource folder", e);
-            }
-
-            setResource(generatedYangDir, project);
-
-            LOG.debug("{} Yang files from: {} marked as resources: {}", LOG_PREFIX, yangFilesRootDir,
-                    META_INF_YANG_STRING_JAR);
-        }
-
-        private static void setResource(final File targetYangDir, final MavenProject project) {
-            Resource res = new Resource();
-            res.setDirectory(targetYangDir.getPath());
-            project.addResource(res);
-        }
-    }
-
     /**
      * Call generate on every generator from plugin configuration
      */
@@ -357,7 +327,11 @@ class YangToSourcesProcessor {
         LOG.debug("{} Folder: {} marked as resources for generator: {}", LOG_PREFIX, resourceBaseDir,
                 codeGeneratorCfg.getCodeGeneratorClass());
 
-        Collection<File> generated = g.generateSources(context.getContext(), outputDir, context.getYangModules());
+        FileUtils.deleteDirectory(outputDir);
+        LOG.info("{} Succesfully deleted output directory {}", LOG_PREFIX, outputDir);
+
+        Collection<File> generated = g.generateSources(context.getContext(), outputDir, context.getYangModules(),
+            context::moduleToResourcePath);
 
         LOG.info("{} Sources generated by {}: {}", LOG_PREFIX, codeGeneratorCfg.getCodeGeneratorClass(), generated);
     }