diff --git a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BitbakeDetectable.java b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BitbakeDetectable.java index bc21e56019..b745ae491d 100644 --- a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BitbakeDetectable.java +++ b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BitbakeDetectable.java @@ -1,6 +1,7 @@ package com.synopsys.integration.detectable.detectables.bitbake; import java.io.File; +import java.io.IOException; import com.synopsys.integration.common.util.finder.FileFinder; import com.synopsys.integration.detectable.Detectable; @@ -9,6 +10,7 @@ import com.synopsys.integration.detectable.detectable.Requirements; import com.synopsys.integration.detectable.detectable.annotation.DetectableInfo; import com.synopsys.integration.detectable.detectable.exception.DetectableException; +import com.synopsys.integration.detectable.detectable.executable.ExecutableFailedException; import com.synopsys.integration.detectable.detectable.executable.resolver.BashResolver; import com.synopsys.integration.detectable.detectable.explanation.PropertyProvided; import com.synopsys.integration.detectable.detectable.result.DetectableResult; @@ -56,7 +58,7 @@ public DetectableResult extractable() throws DetectableException { } @Override - public Extraction extract(ExtractionEnvironment extractionEnvironment) { + public Extraction extract(ExtractionEnvironment extractionEnvironment) throws ExecutableFailedException, IOException { return bitbakeExtractor.extract( environment.getDirectory(), foundBuildEnvScript, diff --git a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BitbakeExtractor.java b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BitbakeExtractor.java index 93e2520af3..48e70c5e79 100644 --- a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BitbakeExtractor.java +++ b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BitbakeExtractor.java @@ -9,10 +9,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.Optional; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.NotImplementedException; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,7 +27,6 @@ import com.synopsys.integration.detectable.detectable.util.EnumListFilter; import com.synopsys.integration.detectable.detectables.bitbake.model.BitbakeEnvironment; import com.synopsys.integration.detectable.detectables.bitbake.model.BitbakeGraph; -import com.synopsys.integration.detectable.detectables.bitbake.model.BitbakeRecipe; import com.synopsys.integration.detectable.detectables.bitbake.parse.BitbakeEnvironmentParser; import com.synopsys.integration.detectable.detectables.bitbake.parse.BitbakeGraphTransformer; import com.synopsys.integration.detectable.detectables.bitbake.parse.BitbakeRecipesParser; @@ -42,20 +43,18 @@ public class BitbakeExtractor { private final GraphParserTransformer graphParserTransformer; private final BitbakeGraphTransformer bitbakeGraphTransformer; private final BitbakeRecipesParser bitbakeRecipesParser; - private final BitbakeRecipesToLayerMapConverter bitbakeRecipesToLayerMap; private final ToolVersionLogger toolVersionLogger; private final BuildFileFinder buildFileFinder; private final LicenseManifestParser licenseManifestParser; private final BitbakeEnvironmentParser bitbakeEnvironmentParser; public BitbakeExtractor(DetectableExecutableRunner executableRunner, GraphParserTransformer graphParserTransformer, BitbakeGraphTransformer bitbakeGraphTransformer, - BitbakeRecipesParser bitbakeRecipesParser, BitbakeRecipesToLayerMapConverter bitbakeRecipesToLayerMap, ToolVersionLogger toolVersionLogger, BuildFileFinder buildFileFinder, + BitbakeRecipesParser bitbakeRecipesParser, ToolVersionLogger toolVersionLogger, BuildFileFinder buildFileFinder, LicenseManifestParser licenseManifestParser, BitbakeEnvironmentParser bitbakeEnvironmentParser) { this.executableRunner = executableRunner; this.graphParserTransformer = graphParserTransformer; this.bitbakeGraphTransformer = bitbakeGraphTransformer; this.bitbakeRecipesParser = bitbakeRecipesParser; - this.bitbakeRecipesToLayerMap = bitbakeRecipesToLayerMap; this.toolVersionLogger = toolVersionLogger; this.buildFileFinder = buildFileFinder; this.licenseManifestParser = licenseManifestParser; @@ -71,36 +70,22 @@ public Extraction extract( Integer searchDepth, EnumListFilter dependencyTypeFilter, ExecutableTarget bash - ) { + ) throws ExecutableFailedException, IOException { List codeLocations = new ArrayList<>(); - BitbakeSession bitbakeSession = new BitbakeSession(executableRunner, bitbakeRecipesParser, sourceDirectory, buildEnvScript, sourceArguments, bash, toolVersionLogger, buildFileFinder, bitbakeEnvironmentParser); bitbakeSession.logBitbakeVersion(); File buildDir = bitbakeSession.determineBuildDir(); BitbakeEnvironment bitbakeEnvironment = bitbakeSession.executeBitbakeForEnvironment(); - for (String packageName : packageNames) { - Map imageRecipes = null; + ShowRecipesResults showRecipesResults = bitbakeSession.executeBitbakeForRecipeLayerCatalog(); + for (String targetImage : packageNames) { try { - if (dependencyTypeFilter.shouldExclude(BitbakeDependencyType.BUILD)) { - imageRecipes = readImageRecipes(buildDir, packageName, bitbakeEnvironment, followSymLinks, searchDepth); - } - BitbakeGraph bitbakeGraph = generateBitbakeGraph(bitbakeSession, buildDir, packageName, followSymLinks, searchDepth); - List bitbakeRecipes = bitbakeSession.executeBitbakeForRecipeLayerCatalog(); - Map recipeNameToLayersMap = bitbakeRecipesToLayerMap.convert(bitbakeRecipes); - - DependencyGraph dependencyGraph = bitbakeGraphTransformer.transform(bitbakeGraph, recipeNameToLayersMap, imageRecipes); - CodeLocation codeLocation = new CodeLocation(dependencyGraph); - - codeLocations.add(codeLocation); - + codeLocations.add(generateCodeLocationForTargetImage(followSymLinks, searchDepth, dependencyTypeFilter, bitbakeSession, buildDir, bitbakeEnvironment, showRecipesResults, targetImage)); } catch (IOException | IntegrationException | NotImplementedException | ExecutableFailedException e) { - logger.error(String.format("Failed to extract a Code Location while running Bitbake against package '%s': %s", packageName, e.getMessage())); + logger.error(String.format("Failed to extract a Code Location while running Bitbake against package '%s': %s", targetImage, e.getMessage())); logger.debug(e.getMessage(), e); } } - Extraction extraction; - if (codeLocations.isEmpty()) { extraction = new Extraction.Builder() .failure("No Code Locations were generated during extraction") @@ -111,10 +96,21 @@ public Extraction extract( .success(codeLocations) .build(); } - return extraction; } + @NotNull + private CodeLocation generateCodeLocationForTargetImage(final boolean followSymLinks, final Integer searchDepth, final EnumListFilter dependencyTypeFilter, final BitbakeSession bitbakeSession, final File buildDir, + final BitbakeEnvironment bitbakeEnvironment, final ShowRecipesResults showRecipesResults, final String packageName) throws IntegrationException, IOException, ExecutableFailedException { + Map imageRecipes = null; + if (dependencyTypeFilter.shouldExclude(BitbakeDependencyType.BUILD)) { + imageRecipes = readImageRecipes(buildDir, packageName, bitbakeEnvironment, followSymLinks, searchDepth); + } + BitbakeGraph bitbakeGraph = generateBitbakeGraph(bitbakeSession, buildDir, packageName, showRecipesResults.getLayerNames(), followSymLinks, searchDepth); + DependencyGraph dependencyGraph = bitbakeGraphTransformer.transform(bitbakeGraph, showRecipesResults.getRecipesWithLayers(), imageRecipes); + return new CodeLocation(dependencyGraph); + } + private Map readImageRecipes(File buildDir, String targetImageName, BitbakeEnvironment bitbakeEnvironment, boolean followSymLinks, int searchDepth) throws IntegrationException, IOException { Optional licenseManifestFile = buildFileFinder.findLicenseManifestFile(buildDir, targetImageName, bitbakeEnvironment, followSymLinks, searchDepth); if (licenseManifestFile.isPresent()) { @@ -127,10 +123,11 @@ private Map readImageRecipes(File buildDir, String targetImageNa } private BitbakeGraph generateBitbakeGraph(BitbakeSession bitbakeSession, - File buildDir, - String packageName, - boolean followSymLinks, - Integer searchDepth + File buildDir, + String packageName, + Set knownLayers, + boolean followSymLinks, + Integer searchDepth ) throws IOException, IntegrationException, ExecutableFailedException { File taskDependsFile = bitbakeSession.executeBitbakeForDependencies(buildDir, packageName, followSymLinks, searchDepth); if (logger.isTraceEnabled()) { @@ -138,6 +135,6 @@ private BitbakeGraph generateBitbakeGraph(BitbakeSession bitbakeSession, } InputStream dependsFileInputStream = FileUtils.openInputStream(taskDependsFile); GraphParser graphParser = new GraphParser(dependsFileInputStream); - return graphParserTransformer.transform(graphParser); + return graphParserTransformer.transform(graphParser, knownLayers); } } diff --git a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BitbakeRecipesToLayerMapConverter.java b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BitbakeRecipesToLayerMapConverter.java deleted file mode 100644 index 71d7c4860b..0000000000 --- a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BitbakeRecipesToLayerMapConverter.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.synopsys.integration.detectable.detectables.bitbake; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.synopsys.integration.detectable.detectables.bitbake.model.BitbakeRecipe; - -public class BitbakeRecipesToLayerMapConverter { - public Map convert(List bitbakeRecipes) { - Map recipeNameToLayersMap = new HashMap<>(); - - for (BitbakeRecipe bitbakeRecipe : bitbakeRecipes) { - String key = bitbakeRecipe.getName(); - bitbakeRecipe.getLayerNames().stream().findFirst().ifPresent(layer -> recipeNameToLayersMap.put(key, layer)); - } - - return recipeNameToLayersMap; - } -} diff --git a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BitbakeSession.java b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BitbakeSession.java index 8a2ee01b1a..ecd9137f28 100644 --- a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BitbakeSession.java +++ b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BitbakeSession.java @@ -12,7 +12,6 @@ import com.synopsys.integration.detectable.detectable.executable.DetectableExecutableRunner; import com.synopsys.integration.detectable.detectable.executable.ExecutableFailedException; import com.synopsys.integration.detectable.detectables.bitbake.model.BitbakeEnvironment; -import com.synopsys.integration.detectable.detectables.bitbake.model.BitbakeRecipe; import com.synopsys.integration.detectable.detectables.bitbake.parse.BitbakeEnvironmentParser; import com.synopsys.integration.detectable.detectables.bitbake.parse.BitbakeRecipesParser; import com.synopsys.integration.detectable.util.ToolVersionLogger; @@ -96,7 +95,7 @@ public BitbakeEnvironment executeBitbakeForEnvironment() { } } - public List executeBitbakeForRecipeLayerCatalog() throws IOException, ExecutableFailedException { + public ShowRecipesResults executeBitbakeForRecipeLayerCatalog() throws IOException, ExecutableFailedException { ExecutableOutput executableOutput = runBitbake(BITBAKE_LAYERS_SHOW_RECIPES_COMMAND); return bitbakeRecipesParser.parseShowRecipes(executableOutput.getStandardOutputAsList()); } diff --git a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BuildFileFinder.java b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BuildFileFinder.java index 2519437c22..a331547964 100644 --- a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BuildFileFinder.java +++ b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/BuildFileFinder.java @@ -67,7 +67,6 @@ public Optional findLicenseManifestFile(File buildDir, String targetImageN @NotNull private List generateListOfFiles(final File licensesDir) { - // TODO surely there's a single-line way to do this (via nio or apache FileUtils) File[] licensesDirContentsArray = licensesDir.listFiles(); if (licensesDirContentsArray == null) { return new ArrayList<>(0); diff --git a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/ShowRecipesResults.java b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/ShowRecipesResults.java new file mode 100644 index 0000000000..dc77f60a5c --- /dev/null +++ b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/ShowRecipesResults.java @@ -0,0 +1,23 @@ +package com.synopsys.integration.detectable.detectables.bitbake; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class ShowRecipesResults { + private final Set layerNames; + private final Map> recipesWithLayers; + + public ShowRecipesResults(final Set layerNames, Map> recipesWithLayers) { + this.layerNames = layerNames; + this.recipesWithLayers = recipesWithLayers; + } + + public Set getLayerNames() { + return layerNames; + } + + public Map> getRecipesWithLayers() { + return recipesWithLayers; + } +} diff --git a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/model/BitbakeGraph.java b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/model/BitbakeGraph.java index d652e066f4..be01403ff4 100644 --- a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/model/BitbakeGraph.java +++ b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/model/BitbakeGraph.java @@ -23,8 +23,10 @@ private BitbakeNode getOrCreate(String name) { return newNode; } - public void addNode(String name, @Nullable String version) { - getOrCreate(name).setVersion(version); + public void addNode(String name, @Nullable String version, @Nullable String layer) { + BitbakeNode node = getOrCreate(name); + node.setVersion(version); + node.setLayer(layer); } public void addChild(String parent, String child) { diff --git a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/model/BitbakeNode.java b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/model/BitbakeNode.java index d7f1b15213..7b314eaac8 100644 --- a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/model/BitbakeNode.java +++ b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/model/BitbakeNode.java @@ -7,6 +7,7 @@ public class BitbakeNode { private final String name; private String version = null; + private String layer = null; private final Set children = new HashSet<>(); public BitbakeNode(String name) {this.name = name;} @@ -19,6 +20,10 @@ public void setVersion(String version) { this.version = version; } + public void setLayer(String layer) { + this.layer = layer; + } + public String getName() { return name; } @@ -27,6 +32,10 @@ public Optional getVersion() { return Optional.ofNullable(version); } + public Optional getLayer() { + return Optional.ofNullable(layer); + } + public Set getChildren() { return children; } diff --git a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/model/GraphNodeLabelDetails.java b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/model/GraphNodeLabelDetails.java new file mode 100644 index 0000000000..a38a85b6e0 --- /dev/null +++ b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/model/GraphNodeLabelDetails.java @@ -0,0 +1,25 @@ +package com.synopsys.integration.detectable.detectables.bitbake.model; + +public class GraphNodeLabelDetails { + private final String nameType; + private final String version; + private final String recipeSpec; + + public GraphNodeLabelDetails(final String nameType, final String version, final String recipeSpec) { + this.nameType = nameType; + this.version = version; + this.recipeSpec = recipeSpec; + } + + public String getNameType() { + return nameType; + } + + public String getVersion() { + return version; + } + + public String getRecipeSpec() { + return recipeSpec; + } +} diff --git a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/parse/BitbakeGraphTransformer.java b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/parse/BitbakeGraphTransformer.java index 4bdb8344fa..5f92bb5a47 100644 --- a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/parse/BitbakeGraphTransformer.java +++ b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/parse/BitbakeGraphTransformer.java @@ -1,10 +1,12 @@ package com.synopsys.integration.detectable.detectables.bitbake.parse; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,21 +35,22 @@ public BitbakeGraphTransformer(ExternalIdFactory externalIdFactory, EnumListFilt this.dependencyTypeFilter = dependencyTypeFilter; } - public DependencyGraph transform(BitbakeGraph bitbakeGraph, Map recipeLayerMap, Map imageRecipes) { + public DependencyGraph transform(BitbakeGraph bitbakeGraph, Map> recipeLayerMap, Map imageRecipes) { Map namesToExternalIds = generateExternalIds(bitbakeGraph, recipeLayerMap, imageRecipes); return buildGraph(bitbakeGraph, namesToExternalIds); } @NotNull - private Map generateExternalIds(BitbakeGraph bitbakeGraph, Map recipeLayerMap, Map imageRecipes) { + private Map generateExternalIds(BitbakeGraph bitbakeGraph, Map> recipeLayerMap, Map imageRecipes) { Map namesToExternalIds = new HashMap<>(); for (BitbakeNode bitbakeNode : bitbakeGraph.getNodes()) { String name = bitbakeNode.getName(); if (bitbakeNode.getVersion().isPresent()) { String version = bitbakeNode.getVersion().get(); + Optional actualLayer = bitbakeNode.getLayer(); if (dependencyTypeFilter.shouldInclude(BitbakeDependencyType.BUILD) || !isBuildDependency(imageRecipes, name, version)) { - Optional dependency = generateExternalId(name, version, recipeLayerMap).map(Dependency::new); + Optional dependency = generateExternalId(name, version, actualLayer.orElse(null), recipeLayerMap).map(Dependency::new); dependency.ifPresent(value -> namesToExternalIds.put(bitbakeNode.getName(), value)); } } else if (name.startsWith(VIRTUAL_PREFIX)) { @@ -117,20 +120,20 @@ private String removeEpochPrefix(String recipeVersion) { return epochlessRecipeVersion; } - private Optional generateExternalId(String dependencyName, String dependencyVersion, Map recipeLayerMap) { - String priorityLayerName = recipeLayerMap.get(dependencyName); + private Optional generateExternalId(String dependencyName, String dependencyVersion, @Nullable String dependencyLayer, Map> recipeLayerMap) { + List recipeLayerNames = recipeLayerMap.get(dependencyName); ExternalId externalId = null; - - if (priorityLayerName != null) { - externalId = externalIdFactory.createYoctoExternalId(priorityLayerName, dependencyName, dependencyVersion); + if (recipeLayerNames != null) { + dependencyLayer = chooseRecipeLayer(dependencyName, dependencyLayer, recipeLayerNames); + externalId = externalIdFactory.createYoctoExternalId(dependencyLayer, dependencyName, dependencyVersion); } else { - logger.debug("Failed to find component '{}' in component layer map.", dependencyName); + logger.debug("Failed to find component '{}' in component layer map. [dependencyVersion: {}; dependencyLayer: {}", dependencyName, dependencyVersion, dependencyLayer); if (dependencyName.endsWith(NATIVE_SUFFIX)) { String alternativeName = dependencyName.replace(NATIVE_SUFFIX, ""); logger.debug("Generating alternative component name '{}' for '{}=={}'", alternativeName, dependencyName, dependencyVersion); - externalId = generateExternalId(alternativeName, dependencyVersion, recipeLayerMap).orElse(null); + externalId = generateExternalId(alternativeName, dependencyVersion, dependencyLayer, recipeLayerMap).orElse(null); } else { - logger.debug("'{}=={}' is not an actual component. Excluding from graph.", dependencyName, dependencyVersion); + logger.debug("'{}:{}' is not an actual component. Excluding from graph.", dependencyName, dependencyVersion); } } @@ -140,4 +143,14 @@ private Optional generateExternalId(String dependencyName, String de return Optional.ofNullable(externalId); } + + private String chooseRecipeLayer(final String dependencyName, @Nullable String dependencyLayer, final List recipeLayerNames) { + if (dependencyLayer == null) { + logger.warn("Did not parse a layer for dependency {} from task-depends.dot; falling back to layer {} (first from show-recipes output)", dependencyName, recipeLayerNames.get(0)); + dependencyLayer = recipeLayerNames.get(0); + } else { + logger.trace("For dependency recipe {}: using layer {} parsed from task-depends.dot", dependencyName, dependencyLayer); + } + return dependencyLayer; + } } diff --git a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/parse/BitbakeRecipesParser.java b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/parse/BitbakeRecipesParser.java index 3a30bee551..19f10a02e2 100644 --- a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/parse/BitbakeRecipesParser.java +++ b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/parse/BitbakeRecipesParser.java @@ -1,11 +1,16 @@ package com.synopsys.integration.detectable.detectables.bitbake.parse; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.slf4j.LoggerFactory; +import com.synopsys.integration.detectable.detectables.bitbake.ShowRecipesResults; import com.synopsys.integration.detectable.detectables.bitbake.model.BitbakeRecipe; import com.synopsys.integration.log.IntLogger; import com.synopsys.integration.log.Slf4jIntLogger; @@ -17,8 +22,9 @@ public class BitbakeRecipesParser { * @param showRecipeLines is the executable output. * @return Recipe names mapped to a recipe's the layer names. */ - public List parseShowRecipes(List showRecipeLines) { - List bitbakeRecipes = new ArrayList<>(); + public ShowRecipesResults parseShowRecipes(List showRecipeLines) { + Map> bitbakeRecipes = new HashMap<>(); + Set layerNames = new HashSet<>(); boolean started = false; BitbakeRecipe currentRecipe = null; @@ -35,17 +41,20 @@ public List parseShowRecipes(List showRecipeLines) { } if (currentRecipe != null) { - bitbakeRecipes.add(currentRecipe); + bitbakeRecipes.put(currentRecipe.getName(), currentRecipe.getLayerNames()); + if (currentRecipe.getLayerNames() != null) { + layerNames.addAll(currentRecipe.getLayerNames()); + } } - return bitbakeRecipes; + return new ShowRecipesResults(layerNames, bitbakeRecipes); } - private BitbakeRecipe parseLine(String line, BitbakeRecipe currentRecipe, List bitbakeRecipes) { + private BitbakeRecipe parseLine(String line, BitbakeRecipe currentRecipe, Map> bitbakeRecipes) { if (line.contains(":") && !line.startsWith(" ")) { // Parse beginning of new component if (currentRecipe != null) { - bitbakeRecipes.add(currentRecipe); + bitbakeRecipes.put(currentRecipe.getName(), currentRecipe.getLayerNames()); } String recipeName = line.replace(":", "").trim(); diff --git a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/parse/GraphNodeLabelParser.java b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/parse/GraphNodeLabelParser.java new file mode 100644 index 0000000000..2fdf92bb18 --- /dev/null +++ b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/parse/GraphNodeLabelParser.java @@ -0,0 +1,44 @@ +package com.synopsys.integration.detectable.detectables.bitbake.parse; + +import java.util.Set; + +import org.jetbrains.annotations.NotNull; + +import com.synopsys.integration.detectable.detectables.bitbake.model.GraphNodeLabelDetails; +import com.synopsys.integration.exception.IntegrationException; + +// Example of a GraphNode label value: +// acl-native do_compile\n:2.3.1-r0\nvirtual:native:/workdir/poky/meta/recipes-support/attr/acl_2.3.1.bb +// Split into: +// acl-native do_compile -> GraphNodeLabelDetails.nameType +// 2.3.1-r0 -> GraphNodeLabelDetails.version +// virtual:native:/workdir/poky/meta/recipes-support/attr/acl_2.3.1.bb -> GraphNodeLabelDetails.recipeSpec +public class GraphNodeLabelParser { + private static final String LABEL_PATH_SEPARATOR = "/"; + + public String parseVersionFromLabel(String label) throws IntegrationException { + GraphNodeLabelDetails labelDetails = parseLabelParts(label); + return labelDetails.getVersion(); + } + + public String parseLayerFromLabel(String label, Set knownLayerNames) throws IntegrationException { + GraphNodeLabelDetails labelDetails = parseLabelParts(label); + String recipeSpec = labelDetails.getRecipeSpec(); + for (String candidateLayerName : knownLayerNames) { + String possibleLayerPathSubstring = LABEL_PATH_SEPARATOR + candidateLayerName + LABEL_PATH_SEPARATOR; + if (recipeSpec.contains(possibleLayerPathSubstring)) { + return candidateLayerName; + } + } + throw new IntegrationException(String.format("Graph Node recipe '%s' does not correspond to any known layer (%s)", label, knownLayerNames)); + } + + @NotNull + private GraphNodeLabelDetails parseLabelParts(final String label) throws IntegrationException { + String[] labelParts = label.split("\\\\n:|\\\\n"); + if (labelParts.length < 3) { + throw new IntegrationException(String.format("Error parsing Graph Node label '%s'; unexpected format.", label)); + } + return new GraphNodeLabelDetails(labelParts[0], labelParts[1], labelParts[2]); + } +} diff --git a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/parse/GraphParserTransformer.java b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/parse/GraphParserTransformer.java index a7c94db5b0..b1a1ecb2f3 100644 --- a/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/parse/GraphParserTransformer.java +++ b/detectable/src/main/java/com/synopsys/integration/detectable/detectables/bitbake/parse/GraphParserTransformer.java @@ -1,6 +1,7 @@ package com.synopsys.integration.detectable.detectables.bitbake.parse; import java.util.Optional; +import java.util.Set; import org.apache.commons.lang3.StringUtils; @@ -8,21 +9,27 @@ import com.paypal.digraph.parser.GraphNode; import com.paypal.digraph.parser.GraphParser; import com.synopsys.integration.detectable.detectables.bitbake.model.BitbakeGraph; +import com.synopsys.integration.exception.IntegrationException; public class GraphParserTransformer { - public BitbakeGraph transform(GraphParser graphParser) { + private final GraphNodeLabelParser graphNodeLabelParser; + + public GraphParserTransformer(GraphNodeLabelParser graphNodeLabelParser) { + this.graphNodeLabelParser = graphNodeLabelParser; + } + + public BitbakeGraph transform(GraphParser graphParser, Set layerNames) throws IntegrationException { BitbakeGraph bitbakeGraph = new BitbakeGraph(); for (GraphNode graphNode : graphParser.getNodes().values()) { - String name = getNameFromNode(graphNode); - getVersionFromNode(graphNode).ifPresent( - version -> bitbakeGraph.addNode(name, version) - ); + String name = parseNameFromNode(graphNode); + Optional layer = parseLayerFromNode(graphNode, layerNames); + parseVersionFromNode(graphNode).ifPresent(ver -> bitbakeGraph.addNode(name, ver, layer.orElse(null))); } for (GraphEdge graphEdge : graphParser.getEdges().values()) { - String parent = getNameFromNode(graphEdge.getNode1()); - String child = getNameFromNode(graphEdge.getNode2()); + String parent = parseNameFromNode(graphEdge.getNode1()); + String child = parseNameFromNode(graphEdge.getNode2()); if (!parent.equals(child)) { bitbakeGraph.addChild(parent, child); } @@ -31,29 +38,36 @@ public BitbakeGraph transform(GraphParser graphParser) { return bitbakeGraph; } - private String getNameFromNode(GraphNode graphNode) { + private String parseNameFromNode(GraphNode graphNode) { String[] nodeIdPieces = graphNode.getId().split(".do_"); return nodeIdPieces[0].replace("\"", ""); } - private Optional getVersionFromNode(GraphNode graphNode) { - Optional attribute = getLabelAttribute(graphNode); - return attribute.map(this::getVersionFromLabel); + private Optional parseVersionFromNode(GraphNode graphNode) throws IntegrationException { + Optional labelValue = getLabelAttribute(graphNode); + if (labelValue.isPresent()) { + return Optional.of(graphNodeLabelParser.parseVersionFromLabel(labelValue.get())); + } else { + return Optional.empty(); + } + } + + private Optional parseLayerFromNode(GraphNode graphNode, Set knownLayerNames) throws IntegrationException { + Optional labelAttribute = getLabelAttribute(graphNode); + if (labelAttribute.isPresent()) { + return Optional.of(graphNodeLabelParser.parseLayerFromLabel(labelAttribute.get(), knownLayerNames)); + } else { + return Optional.empty(); + } } private Optional getLabelAttribute(GraphNode graphNode) { - String attribute = (String) graphNode.getAttribute("label"); + String labelValue = (String) graphNode.getAttribute("label"); Optional result = Optional.empty(); - if (StringUtils.isNotBlank(attribute)) { - result = Optional.of(attribute); + if (StringUtils.isNotBlank(labelValue)) { + result = Optional.of(labelValue); } - return result; } - - private String getVersionFromLabel(String label) { - String[] components = label.split("\\\\n:|\\\\n"); - return components[1]; - } } diff --git a/detectable/src/main/java/com/synopsys/integration/detectable/factory/DetectableFactory.java b/detectable/src/main/java/com/synopsys/integration/detectable/factory/DetectableFactory.java index 4695d2bbfe..4a492fbdf3 100644 --- a/detectable/src/main/java/com/synopsys/integration/detectable/factory/DetectableFactory.java +++ b/detectable/src/main/java/com/synopsys/integration/detectable/factory/DetectableFactory.java @@ -47,11 +47,11 @@ import com.synopsys.integration.detectable.detectables.bitbake.BitbakeDetectable; import com.synopsys.integration.detectable.detectables.bitbake.BitbakeDetectableOptions; import com.synopsys.integration.detectable.detectables.bitbake.BitbakeExtractor; -import com.synopsys.integration.detectable.detectables.bitbake.BitbakeRecipesToLayerMapConverter; import com.synopsys.integration.detectable.detectables.bitbake.BuildFileFinder; import com.synopsys.integration.detectable.detectables.bitbake.parse.BitbakeEnvironmentParser; import com.synopsys.integration.detectable.detectables.bitbake.parse.BitbakeGraphTransformer; import com.synopsys.integration.detectable.detectables.bitbake.parse.BitbakeRecipesParser; +import com.synopsys.integration.detectable.detectables.bitbake.parse.GraphNodeLabelParser; import com.synopsys.integration.detectable.detectables.bitbake.parse.GraphParserTransformer; import com.synopsys.integration.detectable.detectables.bitbake.parse.LicenseManifestParser; import com.synopsys.integration.detectable.detectables.cargo.CargoDetectable; @@ -301,10 +301,9 @@ public BazelDetectable createBazelDetectable(DetectableEnvironment environment, public BitbakeDetectable createBitbakeDetectable(DetectableEnvironment environment, BitbakeDetectableOptions bitbakeDetectableOptions, BashResolver bashResolver) { BitbakeExtractor bitbakeExtractor = new BitbakeExtractor( executableRunner, - new GraphParserTransformer(), + new GraphParserTransformer(new GraphNodeLabelParser()), new BitbakeGraphTransformer(externalIdFactory, bitbakeDetectableOptions.getDependencyTypeFilter()), new BitbakeRecipesParser(), - new BitbakeRecipesToLayerMapConverter(), toolVersionLogger, new BuildFileFinder(fileFinder), new LicenseManifestParser(), diff --git a/detectable/src/test/java/com/synopsys/integration/detectable/detectables/bitbake/unit/BitbakeGraphTransformerTest.java b/detectable/src/test/java/com/synopsys/integration/detectable/detectables/bitbake/unit/BitbakeGraphTransformerTest.java index fa310e0ce0..015a34dbd6 100644 --- a/detectable/src/test/java/com/synopsys/integration/detectable/detectables/bitbake/unit/BitbakeGraphTransformerTest.java +++ b/detectable/src/test/java/com/synopsys/integration/detectable/detectables/bitbake/unit/BitbakeGraphTransformerTest.java @@ -1,6 +1,8 @@ package com.synopsys.integration.detectable.detectables.bitbake.unit; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; @@ -11,6 +13,7 @@ import com.synopsys.integration.bdio.model.externalid.ExternalIdFactory; import com.synopsys.integration.detectable.annotations.UnitTest; import com.synopsys.integration.detectable.detectable.util.EnumListFilter; +import com.synopsys.integration.detectable.detectables.bitbake.BitbakeDependencyType; import com.synopsys.integration.detectable.detectables.bitbake.model.BitbakeGraph; import com.synopsys.integration.detectable.detectables.bitbake.parse.BitbakeGraphTransformer; import com.synopsys.integration.detectable.util.graph.GraphAssert; @@ -22,15 +25,16 @@ public class BitbakeGraphTransformerTest { public void parentHasChild() { ExternalIdFactory externalIdFactory = new ExternalIdFactory(); BitbakeGraph bitbakeGraph = new BitbakeGraph(); - bitbakeGraph.addNode("example", "1:75-r50"); - bitbakeGraph.addNode("foobar", "12"); + bitbakeGraph.addNode("example", "1:75-r50", "meta"); + bitbakeGraph.addNode("foobar", "12", "meta"); bitbakeGraph.addChild("example", "foobar"); - Map recipeToLayerMap = new HashMap<>(); - recipeToLayerMap.put("example", "meta"); - recipeToLayerMap.put("foobar", "meta"); + Map> recipeToLayerMap = new HashMap<>(); + recipeToLayerMap.put("example", Arrays.asList("meta")); + recipeToLayerMap.put("foobar", Arrays.asList("meta")); BitbakeGraphTransformer bitbakeGraphTransformer = new BitbakeGraphTransformer(new ExternalIdFactory(), EnumListFilter.excludeNone()); + DependencyGraph dependencyGraph = bitbakeGraphTransformer.transform(bitbakeGraph, recipeToLayerMap, null); NameVersionGraphAssert graphAssert = new NameVersionGraphAssert(Forge.YOCTO, dependencyGraph); @@ -44,13 +48,13 @@ public void parentHasChild() { public void ignoredNoVersionRelationship() { ExternalIdFactory externalIdFactory = new ExternalIdFactory(); BitbakeGraph bitbakeGraph = new BitbakeGraph(); - bitbakeGraph.addNode("example", "75"); - bitbakeGraph.addNode("foobar", null); + bitbakeGraph.addNode("example", "75", "meta"); + bitbakeGraph.addNode("foobar", null, "meta"); bitbakeGraph.addChild("example", "foobar"); - Map recipeToLayerMap = new HashMap<>(); - recipeToLayerMap.put("example", "meta"); - recipeToLayerMap.put("foobar", "meta"); + Map> recipeToLayerMap = new HashMap<>(); + recipeToLayerMap.put("example", Arrays.asList("meta")); + recipeToLayerMap.put("foobar", Arrays.asList("meta")); BitbakeGraphTransformer bitbakeGraphTransformer = new BitbakeGraphTransformer(new ExternalIdFactory(), EnumListFilter.excludeNone()); DependencyGraph dependencyGraph = bitbakeGraphTransformer.transform(bitbakeGraph, recipeToLayerMap, null); @@ -65,10 +69,10 @@ public void ignoredNoVersionRelationship() { public void ignoredNoVersion() { ExternalIdFactory externalIdFactory = new ExternalIdFactory(); BitbakeGraph bitbakeGraph = new BitbakeGraph(); - bitbakeGraph.addNode("example", null); + bitbakeGraph.addNode("example", null, "meta"); - Map recipeToLayerMap = new HashMap<>(); - recipeToLayerMap.put("example", "meta"); + Map> recipeToLayerMap = new HashMap<>(); + recipeToLayerMap.put("example", Arrays.asList("meta")); BitbakeGraphTransformer bitbakeGraphTransformer = new BitbakeGraphTransformer(new ExternalIdFactory(), EnumListFilter.excludeNone()); DependencyGraph dependencyGraph = bitbakeGraphTransformer.transform(bitbakeGraph, recipeToLayerMap, null); diff --git a/detectable/src/test/java/com/synopsys/integration/detectable/detectables/bitbake/unit/GraphNodeLabelParserTest.java b/detectable/src/test/java/com/synopsys/integration/detectable/detectables/bitbake/unit/GraphNodeLabelParserTest.java new file mode 100644 index 0000000000..a01cb191cb --- /dev/null +++ b/detectable/src/test/java/com/synopsys/integration/detectable/detectables/bitbake/unit/GraphNodeLabelParserTest.java @@ -0,0 +1,39 @@ +package com.synopsys.integration.detectable.detectables.bitbake.unit; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import com.synopsys.integration.detectable.detectables.bitbake.parse.GraphNodeLabelParser; +import com.synopsys.integration.exception.IntegrationException; + +public class GraphNodeLabelParserTest { + + @Test + void testVersion() throws IntegrationException { + String labelValue = "acl-native do_compile\\n:2.3.1-r0\\nvirtual:native:/workdir/poky/meta/recipes-support/attr/acl_2.3.1.bb"; + GraphNodeLabelParser parser = new GraphNodeLabelParser(); + Set knownLayers = new HashSet<>(); + knownLayers.add("meta"); + + String version = parser.parseVersionFromLabel(labelValue); + + assertEquals("2.3.1-r0", version); + } + + @Test + void testLayer() throws IntegrationException { + String labelValue = "acl-native do_compile\\n:2.3.1-r0\\nvirtual:native:/workdir/poky/meta/recipes-support/attr/acl_2.3.1.bb"; + GraphNodeLabelParser parser = new GraphNodeLabelParser(); + Set knownLayers = new HashSet<>(); + knownLayers.add("meta"); + + String layer = parser.parseLayerFromLabel(labelValue, knownLayers); + + assertEquals("meta", layer); + } +} diff --git a/detectable/src/test/java/com/synopsys/integration/detectable/detectables/bitbake/unit/GraphParserTransformerTest.java b/detectable/src/test/java/com/synopsys/integration/detectable/detectables/bitbake/unit/GraphParserTransformerTest.java index aa35c121c3..dea6decc3e 100644 --- a/detectable/src/test/java/com/synopsys/integration/detectable/detectables/bitbake/unit/GraphParserTransformerTest.java +++ b/detectable/src/test/java/com/synopsys/integration/detectable/detectables/bitbake/unit/GraphParserTransformerTest.java @@ -1,6 +1,9 @@ package com.synopsys.integration.detectable.detectables.bitbake.unit; +import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -11,31 +14,36 @@ import com.paypal.digraph.parser.GraphParser; import com.synopsys.integration.detectable.annotations.UnitTest; import com.synopsys.integration.detectable.detectables.bitbake.model.BitbakeGraph; +import com.synopsys.integration.detectable.detectables.bitbake.parse.GraphNodeLabelParser; import com.synopsys.integration.detectable.detectables.bitbake.parse.GraphParserTransformer; +import com.synopsys.integration.exception.IntegrationException; @UnitTest public class GraphParserTransformerTest { @Test - public void parsedVersionFromLabel() { + public void parsedVersionFromLabel() throws IntegrationException { HashMap edges = new HashMap<>(); HashMap nodes = new HashMap<>(); - addNode("name", "name\\n:version\\n/some/path/to.bb", nodes, edges); - BitbakeGraph bitbakeGraph = buildGraph(nodes, edges); + addNode("name", "name\\n:version\\n/some/meta/path/to.bb", nodes, edges); + Set knownLayers = new HashSet<>(Arrays.asList("aaa", "meta", "bbb")); + BitbakeGraph bitbakeGraph = buildGraph(nodes, edges, knownLayers); Assertions.assertEquals(1, bitbakeGraph.getNodes().size()); Assertions.assertEquals("version", bitbakeGraph.getNodes().get(0).getVersion().get()); + Assertions.assertEquals("meta", bitbakeGraph.getNodes().get(0).getLayer().get()); } @Test - public void parsedRelationship() { + public void parsedRelationship() throws IntegrationException { HashMap edges = new HashMap<>(); HashMap nodes = new HashMap<>(); - addNode("parent", "name\\n:parent.version\\n/some/path/to.bb", nodes, edges); - addNode("child", "name\\n:child.version\\n/some/path/to.bb", nodes, edges); + addNode("parent", "name\\n:parent.version\\n/some/meta/path/to.bb", nodes, edges); + addNode("child", "name\\n:child.version\\n/some/meta/path/to.bb", nodes, edges); addEdge("edge1", "parent", "child", nodes, edges); - BitbakeGraph bitbakeGraph = buildGraph(nodes, edges); + Set knownLayers = new HashSet<>(Arrays.asList("aaa", "meta", "bbb")); + BitbakeGraph bitbakeGraph = buildGraph(nodes, edges, knownLayers); Assertions.assertEquals(2, bitbakeGraph.getNodes().size()); Assertions.assertEquals(1, bitbakeGraph.getNodes().get(0).getChildren().size()); @@ -43,20 +51,21 @@ public void parsedRelationship() { } @Test - public void removedQuotesFromName() { + public void removedQuotesFromName() throws IntegrationException { HashMap edges = new HashMap<>(); HashMap nodes = new HashMap<>(); - addNode("quotes\"removed", "example\\n:example\\n/example", nodes, edges); - BitbakeGraph bitbakeGraph = buildGraph(nodes, edges); + addNode("quotes\"removed", "example\\n:example\\n/example/meta/some.bb", nodes, edges); + Set knownLayers = new HashSet<>(Arrays.asList("aaa", "meta", "bbb")); + BitbakeGraph bitbakeGraph = buildGraph(nodes, edges, knownLayers); Assertions.assertEquals(1, bitbakeGraph.getNodes().size()); Assertions.assertEquals("quotesremoved", bitbakeGraph.getNodes().get(0).getName()); } - private BitbakeGraph buildGraph(HashMap nodes, HashMap edges) { - GraphParserTransformer graphParserTransformer = new GraphParserTransformer(); - BitbakeGraph bitbakeGraph = graphParserTransformer.transform(mockParser(nodes, edges)); + private BitbakeGraph buildGraph(HashMap nodes, HashMap edges, Set knownLayers) throws IntegrationException { + GraphParserTransformer graphParserTransformer = new GraphParserTransformer(new GraphNodeLabelParser()); + BitbakeGraph bitbakeGraph = graphParserTransformer.transform(mockParser(nodes, edges), knownLayers); return bitbakeGraph; } diff --git a/docs/markdown/packagemgrs/bitbake.md b/docs/markdown/packagemgrs/bitbake.md index 248634cbba..ca1ad217f7 100644 --- a/docs/markdown/packagemgrs/bitbake.md +++ b/docs/markdown/packagemgrs/bitbake.md @@ -17,10 +17,10 @@ script (by default: oe-init-build-env), and executes BitBake commands to collect The BitBake detector generates one codelocation for each given package (target image) name by performing the following steps: 1. Determines the build directory path by sourcing the given build environment setup script and determining the resulting working directory. 1. Runs 'bitbake --environment' to determine the currently-configured target machine architecture and licenses directory path. +1. Runs 'bitbake-layers show-recipes' to derive the list of layers and collect recipe layer information. 1. For each given package (target image) name: * If the user requested that build dependencies be excluded, [solution_name] locates and reads the license.manifest file for the given package (target image) and the currently-configured target machine architecture. This provides a list of recipes that are included in the target image (the non-build dependencies). * Runs 'bitbake -g {package}' to generate task-depends.dot, and reads recipes and dependency relationships from it. - * Runs 'bitbake-layers show-recipes' to derive each recipe's layer. The first layer listed for each recipe is used as the layer field of the KB externalID [solution_name] generates for the recipe. * If the user requested that build dependencies be excluded: [solution_name] excludes recipes not declared in license.manifest, as well as native recipes. [solution_name] always excludes virtual recipes (recipes with names prefixed with "virtual/"). * [solution_name] adds at the root level of the graph for the package (target image) each recipe found in task-depends.dot that is not excluded as described above. * Child (transitive) relationships are created from those root dependencies to their children (as specified in task-depends.dot). diff --git a/docs/markdown/releasenotes.md b/docs/markdown/releasenotes.md index 23a4823148..049071329e 100644 --- a/docs/markdown/releasenotes.md +++ b/docs/markdown/releasenotes.md @@ -13,6 +13,7 @@ ### Resolved issues +* (IDETECT-2925) Resolved an issue that could cause the Bitbake detector to incorrectly identify the layer of a dependency recipe. * (IDETECT-3080) Fixed an issue where [solution_name] would not include multiple versions of the same package in Cargo projects. ## Version 7.10.0 diff --git a/src/test/java/com/synopsys/integration/detect/battery/detector/BitbakeBattery.java b/src/test/java/com/synopsys/integration/detect/battery/detector/BitbakeBattery.java index 1ea1f82642..f6211cff0c 100644 --- a/src/test/java/com/synopsys/integration/detect/battery/detector/BitbakeBattery.java +++ b/src/test/java/com/synopsys/integration/detect/battery/detector/BitbakeBattery.java @@ -14,7 +14,7 @@ void testIncludeAll() { DetectorBatteryTestRunner test = new DetectorBatteryTestRunner("bitbake-full", "bitbake/full"); test.sourceFileFromResource("oe-init-build-env"); test.sourceFileFromResource("task-depends.dot"); - test.executableFromResourceFiles(DetectProperties.DETECT_BASH_PATH.getProperty(), "pwd.xout", "environment.xout", "bitbake-g.xout", "bitbake-layers-show-recipes.xout"); + test.executableFromResourceFiles(DetectProperties.DETECT_BASH_PATH.getProperty(), "pwd.xout", "environment.xout", "bitbake-layers-show-recipes.xout", "bitbake-g.xout"); test.property("detect.bitbake.package.names", "core-image-sato"); test.expectBdioResources(); test.run(); @@ -26,7 +26,7 @@ void testExclBuild() { test.sourceFileFromResource("oe-init-build-env"); test.sourceFileFromResource("build/task-depends.dot"); test.sourceFileFromResource("build/tmp/deploy/licenses/core-image-sato-qemux86-64/license.manifest"); - test.executableFromResourceFiles(DetectProperties.DETECT_BASH_PATH.getProperty(), "pwd.xout", "environment.xout", "bitbake-g.xout", "bitbake-layers-show-recipes.xout"); + test.executableFromResourceFiles(DetectProperties.DETECT_BASH_PATH.getProperty(), "pwd.xout", "environment.xout", "bitbake-layers-show-recipes.xout", "bitbake-g.xout"); test.property("detect.bitbake.package.names", "core-image-sato"); test.property("detect.bitbake.dependency.types.excluded", "BUILD"); test.expectBdioResources();