<commit_before>package org.jenkinsci.plugins.p4;

import hudson.AbortException;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.BuildListener;
import hudson.model.TaskListener;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Node;
import hudson.scm.ChangeLogParser;
import hudson.scm.PollingResult;
import hudson.scm.SCMDescriptor;
import hudson.scm.SCMRevisionState;
import hudson.scm.SCM;
import hudson.security.ACL;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import jenkins.model.Jenkins;
import net.sf.json.JSONObject;

import org.acegisecurity.Authentication;
import org.jenkinsci.plugins.p4.browsers.P4Browser;
import org.jenkinsci.plugins.p4.changes.P4ChangeParser;
import org.jenkinsci.plugins.p4.changes.P4ChangeSet;
import org.jenkinsci.plugins.p4.client.ClientHelper;
import org.jenkinsci.plugins.p4.client.ConnectionHelper;
import org.jenkinsci.plugins.p4.credentials.P4StandardCredentials;
import org.jenkinsci.plugins.p4.filters.Filter;
import org.jenkinsci.plugins.p4.filters.FilterPathImpl;
import org.jenkinsci.plugins.p4.filters.FilterUserImpl;
import org.jenkinsci.plugins.p4.populate.ForceCleanImpl;
import org.jenkinsci.plugins.p4.populate.Populate;
import org.jenkinsci.plugins.p4.tagging.TagAction;
import org.jenkinsci.plugins.p4.workspace.Workspace;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;

import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
import com.perforce.p4java.core.file.IFileSpec;
import com.perforce.p4java.exception.AccessException;
import com.perforce.p4java.exception.RequestException;
import com.perforce.p4java.impl.generic.core.Changelist;
import com.perforce.p4java.impl.generic.core.Label;

public class PerforceScm extends SCM {

	private static Logger logger = Logger
			.getLogger(PerforceScm.class.getName());

	private final String credential;
	private final Workspace workspace;
	private final List<Filter> filter;
	private final Populate populate;
	private final P4Browser browser;

	public String getCredential() {
		return credential;
	}

	public Workspace getWorkspace() {
		return workspace;
	}

	public List<Filter> getFilter() {
		return filter;
	}

	public Populate getPopulate() {
		return populate;
	}

	@Override
	public P4Browser getBrowser() {
		return browser;
	}

	/**
	 * Create a constructor that takes non-transient fields, and add the
	 * annotation @DataBoundConstructor to it. Using the annotation helps the
	 * Stapler class to find which constructor that should be used when
	 * automatically copying values from a web form to a class.
	 */
	@DataBoundConstructor
	public PerforceScm(String credential, Workspace workspace,
			List<Filter> filter, Populate populate, P4Browser browser) {
		this.credential = credential;
		this.workspace = workspace;
		this.filter = filter;
		this.populate = populate;
		this.browser = browser;
	}

	public PerforceScm(String credential, Workspace workspace, Populate populate) {
		this.credential = credential;
		this.workspace = workspace;
		this.filter = null;
		this.populate = populate;
		this.browser = null;
	}

	/**
	 * Calculate the state of the workspace of the given build. The returned
	 * object is then fed into compareRemoteRevisionWith as the baseline
	 * SCMRevisionState to determine if the build is necessary, and is added to
	 * the build as an Action for later retrieval.
	 */
	@Override
	public SCMRevisionState calcRevisionsFromBuild(AbstractBuild<?, ?> build,
			Launcher launcher, TaskListener listener) throws IOException,
			InterruptedException {
		// Method not required by Perforce
		return null;
	}

	/**
	 * This method does the actual polling and returns a PollingResult. The
	 * change attribute of the PollingResult the significance of the changes
	 * detected by this poll.
	 */
	@Override
	protected PollingResult compareRemoteRevisionWith(
			AbstractProject<?, ?> project, Launcher launcher,
			FilePath buildWorkspace, TaskListener listener,
			SCMRevisionState baseline) throws IOException, InterruptedException {

		PollingResult state = PollingResult.NO_CHANGES;
		PrintStream log = listener.getLogger();

		AbstractBuild<?, ?> build = project.getLastBuild();
		PerforceScm scm = (PerforceScm) build.getProject().getScm();
		String scmCredential = scm.getCredential();
		Populate scmPopulate = scm.getPopulate();
		List<Filter> scmFilter = scm.getFilter();

		// CAUTION: scmWorkspace environment will have limited access to the
		// environment variables (e.g. NODE_NAME is missing). Instead get the
		// expanded client workspace name from the last build.
		String client = "unset";
		try {
			EnvVars envVars = build.getEnvironment(null);
			client = envVars.get("P4_CLIENT");
			log.println("P4: Polling with client: " + client);
		} catch (Exception e) {
			logger.warning("P4: Unable to read P4_CLIENT");
			return PollingResult.NO_CHANGES;
		}

		ClientHelper p4 = new ClientHelper(scmCredential, listener, client);

		try {
			// expand the label if required
			String pin = scmPopulate.getPin();
			Workspace scmWorkspace = setEnvironment(build, listener);

			// find changes...
			List<Object> changes = new ArrayList<Object>();
			if (pin != null && !pin.isEmpty()) {
				pin = scmWorkspace.expand(pin);
				log.println("P4: Polling with label/change: " + pin);
				changes = p4.listClientChanges(pin);
			} else {
				changes = p4.listClientChanges();
			}

			// filter changes...
			List<Object> remainder = new ArrayList<Object>();
			for (Object c : changes) {
				if (c instanceof Integer) {
					Changelist changelist = p4.getChange((Integer) c);
					// add unfiltered changes to remainder list
					if (!filterChange(changelist, scmFilter)) {
						remainder.add(changelist);
						log.println("... found change: " + changelist.getId());
					}
				}
			}

			// if there is a remainder and the workspace is out of date
			if (!remainder.isEmpty() && p4.updateFiles()) {
				state = PollingResult.BUILD_NOW;
			}
		} catch (Exception e) {
			logger.severe("P4: Polling Error: " + e);
			e.printStackTrace();
			return null;
		} finally {
			// close connection
			p4.disconnect();
		}
		return state;
	}

	/**
	 * Returns true if change should be filtered
	 * 
	 * @param changelist
	 * @return
	 * @throws AccessException
	 * @throws RequestException
	 * @throws Exception
	 */
	private boolean filterChange(Changelist changelist, List<Filter> scmFilter)
			throws Exception {
		// exit early if no filters
		if (scmFilter == null) {
			return false;<commit_msg>Polling will trigger on 'cstat' OR 'sync -n'.<commit_after>package org.jenkinsci.plugins.p4;

import hudson.AbortException;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.BuildListener;
import hudson.model.TaskListener;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Node;
import hudson.scm.ChangeLogParser;
import hudson.scm.PollingResult;
import hudson.scm.SCMDescriptor;
import hudson.scm.SCMRevisionState;
import hudson.scm.SCM;
import hudson.security.ACL;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import jenkins.model.Jenkins;
import net.sf.json.JSONObject;

import org.acegisecurity.Authentication;
import org.jenkinsci.plugins.p4.browsers.P4Browser;
import org.jenkinsci.plugins.p4.changes.P4ChangeParser;
import org.jenkinsci.plugins.p4.changes.P4ChangeSet;
import org.jenkinsci.plugins.p4.client.ClientHelper;
import org.jenkinsci.plugins.p4.client.ConnectionHelper;
import org.jenkinsci.plugins.p4.credentials.P4StandardCredentials;
import org.jenkinsci.plugins.p4.filters.Filter;
import org.jenkinsci.plugins.p4.filters.FilterPathImpl;
import org.jenkinsci.plugins.p4.filters.FilterUserImpl;
import org.jenkinsci.plugins.p4.populate.ForceCleanImpl;
import org.jenkinsci.plugins.p4.populate.Populate;
import org.jenkinsci.plugins.p4.tagging.TagAction;
import org.jenkinsci.plugins.p4.workspace.Workspace;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;

import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
import com.perforce.p4java.core.file.IFileSpec;
import com.perforce.p4java.exception.AccessException;
import com.perforce.p4java.exception.RequestException;
import com.perforce.p4java.impl.generic.core.Changelist;
import com.perforce.p4java.impl.generic.core.Label;

public class PerforceScm extends SCM {

	private static Logger logger = Logger
			.getLogger(PerforceScm.class.getName());

	private final String credential;
	private final Workspace workspace;
	private final List<Filter> filter;
	private final Populate populate;
	private final P4Browser browser;

	public String getCredential() {
		return credential;
	}

	public Workspace getWorkspace() {
		return workspace;
	}

	public List<Filter> getFilter() {
		return filter;
	}

	public Populate getPopulate() {
		return populate;
	}

	@Override
	public P4Browser getBrowser() {
		return browser;
	}

	/**
	 * Create a constructor that takes non-transient fields, and add the
	 * annotation @DataBoundConstructor to it. Using the annotation helps the
	 * Stapler class to find which constructor that should be used when
	 * automatically copying values from a web form to a class.
	 */
	@DataBoundConstructor
	public PerforceScm(String credential, Workspace workspace,
			List<Filter> filter, Populate populate, P4Browser browser) {
		this.credential = credential;
		this.workspace = workspace;
		this.filter = filter;
		this.populate = populate;
		this.browser = browser;
	}

	public PerforceScm(String credential, Workspace workspace, Populate populate) {
		this.credential = credential;
		this.workspace = workspace;
		this.filter = null;
		this.populate = populate;
		this.browser = null;
	}

	/**
	 * Calculate the state of the workspace of the given build. The returned
	 * object is then fed into compareRemoteRevisionWith as the baseline
	 * SCMRevisionState to determine if the build is necessary, and is added to
	 * the build as an Action for later retrieval.
	 */
	@Override
	public SCMRevisionState calcRevisionsFromBuild(AbstractBuild<?, ?> build,
			Launcher launcher, TaskListener listener) throws IOException,
			InterruptedException {
		// Method not required by Perforce
		return null;
	}

	/**
	 * This method does the actual polling and returns a PollingResult. The
	 * change attribute of the PollingResult the significance of the changes
	 * detected by this poll.
	 */
	@Override
	protected PollingResult compareRemoteRevisionWith(
			AbstractProject<?, ?> project, Launcher launcher,
			FilePath buildWorkspace, TaskListener listener,
			SCMRevisionState baseline) throws IOException, InterruptedException {

		PollingResult state = PollingResult.NO_CHANGES;
		PrintStream log = listener.getLogger();

		AbstractBuild<?, ?> build = project.getLastBuild();
		PerforceScm scm = (PerforceScm) build.getProject().getScm();
		String scmCredential = scm.getCredential();
		Populate scmPopulate = scm.getPopulate();
		List<Filter> scmFilter = scm.getFilter();

		// CAUTION: scmWorkspace environment will have limited access to the
		// environment variables (e.g. NODE_NAME is missing). Instead get the
		// expanded client workspace name from the last build.
		String client = "unset";
		try {
			EnvVars envVars = build.getEnvironment(null);
			client = envVars.get("P4_CLIENT");
			log.println("P4: Polling with client: " + client);
		} catch (Exception e) {
			logger.warning("P4: Unable to read P4_CLIENT");
			return PollingResult.NO_CHANGES;
		}

		ClientHelper p4 = new ClientHelper(scmCredential, listener, client);

		try {
			// expand the label if required
			String pin = scmPopulate.getPin();
			Workspace scmWorkspace = setEnvironment(build, listener);

			// find changes...
			List<Object> changes = new ArrayList<Object>();
			if (pin != null && !pin.isEmpty()) {
				pin = scmWorkspace.expand(pin);
				log.println("P4: Polling with label/change: " + pin);
				changes = p4.listClientChanges(pin);
			} else {
				changes = p4.listClientChanges();
			}

			// filter changes...
			List<Object> remainder = new ArrayList<Object>();
			for (Object c : changes) {
				if (c instanceof Integer) {
					Changelist changelist = p4.getChange((Integer) c);
					// add unfiltered changes to remainder list
					if (!filterChange(changelist, scmFilter)) {
						remainder.add(changelist);
						log.println("... found change: " + changelist.getId());
					}
				}
			}

			// if there is a remainder and the workspace is out of date
			if (!remainder.isEmpty() || p4.updateFiles()) {
				state = PollingResult.BUILD_NOW;
			}
		} catch (Exception e) {
			logger.severe("P4: Polling Error: " + e);
			e.printStackTrace();
			return null;
		} finally {
			// close connection
			p4.disconnect();
		}
		return state;
	}

	/**
	 * Returns true if change should be filtered
	 * 
	 * @param changelist
	 * @return
	 * @throws AccessException
	 * @throws RequestException
	 * @throws Exception
	 */
	private boolean filterChange(Changelist changelist, List<Filter> scmFilter)
			throws Exception {
		// exit early if no filters
		if (scmFilter == null) {
			return false;
{'fraction_non_alphanumeric': 0.09850230414746544, 'fraction_numerical': 0.005472350230414746, 'mean_word_length': 4.400077760497667, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '3518414', 'n_tokens_mistral': 4698, 'n_tokens_neox': 4201, 'n_words': 1114}