+ private Set<SourceSpecificContext> getRequiredSourcesFromLib() {
+ Preconditions.checkState(currentPhase == ModelProcessingPhase.SOURCE_PRE_LINKAGE,
+ "Required library sources can be collected only in ModelProcessingPhase.SOURCE_PRE_LINKAGE phase,"
+ + " but current phase was %s", currentPhase);
+ final TreeBasedTable<String, Optional<Revision>, SourceSpecificContext> libSourcesTable = TreeBasedTable.create(
+ String::compareTo, Revision::compare);
+ for (final SourceSpecificContext libSource : libSources) {
+ final ModuleIdentifier libSourceIdentifier = Preconditions.checkNotNull(libSource.getRootIdentifier());
+ libSourcesTable.put(libSourceIdentifier.getName(), libSourceIdentifier.getRevision(), libSource);
+ }
+
+ final Set<SourceSpecificContext> requiredLibs = new HashSet<>();
+ for (final SourceSpecificContext source : sources) {
+ collectRequiredSourcesFromLib(libSourcesTable, requiredLibs, source);
+ removeConflictingLibSources(source, requiredLibs);
+ }
+ return requiredLibs;
+ }
+
+ private void collectRequiredSourcesFromLib(
+ final TreeBasedTable<String, Optional<Revision>, SourceSpecificContext> libSourcesTable,
+ final Set<SourceSpecificContext> requiredLibs, final SourceSpecificContext source) {
+ for (final SourceIdentifier requiredSource : source.getRequiredSources()) {
+ final SourceSpecificContext libSource = getRequiredLibSource(requiredSource, libSourcesTable);
+ if (libSource != null && requiredLibs.add(libSource)) {
+ collectRequiredSourcesFromLib(libSourcesTable, requiredLibs, libSource);
+ }
+ }
+ }
+
+ private static SourceSpecificContext getRequiredLibSource(final SourceIdentifier requiredSource,
+ final TreeBasedTable<String, Optional<Revision>, SourceSpecificContext> libSourcesTable) {
+ return requiredSource.getRevision().isPresent()
+ ? libSourcesTable.get(requiredSource.getName(), requiredSource.getRevision())
+ : getLatestRevision(libSourcesTable.row(requiredSource.getName()));
+ }
+
+ private static SourceSpecificContext getLatestRevision(final SortedMap<Optional<Revision>,
+ SourceSpecificContext> sourceMap) {
+ return sourceMap != null && !sourceMap.isEmpty() ? sourceMap.get(sourceMap.lastKey()) : null;
+ }
+
+ // removes required library sources which would cause namespace/name conflict with one of the main sources
+ // later in the parsing process. this can happen if we add a parent module or a submodule as a main source
+ // and the same parent module or submodule is added as one of the library sources.
+ // such situation may occur when using the yang-system-test artifact - if a parent module/submodule is specified
+ // as its argument and the same dir is specified as one of the library dirs through -p option).
+ private static void removeConflictingLibSources(final SourceSpecificContext source,
+ final Set<SourceSpecificContext> requiredLibs) {
+ final Iterator<SourceSpecificContext> requiredLibsIter = requiredLibs.iterator();
+ while (requiredLibsIter.hasNext()) {
+ final SourceSpecificContext currentReqSource = requiredLibsIter.next();
+ if (source.getRootIdentifier().equals(currentReqSource.getRootIdentifier())) {
+ requiredLibsIter.remove();
+ }
+ }
+ }
+