<commit_before>package hudson.maven.reporters;

import hudson.FilePath;
import hudson.maven.MavenBuild;
import hudson.maven.MavenBuildProxy;
import hudson.maven.MavenBuildProxy.BuildCallable;
import hudson.maven.MavenModule;
import hudson.maven.MavenReporter;
import hudson.maven.MavenReporterDescriptor;
import hudson.maven.MojoInfo;
import hudson.model.Action;
import hudson.model.BuildListener;
import hudson.model.FingerprintMap;
import hudson.model.Hudson;
import hudson.tasks.Fingerprinter.FingerprintAction;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.project.MavenProject;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

/**
 * Records fingerprints of the builds to keep track of dependencies.
 *
 * @author <NAME>
 */
public class MavenFingerprinter extends MavenReporter {

    /**
     * Files whose fingerprints were already recorded.
     */
    private transient Set<File> files;
    /**
     * Fingerprints for files that were used.
     */
    private transient Map<String,String> used;
    /**
     * Fingerprints for files that were produced.
     */
    private transient Map<String,String> produced;

    public boolean preBuild(MavenBuildProxy build, MavenProject pom, BuildListener listener) throws InterruptedException, IOException {
        files = new HashSet<File>();
        used = new HashMap<String,String>();
        produced = new HashMap<String,String>();
        return true;
    }

    public boolean postExecute(MavenBuildProxy build, MavenProject pom, MojoInfo mojo, BuildListener listener, Throwable error) throws InterruptedException, IOException {
        boolean updated = false;

        // really nice if we can do this in preExecute,
        // but dependency resolution only happens after preExecute.
        updated |= record(pom.getArtifacts(),used);

        // try to pick up artifacts as soon as they are found.
        updated |= record(pom.getArtifact(),produced);
        updated |= record(pom.getAttachedArtifacts(),produced);

        if(updated) {
            build.execute(new BuildCallable<Void,IOException>() {
                // record is transient, so needs to make a copy first
                private final Map<String,String> u = used;
                private final Map<String,String> p = produced;

                public Void call(MavenBuild build) throws IOException, InterruptedException {
                    FingerprintMap map = Hudson.getInstance().getFingerprintMap();

                    for (Entry<String, String> e : p.entrySet())
                        map.getOrCreate(build, e.getKey(), e.getValue()).add(build);
                    for (Entry<String, String> e : u.entrySet())
                        map.getOrCreate(null, e.getKey(), e.getValue()).add(build);

                    Map<String,String> all = new HashMap<String, String>(u);
                    all.putAll(p);

                    // update the build action with new fingerprints
                    FingerprintAction a = build.getAction(FingerprintAction.class);
                    List<Action> actions = build.getActions();
                    if(a!=null)
                        actions.remove(a);
                    actions.add(new FingerprintAction(build,all));
                    return null;
                }
            });
        }

        return true;
    }

    private boolean record(Collection<Artifact> artifacts, Map<String,String> record) throws IOException, InterruptedException {
        boolean updated = false;
        for (Artifact a : artifacts)
            updated |= record(a,record);
        return updated;
    }

    /**
     * Records the fingerprint of the given {@link Artifact}.
     *
     * <p>
     * This method contains the logic to avoid doubly recording the fingerprint
     * of the same file.
     */
    private boolean record(Artifact a, Map<String,String> record) throws IOException, InterruptedException {
        File f = a.getFile();<commit_msg>performance improvement based on the input from http://www.nabble.com/Maven-job-5-times-slower-than-a-free-style-job--td14651245.html Avoid small roundtrips, and instead group them into a bigger batch.<commit_after>package hudson.maven.reporters;

import hudson.FilePath;
import hudson.maven.MavenBuild;
import hudson.maven.MavenBuildProxy;
import hudson.maven.MavenBuildProxy.BuildCallable;
import hudson.maven.MavenModule;
import hudson.maven.MavenReporter;
import hudson.maven.MavenReporterDescriptor;
import hudson.maven.MojoInfo;
import hudson.model.BuildListener;
import hudson.model.FingerprintMap;
import hudson.model.Hudson;
import hudson.tasks.Fingerprinter.FingerprintAction;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.project.MavenProject;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 * Records fingerprints of the builds to keep track of dependencies.
 *
 * @author <NAME>
 */
public class MavenFingerprinter extends MavenReporter {

    /**
     * Files whose fingerprints were already recorded.
     */
    private transient Set<File> files;
    /**
     * Fingerprints for files that were used.
     */
    private transient Map<String,String> used;
    /**
     * Fingerprints for files that were produced.
     */
    private transient Map<String,String> produced;

    public boolean enterModule(MavenBuildProxy build, MavenProject pom, BuildListener listener) throws InterruptedException, IOException {
        files = new HashSet<File>();
        used = new HashMap<String,String>();
        produced = new HashMap<String,String>();
        return true;
    }

    /**
     * Mojos perform different dependency resolution, so we need to check this for each mojo.
     */
    public boolean postExecute(MavenBuildProxy build, MavenProject pom, MojoInfo mojo, BuildListener listener, Throwable error) throws InterruptedException, IOException {
        record(pom.getArtifacts(),used);
        record(pom.getArtifact(),produced);
        record(pom.getAttachedArtifacts(),produced);

        return true;
    }

    /**
     * Sends the collected fingerprints over to the master and record them.
     */
    public boolean leaveModule(MavenBuildProxy build, MavenProject pom, BuildListener listener) throws InterruptedException, IOException {
        build.execute(new BuildCallable<Void,IOException>() {
            // record is transient, so needs to make a copy first
            private final Map<String,String> u = used;
            private final Map<String,String> p = produced;

            public Void call(MavenBuild build) throws IOException, InterruptedException {
                FingerprintMap map = Hudson.getInstance().getFingerprintMap();

                for (Entry<String, String> e : p.entrySet())
                    map.getOrCreate(build, e.getKey(), e.getValue()).add(build);
                for (Entry<String, String> e : u.entrySet())
                    map.getOrCreate(null, e.getKey(), e.getValue()).add(build);

                Map<String,String> all = new HashMap<String, String>(u);
                all.putAll(p);

                // add action
                build.getActions().add(new FingerprintAction(build,all));
                return null;
            }
        });
        return true;
    }

    private boolean record(Collection<Artifact> artifacts, Map<String,String> record) throws IOException, InterruptedException {
        boolean updated = false;
        for (Artifact a : artifacts)
            updated |= record(a,record);
        return updated;
    }

    /**
     * Records the fingerprint of the given {@link Artifact}.
     *
     * <p>
     * This method contains the logic to avoid doubly recording the fingerprint
     * of the same file.
     */
    private boolean record(Artifact a, Map<String,String> record) throws IOException, InterruptedException {
        File f = a.getFile();
{'fraction_non_alphanumeric': 0.09549395530589816, 'fraction_numerical': 0.0010990352912443521, 'mean_word_length': 2.7846580406654344, 'pattern_counts': {'":': 0, '<': 40, '<?xml version=': 0, '>': 40, 'https://': 0, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3956001', 'n_tokens_mistral': 2268, 'n_tokens_neox': 2133, 'n_words': 608}