Package org.jfrog.build.extractor.trigger

Source Code of org.jfrog.build.extractor.trigger.ArtifactoryBuildInfoTrigger

package org.jfrog.build.extractor.trigger;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.apache.ivy.ant.IvyTask;
import org.apache.ivy.core.IvyContext;
import org.apache.ivy.core.event.IvyEvent;
import org.apache.ivy.core.event.IvyEventFilter;
import org.apache.ivy.core.event.publish.EndArtifactPublishEvent;
import org.apache.ivy.core.event.publish.PublishEvent;
import org.apache.ivy.core.event.resolve.EndResolveEvent;
import org.apache.ivy.core.module.id.ModuleRevisionId;
import org.apache.ivy.core.report.ArtifactDownloadReport;
import org.apache.ivy.core.report.ConfigurationResolveReport;
import org.apache.ivy.core.report.ResolveReport;
import org.apache.ivy.plugins.matcher.ExactPatternMatcher;
import org.apache.ivy.plugins.trigger.Trigger;
import org.apache.ivy.util.filter.Filter;
import org.apache.tools.ant.Project;
import org.jfrog.build.api.Artifact;
import org.jfrog.build.api.BuildInfoFields;
import org.jfrog.build.api.Dependency;
import org.jfrog.build.api.Module;
import org.jfrog.build.api.builder.ArtifactBuilder;
import org.jfrog.build.api.builder.DependencyBuilder;
import org.jfrog.build.api.builder.ModuleBuilder;
import org.jfrog.build.api.util.FileChecksumCalculator;
import org.jfrog.build.client.ArtifactoryClientConfiguration;
import org.jfrog.build.client.DeployDetails;
import org.jfrog.build.client.IncludeExcludePatterns;
import org.jfrog.build.client.PatternMatcher;
import org.jfrog.build.context.BuildContext;
import org.jfrog.build.util.IvyResolverHelper;

import java.io.File;
import java.util.List;
import java.util.Map;

import static org.jfrog.build.extractor.BuildInfoExtractorUtils.getModuleIdString;
import static org.jfrog.build.extractor.BuildInfoExtractorUtils.getTypeString;

/**
* This trigger is fired after a successful {@code post-resolve} event. After which the event gives a list of
* dependencies via the {@link ResolveReport} with file locations and configurations.
*
* @author Tomer Cohen
*/
public class ArtifactoryBuildInfoTrigger implements Trigger {

    private static final String MD5 = "MD5";
    private static final String SHA1 = "SHA1";
    private BuildContext ctx;
    private final Filter filter;
    private String eventName;

    public ArtifactoryBuildInfoTrigger(String eventName) {
        this.eventName = eventName;
        this.filter = new IvyEventFilter(eventName, null, ExactPatternMatcher.INSTANCE);
    }

    public void setIvyBuildContext(BuildContext ctx) {
        this.ctx = ctx;
    }

    @Override
    public Filter getEventFilter() {
        return filter;
    }

    public void progress(IvyEvent event) {
        try {
            Project project = (Project) IvyContext.peekInContextStack(IvyTask.ANT_PROJECT_CONTEXT_KEY);
            if (project != null) {
                project.log("[buildinfo:collect] Received Event: " + event.getName(), Project.MSG_DEBUG);
            }
            if (EndResolveEvent.NAME.equals(event.getName())) {
                collectDependencyInformation(event);
            } else if (EndArtifactPublishEvent.NAME.equals(event.getName())) {
                collectModuleInformation(event);
            }
        } catch (Exception e) {
            RuntimeException re = new RuntimeException("Fail to collect dependencies and modules using the progress trigger in the Artifactory Ivy plugin, due to: " + e.getMessage(), e);
            re.printStackTrace();
            throw re;
        }
    }

    /**
     * Collect dependency information during the build.
     *
     * @param event The end of resolution Ivy event
     */
    private void collectDependencyInformation(IvyEvent event) {
        Project project = (Project) IvyContext.peekInContextStack(IvyTask.ANT_PROJECT_CONTEXT_KEY);
        ResolveReport report = ((EndResolveEvent) event).getReport();
        @SuppressWarnings("unchecked") Map<String, String> attributes = event.getAttributes();
        Module module = getOrCreateModule(attributes);
        project.log("[buildinfo:collect] Collecting dependencies for " + module.getId(), Project.MSG_INFO);
        if (module.getDependencies() == null || module.getDependencies().isEmpty()) {
            String[] configurations = report.getConfigurations();
            List<Dependency> moduleDependencies = Lists.newArrayList();
            for (String configuration : configurations) {
                project.log("[buildinfo:collect] Configuration: " + configuration + " Dependencies", Project.MSG_DEBUG);
                ConfigurationResolveReport configurationReport = report.getConfigurationReport(configuration);
                ArtifactDownloadReport[] allArtifactsReports = configurationReport.getAllArtifactsReports();
                for (final ArtifactDownloadReport artifactsReport : allArtifactsReports) {
                    project.log(
                            "[buildinfo:collect] Artifact Download Report for configuration: " + configuration + " : " + artifactsReport,
                            Project.MSG_DEBUG);
                    ModuleRevisionId id = artifactsReport.getArtifact().getModuleRevisionId();
                    String type = getType(artifactsReport.getArtifact());
                    Dependency dependency = findDependencyInList(id, type, moduleDependencies);
                    if (dependency == null) {
                        DependencyBuilder dependencyBuilder = new DependencyBuilder();
                        dependencyBuilder.type(type).scopes(Lists.newArrayList(configuration));
                        String idString = getModuleIdString(id.getOrganisation(),
                                id.getName(), id.getRevision());
                        dependencyBuilder.id(idString);
                        File file = artifactsReport.getLocalFile();
                        Map<String, String> checksums;
                        try {
                            checksums = FileChecksumCalculator.calculateChecksums(file, MD5, SHA1);
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                        String md5 = checksums.get(MD5);
                        String sha1 = checksums.get(SHA1);
                        dependencyBuilder.md5(md5).sha1(sha1);
                        dependency = dependencyBuilder.build();
                        moduleDependencies.add(dependency);
                        project.log(
                                "[buildinfo:collect] Added dependency '" + dependency.getId() + "'", Project.MSG_DEBUG);
                    } else {
                        if (!dependency.getScopes().contains(configuration)) {
                            dependency.getScopes().add(configuration);
                            project.log(
                                    "[buildinfo:collect] Added scope " + configuration +
                                            " to dependency '" + dependency.getId() + "'", Project.MSG_DEBUG);
                        } else {
                            project.log(
                                    "[buildinfo:collect] Find same dependency twice in configuration '" + configuration +
                                            "' for dependency '" + artifactsReport + "'", Project.MSG_WARN);
                        }
                    }
                }
            }
            module.setDependencies(moduleDependencies);
        }
    }

    /**
     * Collect module information for each module.
     *
     * @param event the Ivy publish event
     */
    private void collectModuleInformation(IvyEvent event) {
        ArtifactoryClientConfiguration.PublisherHandler publisher = ctx.getClientConf().publisher;
        IncludeExcludePatterns patterns = new IncludeExcludePatterns(
                publisher.getIncludePatterns(), publisher.getExcludePatterns());
        boolean excludeArtifactsFromBuild = publisher.isFilterExcludedArtifactsFromBuild();
        Project project = (Project) IvyContext.peekInContextStack(IvyTask.ANT_PROJECT_CONTEXT_KEY);

        // Finding module object from context
        @SuppressWarnings("unchecked") final Map<String, String> map = event.getAttributes();
        Module module = getOrCreateModule(map);
        List<Artifact> artifacts = module.getArtifacts();
        if (artifacts == null) {
            module.setArtifacts(Lists.<Artifact>newArrayList());
        }
        List<Artifact> excludedArtifacts = module.getExcludedArtifacts();
        if (excludedArtifacts == null) {
            module.setExcludedArtifacts(Lists.<Artifact>newArrayList());
        }

        final org.apache.ivy.core.module.descriptor.Artifact pubArtifact = ((PublishEvent) event).getArtifact();
        @SuppressWarnings("unchecked") Map<String, String> extraAttributes = pubArtifact.getExtraAttributes();
        // Using the original file, not the published one that can be far away (network wise)
        String file = map.get("file");
        // But all other attributes are taken from the actual published artifact
        final ModuleRevisionId mrid = pubArtifact.getModuleRevisionId();
        String moduleName = mrid.getName();
        String type = getType(pubArtifact);

        // By default simple name
        String name = pubArtifact.getName() + "-" + mrid.getRevision() + "." + pubArtifact.getExt();

        // Set name from name of published file
        String fullPath = IvyResolverHelper.calculateArtifactPath(publisher, map, extraAttributes);
        int lastSlash = fullPath.lastIndexOf('/');
        if (lastSlash > 0 && lastSlash + 1 < name.length()) {
            name = fullPath.substring(lastSlash + 1);
        }
        project.log("[buildinfo:collect] Collecting artifact " + name + " for module " + moduleName +
                " using file " + file, Project.MSG_INFO);

        if (isArtifactExist(module.getArtifacts(), name) || isArtifactExist(module.getExcludedArtifacts(), name)) {
            return;
        }
        ArtifactBuilder artifactBuilder = new ArtifactBuilder(name);
        artifactBuilder.type(type);

        File artifactFile = new File(file);
        Map<String, String> checksums = calculateFileChecksum(artifactFile);
        String md5 = checksums.get(MD5);
        String sha1 = checksums.get(SHA1);
        artifactBuilder.md5(md5).sha1(sha1);
        Artifact artifact = artifactBuilder.build();
        if (excludeArtifactsFromBuild && PatternMatcher.pathConflicts(fullPath, patterns)) {
            module.getExcludedArtifacts().add(artifact);
        } else {
            module.getArtifacts().add(artifact);
        }
        @SuppressWarnings("unchecked") DeployDetails deployDetails =
                buildDeployDetails(artifactFile, artifact, ctx, map, extraAttributes);
        ctx.addDeployDetailsForModule(deployDetails);
        List<Module> contextModules = ctx.getModules();
        if (contextModules.indexOf(module) == -1) {
            ctx.addModule(module);
        }
    }

    private String getType(org.apache.ivy.core.module.descriptor.Artifact ivyArtifact) {
        return getTypeString(ivyArtifact.getType(),
                ivyArtifact.getExtraAttribute("classifier"),
                ivyArtifact.getExt());
    }

    private String getName(org.apache.ivy.core.module.descriptor.Artifact ivyArtifact) {
        return getTypeString(ivyArtifact.getType(),
                ivyArtifact.getExtraAttribute("classifier"),
                ivyArtifact.getExt());
    }

    private DeployDetails buildDeployDetails(File artifactFile, Artifact artifact,
                                             BuildContext ctx, Map<String, String> map, Map<String, String> extraAttributes) {
        ArtifactoryClientConfiguration clientConf = ctx.getClientConf();
        DeployDetails.Builder builder =
                new DeployDetails.Builder().file(artifactFile).sha1(artifact.getSha1()).md5(artifact.getMd5());
        builder.artifactPath(
                IvyResolverHelper.calculateArtifactPath(clientConf.publisher, map, extraAttributes));
        builder.targetRepository(clientConf.publisher.getRepoKey());
        if (StringUtils.isNotBlank(clientConf.info.getVcsRevision())) {
            builder.addProperty(BuildInfoFields.VCS_REVISION, clientConf.info.getVcsRevision());
        }
        if (StringUtils.isNotBlank(clientConf.info.getVcsUrl())) {
            builder.addProperty(BuildInfoFields.VCS_URL, clientConf.info.getVcsUrl());
        }
        if (StringUtils.isNotBlank(clientConf.info.getBuildName())) {
            builder.addProperty(BuildInfoFields.BUILD_NAME, clientConf.info.getBuildName());
        }
        if (StringUtils.isNotBlank(clientConf.info.getBuildNumber())) {
            builder.addProperty(BuildInfoFields.BUILD_NUMBER, clientConf.info.getBuildNumber());
        }
        String buildTimestamp = clientConf.info.getBuildTimestamp();
        if (StringUtils.isBlank(buildTimestamp)) {
            buildTimestamp = ctx.getBuildStartTime() + "";
        }
        builder.addProperty(BuildInfoFields.BUILD_TIMESTAMP, buildTimestamp);
        if (StringUtils.isNotBlank(clientConf.info.getParentBuildName())) {
            builder.addProperty(BuildInfoFields.BUILD_PARENT_NAME, clientConf.info.getParentBuildName());
        }
        if (StringUtils.isNotBlank(clientConf.info.getParentBuildNumber())) {
            builder.addProperty(BuildInfoFields.BUILD_PARENT_NUMBER, clientConf.info.getParentBuildNumber());
        }
        builder.addProperties(clientConf.publisher.getMatrixParams());
        return builder.build();
    }

    private Map<String, String> calculateFileChecksum(File file) {
        Map<String, String> checksums;
        try {
            checksums = FileChecksumCalculator.calculateChecksums(file, MD5, SHA1);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return checksums;
    }

    private Dependency findDependencyInList(final ModuleRevisionId id, final String type, List<Dependency> moduleDependencies) {
        final String idToFind = getModuleIdString(id.getOrganisation(), id.getName(), "");
        return Iterables.find(moduleDependencies, new Predicate<Dependency>() {
            public boolean apply(Dependency input) {
                return input.getId().startsWith(idToFind) && input.getType().equals(type);
            }
        }, null);
    }

    private Module findModule(List<Module> modules, final String moduleKey) {
        return Iterables.find(modules, new Predicate<Module>() {
            public boolean apply(Module input) {
                return input.getId().startsWith(moduleKey);
            }
        }, null);
    }

    private Module getOrCreateModule(Map<String, String> attributes) {
        List<Module> modules = ctx.getModules();
        final String org = attributes.get("organisation");
        final String moduleName = attributes.get("module");
        String moduleKey = getModuleIdString(org, moduleName, "");
        String moduleId = getModuleIdString(org, moduleName, attributes.get("revision"));
        Module module = findModule(modules, moduleKey);
        if (module == null) {
            ModuleBuilder moduleBuilder = new ModuleBuilder().id(moduleId);
            module = moduleBuilder.build();
            modules.add(module);
        } else {
            module.setId(moduleId);
        }
        return module;
    }

    private boolean isArtifactExist(List<Artifact> artifacts, final String artifactName) {
        return Iterables.any(artifacts, new Predicate<Artifact>() {
            public boolean apply(Artifact input) {
                return input.getName().equals(artifactName);
            }
        });
    }
}
TOP

Related Classes of org.jfrog.build.extractor.trigger.ArtifactoryBuildInfoTrigger

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.