org.whitesource.ant.WhitesourceTask.java Source code

Java tutorial

Introduction

Here is the source code for org.whitesource.ant.WhitesourceTask.java

Source

/**
 * Copyright (C) 2012 White Source Ltd.
 *
 * 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 org.whitesource.ant;

import org.apache.commons.lang.StringUtils;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path;
import org.whitesource.agent.api.ChecksumUtils;
import org.whitesource.agent.api.dispatch.CheckPoliciesResult;
import org.whitesource.agent.api.dispatch.UpdateInventoryResult;
import org.whitesource.agent.api.model.AgentProjectInfo;
import org.whitesource.agent.api.model.Coordinates;
import org.whitesource.agent.api.model.DependencyInfo;
import org.whitesource.agent.report.PolicyCheckReport;
import org.whitesource.agent.client.WhitesourceService;
import org.whitesource.agent.client.WssServiceException;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * Sends an inventory update request to White Source.
 *
 * @author tom.shapira
 */
public class WhitesourceTask extends Task {

    /* --- Property members --- */

    /**
     * Unique identifier of the organization with White Source.
     */
    private String apiKey;

    /**
     * Name or unique identifier of the product to update.
     */
    private String product;

    /**
     * Version of the product to update.
     */
    private String productVersion;

    /**
     * Modules to update.
     */
    private Vector<Module> modules;

    /**
     * Whether or not to stop the build when encountering an error.
     */
    private boolean failOnError;

    /**
     * Check policies configuration.
     */
    private Vector<CheckPolicies> checkPolicies;

    /**
     * White Source service url. Leave blank to use default, SaaS.
     */
    private String wssUrl;

    /* --- Members --- */

    private boolean shouldCheckPolicies;

    private CheckPolicies policyCheck;

    private Collection<AgentProjectInfo> projectInfos;

    private WhitesourceService service;

    /* --- Overridden Ant Task methods --- */

    @Override
    public void init() throws BuildException {
        super.init();

        modules = new Vector<Module>();
        checkPolicies = new Vector<CheckPolicies>();
        failOnError = true;
        shouldCheckPolicies = false;
        projectInfos = new ArrayList<AgentProjectInfo>();
    }

    @Override
    public void execute() throws BuildException {
        validateAndPrepare();
        scanModules();
        createService();
        checkPolicies();
        updateInventory();
    }

    /* --- Private methods --- */

    private void validateAndPrepare() {
        // api key
        if (StringUtils.isBlank(apiKey)) {
            error("Missing API Key");
        }

        // product
        if (StringUtils.isBlank(product)) {
            product = getProject().getName();
        }

        // modules
        if (modules.isEmpty()) {
            Module module = new Module(); // Treat whole project as single module
            module.setName("Default Module");
            addDefaultPaths(module);
            modules.add(module);
        } else {
            int emptyModules = 0;
            for (Module module : modules) {
                if (StringUtils.isBlank(module.getName()) && StringUtils.isBlank(module.getToken())) {
                    error("Expecting module name or token");
                }
                if (module.getPaths().isEmpty()) {
                    emptyModules++;
                }
            }
            if (emptyModules > 0) {
                if (modules.size() == 1) {
                    addDefaultPaths(modules.iterator().next());
                } else {
                    error("Path not set");
                }
            }
        }

        // check policies
        if (!checkPolicies.isEmpty()) {
            shouldCheckPolicies = true;
            policyCheck = checkPolicies.iterator().next();
            File reportDir = policyCheck.getReportdir();
            if (reportDir == null) {
                reportDir = new File(this.getProject().getBaseDir(), "reports");
                policyCheck.setReportdir(reportDir);
            }
            if (!reportDir.exists() && !reportDir.mkdirs()) {
                error("Policies report directory doesn't exists and can not be created");
            }
        }
    }

    private void addDefaultPaths(Module module) {
        Project project = getProject();

        FileSet fs = new FileSet();
        fs.setDir(project.getBaseDir());
        List<String> includes = new ArrayList<String>();
        for (String extension : Constants.DEFAULT_SCAN_EXTENSIONS) {
            includes.add("**/*." + extension);
        }
        fs.setIncludes(StringUtils.join(includes, ","));

        Path path = new Path(project);
        path.addFileset(fs);
        module.addPath(path);
    }

    private void scanModules() {
        log("Collecting OSS usage information");

        for (Module module : modules) {
            // create project info
            AgentProjectInfo projectInfo = new AgentProjectInfo();
            if (StringUtils.isBlank(module.getName())) {
                projectInfo.setProjectToken(module.getToken());
                log("Processing module with token " + module.getToken());
            } else {
                projectInfo.setCoordinates(new Coordinates(null, module.getName(), null));
                log("Processing " + module.getName());
            }

            // get all files located in module paths
            Set<File> filesToUpdate = new HashSet<File>(); // We're using a set in order to avoid chance of duplicate files.
            for (Path path : module.getPaths()) {
                for (String includedFile : path.list()) {
                    File file = new File(includedFile);
                    if (!file.isDirectory()) {
                        filesToUpdate.add(file);
                    }
                }
            }

            // calculate SHA-1 for all files
            Collection<DependencyInfo> dependencies = projectInfo.getDependencies();
            for (File file : filesToUpdate) {
                String fileName = file.getName();
                DependencyInfo dependency = new DependencyInfo();
                dependency.setArtifactId(fileName);
                dependency.setSystemPath(file.getAbsolutePath());
                try {
                    dependency.setSha1(ChecksumUtils.calculateSHA1(file));
                } catch (IOException e) {
                    log("Problem calculating SHA-1 for '" + fileName + "'", e, Project.MSG_DEBUG);
                }
                dependencies.add(dependency);
            }

            projectInfos.add(projectInfo);
            log("Found " + dependencies.size() + " direct dependencies");
            debugAgentProjectInfos(projectInfos);
        }
    }

    private void createService() {
        log("Service Url is " + wssUrl, Project.MSG_DEBUG);
        service = new WhitesourceService(Constants.AGENT_TYPE, Constants.AGENT_VERSION, wssUrl);
    }

    private void checkPolicies() {
        if (shouldCheckPolicies) {
            log("Checking policies");
            try {
                CheckPoliciesResult result = service.checkPolicies(apiKey, product, productVersion, projectInfos);
                handlePoliciesResult(result);
            } catch (WssServiceException e) {
                error(e);
            }
        }
    }

    private void handlePoliciesResult(CheckPoliciesResult result) {
        // generate report
        try {
            log("Creating policies report", Project.MSG_INFO);
            PolicyCheckReport report = new PolicyCheckReport(result);
            report.generate(policyCheck.getReportdir(), false);
        } catch (IOException e) {
            error(e);
        }

        // handle rejections if any
        if (result.hasRejections()) {
            String rejectionsErrorMessage = "Some dependencies does not conform with open source policies, see report for details.";
            if (policyCheck.isFailonrejection()) {
                throw new BuildException(rejectionsErrorMessage);
            } else {
                log(rejectionsErrorMessage, Project.MSG_WARN);
            }
        } else {
            log("All dependencies conform with open source policies");
        }
    }

    private void updateInventory() {
        log("Updating White Source");
        try {
            UpdateInventoryResult result = service.update(apiKey, product, productVersion, projectInfos);
            logUpdateResult(result);
        } catch (WssServiceException e) {
            error("A problem occurred while updating projects: " + e.getMessage());
        }
    }

    private void logUpdateResult(UpdateInventoryResult result) {
        log("White Source update results:");
        log("White Source organization: " + result.getOrganization());

        // newly created projects
        Collection<String> createdProjects = result.getCreatedProjects();
        if (createdProjects.isEmpty()) {
            log("No new projects found");
        } else {
            log(createdProjects.size() + " Newly created projects:");
            for (String projectName : createdProjects) {
                log(projectName);
            }
        }

        // updated projects
        Collection<String> updatedProjects = result.getUpdatedProjects();
        if (updatedProjects.isEmpty()) {
            log("No projects were updated");
        } else {
            log(updatedProjects.size() + " existing projects were updated:");
            for (String projectName : updatedProjects) {
                log(projectName);
            }
        }
    }

    private void error(String errorMsg) {
        if (failOnError) {
            throw new BuildException(errorMsg);
        } else {
            log(errorMsg, Project.MSG_ERR);
        }
    }

    private void error(Exception ex) {
        if (failOnError) {
            throw new BuildException(ex);
        } else {
            log(ex, Project.MSG_ERR);
        }
    }

    private void debugAgentProjectInfos(Collection<AgentProjectInfo> projectInfos) {
        log("----------------- dumping projectInfos -----------------", Project.MSG_DEBUG);
        log("Total number of projects : " + projectInfos.size(), Project.MSG_DEBUG);
        for (AgentProjectInfo projectInfo : projectInfos) {
            log("Project coordinates: " + projectInfo.getCoordinates(), Project.MSG_DEBUG);
            log("Project parent coordinates: " + projectInfo.getParentCoordinates(), Project.MSG_DEBUG);
            log("Project project token: " + projectInfo.getProjectToken(), Project.MSG_DEBUG);

            Collection<DependencyInfo> dependencies = projectInfo.getDependencies();
            log("total # of dependencies: " + dependencies.size(), Project.MSG_DEBUG);
            for (DependencyInfo info : dependencies) {
                log(info + " SHA-1: " + info.getSha1(), Project.MSG_DEBUG);
            }
        }
        log("----------------- dump finished -----------------", Project.MSG_DEBUG);
    }

    /* --- Property set methods --- */

    public void setFailonerror(boolean failonerror) {
        this.failOnError = failonerror;
    }

    public void addModule(Module module) {
        this.modules.add(module);
    }

    public void setApikey(String apikey) {
        this.apiKey = apikey;
    }

    public void addCheckpolicies(CheckPolicies checkpolicies) {
        this.checkPolicies.add(checkpolicies);
    }

    public void setWssurl(String wssurl) {
        this.wssUrl = wssurl;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    public void setProductVersion(String productVersion) {
        this.productVersion = productVersion;
    }
}