• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

devonfw / IDEasy / 22345446363

24 Feb 2026 09:49AM UTC coverage: 70.247% (-0.2%) from 70.474%
22345446363

Pull #1714

github

web-flow
Merge 5655b6589 into 379acdc9d
Pull Request #1714: #404: #1713: advanced logging

4065 of 6384 branches covered (63.67%)

Branch coverage included in aggregate %.

10597 of 14488 relevant lines covered (73.14%)

3.08 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

65.79
cli/src/main/java/com/devonfw/tools/ide/merge/DirectoryMerger.java
1
package com.devonfw.tools.ide.merge;
2

3
import java.io.IOException;
4
import java.nio.file.Files;
5
import java.nio.file.Path;
6
import java.util.HashMap;
7
import java.util.HashSet;
8
import java.util.Iterator;
9
import java.util.Map;
10
import java.util.Set;
11
import java.util.stream.Stream;
12

13
import org.jline.utils.Log;
14
import org.slf4j.Logger;
15
import org.slf4j.LoggerFactory;
16

17
import com.devonfw.tools.ide.context.IdeContext;
18
import com.devonfw.tools.ide.environment.EnvironmentVariables;
19
import com.devonfw.tools.ide.merge.xml.XmlMerger;
20
import com.devonfw.tools.ide.util.FilenameUtil;
21

22
/**
23
 * Implementation of {@link WorkspaceMerger} that does the whole thing:
24
 * <ul>
25
 * <li>It will recursively traverse directories.</li>
26
 * <li>For each setup or update file if will delegate to the according {@link FileMerger} based on the file
27
 * extension.</li>
28
 * </ul>
29
 */
30
public class DirectoryMerger extends AbstractWorkspaceMerger {
31

32
  private static final Logger LOG = LoggerFactory.getLogger(DirectoryMerger.class);
4✔
33

34
  private final Map<String, FileMerger> extension2mergerMap;
35

36
  private final FallbackMerger fallbackMerger;
37

38
  /**
39
   * The constructor.
40
   *
41
   * @param context the {@link #context}.
42
   */
43
  public DirectoryMerger(IdeContext context) {
44

45
    super(context);
3✔
46
    this.extension2mergerMap = new HashMap<>();
5✔
47
    PropertiesMerger propertiesMerger = new PropertiesMerger(context);
5✔
48
    this.extension2mergerMap.put("properties", propertiesMerger);
6✔
49
    this.extension2mergerMap.put("prefs", propertiesMerger); // Eclipse specific
6✔
50
    XmlMerger xmlMerger = new XmlMerger(context);
5✔
51
    this.extension2mergerMap.put("xml", xmlMerger);
6✔
52
    this.extension2mergerMap.put("xmi", xmlMerger);
6✔
53
    this.extension2mergerMap.put("launch", xmlMerger); // Eclipse specific
6✔
54
    JsonMerger jsonMerger = new JsonMerger(context);
5✔
55
    this.extension2mergerMap.put("json", jsonMerger);
6✔
56
    TextMerger textMerger = new TextMerger(context);
5✔
57
    this.extension2mergerMap.put("name", textMerger); // intellij specific
6✔
58
    this.extension2mergerMap.put("editorconfig", textMerger);
6✔
59
    this.extension2mergerMap.put("txt", textMerger);
6✔
60
    this.fallbackMerger = new FallbackMerger(context);
6✔
61
  }
1✔
62

63
  @Override
64
  public int merge(Path setup, Path update, EnvironmentVariables variables, Path workspace) {
65

66
    int errors = 0;
2✔
67
    Set<String> children = null;
2✔
68
    children = addChildren(setup, children);
5✔
69
    children = addChildren(update, children);
5✔
70
    if (children == null) {
2✔
71
      // file merge
72
      FileMerger merger = getMerger(workspace);
4✔
73
      errors += merger.merge(setup, update, variables, workspace);
9✔
74
    } else {
1✔
75
      // directory scan
76
      for (String filename : children) {
10✔
77
        errors += merge(setup.resolve(filename), update.resolve(filename), variables, workspace.resolve(filename));
15✔
78
      }
1✔
79
    }
80
    return errors;
2✔
81
  }
82

83
  private FileMerger getMerger(Path file) {
84

85
    String filename = file.getFileName().toString();
4✔
86
    String extension = FilenameUtil.getExtension(filename);
3✔
87
    if (extension == null) {
2!
88
      LOG.debug("No extension for {}", file);
×
89
    } else {
90
      LOG.trace("Extension is {}", extension);
4✔
91
      FileMerger merger = this.extension2mergerMap.get(extension);
6✔
92
      if (merger != null) {
2✔
93
        return merger;
2✔
94
      }
95
    }
96
    return this.fallbackMerger;
3✔
97
  }
98

99
  @Override
100
  public void inverseMerge(Path workspace, EnvironmentVariables variables, boolean addNewProperties, Path update) {
101

102
    if (Files.isDirectory(update)) {
×
103
      if (!Files.isDirectory(workspace)) {
×
104
        Log.warn("Workspace is missing directory: {}", workspace);
×
105
        return;
×
106
      }
107
      Log.trace("Traversing directory: {}", update);
×
108
      try (Stream<Path> childStream = Files.list(update)) {
×
109
        Iterator<Path> iterator = childStream.iterator();
×
110
        while (iterator.hasNext()) {
×
111
          Path updateChild = iterator.next();
×
112
          Path fileName = updateChild.getFileName();
×
113
          inverseMerge(workspace.resolve(fileName), variables, addNewProperties, update.resolve(fileName));
×
114
        }
×
115
      } catch (IOException e) {
×
116
        throw new IllegalStateException("Failed to list children of folder " + update, e);
×
117
      }
×
118

119
    } else if (Files.exists(workspace)) {
×
120
      Log.debug("Start merging of changes from workspace back to file: {}", update);
×
121
      FileMerger merger = getMerger(workspace);
×
122
      Log.trace("Using merger {}", merger.getClass().getSimpleName());
×
123
      merger.inverseMerge(workspace, variables, addNewProperties, update);
×
124
    } else {
×
125
      Log.warn("No such file or directory: {}", update);
×
126
    }
127
  }
×
128

129
  private Set<String> addChildren(Path folder, Set<String> children) {
130

131
    if (!Files.isDirectory(folder)) {
5✔
132
      return children;
2✔
133
    }
134
    try (Stream<Path> childStream = Files.list(folder)) {
3✔
135
      Iterator<Path> iterator = childStream.iterator();
3✔
136
      while (iterator.hasNext()) {
3✔
137
        Path child = iterator.next();
4✔
138
        if (children == null) {
2✔
139
          children = new HashSet<>();
4✔
140
        }
141
        children.add(child.getFileName().toString());
6✔
142
      }
1✔
143
      return children;
4✔
144
    } catch (IOException e) {
×
145
      throw new IllegalStateException("Failed to list children of folder " + folder, e);
×
146
    }
147
  }
148

149
  @Override
150
  public void upgrade(Path folder) {
151

152
    try (Stream<Path> childStream = Files.list(folder)) {
3✔
153
      Iterator<Path> iterator = childStream.iterator();
3✔
154
      while (iterator.hasNext()) {
3✔
155
        Path child = iterator.next();
4✔
156
        if (Files.isDirectory(child)) {
5!
157
          upgrade(child);
×
158
        } else {
159
          FileMerger merger = getMerger(child);
4✔
160
          merger.upgrade(child);
3✔
161
        }
162
      }
1✔
163
    } catch (IOException e) {
×
164
      throw new IllegalStateException("Failed to list children of folder " + folder, e);
×
165
    }
1✔
166
  }
1✔
167

168
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc