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

devonfw / IDEasy / 13055946744

30 Jan 2025 03:47PM UTC coverage: 68.557% (+0.1%) from 68.45%
13055946744

push

github

web-flow
#993: create IDE start scripts (#994)

Co-authored-by: jan-vcapgemini <59438728+jan-vcapgemini@users.noreply.github.com>

2809 of 4495 branches covered (62.49%)

Branch coverage included in aggregate %.

7260 of 10192 relevant lines covered (71.23%)

3.1 hits per line

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

81.91
cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java
1
package com.devonfw.tools.ide.commandlet;
2

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

12
import com.devonfw.tools.ide.context.AbstractIdeContext;
13
import com.devonfw.tools.ide.context.IdeContext;
14
import com.devonfw.tools.ide.git.GitContext;
15
import com.devonfw.tools.ide.git.GitUrl;
16
import com.devonfw.tools.ide.io.FileAccess;
17
import com.devonfw.tools.ide.property.FlagProperty;
18
import com.devonfw.tools.ide.property.StringProperty;
19
import com.devonfw.tools.ide.repo.CustomToolMetadata;
20
import com.devonfw.tools.ide.step.Step;
21
import com.devonfw.tools.ide.tool.CustomToolCommandlet;
22
import com.devonfw.tools.ide.tool.ToolCommandlet;
23
import com.devonfw.tools.ide.variable.IdeVariables;
24

25
/**
26
 * Abstract {@link Commandlet} base-class for both {@link UpdateCommandlet} and {@link CreateCommandlet}.
27
 */
28
public abstract class AbstractUpdateCommandlet extends Commandlet {
29

30
  /** {@link StringProperty} for the settings repository URL. */
31
  protected final StringProperty settingsRepo;
32

33
  /** {@link FlagProperty} for skipping installation/updating of tools */
34
  protected final FlagProperty skipTools;
35

36
  /**
37
   * The constructor.
38
   *
39
   * @param context the {@link IdeContext}.
40
   */
41
  public AbstractUpdateCommandlet(IdeContext context) {
42

43
    super(context);
3✔
44
    addKeyword(getName());
4✔
45
    this.skipTools = add(new FlagProperty("--skip-tools", false, null));
11✔
46
    this.settingsRepo = new StringProperty("", false, "settingsRepository");
8✔
47
  }
1✔
48

49
  @Override
50
  public void run() {
51

52
    if (!this.context.isSettingsRepositorySymlinkOrJunction() || this.context.isForceMode()) {
4!
53
      updateSettings();
2✔
54
    }
55
    updateConf();
2✔
56
    reloadContext();
2✔
57

58
    if (this.skipTools.isTrue()) {
4✔
59
      this.context.info("Skipping installation/update of tools as specified by the user.");
5✔
60
    } else {
61
      updateSoftware();
2✔
62
    }
63
    createStartScripts();
2✔
64
  }
1✔
65

66
  private void reloadContext() {
67

68
    ((AbstractIdeContext) this.context).reload();
4✔
69
  }
1✔
70

71
  private void updateConf() {
72

73
    Path templatesFolder = this.context.getSettingsPath().resolve(IdeContext.FOLDER_TEMPLATES);
6✔
74
    if (!Files.exists(templatesFolder)) {
5✔
75
      Path legacyTemplatesFolder = this.context.getSettingsPath().resolve(IdeContext.FOLDER_LEGACY_TEMPLATES);
6✔
76
      if (Files.exists(legacyTemplatesFolder)) {
5!
77
        templatesFolder = legacyTemplatesFolder;
×
78
      } else {
79
        this.context.warning("Templates folder is missing in settings repository.");
4✔
80
        return;
1✔
81
      }
82
    }
83

84
    try (Step step = this.context.newStep("Copy configuration templates", templatesFolder)) {
11✔
85
      setupConf(templatesFolder, this.context.getIdeHome());
6✔
86
      step.success();
2✔
87
    }
88
  }
1✔
89

90
  private void setupConf(Path template, Path conf) {
91

92
    List<Path> children = this.context.getFileAccess().listChildren(template, f -> true);
9✔
93
    for (Path child : children) {
10✔
94

95
      String basename = child.getFileName().toString();
4✔
96
      Path confPath = conf.resolve(basename);
4✔
97

98
      if (Files.isDirectory(child)) {
5✔
99
        if (!Files.isDirectory(confPath)) {
5!
100
          this.context.getFileAccess().mkdirs(confPath);
5✔
101
        }
102
        setupConf(child, confPath);
5✔
103
      } else if (Files.isRegularFile(child)) {
5!
104
        if (Files.isRegularFile(confPath)) {
5!
105
          this.context.debug("Configuration {} already exists - skipping to copy from {}", confPath, child);
×
106
        } else {
107
          if (!basename.equals("settings.xml")) {
4!
108
            this.context.info("Copying template {} to {}.", child, conf);
14✔
109
            this.context.getFileAccess().copy(child, conf);
6✔
110
          }
111
        }
112
      }
113
    }
1✔
114
  }
1✔
115

116
  /**
117
   * Updates the settings repository in IDE_HOME/settings by either cloning if no such repository exists or pulling if the repository exists then saves the
118
   * latest current commit ID in the file ".commit.id".
119
   */
120
  protected void updateSettings() {
121

122
    Path settingsPath = this.context.getSettingsPath();
4✔
123
    GitContext gitContext = this.context.getGitContext();
4✔
124
    Step step = null;
2✔
125
    try {
126
      // here we do not use pullOrClone to prevent asking a pointless question for repository URL...
127
      if (Files.isDirectory(settingsPath) && !this.context.getFileAccess().isEmptyDir(settingsPath)) {
11!
128
        step = this.context.newStep("Pull settings repository");
5✔
129
        gitContext.pull(settingsPath);
4✔
130
      } else {
131
        step = this.context.newStep("Clone settings repository");
5✔
132
        // check if a settings repository is given, otherwise prompt user for a repository.
133
        String repository = this.settingsRepo.getValue();
5✔
134
        if (repository == null) {
2!
135
          String message = "Missing your settings at " + settingsPath + " and no SETTINGS_URL is defined.\n"
×
136
              + "Further details can be found here: https://github.com/devonfw/IDEasy/blob/main/documentation/settings.asciidoc\n"
137
              + "Please contact the technical lead of your project to get the SETTINGS_URL for your project.\n"
138
              + "In case you just want to test IDEasy you may simply hit return to install the default settings.\n" + "Settings URL ["
139
              + IdeContext.DEFAULT_SETTINGS_REPO_URL + "]:";
140
          repository = this.context.askForInput(message, IdeContext.DEFAULT_SETTINGS_REPO_URL);
×
141
        } else if ("-".equals(repository)) {
4!
142
          repository = IdeContext.DEFAULT_SETTINGS_REPO_URL;
×
143
        }
144
        gitContext.pullOrClone(GitUrl.of(repository), settingsPath);
5✔
145
      }
146
      this.context.getGitContext().saveCurrentCommitId(settingsPath, this.context.getSettingsCommitIdPath());
8✔
147
      step.success("Successfully updated settings repository.");
3✔
148
    } finally {
149
      if (step != null) {
2!
150
        step.close();
2✔
151
      }
152
    }
153
  }
1✔
154

155
  private void updateSoftware() {
156

157
    try (Step step = this.context.newStep("Install or update software")) {
5✔
158
      Set<ToolCommandlet> toolCommandlets = new HashSet<>();
4✔
159

160
      // installed tools in IDE_HOME/software
161
      List<Path> softwarePaths = this.context.getFileAccess().listChildren(this.context.getSoftwarePath(), Files::isDirectory);
14✔
162
      for (Path softwarePath : softwarePaths) {
10✔
163
        String toolName = softwarePath.getFileName().toString();
4✔
164
        ToolCommandlet toolCommandlet = this.context.getCommandletManager().getToolCommandlet(toolName);
6✔
165
        if (toolCommandlet != null) {
2!
166
          toolCommandlets.add(toolCommandlet);
4✔
167
        }
168
      }
1✔
169

170
      // regular tools in $IDE_TOOLS
171
      List<String> regularTools = IdeVariables.IDE_TOOLS.get(this.context);
6✔
172
      if (regularTools != null) {
2!
173
        for (String regularTool : regularTools) {
10✔
174
          toolCommandlets.add(this.context.getCommandletManager().getRequiredToolCommandlet(regularTool));
8✔
175
        }
1✔
176
      }
177

178
      // custom tools in ide-custom-tools.json
179
      for (CustomToolMetadata customTool : this.context.getCustomToolRepository().getTools()) {
9!
180
        CustomToolCommandlet customToolCommandlet = new CustomToolCommandlet(this.context, customTool);
×
181
        toolCommandlets.add(customToolCommandlet);
×
182
      }
×
183

184
      // update/install the toolCommandlets
185
      for (ToolCommandlet toolCommandlet : toolCommandlets) {
10✔
186
        try {
187
          toolCommandlet.install(false);
4✔
188
        } catch (Exception e) {
1✔
189
          step.error(e, "Installation of {} failed!", toolCommandlet.getName());
11✔
190
        }
1✔
191

192
      }
1✔
193
      step.success();
2✔
194
    }
195
  }
1✔
196

197
  private void createStartScripts() {
198

199
    List<String> ides = IdeVariables.CREATE_START_SCRIPTS.get(this.context);
6✔
200
    if (ides == null) {
2✔
201
      this.context.info("Variable CREATE_START_SCRIPTS is undefined - skipping start script creation.");
4✔
202
      return;
1✔
203
    }
204
    for (String ide : ides) {
10✔
205
      ToolCommandlet tool = this.context.getCommandletManager().getToolCommandlet(ide);
6✔
206
      if (tool == null) {
2!
207
        this.context.error("Undefined IDE '{}' configured in variable CREATE_START_SCRIPTS.");
×
208
      } else {
209
        createStartScript(ide);
3✔
210
      }
211
    }
1✔
212
  }
1✔
213

214
  private void createStartScript(String ide) {
215

216
    this.context.info("Creating start scripts for {}", ide);
10✔
217
    Path workspaces = this.context.getIdeHome().resolve(IdeContext.FOLDER_WORKSPACES);
6✔
218
    try (Stream<Path> childStream = Files.list(workspaces)) {
3✔
219
      Iterator<Path> iterator = childStream.iterator();
3✔
220
      while (iterator.hasNext()) {
3✔
221
        Path child = iterator.next();
4✔
222
        if (Files.isDirectory(child)) {
5!
223
          createStartScript(ide, child.getFileName().toString());
6✔
224
        }
225
      }
1✔
226
    } catch (IOException e) {
×
227
      throw new RuntimeException("Failed to list children of directory " + workspaces, e);
×
228
    }
1✔
229
  }
1✔
230

231
  private void createStartScript(String ide, String workspace) {
232

233
    Path ideHome = this.context.getIdeHome();
4✔
234
    String scriptName = ide + "-" + workspace;
4✔
235
    boolean windows = this.context.getSystemInfo().isWindows();
5✔
236
    if (windows) {
2!
237
      scriptName = scriptName + ".bat";
×
238
    } else {
239
      scriptName = scriptName + ".sh";
3✔
240
    }
241
    Path scriptPath = ideHome.resolve(scriptName);
4✔
242
    if (Files.exists(scriptPath)) {
5!
243
      return;
×
244
    }
245
    String scriptContent;
246
    if (windows) {
2!
247
      scriptContent = "@echo off\r\n"
×
248
          + "pushd %~dp0\r\n"
249
          + "cd workspaces/" + workspace + "\r\n"
250
          + "call ide " + ide + "\r\n"
251
          + "popd\r\n";
252
    } else {
253
      scriptContent = "#!/usr/bin/env bash\n"
4✔
254
          + "cd \"$(dirname \"$0\")\"\n"
255
          + "cd workspaces/" + workspace + "\n"
256
          + "ide " + ide + "\n";
257
    }
258
    FileAccess fileAccess = this.context.getFileAccess();
4✔
259
    fileAccess.writeFileContent(scriptContent, scriptPath);
4✔
260
    fileAccess.makeExecutable(scriptPath);
3✔
261
  }
1✔
262

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