Skip to content

Commit 3c85ec1

Browse files
committed
devonfw#759: rewritten implementation to upgrade variable expressions in workspace templates
1 parent 1902729 commit 3c85ec1

12 files changed

+391
-178
lines changed

cli/src/main/java/com/devonfw/tools/ide/commandlet/UpgradeSettingsCommandlet.java

+25-149
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,23 @@
11
package com.devonfw.tools.ide.commandlet;
22

3-
import java.io.BufferedReader;
43
import java.io.FileWriter;
54
import java.io.IOException;
6-
import java.nio.file.AccessDeniedException;
75
import java.nio.file.Files;
86
import java.nio.file.Path;
97
import java.nio.file.StandardCopyOption;
108
import java.nio.file.StandardOpenOption;
119
import java.util.ArrayList;
1210
import java.util.List;
13-
import java.util.Map;
1411
import java.util.Map.Entry;
1512
import java.util.Properties;
16-
import java.util.concurrent.atomic.AtomicBoolean;
1713
import java.util.stream.Collectors;
1814

1915
import org.json.simple.JSONArray;
2016
import org.json.simple.JSONObject;
2117

2218
import com.devonfw.tools.ide.context.IdeContext;
2319
import com.devonfw.tools.ide.environment.EnvironmentVariables;
20+
import com.devonfw.tools.ide.merge.DirectoryMerger;
2421

2522
/**
2623
* {@link Commandlet} to upgrade settings after a migration from devofw-ide to IDEasy.
@@ -50,8 +47,6 @@ public void run() {
5047
updateDevonProperties();
5148
replaceLegacyVariablesAndBracketsInWorkspace();
5249
checkIfLegacyFolderExists();
53-
handleReplacementPatternsFiles();
54-
checkForXmlNamespace();
5550
}
5651

5752
private void checkIfLegacyFolderExists() {
@@ -96,158 +91,39 @@ private void checkIfLegacyFolderExists() {
9691
private void replaceLegacyVariablesAndBracketsInWorkspace() {
9792
this.context.info("Scanning for legacy variables...");
9893

99-
Map<String, String> legacyToNewMapping = Map.of(
100-
"${DEVON_IDE_HOME}", "$[IDE_HOME]",
101-
"${MAVEN_VERSION}", "$[MVN_VERSION]",
102-
"${SETTINGS_PATH}", "$[IDE_HOME]/settings"
103-
);
104-
105-
Path settingsDirectory = context.getIdeHome().resolve("settings");
106-
107-
try {
108-
Files.walk(settingsDirectory)
109-
.filter(path -> Files.isDirectory(path) && path.getFileName().toString().equals("workspace"))
110-
.forEach(workspaceDir -> {
111-
try {
112-
Files.walk(workspaceDir)
113-
.filter(Files::isRegularFile)
114-
.forEach(file -> {
115-
try {
116-
String content = Files.readString(file);
117-
String originalContent = content;
118-
119-
for (Map.Entry<String, String> entry : legacyToNewMapping.entrySet()) {
120-
content = content.replace(entry.getKey(), entry.getValue());
121-
}
122-
123-
content = content.replace("{", "[");
124-
content = content.replace("}", "]");
125-
126-
if (!content.equals(originalContent)) {
127-
Files.writeString(file, content, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
128-
this.context.success("Successfully updated variables/brackets " + file);
129-
}
130-
} catch (AccessDeniedException e) {
131-
this.context.error("Access denied to file: " + file + ", exception: " + e);
132-
} catch (IOException e) {
133-
this.context.error("Error processing file: " + file + ", exception: " + e);
134-
}
135-
});
136-
} catch (IOException e) {
137-
this.context.error("Error while processing files in workspace: " + workspaceDir, e);
138-
}
139-
});
140-
} catch (IOException e) {
141-
this.context.error("Error while scanning for workspace directories", e);
142-
}
143-
}
144-
145-
private void handleReplacementPatternsFiles() {
146-
this.context.info("Scanning for legacy files");
147-
148-
Path settingsDirectory = context.getIdeHome().resolve("settings");
149-
150-
try {
151-
Files.walk(settingsDirectory)
152-
.filter(path -> Files.isRegularFile(path) && path.getFileName().toString().equals("replacement-patterns.properties"))
153-
.forEach(file -> {
154-
try {
155-
String content = Files.readString(file);
156-
if (!content.trim().isEmpty()) {
157-
this.context.warning("The file 'replacement-patterns.properties' is not empty: " + file);
158-
}
159-
160-
Files.delete(file);
161-
this.context.success("Deleted 'replacement-patterns.properties' from: " + file);
162-
} catch (IOException e) {
163-
this.context.error("Error processing 'replacement-patterns.properties' file: " + file, e);
164-
}
165-
});
166-
} catch (IOException e) {
167-
this.context.error("Error scanning for 'replacement-patterns.properties' file", e);
94+
DirectoryMerger merger = this.context.getWorkspaceMerger();
95+
Path settingsDir = this.context.getSettingsPath();
96+
Path workspaceDir = settingsDir.resolve(IdeContext.FOLDER_WORKSPACE);
97+
if (Files.isDirectory(workspaceDir)) {
98+
merger.upgrade(workspaceDir);
16899
}
169-
}
170-
171-
private void checkForXmlNamespace() {
172-
this.context.info("Scanning XML files...");
173-
Path settingsDirectory = context.getSettingsPath();
174-
AtomicBoolean missingNamespaceFound = new AtomicBoolean(false);
175-
176-
try {
177-
List<Path> workspaceDirs = findWorkspaceDirectories(settingsDirectory);
178-
179-
for (Path workspaceDir : workspaceDirs) {
180-
missingNamespaceFound.set(
181-
checkXmlFilesForNamespace(workspaceDir, missingNamespaceFound.get()));
100+
this.context.getFileAccess().listChildrenMapped(settingsDir, child -> {
101+
Path childWorkspaceDir = child.resolve(IdeContext.FOLDER_WORKSPACE);
102+
if (Files.isDirectory(childWorkspaceDir)) {
103+
merger.upgrade(childWorkspaceDir);
182104
}
183-
184-
// Output the result
185-
if (missingNamespaceFound.get()) {
186-
this.context.warning("For further information, please visit https://github.com/devonfw/IDEasy/blob/main/documentation/configurator.adoc#xml-merger");
187-
} else {
188-
this.context.success("Your XML files are up to date");
189-
}
190-
191-
} catch (IOException e) {
192-
this.context.error("Error walking through the 'settings' directory", e);
193-
}
105+
return null;
106+
});
194107
}
195108

196-
private List<Path> findWorkspaceDirectories(Path settingsDirectory) throws IOException {
109+
private List<Path> findWorkspaceDirectories() {
110+
Path settingsDir = this.context.getSettingsPath();
197111
List<Path> workspaceDirs = new ArrayList<>();
198-
Files.walk(settingsDirectory)
199-
.filter(path -> Files.isDirectory(path) && path.getFileName().toString().equals("workspace"))
200-
.forEach(workspaceDirs::add);
201-
return workspaceDirs;
202-
}
203-
204-
private boolean checkXmlFilesForNamespace(Path workspaceDir, boolean missingNamespaceFound) {
205-
try {
206-
List<Path> xmlFiles = findXmlFilesInDirectory(workspaceDir);
207-
208-
for (Path xmlFile : xmlFiles) {
209-
missingNamespaceFound = checkXmlNamespaceInFile(xmlFile, missingNamespaceFound);
210-
}
211-
} catch (IOException e) {
212-
this.context.error("Error processing workspace directory: " + workspaceDir, e);
112+
Path workspaceDir = settingsDir.resolve(IdeContext.FOLDER_WORKSPACE);
113+
if (Files.isDirectory(workspaceDir)) {
114+
workspaceDirs.add(workspaceDir);
213115
}
214-
return missingNamespaceFound;
215-
}
216-
217-
private List<Path> findXmlFilesInDirectory(Path directory) throws IOException {
218-
List<Path> xmlFiles = new ArrayList<>();
219-
Files.walk(directory)
220-
.filter(file -> Files.isRegularFile(file) && file.toString().endsWith(".xml"))
221-
.forEach(xmlFiles::add);
222-
return xmlFiles;
223-
}
224-
225-
private boolean checkXmlNamespaceInFile(Path xmlFile, boolean missingNamespaceFound) {
226-
try (BufferedReader reader = Files.newBufferedReader(xmlFile)) {
227-
String line;
228-
int linesRead = 0;
229-
boolean namespaceFound = false;
230-
231-
while ((line = reader.readLine()) != null && linesRead < 3) {
232-
linesRead++;
233-
if (line.contains("\"https://github.com/devonfw/IDEasy/merge\"")) {
234-
namespaceFound = true;
235-
break;
236-
}
116+
List<Path> childWorkspaceDirs = this.context.getFileAccess().listChildrenMapped(settingsDir, child -> {
117+
Path childWorkspaceDir = child.resolve(IdeContext.FOLDER_WORKSPACE);
118+
if (Files.isDirectory(childWorkspaceDir)) {
119+
return childWorkspaceDir;
237120
}
238-
239-
if (!namespaceFound) {
240-
this.context.warning("The XML file " + xmlFile + " does not contain the required 'xmlns:merge' attribute.");
241-
missingNamespaceFound = true;
242-
}
243-
244-
} catch (IOException e) {
245-
this.context.error("Error reading the file: " + xmlFile, e);
246-
}
247-
return missingNamespaceFound;
121+
return null;
122+
});
123+
workspaceDirs.addAll(childWorkspaceDirs);
124+
return workspaceDirs;
248125
}
249126

250-
251127
private void createCustomToolsJson(String variable) {
252128
try (FileWriter writer = new FileWriter(context.getIdeHome().resolve("settings").resolve(IdeContext.FILE_CUSTOM_TOOLS).toString())) {
253129
JSONArray tabelObject = new JSONArray();

cli/src/main/java/com/devonfw/tools/ide/io/FileAccess.java

+14-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.List;
66
import java.util.Set;
77
import java.util.function.Consumer;
8+
import java.util.function.Function;
89
import java.util.function.Predicate;
910

1011
/**
@@ -237,7 +238,19 @@ default void extract(Path archiveFile, Path targetDir, Consumer<Path> postExtrac
237238
* @return all children of the given {@link Path} that match the given {@link Predicate}. Will be the empty list of the given {@link Path} is not an existing
238239
* directory.
239240
*/
240-
List<Path> listChildren(Path dir, Predicate<Path> filter);
241+
default List<Path> listChildren(Path dir, Predicate<Path> filter) {
242+
243+
return listChildrenMapped(dir, child -> (filter.test(child)) ? child : null);
244+
}
245+
246+
/**
247+
* @param dir the {@link Path} to the directory where to list the children.
248+
* @param filter the filter {@link Function} used to {@link Function#apply(Object) filter and transform} children to include. If the {@link Function}
249+
* returns {@code null}, the child will be filtered, otherwise the returned {@link Path} will be included in the resulting {@link List}.
250+
* @return all children of the given {@link Path} returned by the given {@link Function}. Will be the empty list of the given {@link Path} is not an existing
251+
* directory.
252+
*/
253+
List<Path> listChildrenMapped(Path dir, Function<Path, Path> filter);
241254

242255
/**
243256
* Finds the existing file with the specified name in the given list of directories.

cli/src/main/java/com/devonfw/tools/ide/io/FileAccessImpl.java

+9-4
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,7 @@ private Path findFirstRecursive(Path dir, Predicate<Path> filter, boolean recurs
828828
}
829829

830830
@Override
831-
public List<Path> listChildren(Path dir, Predicate<Path> filter) {
831+
public List<Path> listChildrenMapped(Path dir, Function<Path, Path> filter) {
832832

833833
if (!Files.isDirectory(dir)) {
834834
return List.of();
@@ -838,9 +838,14 @@ public List<Path> listChildren(Path dir, Predicate<Path> filter) {
838838
Iterator<Path> iterator = childStream.iterator();
839839
while (iterator.hasNext()) {
840840
Path child = iterator.next();
841-
if (filter.test(child)) {
842-
this.context.trace("Accepted file {}", child);
843-
children.add(child);
841+
Path filteredChild = filter.apply(child);
842+
if (filteredChild != null) {
843+
if (filteredChild == child) {
844+
this.context.trace("Accepted file {}", child);
845+
} else {
846+
this.context.trace("Accepted file {} and mapped to {}", child, filteredChild);
847+
}
848+
children.add(filteredChild);
844849
} else {
845850
this.context.trace("Ignoring file {} according to filter", child);
846851
}

cli/src/main/java/com/devonfw/tools/ide/merge/AbstractWorkspaceMerger.java

-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88

99
/**
1010
* {@link WorkspaceMerger} responsible for a single type of {@link Path}.
11-
*
12-
* @since 3.0.0
1311
*/
1412
public abstract class AbstractWorkspaceMerger implements WorkspaceMerger {
1513

cli/src/main/java/com/devonfw/tools/ide/merge/DirectoryMerger.java

+29-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.util.Iterator;
99
import java.util.Map;
1010
import java.util.Set;
11+
import java.util.stream.Stream;
1112

1213
import org.jline.utils.Log;
1314

@@ -99,8 +100,8 @@ public void inverseMerge(Path workspace, EnvironmentVariables variables, boolean
99100
return;
100101
}
101102
Log.trace("Traversing directory: {}", update);
102-
try {
103-
Iterator<Path> iterator = Files.list(update).iterator();
103+
try (Stream<Path> childStream = Files.list(update)) {
104+
Iterator<Path> iterator = childStream.iterator();
104105
while (iterator.hasNext()) {
105106
Path updateChild = iterator.next();
106107
Path fileName = updateChild.getFileName();
@@ -125,8 +126,8 @@ private Set<String> addChildren(Path folder, Set<String> children) {
125126
if (!Files.isDirectory(folder)) {
126127
return children;
127128
}
128-
try {
129-
Iterator<Path> iterator = Files.list(folder).iterator();
129+
try (Stream<Path> childStream = Files.list(folder)) {
130+
Iterator<Path> iterator = childStream.iterator();
130131
while (iterator.hasNext()) {
131132
Path child = iterator.next();
132133
if (children == null) {
@@ -140,4 +141,28 @@ private Set<String> addChildren(Path folder, Set<String> children) {
140141
}
141142
}
142143

144+
@Override
145+
public void upgrade(Path folder) {
146+
147+
try (Stream<Path> childStream = Files.list(folder)) {
148+
Iterator<Path> iterator = childStream.iterator();
149+
while (iterator.hasNext()) {
150+
Path child = iterator.next();
151+
if (Files.isDirectory(child)) {
152+
upgrade(child);
153+
} else {
154+
String filename = child.getFileName().toString();
155+
if ("replacement-patterns.properties".equals(filename)) {
156+
this.context.warning("Found obsolete file {}", child);
157+
// Files.delete(child);
158+
}
159+
FileMerger merger = getMerger(child);
160+
merger.upgrade(child);
161+
}
162+
}
163+
} catch (IOException e) {
164+
throw new IllegalStateException("Failed to list children of folder " + folder, e);
165+
}
166+
}
167+
143168
}

cli/src/main/java/com/devonfw/tools/ide/merge/FallbackMerger.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88

99
/**
1010
* Implementation of {@link FileMerger} to use as fallback. It can not actually merge but will simply overwrite the files.
11-
*
12-
* @since 3.0.0
1311
*/
1412
public class FallbackMerger extends FileMerger {
1513

@@ -39,4 +37,9 @@ public void inverseMerge(Path workspaceFile, EnvironmentVariables resolver, bool
3937
// nothing by default, we could copy the workspace file back to the update file if it exists...
4038
}
4139

40+
@Override
41+
protected boolean doUpgrade(Path workspaceFile) throws Exception {
42+
43+
return false;
44+
}
4245
}

0 commit comments

Comments
 (0)