package hudson.plugins.accurev;
import hudson.EnvVars;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.TaskListener;
import hudson.plugins.accurev.AccurevSCM.AccurevServer;
import hudson.plugins.accurev.cmd.History;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOCase;
import org.apache.commons.lang.StringUtils;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class CheckForChanges {
/**
* @param server server
* @param accurevEnv accurev environment
* @param workspace workspace
* @param listener listener
* @param launcher launcher
* @param stream stream
* @param buildDate build Date
* @param logger logger
* @param scm Accurev SCm
* @return if there are any new transactions in the stream since the last build was done
*/
//stream param is of type AccurevStream
public static boolean checkStreamForChanges(AccurevServer server,
EnvVars accurevEnv,
FilePath workspace,
TaskListener listener,
Launcher launcher,
AccurevStream stream,
Date buildDate,
Logger logger,
AccurevSCM scm) {
AccurevTransaction latestCodeChangeTransaction = new AccurevTransaction();
String filterForPollSCM = scm.getFilterForPollSCM();
String subPath = scm.getSubPath();
latestCodeChangeTransaction.setDate(AccurevSCM.NO_TRANS_DATE);
//query AccuRev for the latest transactions of each kind defined in transactionTypes using getTimeOfLatestTransaction
List<String> validTransactionTypes;
if (stream.getType().name().equalsIgnoreCase("workspace")) {
validTransactionTypes = AccurevServer.DEFAULT_VALID_WORKSPACE_TRANSACTION_TYPES;
} else {
validTransactionTypes = AccurevServer.DEFAULT_VALID_STREAM_TRANSACTION_TYPES;
}
listener.getLogger().println(//
"Checking transactions of type " + String.join(", ", validTransactionTypes) + //
" in stream [" + stream.getName() + "]");
boolean isTransLatestThanBuild = false;
Collection<String> serverPaths;
Set<String> pollingFilters = getListOfPollingFilters(filterForPollSCM, subPath);
for (final String transactionType : validTransactionTypes) {
try {
final AccurevTransaction tempTransaction = History.getLatestTransaction(scm, server, accurevEnv, workspace,
listener, launcher, stream.getName(), transactionType);
if (tempTransaction != null) {
listener.getLogger().println(
"Last transaction of type [" + transactionType + "] is " + tempTransaction);
if (latestCodeChangeTransaction.getDate().before(tempTransaction.getDate())) {
//check the affected
serverPaths = tempTransaction.getAffectedPaths();
if (tempTransaction.getAffectedPaths().size() > 0) {
if (!changesMatchFilter(serverPaths, pollingFilters)) {
// Continue to next transaction (that may have a match)
continue;
}
}
}
latestCodeChangeTransaction = tempTransaction;
if (latestCodeChangeTransaction.getDate().equals(AccurevSCM.NO_TRANS_DATE)) {
listener.getLogger().println("No last transaction found.");
}
//log last transaction information if retrieved
if (buildDate != null && buildDate.before(latestCodeChangeTransaction.getDate())) {
listener.getLogger().println("Last valid trans " + latestCodeChangeTransaction);
isTransLatestThanBuild = true;
}
} else {
listener.getLogger().println("No transactions of type [" + transactionType + "]");
}
} catch (Exception e) {
final String msg = "getLatestTransaction failed when checking the stream " + stream.getName() + " for changes with transaction type " + transactionType;
listener.getLogger().println(msg);
e.printStackTrace(listener.getLogger());
logger.log(Level.WARNING, msg, e);
}
}
return isTransLatestThanBuild;
}
public static boolean changesMatchFilter(Collection<String> serverPaths, Collection<String> filters) {
if (CollectionUtils.isEmpty(filters)) {
// No filters, so always a match.
return true;
}
for (String path : serverPaths) {
path = sanitizeSlashes(path);
for (String filter : filters) {
if (pathMatcher(path, filter)) {
return true;
}
}
}
return false;
}
public static boolean pathMatcher(String path, String wildcard) {
return FilenameUtils.wildcardMatch(path, wildcard, IOCase.INSENSITIVE);
}
private static Set<String> getListOfPollingFilters(String filterForPollSCM, String subPath) {
if (StringUtils.isNotBlank(filterForPollSCM)) {
return splitAndSanitizeFilters(filterForPollSCM);
}
return splitAndSanitizeFilters(subPath);
}
private static Set<String> splitAndSanitizeFilters(String input) {
if (StringUtils.isBlank(input)) {
return null;
}
final char DELIMITER = ',';
final String STRIP_CHARS = " \t\n\r/";
String[] filters = StringUtils.split(sanitizeSlashes(input), DELIMITER);
filters = StringUtils.stripAll(filters, STRIP_CHARS);
return new HashSet<>(Arrays.asList(filters));
}
private static String sanitizeSlashes(String input) {
return input.replace('\\', '/');
}
}