import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Sets;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.LoggerFactory;
/**
- * Inter-module dependency resolved. Given a set of schema source identifiers and their
- * corresponding dependency information, the {@link #create(Map)} method creates a
- * a view of how consistent the dependencies are. In particular, this detects whether
- * any imports are unsatisfied.
+ * Inter-module dependency resolved. Given a set of schema source identifiers and their corresponding dependency
+ * information, the {@link #create(Map)} method creates a a view of how consistent the dependencies are. In particular,
+ * this detects whether any import/include/belongs-to statements are unsatisfied.
*/
// FIXME: improve this class to track and expose how wildcard imports were resolved.
// That information will allow us to track "damage" to dependency resolution
private final ImmutableList<SourceIdentifier> unresolvedSources;
private final ImmutableMultimap<SourceIdentifier, SourceDependency> unsatisfiedImports;
- protected DependencyResolver(final Map<SourceIdentifier, SourceInfo> depInfo) {
+ DependencyResolver(final Map<SourceIdentifier, SourceInfo> depInfo) {
final var resolved = Sets.<SourceIdentifier>newHashSetWithExpectedSize(depInfo.size());
final var pending = new HashMap<>(depInfo);
+ final var submodules = new ArrayList<Submodule>();
+ // First pass: resolve 'include' and 'import' statements for each source
boolean progress;
do {
progress = false;
resolved.add(sourceId);
it.remove();
progress = true;
+
+ // Stash submodules for second pass
+ if (dep instanceof Submodule submodule) {
+ submodules.add(submodule);
+ }
}
}
} while (progress);
+ // Second pass: validate 'belongs-to' in submodules
+ for (var submodule : submodules) {
+ final var belongsTo = submodule.belongsTo();
+ if (!isKnown(resolved, belongsTo)) {
+ // belongs-to check failed, move the source back to pending
+ final var sourceId = submodule.sourceId();
+ LOG.debug("Source {} is missing belongs-to {}", sourceId, belongsTo);
+ pending.put(sourceId, submodule);
+ resolved.remove(sourceId);
+ }
+ }
+
resolvedSources = ImmutableList.copyOf(resolved);
unresolvedSources = ImmutableList.copyOf(pending.keySet());
return false;
}
}
- if (info instanceof Submodule submodule) {
- final var dep = submodule.belongsTo();
- if (!isKnown(resolved, dep)) {
- LOG.debug("Source {} is missing belongs-to {}", info.sourceId(), dep);
- return false;
- }
- }
return true;
}
"/model/baz.yang");
assertThat(resolved.resolvedSources()).containsExactlyInAnyOrder(
new SourceIdentifier("bar", "2013-07-03"),
- new SourceIdentifier("baz", "2013-02-27"));
- assertThat(resolved.unresolvedSources()).containsExactlyInAnyOrder(
+ new SourceIdentifier("baz", "2013-02-27"),
new SourceIdentifier("foo", "2013-02-27"),
new SourceIdentifier("subfoo", "2013-02-27"));
+ assertEquals(List.of(), resolved.unresolvedSources());
assertEquals(ImmutableMultimap.of(), resolved.unsatisfiedImports());
}