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

devonfw / IDEasy / 12084849850

29 Nov 2024 12:34PM UTC coverage: 67.031% (-0.4%) from 67.412%
12084849850

push

github

web-flow
#758: improve status commandlet (#816)

2500 of 4078 branches covered (61.3%)

Branch coverage included in aggregate %.

6515 of 9371 relevant lines covered (69.52%)

3.07 hits per line

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

82.51
cli/src/main/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesFile.java
1
package com.devonfw.tools.ide.environment;
2

3
import java.io.BufferedReader;
4
import java.io.BufferedWriter;
5
import java.io.IOException;
6
import java.nio.file.Files;
7
import java.nio.file.Path;
8
import java.nio.file.StandardOpenOption;
9
import java.util.ArrayList;
10
import java.util.HashMap;
11
import java.util.HashSet;
12
import java.util.List;
13
import java.util.Map;
14
import java.util.Objects;
15
import java.util.Set;
16

17
import com.devonfw.tools.ide.context.IdeContext;
18
import com.devonfw.tools.ide.variable.IdeVariables;
19
import com.devonfw.tools.ide.variable.VariableDefinition;
20

21
/**
22
 * Implementation of {@link EnvironmentVariables}.
23
 */
24
public final class EnvironmentVariablesPropertiesFile extends EnvironmentVariablesMap {
1✔
25

26
  private static final String NEWLINE = "\n";
27

28
  private final EnvironmentVariablesType type;
29

30
  private Path propertiesFilePath;
31

32
  private final Map<String, String> variables;
33

34
  private final Set<String> exportedVariables;
35

36
  private final Set<String> modifiedVariables;
37

38
  /**
39
   * The constructor.
40
   *
41
   * @param parent the parent {@link EnvironmentVariables} to inherit from.
42
   * @param type the {@link #getType() type}.
43
   * @param propertiesFilePath the {@link #getSource() source}.
44
   * @param context the {@link IdeContext}.
45
   */
46
  public EnvironmentVariablesPropertiesFile(AbstractEnvironmentVariables parent, EnvironmentVariablesType type,
47
      Path propertiesFilePath, IdeContext context) {
48

49
    super(parent, context);
4✔
50
    Objects.requireNonNull(type);
3✔
51
    assert (type != EnvironmentVariablesType.RESOLVED);
4!
52
    this.type = type;
3✔
53
    this.propertiesFilePath = propertiesFilePath;
3✔
54
    this.variables = new HashMap<>();
5✔
55
    this.exportedVariables = new HashSet<>();
5✔
56
    this.modifiedVariables = new HashSet<>();
5✔
57
    load();
2✔
58
  }
1✔
59

60
  private void load() {
61

62
    if (this.propertiesFilePath == null) {
3✔
63
      return;
1✔
64
    }
65
    if (!Files.exists(this.propertiesFilePath)) {
6✔
66
      this.context.trace("Properties not found at {}", this.propertiesFilePath);
11✔
67
      return;
1✔
68
    }
69
    this.context.trace("Loading properties from {}", this.propertiesFilePath);
11✔
70
    boolean legacyProperties = this.propertiesFilePath.getFileName().toString().equals(LEGACY_PROPERTIES);
7✔
71
    try (BufferedReader reader = Files.newBufferedReader(this.propertiesFilePath)) {
4✔
72
      String line;
73
      do {
74
        line = reader.readLine();
3✔
75
        if (line != null) {
2✔
76
          VariableLine variableLine = VariableLine.of(line, this.context, getSource());
7✔
77
          String name = variableLine.getName();
3✔
78
          if (name != null) {
2✔
79
            VariableLine migratedVariableLine = migrateLine(variableLine, false);
5✔
80
            if (migratedVariableLine == null) {
2!
81
              this.context.warning("Illegal variable definition: {}", variableLine);
×
82
              continue;
×
83
            }
84
            String migratedName = migratedVariableLine.getName();
3✔
85
            String migratedValue = migratedVariableLine.getValue();
3✔
86
            boolean legacyVariable = IdeVariables.isLegacyVariable(name);
3✔
87
            if (legacyVariable && !legacyProperties) {
4✔
88
              this.context.warning("Legacy variable name is used to define variable {} in {} - please cleanup your configuration.", variableLine,
15✔
89
                  this.propertiesFilePath);
90
            }
91
            String oldValue = this.variables.get(migratedName);
6✔
92
            if (oldValue != null) {
2✔
93
              VariableDefinition<?> variableDefinition = IdeVariables.get(name);
3✔
94
              if (legacyVariable) {
2✔
95
                // if the legacy name was configured we do not want to override the official variable!
96
                this.context.warning("Both legacy variable {} and official variable {} are configured in {} - ignoring legacy variable declaration!",
10✔
97
                    variableDefinition.getLegacyName(), variableDefinition.getName(), this.propertiesFilePath);
12✔
98
              } else {
99
                this.context.warning("Duplicate variable definition {} with old value '{}' and new value '{}' in {}", name, oldValue, migratedValue,
23✔
100
                    this.propertiesFilePath);
101
                this.variables.put(migratedName, migratedValue);
6✔
102
              }
103
            } else {
1✔
104
              this.variables.put(migratedName, migratedValue);
6✔
105
            }
106
            if (variableLine.isExport()) {
3✔
107
              this.exportedVariables.add(migratedName);
5✔
108
            }
109
          }
110
        }
111
      } while (line != null);
2✔
112
    } catch (IOException e) {
×
113
      throw new IllegalStateException("Failed to load properties from " + this.propertiesFilePath, e);
×
114
    }
1✔
115
  }
1✔
116

117
  @Override
118
  public void save() {
119

120
    if (this.modifiedVariables.isEmpty()) {
4!
121
      this.context.trace("No changes to save in properties file {}", this.propertiesFilePath);
×
122
      return;
×
123
    }
124
    Path newPropertiesFilePath = this.propertiesFilePath;
3✔
125
    String propertiesFileName = this.propertiesFilePath.getFileName().toString();
5✔
126
    Path propertiesParentPath = newPropertiesFilePath.getParent();
3✔
127

128
    if (LEGACY_PROPERTIES.equals(propertiesFileName)) {
4!
129
      newPropertiesFilePath = propertiesParentPath.resolve(DEFAULT_PROPERTIES);
×
130
      this.context.info("Converting legacy properties to {}", newPropertiesFilePath);
×
131
    }
132

133
    this.context.getFileAccess().mkdirs(propertiesParentPath);
5✔
134
    List<VariableLine> lines = new ArrayList<>();
4✔
135

136
    // Skip reading if the file does not exist
137
    if (Files.exists(this.propertiesFilePath)) {
6✔
138
      try (BufferedReader reader = Files.newBufferedReader(this.propertiesFilePath)) {
4✔
139
        String line;
140
        do {
141
          line = reader.readLine();
3✔
142
          if (line != null) {
2✔
143
            VariableLine variableLine = VariableLine.of(line, this.context, getSource());
7✔
144
            lines.add(variableLine);
4✔
145
          }
146
        } while (line != null);
2✔
147
      } catch (IOException e) {
×
148
        throw new IllegalStateException("Failed to load existing properties from " + this.propertiesFilePath, e);
×
149
      }
1✔
150
    } else {
151
      this.context.debug("Properties file {} does not exist, skipping read.", newPropertiesFilePath);
10✔
152
    }
153

154
    try (BufferedWriter writer = Files.newBufferedWriter(newPropertiesFilePath, StandardOpenOption.CREATE,
13✔
155
        StandardOpenOption.TRUNCATE_EXISTING)) {
156
      // copy and modify original lines from properties file
157
      for (VariableLine line : lines) {
10✔
158
        VariableLine newLine = migrateLine(line, true);
5✔
159
        if (newLine == null) {
2!
160
          this.context.debug("Removed variable line '{}' from {}", line, newPropertiesFilePath);
×
161
        } else {
162
          if (newLine != line) {
3✔
163
            this.context.debug("Changed variable line from '{}' to '{}' in {}", line, newLine, newPropertiesFilePath);
18✔
164
          }
165
          writer.append(newLine.toString());
5✔
166
          writer.append(NEWLINE);
4✔
167
          String name = line.getName();
3✔
168
          if (name != null) {
2✔
169
            this.modifiedVariables.remove(name);
5✔
170
          }
171
        }
172
      }
1✔
173
      // append variables that have been newly added
174
      for (String name : this.modifiedVariables) {
11✔
175
        String value = this.variables.get(name);
6✔
176
        if (value == null) {
2!
177
          this.context.trace("Internal error: removed variable {} was not found in {}", name, this.propertiesFilePath);
×
178
        } else {
179
          boolean export = this.exportedVariables.contains(name);
5✔
180
          VariableLine line = VariableLine.of(export, name, value);
5✔
181
          writer.append(line.toString());
5✔
182
          writer.append(NEWLINE);
4✔
183
        }
184
      }
1✔
185
      this.modifiedVariables.clear();
3✔
186
    } catch (IOException e) {
×
187
      throw new IllegalStateException("Failed to save properties to " + newPropertiesFilePath, e);
×
188
    }
1✔
189
    this.propertiesFilePath = newPropertiesFilePath;
3✔
190
  }
1✔
191

192
  private VariableLine migrateLine(VariableLine line, boolean saveNotLoad) {
193

194
    String name = line.getName();
3✔
195
    if (name != null) {
2✔
196
      VariableDefinition<?> variableDefinition = IdeVariables.get(name);
3✔
197
      if (variableDefinition != null) {
2✔
198
        line = variableDefinition.migrateLine(line);
4✔
199
      }
200
      if (saveNotLoad) {
2✔
201
        name = line.getName();
3✔
202
        if (this.modifiedVariables.contains(name)) {
5✔
203
          String value = this.variables.get(name);
6✔
204
          if (value == null) {
2!
205
            return null;
×
206
          } else {
207
            line = line.withValue(value);
4✔
208
          }
209
        }
210
        boolean newExport = this.exportedVariables.contains(name);
5✔
211
        if (line.isExport() != newExport) {
4✔
212
          line = line.withExport(newExport);
4✔
213
        }
214
      }
215
    }
216
    return line;
2✔
217
  }
218

219
  @Override
220
  protected Map<String, String> getVariables() {
221

222
    return this.variables;
3✔
223
  }
224

225
  @Override
226
  protected void collectVariables(Map<String, VariableLine> variables, boolean onlyExported, AbstractEnvironmentVariables resolver) {
227

228
    for (String key : this.variables.keySet()) {
12✔
229
      variables.computeIfAbsent(key, k -> createVariableLine(key, onlyExported, resolver));
15✔
230
    }
1✔
231
    super.collectVariables(variables, onlyExported, resolver);
5✔
232
  }
1✔
233

234
  @Override
235
  protected boolean isExported(String name) {
236

237
    if (this.exportedVariables.contains(name)) {
5!
238
      return true;
×
239
    }
240
    return super.isExported(name);
4✔
241
  }
242

243
  @Override
244
  public EnvironmentVariablesType getType() {
245

246
    return this.type;
3✔
247
  }
248

249
  @Override
250
  public Path getPropertiesFilePath() {
251

252
    return this.propertiesFilePath;
3✔
253
  }
254

255
  @Override
256
  public Path getLegacyPropertiesFilePath() {
257

258
    if (this.propertiesFilePath == null) {
×
259
      return null;
×
260
    }
261
    if (this.propertiesFilePath.getFileName().toString().equals(LEGACY_PROPERTIES)) {
×
262
      return this.propertiesFilePath;
×
263
    }
264
    Path legacyProperties = this.propertiesFilePath.getParent().resolve(LEGACY_PROPERTIES);
×
265
    if (Files.exists(legacyProperties)) {
×
266
      return legacyProperties;
×
267
    }
268
    return null;
×
269
  }
270

271
  @Override
272
  public String set(String name, String value, boolean export) {
273

274
    String oldValue = this.variables.put(name, value);
7✔
275
    boolean flagChanged = export != this.exportedVariables.contains(name);
10✔
276
    if (Objects.equals(value, oldValue) && !flagChanged) {
6✔
277
      this.context.trace("Set variable '{}={}' caused no change in {}", name, value, this.propertiesFilePath);
20✔
278
    } else {
279
      this.context.debug("Set variable '{}={}' in {}", name, value, this.propertiesFilePath);
19✔
280
      this.modifiedVariables.add(name);
5✔
281
      if (export && (value != null)) {
4!
282
        this.exportedVariables.add(name);
6✔
283
      } else {
284
        this.exportedVariables.remove(name);
5✔
285
      }
286
    }
287
    return oldValue;
2✔
288
  }
289

290
}
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

© 2025 Coveralls, Inc