/* * Copyright 2016 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.thoughtworks.go.domain; import com.thoughtworks.go.config.materials.PackageMaterial; import com.thoughtworks.go.config.materials.SubprocessExecutionContext; import com.thoughtworks.go.config.materials.dependency.DependencyMaterial; import com.thoughtworks.go.domain.materials.*; import com.thoughtworks.go.util.command.ConsoleOutputStreamConsumer; import com.thoughtworks.go.util.command.EnvironmentVariableContext; import java.io.File; import java.io.Serializable; import java.util.*; import static com.thoughtworks.go.util.ExceptionUtils.*; public class MaterialRevision implements Serializable { private Material material; private boolean changed; private Modifications modifications; public MaterialRevision(Material material, boolean changed, List<Modification> modifications) { bombIfNull(modifications, "modifications cannot be null"); bombIf(modifications.contains(null), "modifications cannot be null"); this.material = material; this.changed = changed; this.modifications = new Modifications(modifications); } public MaterialRevision(Material material, List<Modification> modifications) { this(material, false, modifications); } public MaterialRevision(Material material, Modification... modifications) { this(material, false, modifications); } public MaterialRevision(Material material, boolean changed, Modification... modifications) { this(material, changed, Arrays.asList(modifications)); } public int numberOfModifications() { return modifications.size(); } public Date getDateOfLatestModification() { if (modifications.size() > 0) { return modifications.get(0).getModifiedTime(); } else { return null; } } public Material getMaterial() { return material; } public Revision getRevision() { if (material == null) { return new NullRevision(); } return modifications.latestRevision(material); } public Revision getOldestRevision() { return material == null ? new NullRevision() : material.oldestRevision(modifications); } public String getLatestRevisionString() { return getRevision().getRevision(); } public String getLatestShortRevision() { return material.getShortRevision(getLatestRevisionString()); } public boolean hasModifications() { return modifications.size() > 0; } public Modification getModification(int i) { return modifications.get(i); } public void accept(ModificationVisitor visitor) { visitor.visit(this); visitor.visit(material, getRevision()); for (Modification modification : modifications) { modification.accept(visitor); } } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } MaterialRevision that = (MaterialRevision) o; if (material != null ? !material.equals(that.material) : that.material != null) { return false; } if (modifications != null ? !modifications.equals(that.modifications) : that.modifications != null) { return false; } return true; } public int hashCode() { int result; result = (material != null ? material.hashCode() : 0); result = 31 * result + (modifications != null ? modifications.hashCode() : 0); return result; } public String toString() { return "[" + material + ", " + getRevision() + ";" + modifications.toString() + "]"; } public void updateTo(File baseDir, ConsoleOutputStreamConsumer consumer, final SubprocessExecutionContext execCtx) { material.updateTo(consumer, baseDir, toRevisionContext(), execCtx); } public RevisionContext toRevisionContext() { return new RevisionContext(getRevision(), getOldestRevision(), numberOfModifications()); } public Boolean hasChangedSince(MaterialRevision original) { return !(sameRevision(original) && sameMaterial(original)); } private boolean sameMaterial(MaterialRevision original) { return (material.equals(original.material)); } private boolean sameRevision(MaterialRevision original) { return getRevision().equals(original.getRevision()); } public MaterialRevision latestChanges(Material newMaterial, List<Modification> oldModifications, List<Modification> newModifications) { if (newModifications.isEmpty()) { List<Modification> result = new ArrayList<>(); if (!oldModifications.isEmpty()) { result.add(new Modification(oldModifications.get(0))); } MaterialRevision materialRevision = new MaterialRevision(newMaterial, result); materialRevision.markAsNotChanged(); return materialRevision; } else { MaterialRevision materialRevision = new MaterialRevision(newMaterial, newModifications); materialRevision.markAsChanged(); return materialRevision; } } public void markAsChanged() { this.changed = true; } public void markAsNotChanged() { this.changed = false; } public String buildCausedBy() { //TODO: #2363 May move this logic to material object later if (material instanceof DependencyMaterial) { return getRevision().getRevision(); } else { return modifications.getUsername(); } } public String buildCauseMessage() { StringBuilder builder = new StringBuilder(); //TODO: #2363 May move this logic to material object later if (material instanceof DependencyMaterial) { return builder.append("triggered by ").append(getRevision().getRevision()).toString(); } else { return builder.append("modified by ").append(buildCausedBy()).toString(); } } public Modifications getModifications() { return modifications; } public boolean hasSameHeadAs(MaterialRevision peer) { return this.getRevision().equals(peer.getRevision()); } public MaterialRevision filter(MaterialRevision previous) { if (modifications.shouldBeIgnoredByFilterIn(material.config())) { return previous; } else { return this; } } public boolean isChanged() { return changed; } public Modification getLatestModification() { assertHasModifications(); return modifications.get(0); } public Modification getOldestModification() { assertHasModifications(); return modifications.get(modifications.size() - 1); } private void assertHasModifications() { if (modifications.size() == 0) { bomb(String.format("There are no modifications on material %s.", material)); } } public void populateEnvironmentVariables(EnvironmentVariableContext context, File workingDir) { material.populateEnvironmentContext(context, this, workingDir); } public String getMaterialName() { return material.getDisplayName(); } public String getTruncatedMaterialName() { return material.getTruncatedDisplayName(); } public String getMaterialType() { return material.getTypeForDisplay(); } public String getLatestComment() { return getLatestModification().getComment(); } public String getLatestUser() { return getLatestModification().getUserDisplayName(); } public MaterialRevision subtract(MaterialRevision other) { List<Modification> newModifications = new ArrayList<>(); for (Modification modification : modifications) { if (!other.hasModification(modification)) { newModifications.add(modification); } } return new MaterialRevision(material, newModifications); } private boolean hasModification(Modification modification) { return modifications.contains(modification); } public void addModifications(List<Modification> modifications) { this.modifications.addAll(modifications); } public void replaceModifications(List<Modification> modifications) { this.modifications.clear(); this.modifications.addAll(modifications); } @Deprecated //used only in triangle dependency case of fan-in off - Srini public void updateRevisionChangedStatus(MaterialRevision revisionFor) { if (revisionFor.isChanged() && revisionFor.hasModification(getLatestModification())) { markAsChanged(); } else { markAsNotChanged(); } } public boolean isDependencyMaterialRevision() { return material instanceof DependencyMaterial; } public boolean isPackageMaterialRevision() { return material instanceof PackageMaterial; } public Set<String> getCardNumbersFromComments() { TreeSet<String> cardNumbers = new TreeSet<>(); for (Modification modification : modifications) { cardNumbers.addAll(modification.getCardNumbersFromComment()); } return cardNumbers; } }