Skip to content

Commit 3b2c3ea

Browse files
authored
fix: Remove extra files from the jar-resources folder (#15714)
When you remove an add-on or change Vaadin version, you want the old files to be removed so they do not interfere with the compilation
1 parent 751278a commit 3b2c3ea

File tree

5 files changed

+106
-34
lines changed

5 files changed

+106
-34
lines changed

flow-plugins/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/maven/BuildFrontendMojoTest.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ public class BuildFrontendMojoTest {
101101
private File openApiJsonFile;
102102
private File generatedTsFolder;
103103
private File tokenFile;
104+
private File jarResourcesSource;
104105

105106
private final BuildFrontendMojo mojo = Mockito.spy(new BuildFrontendMojo());
106107
private Lookup lookup;
@@ -141,6 +142,9 @@ public void setup() throws Exception {
141142
webpackOutputDirectory = new File(projectBase, VAADIN_WEBAPP_RESOURCES);
142143
resourceOutputDirectory = new File(projectBase,
143144
VAADIN_SERVLET_RESOURCES);
145+
jarResourcesSource = new File(projectBase,
146+
"jar-resources-source/META-INF/frontend");
147+
jarResourcesSource.mkdirs();
144148

145149
projectFrontendResourcesDirectory = new File(npmFolder,
146150
"flow_resources");
@@ -193,6 +197,8 @@ public void setup() throws Exception {
193197
projectBase);
194198
ReflectionUtils.setVariableValueInObject(mojo, "projectBuildDir",
195199
Paths.get(projectBase.toString(), "target").toString());
200+
Mockito.when(mojo.getJarFiles()).thenReturn(
201+
Set.of(jarResourcesSource.getParentFile().getParentFile()));
196202

197203
generatedFolder.mkdirs();
198204

@@ -640,10 +646,16 @@ private List<String> getExpectedImports() {
640646
private void createExpectedImports(File directoryWithImportsJs,
641647
File nodeModulesPath) throws IOException {
642648
for (String expectedImport : getExpectedImports()) {
643-
File newFile = resolveImportFile(directoryWithImportsJs,
644-
nodeModulesPath, expectedImport);
645-
newFile.getParentFile().mkdirs();
646-
Assert.assertTrue(newFile.createNewFile());
649+
if (expectedImport.startsWith("./generated/jar-resources/")) {
650+
File newFile = new File(jarResourcesSource, expectedImport
651+
.substring("./generated/jar-resources/".length()));
652+
Assert.assertTrue(newFile.createNewFile());
653+
} else {
654+
File newFile = resolveImportFile(directoryWithImportsJs,
655+
nodeModulesPath, expectedImport);
656+
newFile.getParentFile().mkdirs();
657+
Assert.assertTrue(newFile.createNewFile());
658+
}
647659
}
648660
}
649661

flow-server/src/main/java/com/vaadin/flow/server/frontend/JarContentsManager.java

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.List;
2525
import java.util.Locale;
2626
import java.util.Objects;
27+
import java.util.Set;
2728
import java.util.jar.JarEntry;
2829
import java.util.jar.JarFile;
2930
import java.util.stream.Collectors;
@@ -190,6 +191,8 @@ private byte[] getJarEntryContents(JarFile jarFile, JarEntry entry) {
190191
* @param wildcardPathExclusions
191192
* wildcard exclusions that are used to check each path against
192193
* before copying
194+
* @return names of the files that were either copied or already existed in
195+
* the output directory
193196
* @throws IllegalArgumentException
194197
* if jar file specified is not a file or does not exist or if
195198
* output directory is not a directory or does not exist
@@ -199,7 +202,7 @@ private byte[] getJarEntryContents(JarFile jarFile, JarEntry entry) {
199202
* if {@link IOException} occurs during the operation, for
200203
* instance, when jar file specified is not a jar file
201204
*/
202-
public void copyFilesFromJarTrimmingBasePath(File jar,
205+
public Set<String> copyFilesFromJarTrimmingBasePath(File jar,
203206
String jarDirectoryToCopyFrom, File outputDirectory,
204207
String... wildcardPathExclusions) {
205208
requireFileExistence(jar);
@@ -213,13 +216,16 @@ public void copyFilesFromJarTrimmingBasePath(File jar,
213216
String basePath = normalizeJarBasePath(jarDirectoryToCopyFrom);
214217

215218
try (JarFile jarFile = new JarFile(jar, false)) {
216-
jarFile.stream().filter(file -> !file.isDirectory())
219+
Set<String> handledFiles = jarFile.stream()
220+
.filter(file -> !file.isDirectory())
217221
.filter(file -> file.getName().toLowerCase(Locale.ENGLISH)
218222
.startsWith(basePath.toLowerCase(Locale.ENGLISH)))
219223
.filter(file -> isFileIncluded(file,
220224
wildcardPathExclusions))
221-
.forEach(jarEntry -> copyJarEntryTrimmingBasePath(jarFile,
222-
jarEntry, basePath, outputDirectory));
225+
.map(jarEntry -> copyJarEntryTrimmingBasePath(jarFile,
226+
jarEntry, basePath, outputDirectory))
227+
.collect(Collectors.toSet());
228+
return handledFiles;
223229
} catch (IOException e) {
224230
throw new UncheckedIOException(String.format(
225231
"Failed to extract files from jarFile '%s' to directory '%s'",
@@ -243,6 +249,8 @@ public void copyFilesFromJarTrimmingBasePath(File jar,
243249
* @param wildcardPathInclusions
244250
* wildcard inclusions that are used to check each path against
245251
* before copying
252+
* @return names of the files that were either copied or already existed in
253+
* the output directory
246254
* @throws IllegalArgumentException
247255
* if jar file specified is not a file or does not exist or if
248256
* output directory is not a directory or does not exist
@@ -252,7 +260,7 @@ public void copyFilesFromJarTrimmingBasePath(File jar,
252260
* if {@link IOException} occurs during the operation, for
253261
* instance, when jar file specified is not a jar file
254262
*/
255-
public void copyIncludedFilesFromJarTrimmingBasePath(File jar,
263+
public Set<String> copyIncludedFilesFromJarTrimmingBasePath(File jar,
256264
String jarDirectoryToCopyFrom, File outputDirectory,
257265
String... wildcardPathInclusions) {
258266
requireFileExistence(jar);
@@ -266,12 +274,15 @@ public void copyIncludedFilesFromJarTrimmingBasePath(File jar,
266274
String basePath = normalizeJarBasePath(jarDirectoryToCopyFrom);
267275

268276
try (JarFile jarFile = new JarFile(jar, false)) {
269-
jarFile.stream().filter(file -> !file.isDirectory())
277+
Set<String> handledFiles = jarFile.stream()
278+
.filter(file -> !file.isDirectory())
270279
.filter(file -> file.getName().toLowerCase(Locale.ENGLISH)
271280
.startsWith(basePath.toLowerCase(Locale.ENGLISH)))
272281
.filter(file -> includeFile(file, wildcardPathInclusions))
273-
.forEach(jarEntry -> copyJarEntryTrimmingBasePath(jarFile,
274-
jarEntry, basePath, outputDirectory));
282+
.map(jarEntry -> copyJarEntryTrimmingBasePath(jarFile,
283+
jarEntry, basePath, outputDirectory))
284+
.collect(Collectors.toSet());
285+
return handledFiles;
275286
} catch (IOException e) {
276287
throw new UncheckedIOException(String.format(
277288
"Failed to extract files from jarFile '%s' to directory '%s'",
@@ -300,7 +311,7 @@ private boolean includeFile(ZipEntry file, String... pathInclusions) {
300311
.wildcardMatch(filePath, inclusionRule));
301312
}
302313

303-
private void copyJarEntryTrimmingBasePath(JarFile jarFile,
314+
private String copyJarEntryTrimmingBasePath(JarFile jarFile,
304315
ZipEntry jarEntry, String basePath, File outputDirectory) {
305316
String fullPath = jarEntry.getName();
306317
String relativePath = fullPath
@@ -315,6 +326,7 @@ private void copyJarEntryTrimmingBasePath(JarFile jarFile,
315326
FileUtils.copyInputStreamToFile(
316327
jarFile.getInputStream(jarEntry), target);
317328
}
329+
return relativePath;
318330
} catch (IOException e) {
319331
throw new UncheckedIOException(String.format(
320332
"Failed to extract jar entry '%s' from jarFile", jarEntry),

flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskCopyFrontendFiles.java

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,22 @@
1515
*/
1616
package com.vaadin.flow.server.frontend;
1717

18+
import static com.vaadin.flow.server.Constants.COMPATIBILITY_RESOURCES_FRONTEND_DEFAULT;
19+
import static com.vaadin.flow.server.Constants.RESOURCES_FRONTEND_DEFAULT;
20+
import static com.vaadin.flow.server.Constants.RESOURCES_JAR_DEFAULT;
21+
1822
import java.io.File;
23+
import java.io.IOException;
24+
import java.nio.file.Files;
25+
import java.nio.file.Path;
26+
import java.util.HashSet;
1927
import java.util.Set;
2028
import java.util.stream.Collectors;
29+
import java.util.stream.Stream;
2130

2231
import org.slf4j.Logger;
2332
import org.slf4j.LoggerFactory;
2433

25-
import static com.vaadin.flow.server.Constants.COMPATIBILITY_RESOURCES_FRONTEND_DEFAULT;
26-
import static com.vaadin.flow.server.Constants.RESOURCES_FRONTEND_DEFAULT;
27-
import static com.vaadin.flow.server.Constants.RESOURCES_JAR_DEFAULT;
28-
2934
/**
3035
* Copies JavaScript and CSS files from JAR files into a given folder.
3136
* <p>
@@ -61,33 +66,60 @@ public void execute() {
6166
log().info("Copying frontend resources from jar files ...");
6267
File targetDirectory = options.getJarFrontendResourcesFolder();
6368
TaskCopyLocalFrontendFiles.createTargetFolder(targetDirectory);
69+
Set<String> existingFiles;
70+
try {
71+
existingFiles = getFilesInDirectory(targetDirectory);
72+
} catch (IOException e) {
73+
// If we do not find the existing files, we will not delete anything
74+
existingFiles = new HashSet<>();
75+
log().error("Unable to list contents of the directory "
76+
+ targetDirectory.getAbsolutePath());
77+
}
6478
JarContentsManager jarContentsManager = new JarContentsManager();
79+
Set<String> handledFiles = new HashSet<>();
6580
for (File location : resourceLocations) {
6681
if (location.isDirectory()) {
67-
TaskCopyLocalFrontendFiles.copyLocalResources(
68-
new File(location, RESOURCES_FRONTEND_DEFAULT),
69-
targetDirectory);
70-
TaskCopyLocalFrontendFiles.copyLocalResources(
71-
new File(location,
82+
handledFiles
83+
.addAll(TaskCopyLocalFrontendFiles.copyLocalResources(
84+
new File(location, RESOURCES_FRONTEND_DEFAULT),
85+
targetDirectory));
86+
handledFiles.addAll(TaskCopyLocalFrontendFiles
87+
.copyLocalResources(new File(location,
7288
COMPATIBILITY_RESOURCES_FRONTEND_DEFAULT),
73-
targetDirectory);
89+
targetDirectory));
7490
} else {
75-
jarContentsManager.copyIncludedFilesFromJarTrimmingBasePath(
76-
location, RESOURCES_FRONTEND_DEFAULT, targetDirectory,
77-
WILDCARD_INCLUSIONS);
78-
jarContentsManager.copyIncludedFilesFromJarTrimmingBasePath(
79-
location, COMPATIBILITY_RESOURCES_FRONTEND_DEFAULT,
80-
targetDirectory, WILDCARD_INCLUSIONS);
81-
jarContentsManager.copyIncludedFilesFromJarTrimmingBasePath(
82-
location, RESOURCES_JAR_DEFAULT, targetDirectory,
83-
WILDCARD_INCLUSION_APP_THEME_JAR);
91+
handledFiles.addAll(jarContentsManager
92+
.copyIncludedFilesFromJarTrimmingBasePath(location,
93+
RESOURCES_FRONTEND_DEFAULT, targetDirectory,
94+
WILDCARD_INCLUSIONS));
95+
handledFiles.addAll(jarContentsManager
96+
.copyIncludedFilesFromJarTrimmingBasePath(location,
97+
COMPATIBILITY_RESOURCES_FRONTEND_DEFAULT,
98+
targetDirectory, WILDCARD_INCLUSIONS));
99+
handledFiles.addAll(jarContentsManager
100+
.copyIncludedFilesFromJarTrimmingBasePath(location,
101+
RESOURCES_JAR_DEFAULT, targetDirectory,
102+
WILDCARD_INCLUSION_APP_THEME_JAR));
84103
}
85104
}
105+
existingFiles.removeAll(handledFiles);
106+
existingFiles.forEach(
107+
filename -> new File(targetDirectory, filename).delete());
86108
long ms = (System.nanoTime() - start) / 1000000;
87109
log().info("Visited {} resources. Took {} ms.",
88110
resourceLocations.size(), ms);
89111
}
90112

113+
static Set<String> getFilesInDirectory(File targetDirectory)
114+
throws IOException {
115+
try (Stream<Path> stream = Files.walk(targetDirectory.toPath())) {
116+
return stream.filter(path -> path.toFile().isFile())
117+
.map(path -> targetDirectory.toPath().relativize(path)
118+
.toString())
119+
.collect(Collectors.toSet());
120+
}
121+
}
122+
91123
private Logger log() {
92124
return LoggerFactory.getLogger(this.getClass());
93125
}

flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskCopyLocalFrontendFiles.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@
2121
import java.nio.file.Files;
2222
import java.nio.file.Path;
2323
import java.nio.file.Paths;
24+
import java.util.Collections;
25+
import java.util.HashSet;
2426
import java.util.Objects;
27+
import java.util.Set;
2528
import java.util.stream.Stream;
2629

2730
import org.apache.commons.io.FileUtils;
@@ -65,18 +68,21 @@ public void execute() {
6568
}
6669
}
6770

68-
static void copyLocalResources(File source, File target) {
71+
static Set<String> copyLocalResources(File source, File target) {
6972
if (!source.isDirectory() || !target.isDirectory()) {
70-
return;
73+
return Collections.emptySet();
7174
}
7275
try {
76+
Set<String> handledFiles = new HashSet<>(
77+
TaskCopyFrontendFiles.getFilesInDirectory(source));
7378
FileUtils.copyDirectory(source, target);
7479
try (Stream<Path> fileStream = Files
7580
.walk(Paths.get(target.getPath()))) {
7681
// used with try-with-resources as defined in walk API note
7782
fileStream.filter(file -> !Files.isWritable(file)).forEach(
7883
filePath -> filePath.toFile().setWritable(true));
7984
}
85+
return handledFiles;
8086
} catch (IOException e) {
8187
throw new UncheckedIOException(String.format(
8288
"Failed to copy project frontend resources from '%s' to '%s'",

flow-server/src/test/java/com/vaadin/flow/server/frontend/TaskCopyFrontendFilesTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ public void should_collectJsAndCssFilesFromJars_modernResourceFolder()
7070
"dir-with-modern-frontend");
7171
}
7272

73+
@Test
74+
public void should_collectJsAndCssFilesFromJars_removeExtraFiles()
75+
throws IOException {
76+
File dummy = new File(frontendDepsFolder, "dummy.ts");
77+
frontendDepsFolder.mkdirs();
78+
dummy.createNewFile();
79+
should_collectJsAndCssFilesFromJars("jar-with-modern-frontend.jar",
80+
"dir-with-modern-frontend");
81+
}
82+
7383
@Test
7484
public void should_createPackageJson() throws IOException {
7585
Options options = new Options(Mockito.mock(Lookup.class), npmFolder)

0 commit comments

Comments
 (0)