| @@ -18,10 +18,16 @@ | |||||
| package org.apache.tools.ant.taskdefs; | package org.apache.tools.ant.taskdefs; | ||||
| import java.io.File; | 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.List; | ||||
| import java.util.StringTokenizer; | |||||
| import java.util.Objects; | |||||
| import java.util.Vector; | 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.BuildException; | ||||
| import org.apache.tools.ant.Project; | 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.Mapper; | ||||
| import org.apache.tools.ant.types.Path; | import org.apache.tools.ant.types.Path; | ||||
| import org.apache.tools.ant.types.Reference; | 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.ResourceCollection; | ||||
| import org.apache.tools.ant.types.resources.Resources; | import org.apache.tools.ant.types.resources.Resources; | ||||
| import org.apache.tools.ant.types.resources.Union; | import org.apache.tools.ant.types.resources.Union; | ||||
| import org.apache.tools.ant.util.FileNameMapper; | import org.apache.tools.ant.util.FileNameMapper; | ||||
| import org.apache.tools.ant.util.IdentityMapper; | import org.apache.tools.ant.util.IdentityMapper; | ||||
| import org.apache.tools.ant.util.PropertyOutputStream; | |||||
| /** | /** | ||||
| * Converts path and classpath information to a specific target OS | * Converts path and classpath information to a specific target OS | ||||
| @@ -195,7 +201,7 @@ public class PathConvert extends Task { | |||||
| private synchronized Resources getPath() { | private synchronized Resources getPath() { | ||||
| if (path == null) { | if (path == null) { | ||||
| path = new Resources(getProject()); | path = new Resources(getProject()); | ||||
| path.setCache(true); | |||||
| path.setCache(false); | |||||
| } | } | ||||
| return path; | return path; | ||||
| } | } | ||||
| @@ -344,56 +350,18 @@ public class PathConvert extends Task { | |||||
| } | } | ||||
| validateSetup(); // validate our setup | 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; | 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 { | } finally { | ||||
| path = savedPath; | 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 | * 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, | * 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. | * @return String Updated element. | ||||
| */ | */ | ||||
| private String mapElement(String elem) { | 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); | |||||
| } | } | ||||
| /** | /** | ||||