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

devonfw / IDEasy / 9907372175

12 Jul 2024 11:49AM UTC coverage: 61.142% (-0.02%) from 61.162%
9907372175

push

github

hohwille
fixed tests

1997 of 3595 branches covered (55.55%)

Branch coverage included in aggregate %.

5296 of 8333 relevant lines covered (63.55%)

2.8 hits per line

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

13.95
cli/src/main/java/com/devonfw/tools/ide/repo/CustomToolRepositoryImpl.java
1
package com.devonfw.tools.ide.repo;
2

3
import java.io.BufferedReader;
4
import java.io.InputStream;
5
import java.io.InputStreamReader;
6
import java.io.Reader;
7
import java.net.URLDecoder;
8
import java.nio.charset.StandardCharsets;
9
import java.nio.file.Files;
10
import java.nio.file.Path;
11
import java.util.ArrayList;
12
import java.util.Collection;
13
import java.util.Collections;
14
import java.util.HashMap;
15
import java.util.List;
16
import java.util.Map;
17
import javax.json.Json;
18
import javax.json.JsonArray;
19
import javax.json.JsonObject;
20
import javax.json.JsonReader;
21
import javax.json.JsonString;
22
import javax.json.JsonStructure;
23
import javax.json.JsonValue;
24
import javax.json.JsonValue.ValueType;
25

26
import com.devonfw.tools.ide.context.IdeContext;
27
import com.devonfw.tools.ide.url.model.file.UrlDownloadFileMetadata;
28
import com.devonfw.tools.ide.version.VersionIdentifier;
29

30
/**
31
 * Implementation of {@link CustomToolRepository}.
32
 */
33
public class CustomToolRepositoryImpl extends AbstractToolRepository implements CustomToolRepository {
34

35
  private final String id;
36

37
  private final Map<String, CustomTool> toolsMap;
38

39
  private final Collection<CustomTool> tools;
40

41
  /**
42
   * The constructor.
43
   *
44
   * @param context the owning {@link IdeContext}.
45
   * @param tools the {@link CustomTool}s.
46
   */
47
  public CustomToolRepositoryImpl(IdeContext context, Collection<CustomTool> tools) {
48

49
    super(context);
3✔
50
    this.toolsMap = new HashMap<>(tools.size());
7✔
51
    String repoId = null;
2✔
52
    for (CustomTool tool : tools) {
6!
53
      String name = tool.getTool();
×
54
      CustomTool duplicate = this.toolsMap.put(name, tool);
×
55
      if (duplicate != null) {
×
56
        throw new IllegalStateException("Duplicate custom tool '" + name + "'!");
×
57
      }
58
      if (repoId == null) {
×
59
        repoId = computeId(tool.getRepositoryUrl());
×
60
      }
61
    }
×
62
    if (repoId == null) {
2!
63
      repoId = "custom";
2✔
64
    }
65
    this.id = repoId;
3✔
66
    this.tools = Collections.unmodifiableCollection(this.toolsMap.values());
6✔
67
  }
1✔
68

69
  private static String computeId(String url) {
70

71
    String id = url;
×
72
    int schemaIndex = id.indexOf("://");
×
73
    if (schemaIndex > 0) {
×
74
      id = id.substring(schemaIndex + 3); // remove schema like "https://"
×
75
      id = URLDecoder.decode(id, StandardCharsets.UTF_8);
×
76
    }
77
    id.replace('\\', '/').replace("//", "/"); // normalize slashes
×
78
    if (id.startsWith("/")) {
×
79
      id = id.substring(1);
×
80
    }
81
    StringBuilder sb = new StringBuilder(id.length());
×
82
    if (schemaIndex > 0) { // was a URL?
×
83
      int slashIndex = id.indexOf('/');
×
84
      if (slashIndex > 0) {
×
85
        sb.append(id.substring(0, slashIndex).replace(':', '_'));
×
86
        sb.append('/');
×
87
        id = id.substring(slashIndex + 1);
×
88
      }
89
    }
90
    int length = id.length();
×
91
    for (int i = 0; i < length; i++) {
×
92
      char c = id.charAt(i);
×
93
      if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || ((c >= '0') && (c <= '9')) || (c == '.')
×
94
          || (c == '-')) {
95
        sb.append(c);
×
96
      } else {
97
        sb.append('_');
×
98
      }
99
    }
100
    return sb.toString();
×
101
  }
102

103
  @Override
104
  public String getId() {
105

106
    return this.id;
×
107
  }
108

109
  @Override
110
  protected UrlDownloadFileMetadata getMetadata(String tool, String edition, VersionIdentifier version) {
111

112
    CustomTool customTool = this.toolsMap.get(tool);
×
113
    if (customTool == null) {
×
114
      throw new IllegalArgumentException("Undefined custom tool '" + tool + "'!");
×
115
    }
116
    if (!version.equals(customTool.getVersion())) {
×
117
      throw new IllegalArgumentException("Undefined version '" + version + "' for custom tool '" + tool
×
118
          + "' - expected version '" + customTool.getVersion() + "'!");
×
119
    }
120
    if (!edition.equals(customTool.getEdition())) {
×
121
      throw new IllegalArgumentException("Undefined edition '" + edition + "' for custom tool '" + tool + "'!");
×
122
    }
123
    return customTool;
×
124
  }
125

126
  @Override
127
  public VersionIdentifier resolveVersion(String tool, String edition, VersionIdentifier version) {
128

129
    return getMetadata(tool, edition, version).getVersion();
×
130
  }
131

132
  @Override
133
  public Collection<CustomTool> getTools() {
134

135
    return this.tools;
3✔
136
  }
137

138
  /**
139
   * @param context the owning {@link IdeContext}.
140
   * @return the {@link CustomToolRepository}.
141
   */
142
  public static CustomToolRepository of(IdeContext context) {
143

144
    Path settingsPath = context.getSettingsPath();
3✔
145
    Path customToolsJson = null;
2✔
146
    if (settingsPath != null) {
2✔
147
      customToolsJson = settingsPath.resolve(FILE_CUSTOM_TOOLS);
4✔
148
    }
149
    List<CustomTool> tools = new ArrayList<>();
4✔
150
    if ((customToolsJson != null) && Files.exists(customToolsJson)) {
7!
151
      try (InputStream in = Files.newInputStream(customToolsJson);
×
152
          Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8)) {
×
153

154
        JsonReader jsonReader = Json.createReader(new BufferedReader(reader));
×
155
        JsonStructure json = jsonReader.read();
×
156
        JsonObject jsonRoot = requireObject(json);
×
157
        String defaultUrl = getString(jsonRoot, "url", "");
×
158
        JsonArray jsonTools = requireArray(jsonRoot.get("tools"));
×
159
        for (JsonValue jsonTool : jsonTools) {
×
160
          JsonObject jsonToolObject = requireObject(jsonTool);
×
161
          String name = getString(jsonToolObject, "name");
×
162
          String version = getString(jsonToolObject, "version");
×
163
          String url = getString(jsonToolObject, "url", defaultUrl);
×
164
          boolean osAgnostic = getBoolean(jsonToolObject, "os-agnostic", Boolean.FALSE);
×
165
          boolean archAgnostic = getBoolean(jsonToolObject, "arch-agnostic", Boolean.TRUE);
×
166
          if (url.isEmpty()) {
×
167
            throw new IllegalStateException("Missing 'url' property for tool '" + name + "'!");
×
168
          }
169
          // TODO
170
          String checksum = null;
×
171
          CustomTool customTool = new CustomTool(name, VersionIdentifier.of(version), osAgnostic, archAgnostic, url,
×
172
              checksum, context.getSystemInfo());
×
173
          tools.add(customTool);
×
174
        }
×
175
      } catch (Exception e) {
×
176
        throw new IllegalStateException("Failed to read JSON from " + customToolsJson, e);
×
177
      }
×
178
    }
179
    return new CustomToolRepositoryImpl(context, tools);
6✔
180
  }
181

182
  private static boolean getBoolean(JsonObject json, String property, Boolean defaultValue) {
183

184
    JsonValue value = json.get(property);
×
185
    if (value == null) {
×
186
      if (defaultValue == null) {
×
187
        throw new IllegalArgumentException("Missing string property '" + property + "' in JSON: " + json);
×
188
      }
189
      return defaultValue.booleanValue();
×
190
    }
191
    ValueType valueType = value.getValueType();
×
192
    if (valueType == ValueType.TRUE) {
×
193
      return true;
×
194
    } else if (valueType == ValueType.FALSE) {
×
195
      return false;
×
196
    } else {
197
      throw new IllegalStateException("Expected value type boolean but found " + valueType + " for JSON: " + json);
×
198
    }
199
  }
200

201
  private static String getString(JsonObject json, String property) {
202

203
    return getString(json, property, null);
×
204
  }
205

206
  private static String getString(JsonObject json, String property, String defaultValue) {
207

208
    JsonValue value = json.get(property);
×
209
    if (value == null) {
×
210
      if (defaultValue == null) {
×
211
        throw new IllegalArgumentException("Missing string property '" + property + "' in JSON: " + json);
×
212
      }
213
      return defaultValue;
×
214
    }
215
    require(value, ValueType.STRING);
×
216
    return ((JsonString) value).getString();
×
217
  }
218

219
  /**
220
   * @param json the {@link JsonValue} to check.
221
   */
222
  private static JsonObject requireObject(JsonValue json) {
223

224
    require(json, ValueType.OBJECT);
×
225
    return (JsonObject) json;
×
226
  }
227

228
  /**
229
   * @param json the {@link JsonValue} to check.
230
   */
231
  private static JsonArray requireArray(JsonValue json) {
232

233
    require(json, ValueType.ARRAY);
×
234
    return (JsonArray) json;
×
235
  }
236

237
  /**
238
   * @param json the {@link JsonValue} to check.
239
   * @param type the expected {@link ValueType}.
240
   */
241
  private static void require(JsonValue json, ValueType type) {
242

243
    ValueType actualType = json.getValueType();
×
244
    if (actualType != type) {
×
245
      throw new IllegalStateException(
×
246
          "Expected value type " + type + " but found " + actualType + " for JSON: " + json);
247
    }
248
  }
×
249

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