MacroStringHelper.substituteParameters("", this, build, null);
// Use local variables so that substitutions are not saved
String p4Label = MacroStringHelper.substituteParameters(this.p4Label, this, build, null);
String viewMask = MacroStringHelper.substituteParameters(this.viewMask, this, build, null);
Depot depot = getDepot(launcher,workspace, build.getProject(), build, build.getBuiltOn());
String p4Stream = MacroStringHelper.substituteParameters(this.p4Stream, this, build, null);
// Pull from optional named parameters
boolean wipeBeforeBuild = overrideWithBooleanParameter(
"P4CLEANWORKSPACE", build, this.wipeBeforeBuild);
boolean quickCleanBeforeBuild = overrideWithBooleanParameter(
"P4QUICKCLEANWORKSPACE", build, this.quickCleanBeforeBuild);
boolean wipeRepoBeforeBuild = overrideWithBooleanParameter(
"P4CLEANREPOINWORKSPACE", build, this.wipeRepoBeforeBuild);
boolean forceSync = overrideWithBooleanParameter(
"P4FORCESYNC", build, this.forceSync);
boolean disableChangeLogOnly = overrideWithBooleanParameter(
"P4DISABLECHANGELOG", build, this.disableChangeLogOnly);
boolean disableSyncOnly = overrideWithBooleanParameter(
"P4DISABLESYNCONLY", build, this.disableSyncOnly);
disableSyncOnly = overrideWithBooleanParameter(
"P4DISABLESYNC", build, this.disableSyncOnly);
boolean oneChangelistOnly = overrideWithBooleanParameter(
"P4ONECHANGELIST", build, false);
// If we're doing a matrix build, we should always force sync.
if ((Object)build instanceof MatrixBuild || (Object)build instanceof MatrixRun) {
if (!alwaysForceSync && !wipeBeforeBuild)
log.println("This is a matrix build; It is HIGHLY recommended that you enable the " +
"'Always Force Sync' or 'Clean Workspace' options. " +
"Failing to do so will likely result in child builds not being synced properly.");
}
try {
// keep projectPath local so any modifications for slaves don't get saved
String effectiveProjectPath= getEffectiveProjectPath(build,
build.getProject(), build.getBuiltOn(), log, depot);
Workspace p4workspace = getPerforceWorkspace(build.getProject(), effectiveProjectPath, depot, build.getBuiltOn(), build, launcher, workspace, listener, false);
boolean dirtyWorkspace = p4workspace.isDirty();
saveWorkspaceIfDirty(depot, p4workspace, log);
//Wipe/clean workspace
String p4config;
WipeWorkspaceExcludeFilter wipeFilter;
try {
p4config = MacroStringHelper.substituteParameters("${P4CONFIG}", this, build, null);
wipeFilter = new WipeWorkspaceExcludeFilter(".p4config",p4config);
} catch (ParameterSubstitutionException ex) {
wipeFilter = new WipeWorkspaceExcludeFilter();
}
if (wipeBeforeBuild || quickCleanBeforeBuild) {
long cleanStartTime = System.currentTimeMillis();
if (wipeRepoBeforeBuild) {
log.println("Clear workspace includes .repository ...");
} else {
log.println("Note: .repository directory in workspace (if exists) is skipped during clean.");
wipeFilter.exclude(".repository");
}
if (wipeBeforeBuild) {
log.println("Wiping workspace...");
List<FilePath> workspaceDirs = workspace.list(wipeFilter);
for (FilePath dir : workspaceDirs) {
dir.deleteRecursive();
}
log.println("Wiped workspace.");
forceSync = true;
}
if (quickCleanBeforeBuild) {
QuickCleaner quickCleaner = new QuickCleaner(depot.getExecutable(), depot.getP4Ticket(), launcher, depot, workspace, wipeFilter);
log.println("Quickly cleaning workspace...");
quickCleaner.doClean();
log.println("Workspace is clean.");
if (restoreChangedDeletedFiles) {
log.println("Restoring changed and deleted files...");
quickCleaner.doRestore();
log.println("Files restored.");
}
}
long cleanEndTime = System.currentTimeMillis();
long cleanDuration = cleanEndTime - cleanStartTime;
log.println("Clean complete, took " + cleanDuration + " ms");
}
// In case of a stream depot, we want Perforce to handle the client views. So let's re-initialize
// the p4workspace object if it was changed since the last build. Also, populate projectPath with
// the current view from Perforce. We need it for labeling.
if (useStreamDepot) {
if (dirtyWorkspace) {
// Support for concurrent builds
String p4Client = getConcurrentClientName(workspace, getEffectiveClientName(build, null));
p4workspace = depot.getWorkspaces().getWorkspace(p4Client, p4Stream);
}
effectiveProjectPath = p4workspace.getTrimmedViewsAsString();
}
// If we're not managing the view, populate the projectPath with the current view from perforce
// This is both for convenience, and so the labeling mechanism can operate correctly
if (!updateView) {
effectiveProjectPath = p4workspace.getTrimmedViewsAsString();
}
String p4WorkspacePath = "//" + p4workspace.getName() + "/...";
int lastChange = getLastChange((Run)build.getPreviousBuild());
log.println("Last build changeset: " + lastChange);
// Determine changeset number
int newestChange = lastChange;
List<Changelist> changes;
if (p4Label != null && !p4Label.trim().isEmpty()) {
newestChange = depot.getChanges().getHighestLabelChangeNumber(p4workspace, p4Label.trim(), p4WorkspacePath);
} else {
if (p4UpstreamProject != null && p4UpstreamProject.length() > 0) {
log.println("Using last successful or unstable build of upstream project " + p4UpstreamProject);
Job job = Hudson.getInstance().getItemByFullName(p4UpstreamProject, Job.class);
if (job == null) {
throw new AbortException(
"Configured upstream job does not exist anymore: " + p4UpstreamProject + ". Please update your job configuration.");
}
Run upStreamRun = job.getLastSuccessfulBuild();
int lastUpStreamChange = getLastChangeNoFirstChange(upStreamRun);
if (lastUpStreamChange > 0) {
log.println("Using P4 revision " + lastUpStreamChange + " from upstream project " + p4UpstreamProject);
newestChange = lastUpStreamChange;
} else {
log.println("No P4 revision found in upstream project " + p4UpstreamProject);
throw new AbortException(
"Configured upstream job has not been run yet: " + p4UpstreamProject + ". Please run it once befor launching a new build.");
}
} else
if (p4Counter != null && !updateCounterValue) {
//use a counter
String counterName;
counterName = MacroStringHelper.substituteParameters(this.p4Counter, this, build, null);
Counter counter = depot.getCounters().getCounter(counterName);
newestChange = counter.getValue();
} else {
//use the latest submitted change from workspace, or depot
try {
List<Integer> workspaceChanges = depot.getChanges().getChangeNumbers(p4WorkspacePath, 0, 1);
if (workspaceChanges != null && workspaceChanges.size() > 0) {
newestChange = workspaceChanges.get(0);
} else {
List<Integer> depotChanges = depot.getChanges().getChangeNumbers("//...", 0, 1);
if (depotChanges != null && depotChanges.size() > 0) {
newestChange = depotChanges.get(0);
}
}
} catch (PerforceException e) {
//fall back onto 'change' counter value
log.println("Failed to get last submitted changeset in the view, falling back to change counter. Error was: " + e.getMessage());
Counter counter = depot.getCounters().getCounter("change");
newestChange = counter.getValue();
}
}
}
// Set newestChange down to the next available changeset if we're building one change at a time
if (oneChangelistOnly && build.getPreviousBuild() != null
&& lastChange > 0 && newestChange > lastChange) {
List<Integer> workspaceChanges = depot.getChanges().getChangeNumbersInRange(
p4workspace, lastChange+1, newestChange, viewMask, showIntegChanges);
for (int i = workspaceChanges.size()-1; i >= 0; --i) {
int changeNumber = workspaceChanges.get(i);
Changelist changelist = depot.getChanges().getChangelist(changeNumber, fileLimit);
if (!isChangelistExcluded(changelist, build.getProject(), build.getBuiltOn(), p4workspace.getViewsAsString(), log)) {
newestChange = changeNumber;
break;
}
log.println("Changelist "+changeNumber+" is composed of file(s) and/or user(s) that are excluded.");
}
log.println("Remaining changes: " + workspaceChanges);
log.println("Building next changeset in sequence: " + newestChange);
}
if (build instanceof MatrixRun) {
newestChange = getOrSetMatrixChangeSet(build, depot, newestChange, effectiveProjectPath, log);
}
if (lastChange <= 0) {
lastChange = newestChange - MAX_CHANGESETS_ON_FIRST_BUILD;
if (lastChange < 0) {
lastChange = 0;
}
}
// Get ChangeLog
if (!disableChangeLogOnly) {
int lastChangeToDisplay = lastChange+1;
if (lastChange > newestChange) {
// If we're building an older change, display it anyway
// TODO: This can be considered inconsistent behavior
lastChangeToDisplay = newestChange;
}
List<Integer> changeNumbersTo;
if (useViewMaskForChangeLog && useViewMask) {
changeNumbersTo = depot.getChanges().getChangeNumbersInRange(p4workspace, lastChangeToDisplay, newestChange, viewMask, showIntegChanges);
} else {
changeNumbersTo = depot.getChanges().getChangeNumbersInRange(p4workspace, lastChangeToDisplay, newestChange, showIntegChanges);
}
changes = depot.getChanges().getChangelistsFromNumbers(changeNumbersTo, fileLimit);
if (changes.size() > 0) {
// Save the changes we discovered.
PerforceChangeLogSet.saveToChangeLog(
new FileOutputStream(changelogFile), changes);
newestChange = changes.get(0).getChangeNumber();
// Get and store information about committers
retrieveUserInformation(depot, changes);
} else {
// No new changes discovered (though the definition of the workspace or label may have changed).
createEmptyChangeLog(changelogFile, listener, "changelog");
}
}
// Sync workspace
if (!disableSyncOnly) {
// Now we can actually do the sync process...
StringBuilder sbMessage = new StringBuilder("Sync'ing workspace to ");
StringBuilder sbSyncPath = new StringBuilder(p4WorkspacePath);
StringBuilder sbSyncPathSuffix = new StringBuilder();
sbSyncPathSuffix.append("@");
if (p4Label != null && !p4Label.trim().isEmpty()) {
sbMessage.append("label ");
sbMessage.append(p4Label);
sbSyncPathSuffix.append(p4Label);
} else {
sbMessage.append("changelist ");
sbMessage.append(newestChange);
sbSyncPathSuffix.append(newestChange);
}
sbSyncPath.append(sbSyncPathSuffix);
if (forceSync || alwaysForceSync)
sbMessage.append(" (forcing sync of unchanged files).");
else
sbMessage.append(".");
log.println(sbMessage.toString());
String syncPath = sbSyncPath.toString();
long startTime = System.currentTimeMillis();
if (useViewMaskForSyncing && useViewMask) {
for (String path : viewMask.replaceAll("\r", "").split("\n")) {
StringBuilder sbMaskPath = new StringBuilder(path);
sbMaskPath.append(sbSyncPathSuffix);
String maskPath = sbMaskPath.toString();
depot.getWorkspaces().syncTo(maskPath, forceSync || alwaysForceSync, dontUpdateServer);
}
} else {
depot.getWorkspaces().syncTo(syncPath, forceSync || alwaysForceSync, dontUpdateServer);
}
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
log.println("Sync complete, took " + duration + " ms");
}
boolean doSaveProject = false;
// reset one time use variables...
if (this.forceSync == true || this.firstChange != -1) {
this.forceSync = false;
this.firstChange = -1;
// save the one-time use variables...
doSaveProject = true;
}
// If we aren't managing the client views, update the current ones
// with those from perforce, and save them if they have changed.
if (!this.updateView && !effectiveProjectPath.equals(this.projectPath)) {
this.projectPath = effectiveProjectPath;
doSaveProject = true;
}
if (doSaveProject) {
build.getParent().save();
}
// Add tagging action that enables the user to create a label
// for this build.
build.addAction(new PerforceTagAction(
build, depot, newestChange, effectiveProjectPath, MacroStringHelper.substituteParameters(p4User, this, build, null)));
build.addAction(new PerforceSCMRevisionState(newestChange));
if (p4Counter != null && updateCounterValue) {
// Set or create a counter to mark this change
Counter counter = new Counter();
String counterName = MacroStringHelper.substituteParameters(this.p4Counter, this, build, null);
counter.setName(counterName);
counter.setValue(newestChange);
log.println("Updating counter " + counterName + " to " + newestChange);
depot.getCounters().saveCounter(counter);
}
// remember the p4Ticket if we were issued one
// otherwise keep the last one issued
if (depot.getP4Ticket() != null)
p4Ticket = depot.getP4Ticket();
return true;
} catch (PerforceException e) {
log.print("Caught exception communicating with perforce. " + e.getMessage());