blob: d09e963355d696845603ea28437d3a21aacbe45f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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
*
* https://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 org.apache.ivy.ant;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.regex.Pattern;
import org.apache.ivy.Ivy;
import org.apache.ivy.core.module.id.ModuleId;
import org.apache.ivy.core.module.id.ModuleRevisionId;
import org.apache.ivy.core.resolve.ResolvedModuleRevision;
import org.apache.ivy.core.search.SearchEngine;
import org.apache.ivy.core.settings.IvySettings;
import org.apache.ivy.plugins.latest.ArtifactInfo;
import org.apache.ivy.plugins.latest.LatestStrategy;
import org.apache.ivy.plugins.matcher.ExactOrRegexpPatternMatcher;
import org.apache.ivy.plugins.matcher.ExactPatternMatcher;
import org.apache.ivy.plugins.matcher.Matcher;
import org.apache.ivy.plugins.matcher.PatternMatcher;
import org.apache.ivy.plugins.resolver.DependencyResolver;
import org.apache.ivy.plugins.version.VersionMatcher;
import org.apache.tools.ant.BuildException;
import static org.apache.ivy.util.StringUtils.isNullOrEmpty;
/**
* Look for the latest module in the repository matching the given criteria, and sets a set of
* properties according to what was found.
*/
public class IvyBuildNumber extends IvyTask {
public static class ResolvedModuleRevisionArtifactInfo implements ArtifactInfo {
private ModuleRevisionId rmr;
public ResolvedModuleRevisionArtifactInfo(ModuleRevisionId rmr) {
this.rmr = rmr;
}
public String getRevision() {
return rmr.getRevision();
}
public long getLastModified() {
return -1;
}
}
private String organisation;
private String module;
private String branch;
private String revision;
private String revSep = ".";
private String prefix = "ivy.";
private String defaultValue = "0";
private String defaultBuildNumber = "0";
private String resolver = null;
public String getModule() {
return module;
}
public void setModule(String module) {
this.module = module;
}
public String getOrganisation() {
return organisation;
}
public void setOrganisation(String organisation) {
this.organisation = organisation;
}
public String getRevision() {
return revision;
}
public void setRevision(String revision) {
this.revision = revision;
}
public String getBranch() {
return branch;
}
public void setBranch(String branch) {
this.branch = branch;
}
public String getDefault() {
return defaultValue;
}
public void setDefault(String default1) {
defaultValue = default1;
}
public String getResolver() {
return resolver;
}
public void setResolver(String resolver) {
this.resolver = resolver;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public void doExecute() throws BuildException {
if (organisation == null) {
throw new BuildException("no organisation provided for ivy buildnumber task");
}
if (module == null) {
throw new BuildException("no module name provided for ivy buildnumber task");
}
if (prefix == null) {
throw new BuildException("null prefix not allowed");
}
Ivy ivy = getIvyInstance();
IvySettings settings = ivy.getSettings();
if (branch == null) {
branch = settings.getDefaultBranch(new ModuleId(organisation, module));
}
if (isNullOrEmpty(revision)) {
revision = "latest.integration";
} else if (!revision.endsWith("+")) {
revision += "+";
}
if (!prefix.endsWith(".") && !prefix.isEmpty()) {
prefix += ".";
}
SearchEngine searcher = new SearchEngine(settings);
PatternMatcher patternMatcher = new PatternMatcher() {
private PatternMatcher exact = new ExactPatternMatcher();
private PatternMatcher regexp = new ExactOrRegexpPatternMatcher();
public Matcher getMatcher(String expression) {
if (expression.equals(organisation) || expression.equals(module)
|| expression.equals(branch)) {
return exact.getMatcher(expression);
} else {
return regexp.getMatcher(expression);
}
}
public String getName() {
return "buildnumber-matcher";
}
};
String revisionPattern = ".*";
if (revision.endsWith("+")) {
revisionPattern = Pattern.quote(revision.substring(0, revision.length() - 1)) + ".*";
}
ModuleRevisionId mrid = ModuleRevisionId.newInstance(organisation, module, branch,
revisionPattern);
ModuleRevisionId[] revisions;
if (resolver == null) {
revisions = searcher.listModules(mrid, patternMatcher);
} else {
DependencyResolver depResolver = settings.getResolver(resolver);
if (depResolver == null) {
throw new BuildException("Unknown resolver: " + resolver);
}
revisions = searcher.listModules(depResolver, mrid, patternMatcher);
}
List<ArtifactInfo> infos = new ArrayList<>(revisions.length);
for (ModuleRevisionId rev : revisions) {
infos.add(new ResolvedModuleRevisionArtifactInfo(rev));
}
VersionMatcher matcher = settings.getVersionMatcher();
LatestStrategy latestStrategy = settings.getLatestStrategy("latest-revision");
List<ArtifactInfo> sorted = latestStrategy.sort(infos.toArray(new ArtifactInfo[revisions.length]));
ModuleRevisionId askedMrid = ModuleRevisionId.newInstance(organisation, module, branch,
revision);
String foundRevision = null;
ListIterator<ArtifactInfo> iter = sorted.listIterator(sorted.size());
while (iter.hasPrevious()) {
ResolvedModuleRevisionArtifactInfo info = (ResolvedModuleRevisionArtifactInfo) iter
.previous();
if (!matcher.accept(askedMrid, info.rmr)) {
continue;
}
if (matcher.needModuleDescriptor(askedMrid, info.rmr)) {
ResolvedModuleRevision rmr = ivy.findModule(info.rmr);
if (matcher.accept(askedMrid, rmr.getDescriptor())) {
foundRevision = info.rmr.getRevision();
}
} else {
foundRevision = info.rmr.getRevision();
}
if (foundRevision != null) {
break;
}
}
NewRevision newRevision = computeNewRevision(foundRevision);
setProperty("revision", newRevision.getRevision());
setProperty("new.revision", newRevision.getNewRevision());
setProperty("build.number", newRevision.getBuildNumber());
setProperty("new.build.number", newRevision.getNewBuildNumber());
}
private void setProperty(String propertyName, String value) {
if (value != null) {
getProject().setProperty(prefix + propertyName, value);
}
}
private NewRevision computeNewRevision(String revision) {
String revPrefix = "latest.integration".equals(this.revision) ? "" : this.revision
.substring(0, this.revision.length() - 1);
if (revision != null && !revision.startsWith(revPrefix)) {
throw new BuildException("invalid exception found in repository: '" + revision
+ "' for '" + revPrefix + "'");
}
if (revision == null) {
if (revPrefix.length() > 0) {
return new NewRevision(revision, revPrefix
+ (revPrefix.endsWith(revSep) ? defaultBuildNumber : revSep
+ defaultBuildNumber), null, defaultBuildNumber);
} else {
Range r = findLastNumber(defaultValue);
if (r == null) { // no number found
return new NewRevision(revision, defaultValue, null, null);
} else {
long n = Long.parseLong(defaultValue.substring(r.getStartIndex(),
r.getEndIndex()));
return new NewRevision(revision, defaultValue, null, String.valueOf(n));
}
}
}
Range r;
if (revPrefix.length() == 0) {
r = findLastNumber(revision);
if (r == null) {
return new NewRevision(revision, revision
+ (revision.endsWith(revSep) ? "1" : revSep + "1"), null, "1");
}
} else {
r = findFirstNumber(revision, revPrefix.length());
if (r == null) {
return new NewRevision(revision, revPrefix
+ (revPrefix.endsWith(revSep) ? "1" : revSep + "1"), null, "1");
}
}
long n = Long.parseLong(revision.substring(r.getStartIndex(), r.getEndIndex())) + 1;
return new NewRevision(revision, revision.substring(0, r.getStartIndex()) + n,
String.valueOf(n - 1), String.valueOf(n));
}
private Range findFirstNumber(String str, int startIndex) {
// let's find the first digit in the string
int startNumberIndex = startIndex;
while (startNumberIndex < str.length() && !Character.isDigit(str.charAt(startNumberIndex))) {
startNumberIndex++;
}
if (startNumberIndex == str.length()) {
return null;
}
// let's find the end of the number
int endNumberIndex = startNumberIndex + 1;
while (endNumberIndex < str.length() && Character.isDigit(str.charAt(endNumberIndex))) {
endNumberIndex++;
}
return new Range(startNumberIndex, endNumberIndex);
}
private Range findLastNumber(String str) {
int endNumberIndex = str.length() - 1;
while (endNumberIndex >= 0 && !Character.isDigit(str.charAt(endNumberIndex))) {
endNumberIndex--;
}
int startNumberIndex = (endNumberIndex == -1) ? -1 : endNumberIndex - 1;
while (startNumberIndex >= 0 && Character.isDigit(str.charAt(startNumberIndex))) {
startNumberIndex--;
}
endNumberIndex++;
startNumberIndex++;
if (startNumberIndex == endNumberIndex) { // no number found
return null;
} else {
return new Range(startNumberIndex, endNumberIndex);
}
}
private static class Range {
private int startIndex;
private int endIndex;
public Range(int startIndex, int endIndex) {
this.startIndex = startIndex;
this.endIndex = endIndex;
}
public int getStartIndex() {
return startIndex;
}
public int getEndIndex() {
return endIndex;
}
}
private static class NewRevision {
private String revision;
private String newRevision;
private String buildNumber;
private String newBuildNumber;
public NewRevision(String revision, String newRevision, String buildNumber,
String newBuildNumber) {
this.revision = revision;
this.newRevision = newRevision;
this.buildNumber = buildNumber;
this.newBuildNumber = newBuildNumber;
}
public String getRevision() {
return revision;
}
public String getNewRevision() {
return newRevision;
}
public String getBuildNumber() {
return buildNumber;
}
public String getNewBuildNumber() {
return newBuildNumber;
}
}
public String getRevSep() {
return revSep;
}
public void setRevSep(String revSep) {
this.revSep = revSep;
}
public String getDefaultBuildNumber() {
return defaultBuildNumber;
}
public void setDefaultBuildNumber(String defaultBuildNumber) {
this.defaultBuildNumber = defaultBuildNumber;
}
}