From 5ff9c7c697393ca08799d8eac0b03d5c717d5b84 Mon Sep 17 00:00:00 2001 From: Jan Geertsma Date: Mon, 9 Feb 2026 11:24:49 +0200 Subject: [PATCH 1/4] Add support for Meson introspect --- .../detectables/meson/MesonDetectable.java | 44 +++++++++ .../detectables/meson/MesonExtractor.java | 92 +++++++++++++++++++ .../parse/MesonDependencyFileParser.java | 85 +++++++++++++++++ .../meson/parse/MesonProjectFileParser.java | 53 +++++++++++ .../detectable/factory/DetectableFactory.java | 11 +++ .../detector/base/DetectorType.java | 1 + .../main/markdown/components/detectors.dita | 20 ++++ .../enumeration/DetectGroup.java | 1 + .../tool/detector/DetectorRuleFactory.java | 6 ++ .../factory/DetectDetectableFactory.java | 5 + 10 files changed, 318 insertions(+) create mode 100644 detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonDetectable.java create mode 100644 detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonExtractor.java create mode 100644 detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonDependencyFileParser.java create mode 100644 detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonProjectFileParser.java diff --git a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonDetectable.java b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonDetectable.java new file mode 100644 index 0000000000..a2198f28b8 --- /dev/null +++ b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonDetectable.java @@ -0,0 +1,44 @@ +package com.blackduck.integration.detectable.detectables.meson; + +import com.blackduck.integration.common.util.finder.FileFinder; +import com.blackduck.integration.detectable.Detectable; +import com.blackduck.integration.detectable.DetectableEnvironment; +import com.blackduck.integration.detectable.detectable.DetectableAccuracyType; +import com.blackduck.integration.detectable.detectable.Requirements; +import com.blackduck.integration.detectable.detectable.annotation.DetectableInfo; +import com.blackduck.integration.detectable.detectable.result.DetectableResult; +import com.blackduck.integration.detectable.detectable.result.PassedDetectableResult; +import com.blackduck.integration.detectable.extraction.Extraction; +import com.blackduck.integration.detectable.extraction.ExtractionEnvironment; + +@DetectableInfo(name = "meson", language = "C/C++", forge = "N/A", accuracy = DetectableAccuracyType.HIGH, requirementsMarkdown = "File: meson.build") +public class MesonDetectable extends Detectable { + public static final String detectable_file = "meson.build"; + public static final String introspect_project = "intro-projectinfo.json"; + public static final String introspect_dependencies = "intro-dependencies.json"; + private final FileFinder fileFinder; + private final MesonExtractor mesonExtractor; + + public MesonDetectable(DetectableEnvironment environment, FileFinder fileFinder, MesonExtractor mesonExtractor) { + super(environment); + this.fileFinder = fileFinder; + this.mesonExtractor = mesonExtractor; + } + + @Override + public DetectableResult applicable() { + Requirements requirements = new Requirements(fileFinder, environment); + requirements.file(detectable_file); + return requirements.result(); + } + + @Override + public DetectableResult extractable() { + return new PassedDetectableResult(); + } + + @Override + public Extraction extract(ExtractionEnvironment extractionEnvironment) { + return mesonExtractor.extract(environment.getDirectory()); + } +} diff --git a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonExtractor.java b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonExtractor.java new file mode 100644 index 0000000000..a8a60bac41 --- /dev/null +++ b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonExtractor.java @@ -0,0 +1,92 @@ +package com.blackduck.integration.detectable.detectables.meson; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.blackduck.integration.bdio.graph.DependencyGraph; +import com.blackduck.integration.common.util.finder.FileFinder; +import com.blackduck.integration.detectable.detectable.codelocation.CodeLocation; +import com.blackduck.integration.detectable.detectables.meson.parse.MesonDependencyFileParser; +import com.blackduck.integration.detectable.detectables.meson.parse.MesonProjectFileParser; +import com.blackduck.integration.detectable.extraction.Extraction; +import com.blackduck.integration.util.NameVersion; +import com.google.gson.Gson; + +public class MesonExtractor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final MesonProjectFileParser mesonProjectFileParser; + private final MesonDependencyFileParser mesonDependencyFileParser; + private final FileFinder fileFinder; + private final Gson gson; + + private static final String introspect_project = "intro-projectinfo.json"; + private static final String introspect_dependencies = "intro-dependencies.json"; + + public MesonExtractor( + MesonProjectFileParser mesonProjectFileParser, + MesonDependencyFileParser mesonDependencyFileParser, + FileFinder fileFinder, + Gson gson + ) { + this.mesonProjectFileParser = mesonProjectFileParser; + this.mesonDependencyFileParser = mesonDependencyFileParser; + this.fileFinder = fileFinder; + this.gson = gson; + } + + public Extraction extract(File directory) { + try { + // Find the intro-projectinfo.json file in subdirectories + File projectFile = fileFinder.findFile(directory, introspect_project, false, 2); + if (projectFile == null) { + return new Extraction.Builder() + .failure("Could not find " + introspect_project + " in any subdirectory").build(); + } + NameVersion nameVersion = determineProjectNameVersion(projectFile.getAbsolutePath()); + logger.debug("Found Meson project file: {}", projectFile.getAbsolutePath()); + + // Parse dependencies from intro-dependencies.json + File dependencyFile = fileFinder.findFile(directory, introspect_dependencies, false, 2); + if (dependencyFile == null) { + return new Extraction.Builder() + .failure("Could not find " + introspect_dependencies + " in any subdirectory").build(); + } + String dependenciesJsonContents = Files.readString(dependencyFile.toPath(), StandardCharsets.UTF_8); + logger.trace("Dependencies JSON contents: {}", dependenciesJsonContents); + DependencyGraph dependencyGraph = mesonDependencyFileParser.parseProjectDependencies(gson, dependenciesJsonContents); + CodeLocation codeLocation = new CodeLocation(dependencyGraph); + logger.debug("Found Meson dependency file: {}", dependencyFile.getAbsolutePath()); + + return new Extraction.Builder() + .success(codeLocation) + .projectName(nameVersion.getName()) + .projectVersion(nameVersion.getVersion()) + .build(); + } catch (Exception e) { + logger.error("Failed to extract Meson dependencies", e); + return new Extraction.Builder().exception(e).build(); + } + } + + private NameVersion determineProjectNameVersion(String projectFilePath) { + final String defaultProjectName = ""; + final String defaultProjectVersion = ""; + + try { + File projectInfoFile = new File(projectFilePath); + if (projectInfoFile != null) { + String projectJsonContents = Files.readString(projectInfoFile.toPath()); + logger.debug("Found Meson project info file: {}", projectInfoFile.getAbsolutePath()); + return mesonProjectFileParser.getProjectNameVersion(gson, projectJsonContents, defaultProjectName, defaultProjectVersion); + } + } catch (Exception e) { + logger.warn("Failed to parse Meson introspect, using defaults", e); + } + + return new NameVersion(defaultProjectName, defaultProjectVersion); + } +} diff --git a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonDependencyFileParser.java b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonDependencyFileParser.java new file mode 100644 index 0000000000..b165c02b68 --- /dev/null +++ b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonDependencyFileParser.java @@ -0,0 +1,85 @@ +package com.blackduck.integration.detectable.detectables.meson.parse; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.blackduck.integration.bdio.graph.BasicDependencyGraph; +import com.blackduck.integration.bdio.graph.DependencyGraph; +import com.blackduck.integration.bdio.model.Forge; +import com.blackduck.integration.bdio.model.dependency.Dependency; +import com.blackduck.integration.bdio.model.externalid.ExternalId; +import com.blackduck.integration.bdio.model.externalid.ExternalIdFactory; +import com.google.gson.Gson; + +public class MesonDependencyFileParser { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final ExternalIdFactory externalIdFactory; + + public MesonDependencyFileParser(ExternalIdFactory externalIdFactory) { + this.externalIdFactory = externalIdFactory; + } + + public DependencyGraph parseProjectDependencies(Gson gson, String jsonContents) { + DependencyGraph graph = new BasicDependencyGraph(); + + try { + if (jsonContents == null || jsonContents.trim().isEmpty()) { + logger.warn("Empty or null JSON contents for Meson dependencies"); + return graph; + } + + logger.trace("Parsing Meson dependencies JSON (length: {})", jsonContents.length()); + MesonDependency[] dependencies = gson.fromJson(jsonContents, MesonDependency[].class); + + if (dependencies == null) { + logger.warn("Failed to parse Meson dependencies - gson returned null"); + return graph; + } + + logger.debug("Found {} Meson dependencies", dependencies.length); + + for (MesonDependency dep : dependencies) { + if (!"internal".equals(dep.getType()) + && StringUtils.isNotBlank(dep.getName()) + && StringUtils.isNotBlank(dep.getVersion())) { + + //TODO: What is a forge in this instance? + //TODO: What is a scope? + ExternalId dependencyExternalId = externalIdFactory.createNameVersionExternalId( + Forge.GITLAB , + dep.getName(), + dep.getVersion()); + Dependency dependency = new Dependency(dep.getName(), dep.getVersion(), dependencyExternalId, null); + logger.trace("Adding dependency: {}", dependency.getExternalId().toString()); + graph.addDirectDependency(dependency); + } else { + logger.debug("Skipping dependency - name: '{}', type: '{}', version: '{}'", + dep.getName(), dep.getType(), dep.getVersion()); + } + } + } catch (Exception e) { + logger.warn("Failed to parse Meson dependency JSON", e); + } + + return graph; + } + + private static class MesonDependency { + private String name; + private String type; + private String version; + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + public String getVersion() { + return version; + } + } +} diff --git a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonProjectFileParser.java b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonProjectFileParser.java new file mode 100644 index 0000000000..fb6ee1a7b3 --- /dev/null +++ b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonProjectFileParser.java @@ -0,0 +1,53 @@ +package com.blackduck.integration.detectable.detectables.meson.parse; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.blackduck.integration.util.NameVersion; +import com.google.gson.Gson; + +public class MesonProjectFileParser { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + public MesonProjectFileParser() { + } + + public NameVersion getProjectNameVersion(Gson gson, String jsonContents, String defaultProjectName, + String defaultProjectVersion) { + try { + MesonProjectInfo projectInfo = gson.fromJson(jsonContents, MesonProjectInfo.class); + + String projectName = defaultProjectName; + String projectVersion = defaultProjectVersion; + + if (StringUtils.isNotBlank(projectInfo.getDescriptiveName())) { + projectName = projectInfo.getDescriptiveName(); + logger.debug("Extracted project name: {}", projectName); + } + + if (StringUtils.isNotBlank(projectInfo.getVersion())) { + projectVersion = projectInfo.getVersion(); + logger.debug("Extracted project version: {}", projectVersion); + } + + return new NameVersion(projectName, projectVersion); + } catch (Exception e) { + logger.warn("Failed to parse Meson project JSON, using defaults", e); + return new NameVersion(defaultProjectName, defaultProjectVersion); + } + } + + private static class MesonProjectInfo { + private String version; + private String descriptive_name; + + public String getVersion() { + return version; + } + + public String getDescriptiveName() { + return descriptive_name; + } + } +} diff --git a/detectable/src/main/java/com/blackduck/integration/detectable/factory/DetectableFactory.java b/detectable/src/main/java/com/blackduck/integration/detectable/factory/DetectableFactory.java index 00b3eb96af..89b8b30618 100644 --- a/detectable/src/main/java/com/blackduck/integration/detectable/factory/DetectableFactory.java +++ b/detectable/src/main/java/com/blackduck/integration/detectable/factory/DetectableFactory.java @@ -176,6 +176,10 @@ import com.blackduck.integration.detectable.detectables.maven.cli.MavenPomDetectable; import com.blackduck.integration.detectable.detectables.maven.cli.MavenPomWrapperDetectable; import com.blackduck.integration.detectable.detectables.maven.parsing.MavenProjectInspectorDetectable; +import com.blackduck.integration.detectable.detectables.meson.MesonDetectable; +import com.blackduck.integration.detectable.detectables.meson.MesonExtractor; +import com.blackduck.integration.detectable.detectables.meson.parse.MesonDependencyFileParser; +import com.blackduck.integration.detectable.detectables.meson.parse.MesonProjectFileParser; import com.blackduck.integration.detectable.detectables.npm.cli.NpmCliDetectable; import com.blackduck.integration.detectable.detectables.npm.cli.NpmCliExtractor; import com.blackduck.integration.detectable.detectables.npm.cli.NpmCliExtractorOptions; @@ -396,6 +400,13 @@ public ClangDetectable createClangDetectable(DetectableEnvironment environment, ); } + public MesonDetectable createMesonDetectable(DetectableEnvironment environment) { + MesonProjectFileParser mesonProjectFileParser = new MesonProjectFileParser(); + MesonDependencyFileParser mesonDependencyFileParser = new MesonDependencyFileParser(externalIdFactory); + MesonExtractor mesonExtractor = new MesonExtractor(mesonProjectFileParser, mesonDependencyFileParser, fileFinder, gson); + return new MesonDetectable(environment, fileFinder, mesonExtractor); + } + public ComposerLockDetectable createComposerDetectable(DetectableEnvironment environment, ComposerLockDetectableOptions composerLockDetectableOptions) { PackagistParser packagistParser = new PackagistParser(externalIdFactory, composerLockDetectableOptions.getDependencyTypeFilter()); ComposerLockExtractor composerLockExtractor = new ComposerLockExtractor(packagistParser); diff --git a/detector/src/main/java/com/blackduck/integration/detector/base/DetectorType.java b/detector/src/main/java/com/blackduck/integration/detector/base/DetectorType.java index 9568e12023..7c67ba7fa3 100644 --- a/detector/src/main/java/com/blackduck/integration/detector/base/DetectorType.java +++ b/detector/src/main/java/com/blackduck/integration/detector/base/DetectorType.java @@ -26,6 +26,7 @@ public enum DetectorType { // TODO: 8.0.0 Rename DetectorTypes IVY, LERNA, MAVEN, + MESON, NPM, NUGET, // MSBUILD PACKAGIST, diff --git a/documentation/src/main/markdown/components/detectors.dita b/documentation/src/main/markdown/components/detectors.dita index 0eb1a5be98..276f3a7a96 100644 --- a/documentation/src/main/markdown/components/detectors.dita +++ b/documentation/src/main/markdown/components/detectors.dita @@ -562,6 +562,26 @@ LOW + + + MESON + + + + + + + + + + meson introspect + C++ + N/A + +

File: meson-info/intro-dependencies.json

+
+ HIGH +
NPM diff --git a/src/main/java/com/blackduck/integration/detect/configuration/enumeration/DetectGroup.java b/src/main/java/com/blackduck/integration/detect/configuration/enumeration/DetectGroup.java index c89d382045..653e60ead4 100644 --- a/src/main/java/com/blackduck/integration/detect/configuration/enumeration/DetectGroup.java +++ b/src/main/java/com/blackduck/integration/detect/configuration/enumeration/DetectGroup.java @@ -51,6 +51,7 @@ public enum DetectGroup implements Group { HEX("hex", DETECTORS), LERNA("lerna", DETECTORS), MAVEN("maven", DETECTORS), + MESON("meson", DETECTORS), NPM("npm", DETECTORS), NUGET("nuget", DETECTORS), PACKAGIST("packagist", DETECTORS), diff --git a/src/main/java/com/blackduck/integration/detect/tool/detector/DetectorRuleFactory.java b/src/main/java/com/blackduck/integration/detect/tool/detector/DetectorRuleFactory.java index d3b7b00741..9c0f29ac02 100644 --- a/src/main/java/com/blackduck/integration/detect/tool/detector/DetectorRuleFactory.java +++ b/src/main/java/com/blackduck/integration/detect/tool/detector/DetectorRuleFactory.java @@ -29,6 +29,7 @@ import com.blackduck.integration.detectable.detectables.lerna.LernaDetectable; import com.blackduck.integration.detectable.detectables.maven.cli.MavenPomDetectable; import com.blackduck.integration.detectable.detectables.maven.cli.MavenPomWrapperDetectable; +import com.blackduck.integration.detectable.detectables.meson.MesonDetectable; import com.blackduck.integration.detectable.detectables.maven.parsing.MavenProjectInspectorDetectable; import com.blackduck.integration.detectable.detectables.npm.cli.NpmCliDetectable; import com.blackduck.integration.detectable.detectables.npm.lockfile.NpmPackageLockDetectable; @@ -304,6 +305,11 @@ public DetectorRuleSet createRules(DetectDetectableFactory detectableFactory) { .search().defaults(); }); + rules.addDetector(DetectorType.MESON, detector -> { + detector.entryPoint(MesonDetectable.class) + .search().defaults(); + }); + rules.addDetector(DetectorType.OPAM, detector -> { detector.entryPoint(OpamBuildDetectable.class) .search().defaults(); diff --git a/src/main/java/com/blackduck/integration/detect/tool/detector/factory/DetectDetectableFactory.java b/src/main/java/com/blackduck/integration/detect/tool/detector/factory/DetectDetectableFactory.java index 4d10ebdc3d..01e52c360c 100644 --- a/src/main/java/com/blackduck/integration/detect/tool/detector/factory/DetectDetectableFactory.java +++ b/src/main/java/com/blackduck/integration/detect/tool/detector/factory/DetectDetectableFactory.java @@ -37,6 +37,7 @@ import com.blackduck.integration.detectable.detectables.ivy.IvyParseDetectable; import com.blackduck.integration.detectable.detectables.lerna.LernaDetectable; import com.blackduck.integration.detectable.detectables.maven.cli.MavenPomDetectable; +import com.blackduck.integration.detectable.detectables.meson.MesonDetectable; import com.blackduck.integration.detectable.detectables.maven.cli.MavenPomWrapperDetectable; import com.blackduck.integration.detectable.detectables.maven.parsing.MavenProjectInspectorDetectable; import com.blackduck.integration.detectable.detectables.npm.cli.NpmCliDetectable; @@ -137,6 +138,10 @@ public ClangDetectable createClangDetectable(DetectableEnvironment environment) return detectableFactory.createClangDetectable(environment, detectableOptionFactory.createClangDetectableOptions()); } + public MesonDetectable createMesonDetectable(DetectableEnvironment environment) { + return detectableFactory.createMesonDetectable(environment); + } + public ComposerLockDetectable createComposerDetectable(DetectableEnvironment environment) { return detectableFactory.createComposerDetectable(environment, detectableOptionFactory.createComposerLockDetectableOptions()); } From 49a0997cdeab2afa4c64e7035e0d20260add85a0 Mon Sep 17 00:00:00 2001 From: Jan Geertsma Date: Tue, 17 Feb 2026 17:01:38 +0200 Subject: [PATCH 2/4] Fixed to require the build introspects in addition to meson.build Added 2 unit tests for MesonDetectable, 1 functional test MesonDependencyFileParser Mockito the meson.build and introspect files Update dita name to match the detector name Use BufferedReader for the JSON files Use Generic as forge --- .../detectables/meson/MesonDetectable.java | 23 ++++++-- .../detectables/meson/MesonExtractor.java | 30 +++++----- .../parse/MesonDependencyFileParser.java | 31 +++++------ .../meson/parse/MesonProjectFileParser.java | 6 +- .../MesonDependencyFileParserTest.java | 55 +++++++++++++++++++ .../meson/unit/MesonDetectableTest.java | 44 +++++++++++++++ .../main/markdown/components/detectors.dita | 8 ++- 7 files changed, 158 insertions(+), 39 deletions(-) create mode 100644 detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/functional/MesonDependencyFileParserTest.java create mode 100644 detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/unit/MesonDetectableTest.java diff --git a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonDetectable.java b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonDetectable.java index a2198f28b8..75b2e5a39c 100644 --- a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonDetectable.java +++ b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonDetectable.java @@ -1,5 +1,9 @@ package com.blackduck.integration.detectable.detectables.meson; +import java.io.File; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.blackduck.integration.common.util.finder.FileFinder; import com.blackduck.integration.detectable.Detectable; import com.blackduck.integration.detectable.DetectableEnvironment; @@ -7,15 +11,18 @@ import com.blackduck.integration.detectable.detectable.Requirements; import com.blackduck.integration.detectable.detectable.annotation.DetectableInfo; import com.blackduck.integration.detectable.detectable.result.DetectableResult; +import com.blackduck.integration.detectable.detectable.result.FilesNotFoundDetectableResult; import com.blackduck.integration.detectable.detectable.result.PassedDetectableResult; import com.blackduck.integration.detectable.extraction.Extraction; import com.blackduck.integration.detectable.extraction.ExtractionEnvironment; -@DetectableInfo(name = "meson", language = "C/C++", forge = "N/A", accuracy = DetectableAccuracyType.HIGH, requirementsMarkdown = "File: meson.build") +@DetectableInfo(name = "Meson", language = "C/C++", forge = "Generic", accuracy = DetectableAccuracyType.HIGH, requirementsMarkdown = "File: meson.build") public class MesonDetectable extends Detectable { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); public static final String detectable_file = "meson.build"; - public static final String introspect_project = "intro-projectinfo.json"; - public static final String introspect_dependencies = "intro-dependencies.json"; + private static final String introspect_project = "intro-projectinfo.json"; + private static final String introspect_dependencies = "intro-dependencies.json"; + private final FileFinder fileFinder; private final MesonExtractor mesonExtractor; @@ -29,7 +36,15 @@ public MesonDetectable(DetectableEnvironment environment, FileFinder fileFinder, public DetectableResult applicable() { Requirements requirements = new Requirements(fileFinder, environment); requirements.file(detectable_file); - return requirements.result(); + File projectFile = fileFinder.findFile(environment.getDirectory(), introspect_project, false, 2); + logger.debug("found {}",projectFile); + File dependencyFile = fileFinder.findFile(environment.getDirectory(), introspect_dependencies, false, 2); + logger.debug("found {}",dependencyFile); + if (projectFile != null && dependencyFile != null) { + return requirements.result(); + } + logger.debug("even though {} is found, also a builddirectory with the introspect files is needed", detectable_file); + return new FilesNotFoundDetectableResult(); } @Override diff --git a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonExtractor.java b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonExtractor.java index a8a60bac41..2716b01683 100644 --- a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonExtractor.java +++ b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonExtractor.java @@ -1,5 +1,6 @@ package com.blackduck.integration.detectable.detectables.meson; +import java.io.BufferedReader; import java.io.File; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -46,6 +47,7 @@ public Extraction extract(File directory) { return new Extraction.Builder() .failure("Could not find " + introspect_project + " in any subdirectory").build(); } + NameVersion nameVersion = determineProjectNameVersion(projectFile.getAbsolutePath()); logger.debug("Found Meson project file: {}", projectFile.getAbsolutePath()); @@ -55,17 +57,18 @@ public Extraction extract(File directory) { return new Extraction.Builder() .failure("Could not find " + introspect_dependencies + " in any subdirectory").build(); } - String dependenciesJsonContents = Files.readString(dependencyFile.toPath(), StandardCharsets.UTF_8); - logger.trace("Dependencies JSON contents: {}", dependenciesJsonContents); - DependencyGraph dependencyGraph = mesonDependencyFileParser.parseProjectDependencies(gson, dependenciesJsonContents); - CodeLocation codeLocation = new CodeLocation(dependencyGraph); - logger.debug("Found Meson dependency file: {}", dependencyFile.getAbsolutePath()); + try (BufferedReader reader = Files.newBufferedReader(dependencyFile.toPath(), StandardCharsets.UTF_8)) { + DependencyGraph dependencyGraph = mesonDependencyFileParser.parseProjectDependencies(gson, reader); + logger.debug("Found Meson dependency file: {}", dependencyFile.getAbsolutePath()); + CodeLocation codeLocation = new CodeLocation(dependencyGraph); + + return new Extraction.Builder() + .success(codeLocation) + .projectName(nameVersion.getName()) + .projectVersion(nameVersion.getVersion()) + .build(); + } - return new Extraction.Builder() - .success(codeLocation) - .projectName(nameVersion.getName()) - .projectVersion(nameVersion.getVersion()) - .build(); } catch (Exception e) { logger.error("Failed to extract Meson dependencies", e); return new Extraction.Builder().exception(e).build(); @@ -79,9 +82,10 @@ private NameVersion determineProjectNameVersion(String projectFilePath) { try { File projectInfoFile = new File(projectFilePath); if (projectInfoFile != null) { - String projectJsonContents = Files.readString(projectInfoFile.toPath()); - logger.debug("Found Meson project info file: {}", projectInfoFile.getAbsolutePath()); - return mesonProjectFileParser.getProjectNameVersion(gson, projectJsonContents, defaultProjectName, defaultProjectVersion); + try (BufferedReader reader = Files.newBufferedReader(projectInfoFile.toPath(), StandardCharsets.UTF_8)) { + logger.debug("Found Meson project info file: {}", projectInfoFile.getAbsolutePath()); + return mesonProjectFileParser.getProjectNameVersion(gson, reader, defaultProjectName, defaultProjectVersion); + } } } catch (Exception e) { logger.warn("Failed to parse Meson introspect, using defaults", e); diff --git a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonDependencyFileParser.java b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonDependencyFileParser.java index b165c02b68..c17f6544d1 100644 --- a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonDependencyFileParser.java +++ b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonDependencyFileParser.java @@ -1,5 +1,7 @@ package com.blackduck.integration.detectable.detectables.meson.parse; +import java.io.BufferedReader; + import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,6 +15,8 @@ import com.google.gson.Gson; public class MesonDependencyFileParser { + private static final Forge GENERIC_FORGE = new Forge("/", "Generic"); + private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final ExternalIdFactory externalIdFactory; @@ -20,17 +24,11 @@ public MesonDependencyFileParser(ExternalIdFactory externalIdFactory) { this.externalIdFactory = externalIdFactory; } - public DependencyGraph parseProjectDependencies(Gson gson, String jsonContents) { + public DependencyGraph parseProjectDependencies(Gson gson, BufferedReader reader) { DependencyGraph graph = new BasicDependencyGraph(); try { - if (jsonContents == null || jsonContents.trim().isEmpty()) { - logger.warn("Empty or null JSON contents for Meson dependencies"); - return graph; - } - - logger.trace("Parsing Meson dependencies JSON (length: {})", jsonContents.length()); - MesonDependency[] dependencies = gson.fromJson(jsonContents, MesonDependency[].class); + MesonDependency[] dependencies = gson.fromJson(reader, MesonDependency[].class); if (dependencies == null) { logger.warn("Failed to parse Meson dependencies - gson returned null"); @@ -44,18 +42,16 @@ public DependencyGraph parseProjectDependencies(Gson gson, String jsonContents) && StringUtils.isNotBlank(dep.getName()) && StringUtils.isNotBlank(dep.getVersion())) { - //TODO: What is a forge in this instance? - //TODO: What is a scope? - ExternalId dependencyExternalId = externalIdFactory.createNameVersionExternalId( - Forge.GITLAB , - dep.getName(), - dep.getVersion()); - Dependency dependency = new Dependency(dep.getName(), dep.getVersion(), dependencyExternalId, null); + // https://github.com/blackducksoftware/bdio/blob/master/bdio2/src/main/java/com/blackducksoftware/bdio2/Bdio.java#L570 + // https://github.com/blackducksoftware/integration-bdio/blob/master/src/main/java/com/blackduck/integration/bdio/model/Forge.java + // Create ExternalId with generic forge to produce format: pkg:generic/boost@1.83.0 + ExternalId dependencyExternalId = externalIdFactory.createNameVersionExternalId(GENERIC_FORGE, dep.getName(), dep.getVersion()); + dependencyExternalId.createBdioId(); + Dependency dependency = new Dependency(dep.getName(), dep.getVersion(), dependencyExternalId, ""); logger.trace("Adding dependency: {}", dependency.getExternalId().toString()); graph.addDirectDependency(dependency); } else { - logger.debug("Skipping dependency - name: '{}', type: '{}', version: '{}'", - dep.getName(), dep.getType(), dep.getVersion()); + logger.debug("Skipping dependency - name: '{}', type: '{}', version: '{}'", dep.getName(), dep.getType(), dep.getVersion()); } } } catch (Exception e) { @@ -65,6 +61,7 @@ public DependencyGraph parseProjectDependencies(Gson gson, String jsonContents) return graph; } + // Could have extended com.blackduck.integration.util.NameVersion with a type field private static class MesonDependency { private String name; private String type; diff --git a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonProjectFileParser.java b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonProjectFileParser.java index fb6ee1a7b3..3d66d17561 100644 --- a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonProjectFileParser.java +++ b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonProjectFileParser.java @@ -1,5 +1,7 @@ package com.blackduck.integration.detectable.detectables.meson.parse; +import java.io.BufferedReader; + import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,10 +15,10 @@ public class MesonProjectFileParser { public MesonProjectFileParser() { } - public NameVersion getProjectNameVersion(Gson gson, String jsonContents, String defaultProjectName, + public NameVersion getProjectNameVersion(Gson gson, BufferedReader reader, String defaultProjectName, String defaultProjectVersion) { try { - MesonProjectInfo projectInfo = gson.fromJson(jsonContents, MesonProjectInfo.class); + MesonProjectInfo projectInfo = gson.fromJson(reader, MesonProjectInfo.class); String projectName = defaultProjectName; String projectVersion = defaultProjectVersion; diff --git a/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/functional/MesonDependencyFileParserTest.java b/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/functional/MesonDependencyFileParserTest.java new file mode 100644 index 0000000000..a777c1dd5d --- /dev/null +++ b/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/functional/MesonDependencyFileParserTest.java @@ -0,0 +1,55 @@ +package com.blackduck.integration.detectable.detectables.meson.functional; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Assertions; + +import com.blackduck.integration.bdio.model.Forge; +import com.blackduck.integration.detectable.Detectable; +import com.blackduck.integration.detectable.DetectableEnvironment; +import com.blackduck.integration.detectable.extraction.Extraction; +import com.blackduck.integration.detectable.functional.DetectableFunctionalTest; +import com.blackduck.integration.detectable.util.graph.NameVersionGraphAssert; + +public class MesonDependencyFileParserTest extends DetectableFunctionalTest { + public MesonDependencyFileParserTest() throws IOException { + super("meson"); + } + + @Override + protected void setup() throws IOException { + Path root = addDirectory(Paths.get(".")); + Path builddir = addDirectory(Paths.get("builddir/meson-info")); + addFile( + root.resolve("meson.build"), + "project('hello','cpp',default_options: ['cpp_std=c++20', 'default_library=shared'],version : '0.1',)", + "deps = [dependency('boost'),dependency('libcurl'),]", + "exe = executable('hello', 'hello.cpp', install : true)" + ); + addFile( + builddir.resolve("intro-projectinfo.json"), + "{\"version\": \"0.1\", \"descriptive_name\": \"hello\", \"subproject_dir\": \"subprojects\", \"subprojects\": []}" + ); + addFile(builddir.resolve("intro-dependencies.json"), + "[{\"name\": \"boost\", \"type\": \"system\", \"version\": \"1.83.0\", \"compile_args\": [\"-I/usr/include\", \"-DBOOST_ALL_NO_LIB\"], \"link_args\": [], \"include_directories\": [], \"sources\": [], \"extra_files\": [], \"dependencies\": [], \"depends\": [], \"meson_variables\": []}, {\"name\": \"libcurl\", \"type\": \"pkgconfig\", \"version\": \"8.5.0\", \"compile_args\": [\"-I/usr/include/x86_64-linux-gnu\"], \"link_args\": [\"/usr/lib/x86_64-linux-gnu/libcurl.so\"], \"include_directories\": [], \"sources\": [], \"extra_files\": [], \"dependencies\": [], \"depends\": [], \"meson_variables\": []}]" + ); + } + + @NotNull + @Override + public Detectable create(@NotNull DetectableEnvironment detectableEnvironment) { + return detectableFactory.createMesonDetectable(detectableEnvironment); + } + + @Override + public void assertExtraction(@NotNull Extraction extraction) { + Assertions.assertEquals(1, extraction.getCodeLocations().size()); + NameVersionGraphAssert graphAssert = new NameVersionGraphAssert(new Forge("/", "Generic"), extraction.getCodeLocations().get(0).getDependencyGraph()); + graphAssert.hasRootSize(2); + graphAssert.hasRootDependency("boost", "1.83.0"); + graphAssert.hasRootDependency("libcurl", "8.5.0"); + } +} diff --git a/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/unit/MesonDetectableTest.java b/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/unit/MesonDetectableTest.java new file mode 100644 index 0000000000..8a6e0ae67a --- /dev/null +++ b/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/unit/MesonDetectableTest.java @@ -0,0 +1,44 @@ +package com.blackduck.integration.detectable.detectables.meson.unit; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; + +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import com.blackduck.integration.common.util.finder.FileFinder; +import com.blackduck.integration.detectable.DetectableEnvironment; +import com.blackduck.integration.detectable.detectables.meson.MesonDetectable; +import com.blackduck.integration.detectable.detectables.meson.MesonExtractor; +import com.blackduck.integration.detectable.util.MockDetectableEnvironment; + +public class MesonDetectableTest { + + @Test + public void testApplicable() { + DetectableEnvironment environment = MockDetectableEnvironment.empty(); + File envDir = environment.getDirectory(); + + FileFinder fileFinder = Mockito.mock(FileFinder.class); + Mockito.when(fileFinder.findFile(envDir, "meson.build")).thenReturn(new File("meson.build")); + Mockito.when(fileFinder.findFile(envDir, "intro-projectinfo.json", false, 2)).thenReturn(new File("builddir/meson-info/intro-projectinfo.json")); + Mockito.when(fileFinder.findFile(envDir, "intro-dependencies.json", false, 2)).thenReturn(new File("builddir/meson-info/intro-dependencies.json")); + MesonExtractor mesonExtractor = new MesonExtractor(null, null, fileFinder, null); + MesonDetectable detectable = new MesonDetectable(environment, fileFinder, mesonExtractor); + + assertTrue(detectable.applicable().getPassed()); + } + + @Test + public void testNotApplicable() { + DetectableEnvironment environment = MockDetectableEnvironment.empty(); + FileFinder fileFinder = Mockito.mock(FileFinder.class); + File envDir = environment.getDirectory(); + Mockito.when(fileFinder.findFile(envDir, "meson.build", true, 0)).thenReturn(new File("meson.build")); + MesonExtractor mesonExtractor = new MesonExtractor(null, null, fileFinder, null); + MesonDetectable detectable = new MesonDetectable(environment, fileFinder, mesonExtractor); + + assertTrue(!detectable.applicable().getPassed()); + } +} diff --git a/documentation/src/main/markdown/components/detectors.dita b/documentation/src/main/markdown/components/detectors.dita index 276f3a7a96..ecd4f2063e 100644 --- a/documentation/src/main/markdown/components/detectors.dita +++ b/documentation/src/main/markdown/components/detectors.dita @@ -574,11 +574,13 @@ - meson introspect + Meson C++ - N/A + Generic -

File: meson-info/intro-dependencies.json

+

File: meson.build

+

File: */meson-info/intro-project.json

+

File: */meson-info/intro-dependencies.json

HIGH
From 54060da2d1477e1811cba29d059f62a16967e25c Mon Sep 17 00:00:00 2001 From: zahidblackduck Date: Fri, 3 Apr 2026 20:13:16 +0600 Subject: [PATCH 3/4] Refactor Meson extractor to use project info and dependencies files directly --- .../detectables/meson/MesonDetectable.java | 34 +++++++------- .../detectables/meson/MesonExtractor.java | 44 ++++--------------- .../parse/MesonDependencyFileParser.java | 23 ++++------ .../detectable/factory/DetectableFactory.java | 2 +- .../MesonDependencyFileParserTest.java | 4 +- .../meson/unit/MesonDetectableTest.java | 7 +-- 6 files changed, 43 insertions(+), 71 deletions(-) diff --git a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonDetectable.java b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonDetectable.java index 75b2e5a39c..e85e2f2d67 100644 --- a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonDetectable.java +++ b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonDetectable.java @@ -1,8 +1,6 @@ package com.blackduck.integration.detectable.detectables.meson; import java.io.File; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.blackduck.integration.common.util.finder.FileFinder; import com.blackduck.integration.detectable.Detectable; @@ -16,16 +14,18 @@ import com.blackduck.integration.detectable.extraction.Extraction; import com.blackduck.integration.detectable.extraction.ExtractionEnvironment; -@DetectableInfo(name = "Meson", language = "C/C++", forge = "Generic", accuracy = DetectableAccuracyType.HIGH, requirementsMarkdown = "File: meson.build") +@DetectableInfo(name = "Meson", language = "C/C++", forge = "conan", accuracy = DetectableAccuracyType.HIGH, requirementsMarkdown = "Files: meson.build, intro-projectinfo.json, intro-dependencies.json") public class MesonDetectable extends Detectable { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public static final String detectable_file = "meson.build"; - private static final String introspect_project = "intro-projectinfo.json"; - private static final String introspect_dependencies = "intro-dependencies.json"; + public static final String MESON_BUILD_FILENAME = "meson.build"; + private static final String INTROSPECT_PROJECT_FILENAME = "intro-projectinfo.json"; + private static final String INTROSPECT_DEPENDENCIES_FILENAME = "intro-dependencies.json"; private final FileFinder fileFinder; private final MesonExtractor mesonExtractor; + private File projectInfoFile; + private File dependenciesFile; + public MesonDetectable(DetectableEnvironment environment, FileFinder fileFinder, MesonExtractor mesonExtractor) { super(environment); this.fileFinder = fileFinder; @@ -35,16 +35,18 @@ public MesonDetectable(DetectableEnvironment environment, FileFinder fileFinder, @Override public DetectableResult applicable() { Requirements requirements = new Requirements(fileFinder, environment); - requirements.file(detectable_file); - File projectFile = fileFinder.findFile(environment.getDirectory(), introspect_project, false, 2); - logger.debug("found {}",projectFile); - File dependencyFile = fileFinder.findFile(environment.getDirectory(), introspect_dependencies, false, 2); - logger.debug("found {}",dependencyFile); - if (projectFile != null && dependencyFile != null) { + requirements.file(MESON_BUILD_FILENAME); + if (requirements.isAlreadyFailed()) { return requirements.result(); } - logger.debug("even though {} is found, also a builddirectory with the introspect files is needed", detectable_file); - return new FilesNotFoundDetectableResult(); + projectInfoFile = fileFinder.findFile(environment.getDirectory(), INTROSPECT_PROJECT_FILENAME, false, 2); + dependenciesFile = fileFinder.findFile(environment.getDirectory(), INTROSPECT_DEPENDENCIES_FILENAME, false, 2); + if (projectInfoFile == null || dependenciesFile == null) { + return new FilesNotFoundDetectableResult(INTROSPECT_PROJECT_FILENAME, INTROSPECT_DEPENDENCIES_FILENAME); + } + requirements.explainFile(projectInfoFile); + requirements.explainFile(dependenciesFile); + return requirements.result(); } @Override @@ -54,6 +56,6 @@ public DetectableResult extractable() { @Override public Extraction extract(ExtractionEnvironment extractionEnvironment) { - return mesonExtractor.extract(environment.getDirectory()); + return mesonExtractor.extract(projectInfoFile, dependenciesFile); } } diff --git a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonExtractor.java b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonExtractor.java index 2716b01683..a3b0821d33 100644 --- a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonExtractor.java +++ b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonExtractor.java @@ -9,7 +9,6 @@ import org.slf4j.LoggerFactory; import com.blackduck.integration.bdio.graph.DependencyGraph; -import com.blackduck.integration.common.util.finder.FileFinder; import com.blackduck.integration.detectable.detectable.codelocation.CodeLocation; import com.blackduck.integration.detectable.detectables.meson.parse.MesonDependencyFileParser; import com.blackduck.integration.detectable.detectables.meson.parse.MesonProjectFileParser; @@ -21,47 +20,28 @@ public class MesonExtractor { private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final MesonProjectFileParser mesonProjectFileParser; private final MesonDependencyFileParser mesonDependencyFileParser; - private final FileFinder fileFinder; private final Gson gson; - private static final String introspect_project = "intro-projectinfo.json"; - private static final String introspect_dependencies = "intro-dependencies.json"; - public MesonExtractor( MesonProjectFileParser mesonProjectFileParser, MesonDependencyFileParser mesonDependencyFileParser, - FileFinder fileFinder, Gson gson ) { this.mesonProjectFileParser = mesonProjectFileParser; this.mesonDependencyFileParser = mesonDependencyFileParser; - this.fileFinder = fileFinder; this.gson = gson; } - public Extraction extract(File directory) { + public Extraction extract(File projectInfoFile, File dependenciesFile) { try { - // Find the intro-projectinfo.json file in subdirectories - File projectFile = fileFinder.findFile(directory, introspect_project, false, 2); - if (projectFile == null) { - return new Extraction.Builder() - .failure("Could not find " + introspect_project + " in any subdirectory").build(); - } + logger.debug("Parsing Meson project info: {}", projectInfoFile.getAbsolutePath()); + NameVersion nameVersion = determineProjectNameVersion(projectInfoFile); - NameVersion nameVersion = determineProjectNameVersion(projectFile.getAbsolutePath()); - logger.debug("Found Meson project file: {}", projectFile.getAbsolutePath()); - - // Parse dependencies from intro-dependencies.json - File dependencyFile = fileFinder.findFile(directory, introspect_dependencies, false, 2); - if (dependencyFile == null) { - return new Extraction.Builder() - .failure("Could not find " + introspect_dependencies + " in any subdirectory").build(); - } - try (BufferedReader reader = Files.newBufferedReader(dependencyFile.toPath(), StandardCharsets.UTF_8)) { + logger.debug("Parsing Meson dependencies: {}", dependenciesFile.getAbsolutePath()); + try (BufferedReader reader = Files.newBufferedReader(dependenciesFile.toPath(), StandardCharsets.UTF_8)) { DependencyGraph dependencyGraph = mesonDependencyFileParser.parseProjectDependencies(gson, reader); - logger.debug("Found Meson dependency file: {}", dependencyFile.getAbsolutePath()); CodeLocation codeLocation = new CodeLocation(dependencyGraph); - + return new Extraction.Builder() .success(codeLocation) .projectName(nameVersion.getName()) @@ -75,18 +55,12 @@ public Extraction extract(File directory) { } } - private NameVersion determineProjectNameVersion(String projectFilePath) { + private NameVersion determineProjectNameVersion(File projectInfoFile) { final String defaultProjectName = ""; final String defaultProjectVersion = ""; - try { - File projectInfoFile = new File(projectFilePath); - if (projectInfoFile != null) { - try (BufferedReader reader = Files.newBufferedReader(projectInfoFile.toPath(), StandardCharsets.UTF_8)) { - logger.debug("Found Meson project info file: {}", projectInfoFile.getAbsolutePath()); - return mesonProjectFileParser.getProjectNameVersion(gson, reader, defaultProjectName, defaultProjectVersion); - } - } + try (BufferedReader reader = Files.newBufferedReader(projectInfoFile.toPath(), StandardCharsets.UTF_8)) { + return mesonProjectFileParser.getProjectNameVersion(gson, reader, defaultProjectName, defaultProjectVersion); } catch (Exception e) { logger.warn("Failed to parse Meson introspect, using defaults", e); } diff --git a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonDependencyFileParser.java b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonDependencyFileParser.java index c17f6544d1..48b91e04a5 100644 --- a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonDependencyFileParser.java +++ b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonDependencyFileParser.java @@ -8,15 +8,15 @@ import com.blackduck.integration.bdio.graph.BasicDependencyGraph; import com.blackduck.integration.bdio.graph.DependencyGraph; -import com.blackduck.integration.bdio.model.Forge; import com.blackduck.integration.bdio.model.dependency.Dependency; import com.blackduck.integration.bdio.model.externalid.ExternalId; import com.blackduck.integration.bdio.model.externalid.ExternalIdFactory; +import com.blackduck.integration.detectable.detectables.conan.Constants; import com.google.gson.Gson; public class MesonDependencyFileParser { - private static final Forge GENERIC_FORGE = new Forge("/", "Generic"); - + private static final String INTERNAL_DEPENDENCY_TYPE = "internal"; + private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final ExternalIdFactory externalIdFactory; @@ -29,26 +29,22 @@ public DependencyGraph parseProjectDependencies(Gson gson, BufferedReader reader try { MesonDependency[] dependencies = gson.fromJson(reader, MesonDependency[].class); - + if (dependencies == null) { logger.warn("Failed to parse Meson dependencies - gson returned null"); return graph; } - + logger.debug("Found {} Meson dependencies", dependencies.length); for (MesonDependency dep : dependencies) { - if (!"internal".equals(dep.getType()) + if (!INTERNAL_DEPENDENCY_TYPE.equals(dep.getType()) && StringUtils.isNotBlank(dep.getName()) && StringUtils.isNotBlank(dep.getVersion())) { - // https://github.com/blackducksoftware/bdio/blob/master/bdio2/src/main/java/com/blackducksoftware/bdio2/Bdio.java#L570 - // https://github.com/blackducksoftware/integration-bdio/blob/master/src/main/java/com/blackduck/integration/bdio/model/Forge.java - // Create ExternalId with generic forge to produce format: pkg:generic/boost@1.83.0 - ExternalId dependencyExternalId = externalIdFactory.createNameVersionExternalId(GENERIC_FORGE, dep.getName(), dep.getVersion()); - dependencyExternalId.createBdioId(); - Dependency dependency = new Dependency(dep.getName(), dep.getVersion(), dependencyExternalId, ""); - logger.trace("Adding dependency: {}", dependency.getExternalId().toString()); + ExternalId dependencyExternalId = externalIdFactory.createNameVersionExternalId(Constants.conanForge, dep.getName(), dep.getVersion()); + Dependency dependency = new Dependency(dep.getName(), dep.getVersion(), dependencyExternalId); + logger.trace("Adding dependency: {}", dependency.getExternalId()); graph.addDirectDependency(dependency); } else { logger.debug("Skipping dependency - name: '{}', type: '{}', version: '{}'", dep.getName(), dep.getType(), dep.getVersion()); @@ -61,7 +57,6 @@ public DependencyGraph parseProjectDependencies(Gson gson, BufferedReader reader return graph; } - // Could have extended com.blackduck.integration.util.NameVersion with a type field private static class MesonDependency { private String name; private String type; diff --git a/detectable/src/main/java/com/blackduck/integration/detectable/factory/DetectableFactory.java b/detectable/src/main/java/com/blackduck/integration/detectable/factory/DetectableFactory.java index 89b8b30618..e698052be0 100644 --- a/detectable/src/main/java/com/blackduck/integration/detectable/factory/DetectableFactory.java +++ b/detectable/src/main/java/com/blackduck/integration/detectable/factory/DetectableFactory.java @@ -403,7 +403,7 @@ public ClangDetectable createClangDetectable(DetectableEnvironment environment, public MesonDetectable createMesonDetectable(DetectableEnvironment environment) { MesonProjectFileParser mesonProjectFileParser = new MesonProjectFileParser(); MesonDependencyFileParser mesonDependencyFileParser = new MesonDependencyFileParser(externalIdFactory); - MesonExtractor mesonExtractor = new MesonExtractor(mesonProjectFileParser, mesonDependencyFileParser, fileFinder, gson); + MesonExtractor mesonExtractor = new MesonExtractor(mesonProjectFileParser, mesonDependencyFileParser, gson); return new MesonDetectable(environment, fileFinder, mesonExtractor); } diff --git a/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/functional/MesonDependencyFileParserTest.java b/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/functional/MesonDependencyFileParserTest.java index a777c1dd5d..bfa0ad6e0c 100644 --- a/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/functional/MesonDependencyFileParserTest.java +++ b/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/functional/MesonDependencyFileParserTest.java @@ -7,10 +7,10 @@ import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Assertions; -import com.blackduck.integration.bdio.model.Forge; import com.blackduck.integration.detectable.Detectable; import com.blackduck.integration.detectable.DetectableEnvironment; import com.blackduck.integration.detectable.extraction.Extraction; +import com.blackduck.integration.detectable.detectables.conan.Constants; import com.blackduck.integration.detectable.functional.DetectableFunctionalTest; import com.blackduck.integration.detectable.util.graph.NameVersionGraphAssert; @@ -47,7 +47,7 @@ public Detectable create(@NotNull DetectableEnvironment detectableEnvironment) { @Override public void assertExtraction(@NotNull Extraction extraction) { Assertions.assertEquals(1, extraction.getCodeLocations().size()); - NameVersionGraphAssert graphAssert = new NameVersionGraphAssert(new Forge("/", "Generic"), extraction.getCodeLocations().get(0).getDependencyGraph()); + NameVersionGraphAssert graphAssert = new NameVersionGraphAssert(Constants.conanForge, extraction.getCodeLocations().get(0).getDependencyGraph()); graphAssert.hasRootSize(2); graphAssert.hasRootDependency("boost", "1.83.0"); graphAssert.hasRootDependency("libcurl", "8.5.0"); diff --git a/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/unit/MesonDetectableTest.java b/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/unit/MesonDetectableTest.java index 8a6e0ae67a..3c7793bcfa 100644 --- a/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/unit/MesonDetectableTest.java +++ b/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/unit/MesonDetectableTest.java @@ -1,5 +1,6 @@ package com.blackduck.integration.detectable.detectables.meson.unit; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; @@ -24,7 +25,7 @@ public void testApplicable() { Mockito.when(fileFinder.findFile(envDir, "meson.build")).thenReturn(new File("meson.build")); Mockito.when(fileFinder.findFile(envDir, "intro-projectinfo.json", false, 2)).thenReturn(new File("builddir/meson-info/intro-projectinfo.json")); Mockito.when(fileFinder.findFile(envDir, "intro-dependencies.json", false, 2)).thenReturn(new File("builddir/meson-info/intro-dependencies.json")); - MesonExtractor mesonExtractor = new MesonExtractor(null, null, fileFinder, null); + MesonExtractor mesonExtractor = new MesonExtractor(null, null, null); MesonDetectable detectable = new MesonDetectable(environment, fileFinder, mesonExtractor); assertTrue(detectable.applicable().getPassed()); @@ -36,9 +37,9 @@ public void testNotApplicable() { FileFinder fileFinder = Mockito.mock(FileFinder.class); File envDir = environment.getDirectory(); Mockito.when(fileFinder.findFile(envDir, "meson.build", true, 0)).thenReturn(new File("meson.build")); - MesonExtractor mesonExtractor = new MesonExtractor(null, null, fileFinder, null); + MesonExtractor mesonExtractor = new MesonExtractor(null, null, null); MesonDetectable detectable = new MesonDetectable(environment, fileFinder, mesonExtractor); - assertTrue(!detectable.applicable().getPassed()); + assertFalse(detectable.applicable().getPassed()); } } From 962214442905d674eddb81141abde8f46df1ce28 Mon Sep 17 00:00:00 2001 From: zahidblackduck Date: Mon, 6 Apr 2026 16:47:16 +0600 Subject: [PATCH 4/4] add meson forge constant --- .../detectable/detectables/meson/MesonConstants.java | 7 +++++++ .../detectable/detectables/meson/MesonDetectable.java | 2 +- .../detectables/meson/parse/MesonDependencyFileParser.java | 4 ++-- .../meson/functional/MesonDependencyFileParserTest.java | 4 ++-- 4 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonConstants.java diff --git a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonConstants.java b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonConstants.java new file mode 100644 index 0000000000..5db78ae74c --- /dev/null +++ b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonConstants.java @@ -0,0 +1,7 @@ +package com.blackduck.integration.detectable.detectables.meson; + +import com.blackduck.integration.bdio.model.Forge; + +public class MesonConstants { + public static final Forge MESON_FORGE = new Forge("/", "meson"); +} diff --git a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonDetectable.java b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonDetectable.java index e85e2f2d67..3d150101d3 100644 --- a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonDetectable.java +++ b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/MesonDetectable.java @@ -14,7 +14,7 @@ import com.blackduck.integration.detectable.extraction.Extraction; import com.blackduck.integration.detectable.extraction.ExtractionEnvironment; -@DetectableInfo(name = "Meson", language = "C/C++", forge = "conan", accuracy = DetectableAccuracyType.HIGH, requirementsMarkdown = "Files: meson.build, intro-projectinfo.json, intro-dependencies.json") +@DetectableInfo(name = "Meson", language = "C/C++", forge = "meson", accuracy = DetectableAccuracyType.HIGH, requirementsMarkdown = "Files: meson.build, intro-projectinfo.json, intro-dependencies.json") public class MesonDetectable extends Detectable { public static final String MESON_BUILD_FILENAME = "meson.build"; private static final String INTROSPECT_PROJECT_FILENAME = "intro-projectinfo.json"; diff --git a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonDependencyFileParser.java b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonDependencyFileParser.java index 48b91e04a5..8e29aba789 100644 --- a/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonDependencyFileParser.java +++ b/detectable/src/main/java/com/blackduck/integration/detectable/detectables/meson/parse/MesonDependencyFileParser.java @@ -11,7 +11,7 @@ import com.blackduck.integration.bdio.model.dependency.Dependency; import com.blackduck.integration.bdio.model.externalid.ExternalId; import com.blackduck.integration.bdio.model.externalid.ExternalIdFactory; -import com.blackduck.integration.detectable.detectables.conan.Constants; +import com.blackduck.integration.detectable.detectables.meson.MesonConstants; import com.google.gson.Gson; public class MesonDependencyFileParser { @@ -42,7 +42,7 @@ public DependencyGraph parseProjectDependencies(Gson gson, BufferedReader reader && StringUtils.isNotBlank(dep.getName()) && StringUtils.isNotBlank(dep.getVersion())) { - ExternalId dependencyExternalId = externalIdFactory.createNameVersionExternalId(Constants.conanForge, dep.getName(), dep.getVersion()); + ExternalId dependencyExternalId = externalIdFactory.createNameVersionExternalId(MesonConstants.MESON_FORGE, dep.getName(), dep.getVersion()); Dependency dependency = new Dependency(dep.getName(), dep.getVersion(), dependencyExternalId); logger.trace("Adding dependency: {}", dependency.getExternalId()); graph.addDirectDependency(dependency); diff --git a/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/functional/MesonDependencyFileParserTest.java b/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/functional/MesonDependencyFileParserTest.java index bfa0ad6e0c..6f3d4db1bb 100644 --- a/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/functional/MesonDependencyFileParserTest.java +++ b/detectable/src/test/java/com/blackduck/integration/detectable/detectables/meson/functional/MesonDependencyFileParserTest.java @@ -10,7 +10,7 @@ import com.blackduck.integration.detectable.Detectable; import com.blackduck.integration.detectable.DetectableEnvironment; import com.blackduck.integration.detectable.extraction.Extraction; -import com.blackduck.integration.detectable.detectables.conan.Constants; +import com.blackduck.integration.detectable.detectables.meson.MesonConstants; import com.blackduck.integration.detectable.functional.DetectableFunctionalTest; import com.blackduck.integration.detectable.util.graph.NameVersionGraphAssert; @@ -47,7 +47,7 @@ public Detectable create(@NotNull DetectableEnvironment detectableEnvironment) { @Override public void assertExtraction(@NotNull Extraction extraction) { Assertions.assertEquals(1, extraction.getCodeLocations().size()); - NameVersionGraphAssert graphAssert = new NameVersionGraphAssert(Constants.conanForge, extraction.getCodeLocations().get(0).getDependencyGraph()); + NameVersionGraphAssert graphAssert = new NameVersionGraphAssert(MesonConstants.MESON_FORGE, extraction.getCodeLocations().get(0).getDependencyGraph()); graphAssert.hasRootSize(2); graphAssert.hasRootDependency("boost", "1.83.0"); graphAssert.hasRootDependency("libcurl", "8.5.0");