com.blackducksoftware.integration.hub.detect.detector.packagist.PackagistParser.java Source code

Java tutorial

Introduction

Here is the source code for com.blackducksoftware.integration.hub.detect.detector.packagist.PackagistParser.java

Source

/**
 * hub-detect
 *
 * Copyright (C) 2019 Black Duck Software, Inc.
 * http://www.blackducksoftware.com/
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package com.blackducksoftware.integration.hub.detect.detector.packagist;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.blackducksoftware.integration.hub.detect.configuration.DetectConfiguration;
import com.blackducksoftware.integration.hub.detect.configuration.DetectProperty;
import com.blackducksoftware.integration.hub.detect.configuration.PropertyAuthority;
import com.blackducksoftware.integration.hub.detect.workflow.codelocation.DetectCodeLocation;
import com.blackducksoftware.integration.hub.detect.workflow.codelocation.DetectCodeLocationType;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.synopsys.integration.bdio.graph.DependencyGraph;
import com.synopsys.integration.bdio.graph.builder.LazyExternalIdDependencyGraphBuilder;
import com.synopsys.integration.bdio.model.Forge;
import com.synopsys.integration.bdio.model.dependencyid.NameDependencyId;
import com.synopsys.integration.bdio.model.externalid.ExternalId;
import com.synopsys.integration.bdio.model.externalid.ExternalIdFactory;
import com.synopsys.integration.util.NameVersion;

public class PackagistParser {
    private final Logger logger = LoggerFactory.getLogger(PackagistParser.class);

    private final ExternalIdFactory externalIdFactory;
    private final DetectConfiguration detectConfiguration;

    public PackagistParser(final ExternalIdFactory externalIdFactory,
            final DetectConfiguration detectConfiguration) {
        this.externalIdFactory = externalIdFactory;
        this.detectConfiguration = detectConfiguration;
    }

    public PackagistParseResult getDependencyGraphFromProject(final String sourcePath,
            final String composerJsonText, final String composerLockText) {
        final LazyExternalIdDependencyGraphBuilder builder = new LazyExternalIdDependencyGraphBuilder();

        final JsonObject composerJsonObject = new JsonParser().parse(composerJsonText).getAsJsonObject();
        final NameVersion projectNameVersion = parseNameVersionFromJson(composerJsonObject);

        final JsonObject composerLockObject = new JsonParser().parse(composerLockText).getAsJsonObject();
        final List<PackagistPackage> models = convertJsonToModel(composerLockObject,
                detectConfiguration.getBooleanProperty(DetectProperty.DETECT_PACKAGIST_INCLUDE_DEV_DEPENDENCIES,
                        PropertyAuthority.None));
        final List<NameVersion> rootPackages = parseDependencies(composerJsonObject,
                detectConfiguration.getBooleanProperty(DetectProperty.DETECT_PACKAGIST_INCLUDE_DEV_DEPENDENCIES,
                        PropertyAuthority.None));

        models.forEach(it -> {
            final ExternalId id = externalIdFactory.createNameVersionExternalId(Forge.PACKAGIST,
                    it.getNameVersion().getName(), it.getNameVersion().getVersion());
            final NameDependencyId dependencyId = new NameDependencyId(it.getNameVersion().getName());
            builder.setDependencyInfo(dependencyId, it.getNameVersion().getName(), it.getNameVersion().getVersion(),
                    id);
            if (isRootPackage(it.getNameVersion(), rootPackages)) {
                builder.addChildToRoot(dependencyId);
            }
            it.getDependencies().forEach(child -> {
                if (existsInPackages(child, models)) {
                    final NameDependencyId childId = new NameDependencyId(child.getName());
                    builder.addChildWithParent(childId, dependencyId);
                } else {
                    logger.warn("Dependency was not found in packages list but found a require that used it: "
                            + child.getName());
                }
            });
        });

        ExternalId projectExternalId;
        if (projectNameVersion.getName() == null || projectNameVersion.getVersion() == null) {
            projectExternalId = externalIdFactory.createPathExternalId(Forge.PACKAGIST, sourcePath);
        } else {
            projectExternalId = externalIdFactory.createNameVersionExternalId(Forge.PACKAGIST,
                    projectNameVersion.getName(), projectNameVersion.getVersion());
        }

        final DependencyGraph graph = builder.build();
        final DetectCodeLocation codeLocation = new DetectCodeLocation.Builder(DetectCodeLocationType.PACKAGIST,
                sourcePath, projectExternalId, graph).build();

        return new PackagistParseResult(projectNameVersion.getName(), projectNameVersion.getVersion(),
                codeLocation);
    }

    private NameVersion parseNameVersionFromJson(final JsonObject json) {
        final JsonElement nameElement = json.get("name");
        final JsonElement versionElement = json.get("version");

        String name = null;
        String version = null;

        if (nameElement != null) {
            name = nameElement.toString().replace("\"", "");
        }
        if (versionElement != null) {
            version = versionElement.toString().replace("\"", "");
        }

        return new NameVersion(name, version);
    }

    private boolean isRootPackage(final NameVersion nameVersion, final List<NameVersion> rootPackages) {
        return rootPackages.stream().anyMatch(it -> it.getName().equals(nameVersion.getName()));
    }

    private boolean existsInPackages(final NameVersion nameVersion, final List<PackagistPackage> models) {
        return models.stream().anyMatch(it -> it.getNameVersion().getName().equals(nameVersion.getName()));
    }

    private List<PackagistPackage> convertJsonToModel(final JsonObject lockfile, final boolean checkDev) {
        final List<PackagistPackage> packages = new ArrayList<>();
        lockfile.get("packages").getAsJsonArray().forEach(it -> {
            if (it.isJsonObject()) {
                final JsonObject itObject = it.getAsJsonObject();
                final NameVersion nameVersion = parseNameVersionFromJson(itObject);
                final List<NameVersion> dependencies = parseDependencies(itObject, checkDev);
                packages.add(new PackagistPackage(nameVersion, dependencies));
            }
        });
        return packages;
    }

    private List<NameVersion> parseDependencies(final JsonObject packageJson, final boolean checkDev) {
        final List<NameVersion> dependencies = new ArrayList<>();

        final JsonElement require = packageJson.get("require");
        if (require != null && require.isJsonObject()) {
            dependencies.addAll(parseDependenciesFromRequire(require.getAsJsonObject()));
        }

        if (checkDev) {
            final JsonElement devRequire = packageJson.get("require-dev");
            if (devRequire != null && devRequire.isJsonObject()) {
                dependencies.addAll(parseDependenciesFromRequire(devRequire.getAsJsonObject()));
            }

        }

        return dependencies;
    }

    private List<NameVersion> parseDependenciesFromRequire(final JsonObject requireObject) {
        final List<NameVersion> dependencies = new ArrayList<>();
        requireObject.entrySet().forEach(it -> {
            if (!it.getKey().equalsIgnoreCase("php")) {
                final NameVersion nameVersion = new NameVersion(it.getKey().toString(), it.getValue().toString());
                dependencies.add(nameVersion);
            }
        });
        return dependencies;
    }

}