--- /dev/null
+/*
+ * Copyright (c) 2023 PANTHEON.tech, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang2sources.plugin;
+
+import com.google.common.hash.Hashing;
+import com.google.common.hash.HashingInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An {@link InputStream} which captures the sum of its contents.
+ */
+final class CapturingInputStream extends FilterInputStream {
+ private long size;
+
+ CapturingInputStream(final InputStream in) {
+ super(new HashingInputStream(Hashing.crc32c(), in));
+ }
+
+ @Override
+ public int read() throws IOException {
+ final int ret = super.read();
+ if (ret != -1) {
+ size++;
+ }
+ return ret;
+ }
+
+ @Override
+ @SuppressWarnings("checkstyle:parameterName")
+ public int read(final byte[] b, final int off, final int len) throws IOException {
+ final int ret = super.read(b, off, len);
+ if (ret != -1) {
+ size += ret;
+ }
+ return ret;
+ }
+
+ long size() {
+ return size;
+ }
+
+ int crc32c() {
+ return ((HashingInputStream) in).hash().asInt();
+ }
+}
\ No newline at end of file
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.Set;
+import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.maven.plugin.MojoExecutionException;
}
void execute() throws MojoExecutionException, MojoFailureException {
- YangToSourcesState prevState;
+ final YangToSourcesState prevState;
try {
prevState = stateStorage.loadState();
} catch (IOException e) {
* Check if any of the listed files changed. If no changes occurred, simply return empty, which indicates
* end of execution.
*/
+ // FIXME: YANGTOOLS-745: remove this check FileStates instead
if (!Stream.concat(yangFilesInProject.stream(), dependencies.stream().map(ScannedDependency::file))
.anyMatch(buildContext::hasDelta)) {
LOG.info("{} None of {} input files changed", LOG_PREFIX, yangFilesInProject.size() + dependencies.size());
}
final Stopwatch watch = Stopwatch.createStarted();
+ // Determine hash/size of YANG input files in parallel
+ final var projectYangs = new FileStateSet(yangFilesInProject.parallelStream()
+ .map(file -> {
+ try {
+ return FileState.ofFile(file);
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to read " + file, e);
+ }
+ })
+ .collect(ImmutableMap.toImmutableMap(FileState::path, Function.identity())));
+
final List<Entry<YangTextSchemaSource, YangIRSchemaSource>> parsed = yangFilesInProject.parallelStream()
.map(file -> {
final YangTextSchemaSource textSource = YangTextSchemaSource.forPath(file.toPath());
LOG.debug("Found project files: {}", yangFilesInProject);
LOG.info("{} Project model files found: {} in {}", LOG_PREFIX, yangFilesInProject.size(), watch);
+ // Determine hash/size of dependency files
+ // TODO: this produces false positives for Jar files -- there we want to capture the contents of the YANG files,
+ // not the entire file
+ final var dependencyYangs = new FileStateSet(dependencies.parallelStream()
+ .map(ScannedDependency::file)
+ .map(file -> {
+ try {
+ return FileState.ofFile(file);
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to read " + file, e);
+ }
+ })
+ .collect(ImmutableMap.toImmutableMap(FileState::path, Function.identity())));
+
final var outputFiles = ImmutableList.<FileState>builder();
boolean sourcesPersisted = false;
}
}
- // FIXME: store these files into state, so that we can verify/clean up
final var outputState = new YangToSourcesState(
codeGenerators.stream()
.collect(ImmutableMap.toImmutableMap(GeneratorTaskFactory::getIdentifier, GeneratorTaskFactory::arg)),
- new FileStateSet(ImmutableMap.copyOf(uniqueOutputFiles)));
+ projectYangs, dependencyYangs, new FileStateSet(ImmutableMap.copyOf(uniqueOutputFiles)));
try {
stateStorage.storeState(outputState);
/**
* State of the result of a {@link YangToSourcesMojo} execution run.
*/
-// FIXME: expand to capture:
-// - input YANG files
record YangToSourcesState(
@NonNull ImmutableMap<String, FileGeneratorArg> fileGeneratorArgs,
+ @NonNull FileStateSet projectYangs,
+ @NonNull FileStateSet dependencyYangs,
@NonNull FileStateSet outputFiles) implements WritableObject {
// 'ymp' followed by a byte value '1'
private static final int MAGIC = 0x796D7001;
YangToSourcesState {
requireNonNull(fileGeneratorArgs);
+ requireNonNull(projectYangs);
+ requireNonNull(dependencyYangs);
requireNonNull(outputFiles);
}
if (magic != MAGIC) {
throw new IOException("Unrecognized magic " + Integer.toHexString(magic));
}
- return new YangToSourcesState(readConfigurations(in), FileStateSet.readFrom(in));
+ return new YangToSourcesState(readConfigurations(in),
+ FileStateSet.readFrom(in), FileStateSet.readFrom(in), FileStateSet.readFrom(in));
}
@Override
public void writeTo(final DataOutput out) throws IOException {
out.writeInt(MAGIC);
writeConfigurations(out, fileGeneratorArgs.values());
+ projectYangs.writeTo(out);
+ dependencyYangs.writeTo(out);
outputFiles.writeTo(out);
}