All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.metaeffekt.artifact.extractors.configuration.DefaultExtractorConfiguration Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2021-2024 the original author or authors.
 *
 * Licensed 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.metaeffekt.artifact.extractors.configuration;

import com.metaeffekt.artifact.analysis.utils.ArtifactUtils;
import com.metaeffekt.artifact.analysis.utils.FileUtils;
import com.metaeffekt.artifact.analysis.utils.StringUtils;
import org.metaeffekt.core.inventory.processor.model.Artifact;
import org.metaeffekt.core.inventory.processor.model.Constants;
import org.metaeffekt.core.inventory.processor.model.Inventory;
import org.metaeffekt.core.inventory.processor.reader.InventoryReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;

import static com.metaeffekt.artifact.analysis.metascan.Constants.KEY_CONTENT_CHECKSUM;

@Deprecated
public class DefaultExtractorConfiguration extends AbstractExtractorConfiguration {

    private static final Logger LOG = LoggerFactory.getLogger(DefaultExtractorConfiguration.class);

    /**
     * In this file location the packages can be found; the package names are usually version agnostic.
     */
    private final File packageDocBaseDir;

    /**
     * In this file location the package licenses can be found; the package names are usually version agnostic.
     */
    private final File packageLicenseBaseDir;

    /**
     * In this location the web modules can be found.
     */
    private final File webModuleBaseDir;

    /**
     * In this location the not covered files can be found.
     */
    private File extractedFilesBaseDir;

    protected DefaultExtractorConfiguration(String id, File inventoryFile, File extractedFilesBaseDir, String type) {
        super(id, inventoryFile);

        this.extractedFilesBaseDir = extractedFilesBaseDir;
        this.packageDocBaseDir = null;
        this.packageLicenseBaseDir = null;
        this.webModuleBaseDir = null;

        // FIXME: the type argument is only used to differentiate constructor signatures.
    }

    // FIXME: do subclasses for each extraction source type; otherwise we mix too many concepts.
    public DefaultExtractorConfiguration(String id, File inventoryFile, File analysisDir) {
        super(id, inventoryFile);
        this.extractedFilesBaseDir = new File(analysisDir, "extracted-scan");
        this.packageDocBaseDir = exist(new File(analysisDir, "usr-share-doc"));
        this.packageLicenseBaseDir = exist(new File(analysisDir, "usr-share-licenses"));
        this.webModuleBaseDir = exist(new File(analysisDir, "node_modules"));
        if (!this.extractedFilesBaseDir.exists()) {
            this.extractedFilesBaseDir = new File(analysisDir, "scan");
            if (!this.extractedFilesBaseDir.exists() && analysisDir.getName().startsWith("scan-")) {
                this.extractedFilesBaseDir = analysisDir;
            }
        }
    }

    public DefaultExtractorConfiguration(String id, File inventoryFile) {
        this(id, inventoryFile, inventoryFile.getParentFile());
    }

    public void validate() {
        FileUtils.validateExists(getResultInventoryFile());
    }

    public void contribute(File targetDir, Inventory aggregatedInventory) throws IOException {
        final Inventory inventory = new InventoryReader().readInventory(getResultInventoryFile());

        int i = 0;
        int size = inventory.getArtifacts().size();

        final File tmpFolder = new File(targetDir.getParentFile(), ".tmp");
        if (tmpFolder.exists()) {
            FileUtils.deleteDirectory(tmpFolder);
        }
        tmpFolder.mkdirs();

        for (Artifact artifact : inventory.getArtifacts()) {
            artifact.deriveArtifactId();
            i++;

            final String artifactType = artifact.get(Constants.KEY_TYPE);

            if (Constants.ARTIFACT_TYPE_PACKAGE.equals(artifactType)) {
                LOG.info("Compressing [{}], {}/{}", artifact.getId(), i, size);

                final File tmpAggregationFolder = new File(tmpFolder, "content_" + artifact.getId());

                if (packageDocBaseDir != null && packageDocBaseDir.exists()) {

                    // the source dir default is the artifactId (id without version)
                    File sourceDir = new File(packageDocBaseDir, artifact.getArtifactId());

                    // if the artifact has better information, we use that path instead
                    String artifactDocDir = artifact.get(Constants.KEY_DOCUMENTATION_PATH_PACKAGE);
                    if (StringUtils.notEmpty(artifactDocDir)) {
                        // FIXME: we need to modulate the path if extracted in a different environment

                        final File sourceDirCandidate = new File(artifactDocDir);
                        if (sourceDirCandidate.exists() && sourceDirCandidate.isDirectory()) {
                            sourceDir = sourceDirCandidate;
                        }
                    }

                    if (sourceDir.exists()) {
                        if (sourceDir.isDirectory()) {
                            File targetChildFolder = new File(tmpAggregationFolder, "[doc]");
                            targetChildFolder.mkdirs();
                            try {
                                FileUtils.copyDirectory(sourceDir, targetChildFolder);
                            } catch (Exception e) {
                                LOG.error("Cannot contribute package documentation directory {}. {}", sourceDir, e.getMessage());
                                artifact.append("Errors", "Package documentation directory " + sourceDir + " was not copied.", "\n");
                            }
                        } else {
                            LOG.warn("The concluded package documentation directory is not a directory. " +
                                    "Please check whether the data was correctly extracted: {}", sourceDir);
                            artifact.append("Errors", "Corrupt package documentation dir " + sourceDir + " was not copied.", "\n");
                        }
                    }
                }

                if (packageLicenseBaseDir != null && packageLicenseBaseDir.exists()) {

                    File sourceDir = new File(packageLicenseBaseDir, artifact.getArtifactId());

                    // check whether there is a license path and embed the content into a singular location
                    String artifactLicenseDir = artifact.get(Constants.KEY_LICENSE_PATH_PACKAGE);
                    if (StringUtils.notEmpty(artifactLicenseDir)) {
                        // FIXME: we may need to modulate the path from another environment here

                        final File artifactLicensePath = new File(artifactLicenseDir);
                        if (artifactLicensePath.exists() && artifactLicensePath.isDirectory()) {
                            sourceDir = artifactLicensePath;
                        }
                    }

                    if (sourceDir.exists()) {
                        File targetChildFolder = new File(tmpAggregationFolder, "[license]");
                        targetChildFolder.mkdirs();
                        FileUtils.copyDirectory(sourceDir, targetChildFolder);
                    }
                }

                // NOTE: for some reason it is not enough to check the file does not exist.
                PackageExtractorConfiguration.createArchiveFromAggregationFolder(artifact, tmpAggregationFolder, targetDir, tmpFolder);
            }

            if (Constants.ARTIFACT_TYPE_NODEJS_MODULE.equals(artifactType) && webModuleBaseDir != null && webModuleBaseDir.exists()) {
                LOG.info("Compressing [{}], {}/{}", artifact.getId(), i, size);

                // the source dir is the artifactId (id without version)
                String webModuleName = artifact.getArtifactId();
                if (webModuleName.endsWith("@")) webModuleName = webModuleName.substring(0, webModuleName.length() - 1);

                // case: archives are available and can be found using the attribute "Archive Path"
                if (StringUtils.notEmpty(artifact.get("Archive Path"))) {
                    // covered by copy below
                } else {
                    // case: archives are not available, only the unpacked node_modules
                    final File sourceDir = new File(webModuleBaseDir, webModuleName);
                    if (sourceDir.exists()) {

                        // the file name must not include slashes
                        String webModuleZipName = webModuleName.replace("/", "_");

                        // zip to tmp file
                        File targetZipTmpFile = new File(targetDir, webModuleZipName + ".zip_tmp");

                        // use zip native to get deterministic checksums
                        FileUtils.zipNative(sourceDir, targetZipTmpFile);

                        String checksum = FileUtils.computeChecksum(targetZipTmpFile);

                        File targetZipFile = new File(targetDir, String.format("%s-%s.zip", webModuleZipName, checksum));
                        if (targetZipFile.exists()) {
                            targetZipTmpFile.delete();
                        } else {
                            FileUtils.moveFile(targetZipTmpFile, targetZipFile);
                        }

                        // check file exists; move or delete tmp file
                        artifact.set("Archive Path", targetZipFile.getAbsolutePath());

                        // unset the analysis path; this may be propagated from an reference artifact and may point to
                        // the wrong folder. The workbench will recreate this information when the archive file is unpacked.
                        artifact.set("Analysis Path", null);

                        artifact.set(Artifact.Attribute.CHECKSUM, FileUtils.computeChecksum(targetZipFile));
                    }
                }
            }
        }

        // copy normal files
        /**
         if (extractedFilesBaseDir.exists()) {
         FileUtils.copyDirectory(extractedFilesBaseDir, new File(targetDir, String.format("[%s]", getId())));
         }
         **/

        addToInventory(inventory, aggregatedInventory);
    }


    public File getExtractedFilesBaseDir() {
        return extractedFilesBaseDir;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy