import static java.util.Objects.requireNonNull;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
import java.nio.file.attribute.BasicFileAttributes;
import org.eclipse.jdt.annotation.NonNull;
* Hash of a single file state. {@link #size()} corresponds to {@link BasicFileAttributes#size()}.
*/
record FileState(@NonNull String path, long size, int crc32) {
+ /**
+ * A simple interface describing the intended content of a file.
+ */
+ @FunctionalInterface
+ interface FileContent {
+ /**
+ * Write the content of this file to specified {@link OutputStream}.
+ *
+ * @param out OutputStream to write to, guaranteed to be non-null
+ * @throws IOException if any error occurs
+ */
+ void writeTo(@NonNull OutputStream out) throws IOException;
+ }
+
FileState {
requireNonNull(path);
}
+
+ static @NonNull FileState ofWrittenFile(final File file, final FileContent content) throws IOException {
+ try (var out = new CapturingOutputStream(Files.newOutputStream(file.toPath()))) {
+ content.writeTo(out);
+ return new FileState(file.getPath(), out.size(), out.crc32c());
+ }
+ }
}
}
FileState generateFile() {
- try (var out = new CapturingOutputStream(buildContext.newFileOutputStream(target))) {
- file.writeBody(out);
- return new FileState(target.getPath(), out.size(), out.crc32c());
+ final FileState ret;
+ try {
+ ret = FileState.ofWrittenFile(target, file::writeBody);
} catch (IOException e) {
throw new IllegalStateException("Failed to generate file " + target, e);
}
+ buildContext.refresh(target);
+ return ret;
}
}
}
*/
package org.opendaylight.yangtools.yang2sources.plugin;
+import com.google.common.collect.ImmutableList;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
private static final Logger LOG = LoggerFactory.getLogger(Default.class);
@Override
- void addYangsToMetaInf(final MavenProject project, final Collection<YangTextSchemaSource> modelsInProject)
- throws IOException {
+ Collection<FileState> addYangsToMetaInf(final MavenProject project,
+ final Collection<YangTextSchemaSource> modelsInProject) throws IOException {
final File generatedYangDir = new GeneratedDirectories(project).getYangDir();
LOG.debug("Generated dir {}", generatedYangDir);
// copy project's src/main/yang/*.yang to ${project.builddir}/generated-sources/yang/META-INF/yang/
// This honors setups like a Eclipse-profile derived one
final File withMetaInf = new File(generatedYangDir, YangToSourcesProcessor.META_INF_YANG_STRING);
+ final var stateListBuilder = ImmutableList.<FileState>builder();
for (YangTextSchemaSource source : modelsInProject) {
final String fileName = source.getIdentifier().toYangFilename();
final File file = new File(withMetaInf, fileName);
Files.createParentDirs(file);
- source.copyTo(Files.asByteSink(file));
+ stateListBuilder.add(FileState.ofWrittenFile(file, source::copyTo));
LOG.debug("Created file {} for {}", file, source.getIdentifier());
}
setResource(generatedYangDir, project);
LOG.debug("{} YANG files marked as resources: {}", YangToSourcesProcessor.LOG_PREFIX, generatedYangDir);
+
+ return stateListBuilder.build();
}
}
return DEFAULT;
}
- abstract void addYangsToMetaInf(MavenProject project, Collection<YangTextSchemaSource> modelsInProject)
- throws IOException;
+ abstract Collection<FileState> addYangsToMetaInf(MavenProject project,
+ Collection<YangTextSchemaSource> modelsInProject) throws IOException;
static void setResource(final File targetYangDir, final MavenProject project) {
Resource res = new Resource();
LOG.info("{} Project model files found: {} in {}", LOG_PREFIX, yangFilesInProject.size(), watch);
final var outputFiles = ImmutableList.<FileState>builder();
+ boolean sourcesPersisted = false;
for (YangParserConfiguration parserConfig : parserConfigs) {
final Optional<ProcessorModuleReactor> optReactor = createReactor(yangFilesInProject,
LOG.info("{} {} YANG models processed in {}", LOG_PREFIX, holder.getContext().getModules().size(),
sw);
outputFiles.addAll(generateSources(holder, codeGenerators, parserConfig));
+
+ if (!sourcesPersisted) {
+ // add META_INF/yang once
+ final var models = reactor.getModelsInProject();
+ final Collection<FileState> sourceFileStates;
+ try {
+ sourceFileStates = yangProvider.addYangsToMetaInf(project, models);
+ } catch (IOException e) {
+ throw new MojoExecutionException("Failed write model files for " + models, e);
+ }
+
+ sourcesPersisted = true;
+ outputFiles.addAll(sourceFileStates);
+ }
} else {
LOG.info("{} Skipping YANG code generation because property yang.skip is true", LOG_PREFIX);
}
-
- // FIXME: this is not right: we should be generating the models exactly once!
- // add META_INF/yang
- final Collection<YangTextSchemaSource> models = reactor.getModelsInProject();
- try {
- yangProvider.addYangsToMetaInf(project, models);
- } catch (IOException e) {
- throw new MojoExecutionException("Failed write model files for " + models, e);
- }
}
}
doReturn(plugin).when(project).getPlugin(YangToSourcesMojo.PLUGIN_NAME);
try {
- lenient().doNothing().when(yangProvider).addYangsToMetaInf(any(MavenProject.class), anyCollection());
+ lenient().when(yangProvider.addYangsToMetaInf(any(MavenProject.class), anyCollection()))
+ .thenReturn(List.of());
} catch (IOException e) {
throw new AssertionError(e);
}