diff options
author | Matt Benson <mbenson@apache.org> | 2022-02-09 13:00:49 -0600 |
---|---|---|
committer | Matt Benson <mbenson@apache.org> | 2022-02-09 13:00:49 -0600 |
commit | 90ed3ff6cca8634e38d7c3c82858ce48c9c4be2b (patch) | |
tree | 17a53c9f6ed4304cf566bfe315451abe800f4f01 /src | |
parent | af035b0fc772cff76cd3c5879012cf8c91f7ae4e (diff) | |
download | ant-90ed3ff6cca8634e38d7c3c82858ce48c9c4be2b.tar.gz |
pathconvert to outputstream so that logging requires no in-memory String accumulation
Diffstat (limited to 'src')
-rw-r--r-- | src/main/org/apache/tools/ant/taskdefs/PathConvert.java | 126 |
1 files changed, 60 insertions, 66 deletions
diff --git a/src/main/org/apache/tools/ant/taskdefs/PathConvert.java b/src/main/org/apache/tools/ant/taskdefs/PathConvert.java index fa68c3f2e..be46bbdd2 100644 --- a/src/main/org/apache/tools/ant/taskdefs/PathConvert.java +++ b/src/main/org/apache/tools/ant/taskdefs/PathConvert.java @@ -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(true); + path.setCache(false); } 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); } /** |