Skip to content

Commit 61d5ce0

Browse files
authored
fix: Form a correct path for the project folder when on Windows (#16611) (CP: 24.0) (#16613)
Fixes #16605
1 parent 90b1c8a commit 61d5ce0

3 files changed

Lines changed: 135 additions & 42 deletions

File tree

flow-server/src/main/java/com/vaadin/flow/server/AbstractConfiguration.java

Lines changed: 28 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,11 @@
1717

1818
import java.io.File;
1919
import java.io.Serializable;
20-
import java.net.URL;
2120
import java.nio.file.Path;
2221
import java.nio.file.Paths;
2322

24-
import org.slf4j.LoggerFactory;
25-
2623
import com.vaadin.flow.internal.hilla.EndpointRequestUtil;
24+
import com.vaadin.flow.server.frontend.FileIOUtils;
2725
import com.vaadin.flow.server.frontend.FrontendUtils;
2826

2927
import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION;
@@ -190,48 +188,36 @@ default File getProjectFolder() {
190188
}
191189

192190
String folder = getStringProperty(FrontendUtils.PROJECT_BASEDIR, null);
193-
if (folder == null) {
194-
/* Try determining the project folder from the classpath. */
195-
try {
196-
URL url = getClass().getClassLoader().getResource(".");
197-
if (url != null && url.getProtocol().equals("file")) {
198-
// URI decodes the path so that e.g. " " works correctly
199-
String path = url.toURI().getPath();
200-
if (path.endsWith("/target/classes/")) {
201-
folder = path.replaceFirst("/target/classes/$", "");
202-
}
203-
}
204-
} catch (Exception e) {
205-
LoggerFactory.getLogger(getClass()).warn(
206-
"Unable to determine project folder using classpath",
207-
e);
208-
}
191+
if (folder != null) {
192+
return new File(folder);
193+
}
194+
195+
File projectFolder = FileIOUtils.getProjectFolderFromClasspath();
196+
if (projectFolder != null) {
197+
return projectFolder;
209198
}
210199

211-
if (folder == null) {
212-
/*
213-
* Accept user.dir or cwd as a fallback only if the directory seems
214-
* to be a Maven or Gradle project. Check to avoid cluttering server
215-
* directories (see tickets #8249, #8403).
216-
*/
217-
String baseDirCandidate = System.getProperty("user.dir", ".");
218-
Path path = Paths.get(baseDirCandidate);
219-
if (path.toFile().isDirectory()
220-
&& (path.resolve("pom.xml").toFile().exists() || path
221-
.resolve("build.gradle").toFile().exists())) {
222-
return path.toAbsolutePath().toFile();
223-
} else {
224-
throw new IllegalStateException(String.format(
225-
"Failed to determine project directory for dev mode. "
226-
+ "Directory '%s' does not look like a Maven or "
227-
+ "Gradle project. Ensure that you have run the "
228-
+ "prepare-frontend Maven goal, which generates "
229-
+ "'flow-build-info.json', prior to deploying your "
230-
+ "application",
231-
path.toString()));
232-
}
200+
/*
201+
* Accept user.dir or cwd as a fallback only if the directory seems to
202+
* be a Maven or Gradle project. Check to avoid cluttering server
203+
* directories (see tickets #8249, #8403).
204+
*/
205+
String baseDirCandidate = System.getProperty("user.dir", ".");
206+
Path path = Paths.get(baseDirCandidate);
207+
if (path.toFile().isDirectory()
208+
&& (path.resolve("pom.xml").toFile().exists()
209+
|| path.resolve("build.gradle").toFile().exists())) {
210+
return path.toAbsolutePath().toFile();
211+
} else {
212+
throw new IllegalStateException(String.format(
213+
"Failed to determine project directory for dev mode. "
214+
+ "Directory '%s' does not look like a Maven or "
215+
+ "Gradle project. Ensure that you have run the "
216+
+ "prepare-frontend Maven goal, which generates "
217+
+ "'flow-build-info.json', prior to deploying your "
218+
+ "application",
219+
path.toString()));
233220
}
234-
return new File(folder);
235221
}
236222

237223
/**
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright 2000-2023 Vaadin Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package com.vaadin.flow.server.frontend;
17+
18+
import java.io.File;
19+
import java.io.IOException;
20+
import java.net.URISyntaxException;
21+
import java.net.URL;
22+
import java.nio.charset.StandardCharsets;
23+
import java.nio.file.Path;
24+
import java.util.List;
25+
import java.util.stream.Collectors;
26+
27+
import org.apache.commons.io.FileUtils;
28+
import org.slf4j.Logger;
29+
import org.slf4j.LoggerFactory;
30+
31+
public class FileIOUtils {
32+
33+
private FileIOUtils() {
34+
// Utils only
35+
}
36+
37+
private static Logger log() {
38+
return LoggerFactory.getLogger(FileIOUtils.class);
39+
}
40+
41+
/**
42+
* Try determining the project folder from the classpath.
43+
*
44+
* @return A file referring to the project folder or null if the folder
45+
* could not be determined
46+
*/
47+
public static File getProjectFolderFromClasspath() {
48+
try {
49+
URL url = FileIOUtils.class.getClassLoader().getResource(".");
50+
if (url != null && url.getProtocol().equals("file")) {
51+
return getProjectFolderFromClasspath(url);
52+
}
53+
} catch (Exception e) {
54+
log().warn("Unable to determine project folder using classpath", e);
55+
}
56+
return null;
57+
58+
}
59+
60+
static File getProjectFolderFromClasspath(URL rootFolder)
61+
throws URISyntaxException {
62+
// URI decodes the path so that e.g. " " works correctly
63+
// Path.of makes windows paths work correctly
64+
Path path = Path.of(rootFolder.toURI());
65+
if (path.endsWith(Path.of("target", "classes"))) {
66+
return path.getParent().getParent().toFile();
67+
}
68+
69+
return null;
70+
}
71+
72+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.vaadin.flow.server.frontend;
2+
3+
import java.io.File;
4+
import java.net.URL;
5+
6+
import org.junit.Assert;
7+
import org.junit.Assume;
8+
import org.junit.Test;
9+
10+
import com.vaadin.open.OSUtils;
11+
12+
public class FileIOUtilsTest {
13+
14+
@Test
15+
public void projectFolderOnWindows() throws Exception {
16+
Assume.assumeTrue(OSUtils.isWindows());
17+
18+
URL url = new URL(
19+
"file:/C:/Users/John%20Doe/Downloads/my-app%20(21)/my-app/target/classes/");
20+
Assert.assertEquals(new File(
21+
"C:\\Users\\John Doe\\Downloads\\my-app (21)\\my-app\\target\\classes"),
22+
FileIOUtils.getProjectFolderFromClasspath(url));
23+
}
24+
25+
@Test
26+
public void projectFolderOnMacOrLinux() throws Exception {
27+
Assume.assumeFalse(OSUtils.isWindows());
28+
29+
URL url = new URL(
30+
"file:/Users/John%20Doe/Downloads/my-app%20(21)/my-app/target/classes/");
31+
Assert.assertEquals(
32+
new File("/Users/John Doe/Downloads/my-app (21)/my-app"),
33+
FileIOUtils.getProjectFolderFromClasspath(url));
34+
}
35+
}

0 commit comments

Comments
 (0)