Skip to content

Commit

Permalink
Create classpath argfile on windows for run tasks
Browse files Browse the repository at this point in the history
Closes gh-17766
  • Loading branch information
mhalbritter committed Mar 19, 2024
1 parent a65e101 commit 5a77122
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
Expand All @@ -41,6 +45,7 @@
import org.springframework.boot.loader.tools.FileUtils;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

/**
* Base class to run a Spring Boot application.
Expand All @@ -50,6 +55,7 @@
* @author David Liu
* @author Daniel Young
* @author Dmytro Nosan
* @author Moritz Halbritter
* @since 1.3.0
* @see RunMojo
* @see StartMojo
Expand Down Expand Up @@ -239,6 +245,10 @@ private void run(String startClassName) throws MojoExecutionException, MojoFailu
JavaProcessExecutor processExecutor = new JavaProcessExecutor(this.session, this.toolchainManager);
File workingDirectoryToUse = (this.workingDirectory != null) ? this.workingDirectory
: this.project.getBasedir();
if (getLog().isDebugEnabled()) {
getLog().debug("Working directory: " + workingDirectoryToUse);
getLog().debug("Java arguments: " + String.join(" ", args));
}
run(processExecutor, workingDirectoryToUse, args, determineEnvironmentVariables());
}

Expand Down Expand Up @@ -351,13 +361,40 @@ private void addClasspath(List<String> args) throws MojoExecutionException {
getLog().debug("Classpath for forked process: " + classpath);
}
args.add("-cp");
args.add(classpath.toString());
if (needsClasspathArgFile()) {
args.add("@" + writeClasspathArgFile(classpath.toString()));
}
else {
args.add(classpath.toString());
}
}
catch (Exception ex) {
throw new MojoExecutionException("Could not build classpath", ex);
}
}

private boolean needsClasspathArgFile() {
// Windows limits the maximum command length, so we use an argfile there
return runsOnWindows();
}

private boolean runsOnWindows() {
String os = System.getProperty("os.name");
if (!StringUtils.hasLength(os)) {
if (getLog().isWarnEnabled()) {
getLog().warn("System property os.name is not set");
}
return false;
}
return os.toLowerCase(Locale.ROOT).contains("win");
}

private Path writeClasspathArgFile(String classpath) throws IOException {
ArgFile argFile = ArgFile.create();
argFile.write(classpath);
return argFile.getPath();
}

protected URL[] getClassPathUrls() throws MojoExecutionException {
try {
List<URL> urls = new ArrayList<>();
Expand All @@ -372,7 +409,6 @@ protected URL[] getClassPathUrls() throws MojoExecutionException {
}
}

@SuppressWarnings("removal")
private void addAdditionalClasspathLocations(List<URL> urls) throws MalformedURLException {
Assert.state(ObjectUtils.isEmpty(this.directories) || ObjectUtils.isEmpty(this.additionalClasspathElements),
"Either additionalClasspathElements or directories (deprecated) should be set, not both");
Expand Down Expand Up @@ -437,4 +473,32 @@ static String format(String key, String value) {

}

static class ArgFile {

private final Path path;

ArgFile(Path path) {
this.path = path;
}

void write(String content) throws IOException {
String escaped = escape(content);
Files.writeString(this.path, "\"" + escaped + "\"", StandardOpenOption.APPEND);
}

Path getPath() {
return this.path;
}

private String escape(String content) {
return content.replace("\\", "\\\\");
}

static ArgFile create() throws IOException {
Path file = Files.createTempFile("spring-boot-", ".argfile");
return new ArgFile(file);
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* 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
*
* 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.springframework.boot.maven;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

import org.junit.jupiter.api.Test;

import org.springframework.boot.maven.AbstractRunMojo.ArgFile;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Tests for {@link AbstractRunMojo}.
*
* @author Moritz Halbritter
*/
class AbstractRunMojoTests {

@Test
void argfileEscapesContent() throws IOException {
ArgFile file = ArgFile.create();
file.write("some \\ content");
file.write("And even more content");
assertThat(file.getPath()).content(StandardCharsets.UTF_8)
.isEqualTo("\"some \\\\ content\"\"And even more content\"");
}

}

0 comments on commit 5a77122

Please sign in to comment.