@@ -18,10 +18,16 @@
package org.apache.tools.ant.taskdefs;
import java.io.File;
import java.util.ArrayList;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Objects ;
import java.util.Vector;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
@@ -31,12 +37,12 @@ import org.apache.tools.ant.types.EnumeratedAttribute;
import org.apache.tools.ant.types.Mapper;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Reference;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.ResourceCollection;
import org.apache.tools.ant.types.resources.Resources;
import org.apache.tools.ant.types.resources.Union;
import org.apache.tools.ant.util.FileNameMapper;
import org.apache.tools.ant.util.IdentityMapper;
import org.apache.tools.ant.util.PropertyOutputStream;
/**
* Converts path and classpath information to a specific target OS
@@ -195,7 +201,7 @@ public class PathConvert extends Task {
private synchronized Resources getPath() {
if (path == null) {
path = new Resources(getProject());
path.setCache(tru e);
path.setCache(fals e);
}
return path;
}
@@ -344,56 +350,18 @@ public class PathConvert extends Task {
}
validateSetup(); // validate our setup
// Currently, we deal with only two path formats: Unix and Windows
// And Unix is everything that is not Windows
// (with the exception for NetWare and OS/2 below)
// for NetWare and OS/2, piggy-back on Windows, since here and
// in the apply code, the same assumptions can be made as with
// windows - that \\ is an OK separator, and do comparisons
// case-insensitive.
String fromDirSep = onWindows ? "\\" : "/";
StringBuilder rslt = new StringBuilder();
ResourceCollection resources = isPreserveDuplicates() ? path : new Union(path);
List<String> ret = new ArrayList<>();
FileNameMapper mapperImpl = mapper == null ? new IdentityMapper() : mapper.getImplementation();
for (Resource r : resources) {
String[] mapped = mapperImpl.mapFileName(String.valueOf(r));
for (int m = 0; mapped != null && m < mapped.length; ++m) {
ret.add(mapped[m]);
}
}
boolean first = true;
for (String string : ret) {
String elem = mapElement(string); // Apply the path prefix map
// Now convert the path and file separator characters from the
// current os to the target os.
if (!first) {
rslt.append(pathSep);
}
first = false;
StringTokenizer stDirectory = new StringTokenizer(elem, fromDirSep, true);
while (stDirectory.hasMoreTokens()) {
String token = stDirectory.nextToken();
rslt.append(fromDirSep.equals(token) ? dirSep : token);
}
}
// Place the result into the specified property,
// unless setonempty == false
if (setonempty || rslt.length() > 0) {
String value = rslt.toString();
if (property == null) {
log(value);
} else {
log("Set property " + property + " = " + value, Project.MSG_VERBOSE);
getProject().setNewProperty(property, value);
try (Writer w = new OutputStreamWriter(createOutputStream())) {
for (String s : (Iterable<String>) streamResources()::iterator) {
if (first) {
first = false;
} else {
w.write(pathSep);
}
w.write(s);
}
} catch (IOException e) {
throw new BuildException(e);
}
} finally {
path = savedPath;
@@ -402,6 +370,44 @@ public class PathConvert extends Task {
}
}
private OutputStream createOutputStream() {
if (property == null) {
return new LogOutputStream(this);
}
return new PropertyOutputStream(getProject(), property) {
@Override
public void close() {
if (setonempty || size() > 0) {
super.close();
log("Set property " + property + " = " + getProject().getProperty(property), Project.MSG_VERBOSE);
}
}
};
}
private Stream<String> streamResources() {
ResourceCollection resources = isPreserveDuplicates() ? path : Union.getInstance(path);
FileNameMapper mapperImpl = mapper == null ? new IdentityMapper() : mapper.getImplementation();
final boolean parallel = false;
Stream<String> result = StreamSupport.stream(resources.spliterator(), parallel).map(String::valueOf)
.map(mapperImpl::mapFileName).filter(Objects::nonNull).flatMap(Stream::of).map(this::mapElement);
// Currently, we deal with only two path formats: Unix and Windows
// And Unix is everything that is not Windows
// (with the exception for NetWare and OS/2 below)
// for NetWare and OS/2, piggy-back on Windows, since here and
// in the apply code, the same assumptions can be made as with
// windows - that \\ is an OK separator, and do comparisons
// case-insensitive.
final String fromDirSep = onWindows ? "\\" : "/";
if (fromDirSep.equals(dirSep)) {
return result;
}
return result.map(s -> s.replace(fromDirSep, dirSep));
}
/**
* Apply the configured map to a path element. The map is used to convert
* between Windows drive letters and Unix paths. If no map is configured,
@@ -411,20 +417,8 @@ public class PathConvert extends Task {
* @return String Updated element.
*/
private String mapElement(String elem) {
// Iterate over the map entries and apply each one.
// Stop when one of the entries actually changes the element.
for (MapEntry entry : prefixMap) {
String newElem = entry.apply(elem);
// Note I'm using "!=" to see if we got a new object back from
// the apply method.
if (newElem != elem) {
return newElem;
}
}
return elem;
final Predicate<Object> changed = o -> o != elem;
return prefixMap.stream().map(e -> e.apply(elem)).filter(changed).findFirst().orElse(elem);
}
/**