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

devonfw / IDEasy / 30615771109

31 Jul 2026 08:17AM UTC coverage: 72.829% (+0.2%) from 72.593%
30615771109

Pull #2230

github

web-flow
Merge 86f291a3d into 468118d46
Pull Request #2230: #1953: Complete cleanup commandlet implementation and review handoverShow more lines

5092 of 7729 branches covered (65.88%)

Branch coverage included in aggregate %.

13258 of 17467 relevant lines covered (75.9%)

3.22 hits per line

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

77.46
cli/src/main/java/com/devonfw/tools/ide/context/IdeContext.java
1
package com.devonfw.tools.ide.context;
2

3
import java.io.IOException;
4
import java.io.UncheckedIOException;
5
import java.nio.file.Files;
6
import java.nio.file.Path;
7
import java.util.List;
8
import java.util.stream.Stream;
9

10
import com.devonfw.tools.ide.cli.CliAbortException;
11
import com.devonfw.tools.ide.cli.CliException;
12
import com.devonfw.tools.ide.cli.CliOfflineException;
13
import com.devonfw.tools.ide.commandlet.CommandletManager;
14
import com.devonfw.tools.ide.common.SystemPath;
15
import com.devonfw.tools.ide.environment.EnvironmentVariables;
16
import com.devonfw.tools.ide.environment.EnvironmentVariablesType;
17
import com.devonfw.tools.ide.environment.IdeSystem;
18
import com.devonfw.tools.ide.git.GitContext;
19
import com.devonfw.tools.ide.io.FileAccess;
20
import com.devonfw.tools.ide.io.IdeProgressBar;
21
import com.devonfw.tools.ide.io.IdeProgressBarNone;
22
import com.devonfw.tools.ide.log.IdeLogLevel;
23
import com.devonfw.tools.ide.merge.DirectoryMerger;
24
import com.devonfw.tools.ide.network.NetworkStatus;
25
import com.devonfw.tools.ide.os.SystemInfo;
26
import com.devonfw.tools.ide.os.WindowsPathSyntax;
27
import com.devonfw.tools.ide.process.ProcessContext;
28
import com.devonfw.tools.ide.step.Step;
29
import com.devonfw.tools.ide.tool.corepack.Corepack;
30
import com.devonfw.tools.ide.tool.custom.CustomToolRepository;
31
import com.devonfw.tools.ide.tool.gradle.Gradle;
32
import com.devonfw.tools.ide.tool.mvn.Mvn;
33
import com.devonfw.tools.ide.tool.mvn.MvnRepository;
34
import com.devonfw.tools.ide.tool.npm.Npm;
35
import com.devonfw.tools.ide.tool.npm.NpmRepository;
36
import com.devonfw.tools.ide.tool.pip.PipRepository;
37
import com.devonfw.tools.ide.tool.python.PythonRepository;
38
import com.devonfw.tools.ide.tool.repository.ToolRepository;
39
import com.devonfw.tools.ide.tool.uv.UvRepository;
40
import com.devonfw.tools.ide.url.model.UrlMetadata;
41
import com.devonfw.tools.ide.variable.IdeVariables;
42
import com.devonfw.tools.ide.version.IdeVersion;
43
import com.devonfw.tools.ide.version.VersionIdentifier;
44

45
/**
46
 * Interface for the context of IDEasy and the potential current project. Central constants for names of files and folders are defined here and should be
47
 * referenced instead of duplicating such string literals across the code-base. All central components can be accessed from here such as:
48
 * <ul>
49
 * <li>{@link #getPath() system path} (abstraction of PATH environment variable)</li>
50
 * <li>{@link #getCommandletManager() commandlet manager} (access {@link com.devonfw.tools.ide.commandlet.Commandlet}s)</li>
51
 * <li>{@link #getFileAccess() file access} (file and I/O operations on a higher level of abstraction)</li>
52
 * <li>{@link #getNetworkStatus() network status} (determine if we are online or offline)</li>
53
 * <li>{@link #newProcess() process context} (start external programs as process including logging, error handling, background and output processing)</li>
54
 * <li>{@link #newStep(String) step} creation (a sub-task that may fail without stopping the overall process)</li>
55
 * <li>{@link #newProgressBar(String, long, String, long) progress bar} (to display long-running progress for UX)</li>
56
 * <li>{@link #getGitContext() git context} (for git operations like clone, fetch, pull, etc.)</li>
57
 * <li>{@link #getSystemInfo() system info} (for information about OS and CPU architecture)</li>
58
 * <li>{@link #getVariables() environment variables} (to access and modify IDEasy variables according to our configuration layout)</li>
59
 *
60
 * <li>{@link #question(Object[], String, Object...) question} (for interaction to let the end-user decide)</li>
61
 * <li>{@link #getUrls() url metadata} (access ide-urls to find versions, download URLs, dependency and security metadata)</li>
62
 * <li>{@link #getDefaultToolRepository() tool repository} (for abstraction of version resolution and download of tools)</li>
63
 * <li>{@link #getSystem() ide system} (abstraction of {@link java.lang.System} for system environment variables)</li>
64
 * </ul>
65
 */
66
public interface IdeContext extends IdeStartContext {
67

68
  /**
69
   * The default settings URL.
70
   *
71
   * @see com.devonfw.tools.ide.commandlet.AbstractUpdateCommandlet
72
   */
73
  String DEFAULT_SETTINGS_REPO_URL = "https://github.com/devonfw/ide-settings.git";
74

75
  /** The name of the workspaces folder. */
76
  String FOLDER_WORKSPACES = "workspaces";
77

78
  /** The name of the {@link #getSettingsPath() settings} folder. */
79
  String FOLDER_SETTINGS = "settings";
80

81
  /** The name of the {@link #getSoftwarePath() software} folder. */
82
  String FOLDER_SOFTWARE = "software";
83

84
  /** The name of the {@link #getUrlsPath() urls} folder. */
85
  String FOLDER_URLS = "urls";
86

87
  /** The name of the conf folder for project specific user configurations. */
88
  String FOLDER_CONF = "conf";
89

90
  /**
91
   * The name of the folder inside IDE_ROOT reserved for IDEasy. Intentionally starting with an underscore and not a dot to prevent effects like OS hiding,
92
   * maven filtering, .gitignore and to distinguish from {@link #FOLDER_DOT_IDE}.
93
   *
94
   * @see #getIdePath()
95
   */
96
  String FOLDER_UNDERSCORE_IDE = "_ide";
97

98
  /**
99
   * The name of the folder inside {@link #FOLDER_UNDERSCORE_IDE} with the current IDEasy installation.
100
   *
101
   * @see #getIdeInstallationPath()
102
   */
103
  String FOLDER_INSTALLATION = "installation";
104

105
  /**
106
   * The name of the hidden folder for IDE configuration in the users home directory or status information in the IDE_HOME directory.
107
   *
108
   * @see #getUserHomeIde()
109
   */
110
  String FOLDER_DOT_IDE = ".ide";
111

112
  /** The name of the updates folder for temporary data and backup. */
113
  String FOLDER_UPDATES = "updates";
114

115
  /** The name of the volume folder for mounting archives like *.dmg. */
116
  String FOLDER_VOLUME = "volume";
117

118
  /** The name of the backups folder for backup. */
119
  String FOLDER_BACKUPS = "backups";
120

121
  /** The name of the logs folder for log-files (in {@link #FOLDER_UNDERSCORE_IDE}). */
122
  String FOLDER_LOGS = "logs";
123

124
  /** The name of the downloads folder. */
125
  String FOLDER_DOWNLOADS = "Downloads";
126

127
  /** The name of the bin folder where executable files are found by default. */
128
  String FOLDER_BIN = "bin";
129

130
  /** The name of the repositories folder where properties files are stores for each repository */
131
  String FOLDER_REPOSITORIES = "repositories";
132

133
  /** The name of the repositories folder where properties files are stores for each repository */
134
  String FOLDER_LEGACY_REPOSITORIES = "projects";
135

136
  /** The name of the Contents folder inside a MacOS app. */
137
  String FOLDER_CONTENTS = "Contents";
138

139
  /** The name of the Resources folder inside a MacOS app. */
140
  String FOLDER_RESOURCES = "Resources";
141

142
  /** The name of the app folder inside a MacOS app. */
143
  String FOLDER_APP = "app";
144

145
  /** The name of the extra folder inside the software folder */
146
  String FOLDER_EXTRA = "extra";
147

148
  /**
149
   * The name of the {@link #getPluginsPath() plugins folder} and also the plugins folder inside the IDE folders of {@link #getSettingsPath() settings} (e.g.
150
   * settings/eclipse/plugins).
151
   */
152
  String FOLDER_PLUGINS = "plugins";
153

154
  /**
155
   * The name of the workspace folder inside the IDE specific {@link #FOLDER_SETTINGS settings} containing the configuration templates in #FOLDER_SETUP
156
   * #FOLDER_UPDATE.
157
   */
158
  String FOLDER_WORKSPACE = "workspace";
159

160
  /**
161
   * The name of the setup folder inside the {@link #FOLDER_WORKSPACE workspace} folder containing the templates for the configuration templates for the initial
162
   * setup of a workspace. This is closely related with the {@link #FOLDER_UPDATE update} folder.
163
   */
164
  String FOLDER_SETUP = "setup";
165

166
  /**
167
   * The name of the update folder inside the {@link #FOLDER_WORKSPACE workspace} folder containing the templates for the configuration templates for the update
168
   * of a workspace. Configurations in this folder will be applied every time the IDE is started. They will override the settings the user may have manually
169
   * configured every time. This is only for settings that have to be the same for every developer in the project. An example would be the number of spaces used
170
   * for indentation and other code-formatting settings. If all developers in a project team use the same formatter settings, this will actively prevent
171
   * diff-wars. However, the entire team needs to agree on these settings.<br> Never configure aspects inside this update folder that may be of personal flavor
172
   * such as the color theme. Otherwise developers will hate you as you actively take away their freedom to customize the IDE to their personal needs and
173
   * wishes. Therefore do all "biased" or "flavored" configurations in {@link #FOLDER_SETUP setup} so these are only pre-configured but can be changed by the
174
   * user as needed.
175
   */
176
  String FOLDER_UPDATE = "update";
177

178
  /**
179
   * The name of the folder inside {@link #FOLDER_UNDERSCORE_IDE _ide} folder containing internal resources and scripts of IDEasy.
180
   */
181
  String FOLDER_INTERNAL = "internal";
182

183
  /** The file where the installed software version is written to as plain text. */
184
  String FILE_SOFTWARE_VERSION = ".ide.software.version";
185

186
  /** The file where the installed software version is written to as plain text. */
187
  String FILE_LEGACY_SOFTWARE_VERSION = ".devon.software.version";
188

189
  /** The file for the license agreement. */
190
  String FILE_LICENSE_AGREEMENT = ".license.agreement";
191

192
  /** The file extension for a {@link java.util.Properties} file. */
193
  String EXT_PROPERTIES = ".properties";
194

195
  /** The default for {@link #getWorkspaceName()}. */
196
  String WORKSPACE_MAIN = "main";
197

198
  /** The folder with the configuration template files from the settings. */
199
  String FOLDER_TEMPLATES = "templates";
200

201
  /** Legacy folder name used as compatibility fallback if {@link #FOLDER_TEMPLATES} does not exist. */
202
  String FOLDER_LEGACY_TEMPLATES = "devon";
203

204
  /** The default folder name for {@link #getIdeRoot() IDE_ROOT}. */
205
  String FOLDER_PROJECTS = "projects";
206

207
  /**
208
   * file containing the current local commit hash of the settings repository.
209
   */
210
  String SETTINGS_COMMIT_ID = ".commit.id";
211

212
  /** The IDEasy ASCII logo. */
213
  String LOGO = """
4✔
214
      __       ___ ___  ___
215
      ╲ ╲     |_ _|   ╲| __|__ _ ____ _
216
       > >     | || |) | _|/ _` (_-< || |
217
      /_/ ___ |___|___/|___╲__,_/__/╲_, |
218
         |___|                       |__/
219
      """.replace('╲', '\\');
2✔
220

221
  /**
222
   * The keyword for project name convention.
223
   */
224
  String SETTINGS_REPOSITORY_KEYWORD = "settings";
225
  String IS_NOT_INSTALLED_BUT_REQUIRED = "is not installed on your computer but required by IDEasy.";
226
  String WINDOWS_GIT_DOWNLOAD_URL = "https://git-scm.com/download/";
227
  String PLEASE_DOWNLOAD_AND_INSTALL_GIT = "Please download and install git";
228

229
  /**
230
   * @return the {@link NetworkStatus} for online check and related operations.
231
   */
232
  NetworkStatus getNetworkStatus();
233

234
  /**
235
   * @return {@code true} if {@link #isOfflineMode() offline mode} is active or we are NOT {@link #isOnline() online}, {@code false} otherwise.
236
   * @deprecated use {@link #getNetworkStatus()}
237
   */
238
  default boolean isOffline() {
239

240
    return getNetworkStatus().isOffline();
4✔
241
  }
242

243
  /**
244
   * @return {@code true} if we are currently online (Internet access is available), {@code false} otherwise.
245
   * @deprecated use {@link #getNetworkStatus()}
246
   */
247
  default boolean isOnline() {
248

249
    return getNetworkStatus().isOnline();
×
250
  }
251

252
  /**
253
   * Print the IDEasy {@link #LOGO logo}.
254
   */
255
  default void printLogo() {
256

257
    AbstractIdeContext.LOG.info(LOGO);
3✔
258
  }
1✔
259

260
  /**
261
   * Asks the user for a single string input.
262
   *
263
   * @param message The information message to display.
264
   * @param defaultValue The default value to return when no input is provided or {@code null} to keep asking until the user entered a non empty value.
265
   * @return The string input from the user, or the default value if no input is provided.
266
   */
267
  String askForInput(String message, String defaultValue);
268

269
  /**
270
   * Asks the user for a single string input.
271
   *
272
   * @param message The information message to display.
273
   * @return The string input from the user.
274
   */
275
  default String askForInput(String message) {
276
    return askForInput(message, null);
5✔
277
  }
278

279
  /**
280
   * @param question the question to ask.
281
   * @param args arguments for filling the templates
282
   * @return {@code true} if the user answered with "yes", {@code false} otherwise ("no").
283
   */
284
  default boolean question(String question, Object... args) {
285

286
    String yes = "yes";
2✔
287
    String option = question(new String[] { yes, "no" }, question, args);
16✔
288
    if (yes.equals(option)) {
4✔
289
      return true;
2✔
290
    }
291
    return false;
2✔
292
  }
293

294
  /**
295
   * @param <O> type of the option. E.g. {@link String}.
296
   * @param options the available options for the user to answer. There should be at least two options given as otherwise the question cannot make sense.
297
   * @param question the question to ask.
298
   * @return the option selected by the user as answer.
299
   */
300
  @SuppressWarnings("unchecked")
301
  <O> O question(O[] options, String question, Object... args);
302

303
  /**
304
   * Will ask the given question. If the user answers with "yes" the method will return and the process can continue. Otherwise if the user answers with "no" an
305
   * exception is thrown to abort further processing.
306
   *
307
   * @param questionTemplate the yes/no question to {@link #question(String, Object...) ask}.
308
   * @param args the arguments to fill the placeholders in the question template.
309
   * @throws CliAbortException if the user answered with "no" and further processing shall be aborted.
310
   */
311
  default void askToContinue(String questionTemplate, Object... args) {
312
    boolean yesContinue = question(questionTemplate, args);
5✔
313
    if (!yesContinue) {
2✔
314
      throw new CliAbortException();
4✔
315
    }
316
  }
1✔
317

318
  /**
319
   * @param purpose the purpose why Internet connection is required.
320
   * @param explicitOnlineCheck if {@code true}, perform an explicit {@link #isOffline()} check; if {@code false} use {@link #isOfflineMode()}.
321
   * @throws CliException if you are {@link #isOffline() offline}.
322
   */
323
  default void requireOnline(String purpose, boolean explicitOnlineCheck) {
324

325
    if (explicitOnlineCheck) {
2✔
326
      if (isOffline()) {
3✔
327
        throw CliOfflineException.ofPurpose(purpose);
3✔
328
      }
329
    } else {
330
      if (isOfflineMode()) {
3!
331
        throw CliOfflineException.ofPurpose(purpose);
3✔
332
      }
333
    }
334
  }
1✔
335

336
  /**
337
   * @return the {@link SystemInfo}.
338
   */
339
  SystemInfo getSystemInfo();
340

341
  /**
342
   * @return the {@link EnvironmentVariables} with full inheritance.
343
   */
344
  EnvironmentVariables getVariables();
345

346
  /**
347
   * @return the {@link FileAccess}.
348
   */
349
  FileAccess getFileAccess();
350

351
  /**
352
   * @return the {@link CommandletManager}.
353
   */
354
  CommandletManager getCommandletManager();
355

356
  /**
357
   * @return the default {@link ToolRepository}.
358
   */
359
  ToolRepository getDefaultToolRepository();
360

361
  /**
362
   * @return the {@link CustomToolRepository}.
363
   */
364
  CustomToolRepository getCustomToolRepository();
365

366
  /**
367
   * @return the {@link MvnRepository}.
368
   */
369
  MvnRepository getMvnRepository();
370

371
  /**
372
   * @return the {@link NpmRepository}.
373
   */
374
  NpmRepository getNpmRepository();
375

376
  /**
377
   * @return the {@link PipRepository}.
378
   */
379
  PipRepository getPipRepository();
380

381
  /**
382
   * @return the {@link UvRepository}.
383
   */
384
  UvRepository getUvRepository();
385

386
  /**
387
   * @return the {@link PythonRepository}.
388
   */
389
  PythonRepository getPythonRepository();
390

391
  /**
392
   * @return the {@link Path} to the IDE instance directory. You can have as many IDE instances on the same computer as independent tenants for different
393
   *     isolated projects.
394
   * @see com.devonfw.tools.ide.variable.IdeVariables#IDE_HOME
395
   */
396
  Path getIdeHome();
397

398
  /**
399
   * @return the name of the current project.
400
   * @see com.devonfw.tools.ide.variable.IdeVariables#PROJECT_NAME
401
   */
402
  String getProjectName();
403

404
  /**
405
   * @return the IDEasy version the {@link #getIdeHome() current project} was created with or migrated to.
406
   */
407
  VersionIdentifier getProjectVersion();
408

409
  /**
410
   * @param version the new value of {@link #getProjectVersion()}.
411
   */
412
  void setProjectVersion(VersionIdentifier version);
413

414
  /**
415
   * @return the {@link Path} to the IDE installation root directory. This is the top-level folder where the {@link #getIdeHome() IDE instances} are located as
416
   *     sub-folder. There is a reserved ".ide" folder where central IDE data is stored such as the {@link #getUrlsPath() download metadata} and the central
417
   *     software repository.
418
   * @see com.devonfw.tools.ide.variable.IdeVariables#IDE_ROOT
419
   */
420
  Path getIdeRoot();
421

422
  /**
423
   * Finds all IDEasy projects below the configured IDE root.
424
   *
425
   * @return the paths of all detected IDEasy projects.
426
   */
427
  default List<Path> findProjects() {
428

429
    return findProjects(getIdeRoot());
4✔
430
  }
431

432
  /**
433
   * Finds all IDEasy projects below the given IDE root.
434
   *
435
   * @param ideRoot the IDE root containing the IDEasy projects.
436
   * @return the paths of all detected IDEasy projects.
437
   */
438
  static List<Path> findProjects(Path ideRoot) {
439

440
    if ((ideRoot == null) || !Files.isDirectory(ideRoot)) {
7!
441
      return List.of();
×
442
    }
443

444
    try (Stream<Path> children = Files.list(ideRoot)) {
3✔
445
      return children.filter(Files::isDirectory)
11✔
446
          .filter(project -> !FOLDER_UNDERSCORE_IDE.equals(project.getFileName().toString()))
12✔
447
          .filter(project -> Files.isDirectory(project.resolve(FOLDER_WORKSPACES)))
8✔
448
          .toList();
2✔
449
    } catch (IOException e) {
×
450
      throw new UncheckedIOException("Failed to find IDEasy projects in " + ideRoot, e);
×
451
    }
452
  }
453

454
  /**
455
   * @param ideRoot the new value of {@link #getIdeRoot() IDE_ROOT}. Typically detected automatically from the environment and working directory, but may
456
   *     need to be set explicitly (e.g. during the initial installation where the {@code IDE_ROOT} environment variable is not yet available but the
457
   *     installation target is already known).
458
   */
459
  void setIdeRoot(Path ideRoot);
460

461
  /**
462
   * @return the {@link Path} to the {@link #FOLDER_UNDERSCORE_IDE}.
463
   * @see #getIdeRoot()
464
   * @see #FOLDER_UNDERSCORE_IDE
465
   */
466
  Path getIdePath();
467

468
  /**
469
   * @return the {@link Path} to the {@link #FOLDER_INSTALLATION installation} folder of IDEasy. This is a link to the (latest) installed release of IDEasy. On
470
   *     upgrade a new release is installed and the link is switched to the new release.
471
   */
472
  default Path getIdeInstallationPath() {
473

474
    Path idePath = getIdePath();
3✔
475
    if (idePath == null) {
2!
476
      return null;
×
477
    }
478
    return idePath.resolve(FOLDER_INSTALLATION);
4✔
479
  }
480

481
  /**
482
   * @return the current working directory ("user.dir"). This is the directory where the user's shell was located when the IDE CLI was invoked.
483
   */
484
  Path getCwd();
485

486
  /**
487
   * @return the {@link Path} for the temporary directory to use. Will be different from the OS specific temporary directory (java.io.tmpDir).
488
   */
489
  Path getTempPath();
490

491
  /**
492
   * @return the {@link Path} for the temporary download directory to use.
493
   */
494
  Path getTempDownloadPath();
495

496
  /**
497
   * @return the {@link Path} to the download metadata (ide-urls). Here a git repository is cloned and updated (pulled) to always have the latest metadata to
498
   *     download tools.
499
   * @see com.devonfw.tools.ide.url.model.folder.UrlRepository
500
   */
501
  Path getUrlsPath();
502

503
  /**
504
   * @return the {@link UrlMetadata}. Will be lazily instantiated and thereby automatically be cloned or pulled (by default).
505
   */
506
  UrlMetadata getUrls();
507

508
  /**
509
   * @return the {@link Path} to the download cache. All downloads will be placed here using a unique naming pattern that allows to reuse these artifacts. So if
510
   *     the same artifact is requested again it will be taken from the cache to avoid downloading it again.
511
   */
512
  Path getDownloadPath();
513

514
  /**
515
   * @return the {@link Path} to the software folder inside {@link #getIdeHome() IDE_HOME}. All tools for that IDE instance will be linked here from the
516
   *     {@link #getSoftwareRepositoryPath() software repository} as sub-folder named after the according tool.
517
   */
518
  Path getSoftwarePath();
519

520
  /**
521
   * @return the {@link Path} to the extra folder inside software folder inside {@link #getIdeHome() IDE_HOME}. All tools for that IDE instance will be linked
522
   *     here from the {@link #getSoftwareRepositoryPath() software repository} as sub-folder named after the according tool.
523
   */
524
  Path getSoftwareExtraPath();
525

526
  /**
527
   * @return the {@link Path} to the global software repository. This is the central directory where the tools are extracted physically on the local disc. Those
528
   *     are shared among all IDE instances (see {@link #getIdeHome() IDE_HOME}) via symbolic links (see {@link #getSoftwarePath()}). Therefore this repository
529
   *     follows the sub-folder structure {@code «repository»/«tool»/«edition»/«version»/}. So multiple versions of the same tool exist here as different
530
   *     folders. Further, such software may not be modified so e.g. installation of plugins and other kind of changes to such tool need to happen strictly out
531
   *     of the scope of this folders.
532
   */
533
  Path getSoftwareRepositoryPath();
534

535
  /**
536
   * @return the {@link Path} to the {@link #FOLDER_PLUGINS plugins folder} inside {@link #getIdeHome() IDE_HOME}. All plugins of the IDE instance will be
537
   *     stored here. For each tool that supports plugins a sub-folder with the tool name will be created where the plugins for that tool get installed.
538
   */
539
  Path getPluginsPath();
540

541
  /**
542
   * @return the {@link Path} to the central tool repository. All tools will be installed in this location using the directory naming schema of
543
   *     {@code «repository»/«tool»/«edition»/«version»/}. Actual {@link #getIdeHome() IDE instances} will only contain symbolic links to the physical tool
544
   *     installations in this repository. This allows to share and reuse tool installations across multiple {@link #getIdeHome() IDE instances}. The variable
545
   *     {@code «repository»} is typically {@code default} for the tools from our standard {@link #getUrlsPath() ide-urls download metadata} but this will
546
   *     differ for custom tools from a private repository.
547
   */
548
  Path getToolRepositoryPath();
549

550
  /**
551
   * @return the {@link Path} to the users home directory. Typically initialized via the {@link System#getProperty(String) system property} "user.home".
552
   * @see com.devonfw.tools.ide.variable.IdeVariables#HOME
553
   */
554
  Path getUserHome();
555

556
  /**
557
   * @return the {@link Path} to the ".ide" subfolder in the {@link #getUserHome() users home directory}.
558
   */
559
  Path getUserHomeIde();
560

561
  /**
562
   * @return the {@link Path} to the {@link #FOLDER_SETTINGS settings} folder with the cloned git repository containing the project configuration.
563
   */
564
  Path getSettingsPath();
565

566
  /**
567
   * @return the {@link Path} to the {@link #FOLDER_REPOSITORIES repositories} folder with legacy fallback if not present or {@code null} if not found.
568
   */
569
  default Path getRepositoriesPath() {
570

571
    Path settingsPath = getSettingsPath();
3✔
572
    if (settingsPath == null) {
2!
573
      return null;
×
574
    }
575
    Path repositoriesPath = settingsPath.resolve(IdeContext.FOLDER_REPOSITORIES);
4✔
576
    if (Files.isDirectory(repositoriesPath)) {
5✔
577
      return repositoriesPath;
2✔
578
    }
579
    Path legacyRepositoriesPath = settingsPath.resolve(IdeContext.FOLDER_LEGACY_REPOSITORIES);
4✔
580
    if (Files.isDirectory(legacyRepositoriesPath)) {
5!
581
      return legacyRepositoriesPath;
×
582
    }
583
    return null;
2✔
584
  }
585

586
  /**
587
   * @return the {@link Path} to the {@code settings} folder with the cloned git repository containing the project configuration only if the settings repository
588
   *     is in fact a git repository.
589
   */
590
  Path getSettingsGitRepository();
591

592
  /**
593
   * @return {@code true} if the settings repository is a symlink or a junction to a code-repository.
594
   */
595
  boolean isSettingsCodeRepository();
596

597
  /**
598
   * @return the {@link Path} to the file containing the last tracked commit Id of the settings repository.
599
   */
600
  Path getSettingsCommitIdPath();
601

602
  /**
603
   * @return the {@link Path} to the templates folder inside the {@link #getSettingsPath() settings}. The relative directory structure in this templates folder
604
   *     is to be applied to {@link #getIdeHome() IDE_HOME} when the project is set up.
605
   */
606
  default Path getSettingsTemplatePath() {
607
    Path settingsFolder = getSettingsPath();
3✔
608
    Path templatesFolder = settingsFolder.resolve(IdeContext.FOLDER_TEMPLATES);
4✔
609
    if (!Files.isDirectory(templatesFolder)) {
5✔
610
      Path templatesFolderLegacy = settingsFolder.resolve(IdeContext.FOLDER_LEGACY_TEMPLATES);
4✔
611
      if (Files.isDirectory(templatesFolderLegacy)) {
5!
612
        templatesFolder = templatesFolderLegacy;
×
613
      } else {
614
        AbstractIdeContext.LOG.warn("No templates found in settings git repo neither in {} nor in {} - configuration broken", templatesFolder,
5✔
615
            templatesFolderLegacy);
616
        return null;
2✔
617
      }
618
    }
619
    return templatesFolder;
2✔
620
  }
621

622
  /**
623
   * @return the {@link Path} to the {@code conf} folder with instance specific tool configurations and the
624
   *     {@link EnvironmentVariablesType#CONF user specific project configuration}.
625
   */
626
  Path getConfPath();
627

628
  /**
629
   * @return the {@link Path} to the workspaces base folder containing the individual {@link #getWorkspacePath(String) workspaces}.
630
   * @see #getWorkspacePath(String)
631
   */
632
  Path getWorkspacesBasePath();
633

634
  /**
635
   * @return the {@link Path} to the workspace.
636
   * @see #getWorkspaceName()
637
   */
638
  Path getWorkspacePath();
639

640
  /**
641
   * @param workspace the specific workspace name.
642
   * @return the {@link Path} to the specified workspace.
643
   */
644
  Path getWorkspacePath(String workspace);
645

646
  /**
647
   * @return the name of the workspace. Defaults to {@link #WORKSPACE_MAIN}.
648
   */
649
  String getWorkspaceName();
650

651
  /**
652
   * @return the value of the system {@link IdeVariables#PATH PATH} variable. It is automatically extended according to the tools available in
653
   *     {@link #getSoftwarePath() software path} unless {@link #getIdeHome() IDE_HOME} was not found.
654
   */
655
  SystemPath getPath();
656

657
  /**
658
   * @return a new {@link ProcessContext} to {@link ProcessContext#run() run} external commands.
659
   */
660
  ProcessContext newProcess();
661

662
  /**
663
   * @param title the {@link IdeProgressBar#getTitle() title}.
664
   * @param size the {@link IdeProgressBar#getMaxSize() expected maximum size}.
665
   * @param unitName the {@link IdeProgressBar#getUnitName() unit name}.
666
   * @param unitSize the {@link IdeProgressBar#getUnitSize() unit size}.
667
   * @return the new {@link IdeProgressBar} to use.
668
   */
669
  IdeProgressBar newProgressBar(String title, long size, String unitName, long unitSize);
670

671
  /**
672
   * @param title the {@link IdeProgressBar#getTitle() title}.
673
   * @param size the {@link IdeProgressBar#getMaxSize() expected maximum size} in bytes.
674
   * @return the new {@link IdeProgressBar} to use.
675
   */
676
  default IdeProgressBar newProgressBarInMib(String title, long size) {
677

678
    if ((size > 0) && (size < 1024)) {
8✔
679
      return new IdeProgressBarNone(title, size, IdeProgressBar.UNIT_NAME_MB, IdeProgressBar.UNIT_SIZE_MB);
8✔
680
    }
681
    return newProgressBar(title, size, IdeProgressBar.UNIT_NAME_MB, IdeProgressBar.UNIT_SIZE_MB);
7✔
682
  }
683

684
  /**
685
   * @param size the {@link IdeProgressBar#getMaxSize() expected maximum size} in bytes.
686
   * @return the new {@link IdeProgressBar} for copy.
687
   */
688
  default IdeProgressBar newProgressBarForDownload(long size) {
689

690
    return newProgressBarInMib(IdeProgressBar.TITLE_DOWNLOADING, size);
5✔
691
  }
692

693
  /**
694
   * @param size the {@link IdeProgressBar#getMaxSize() expected maximum size} in bytes.
695
   * @return the new {@link IdeProgressBar} for extracting.
696
   */
697
  default IdeProgressBar newProgressbarForExtracting(long size) {
698

699
    return newProgressBarInMib(IdeProgressBar.TITLE_EXTRACTING, size);
5✔
700
  }
701

702
  /**
703
   * @param size the {@link IdeProgressBar#getMaxSize() expected maximum size} in bytes.
704
   * @return the new {@link IdeProgressBar} for copy.
705
   */
706
  default IdeProgressBar newProgressbarForCopying(long size) {
707

708
    return newProgressBarInMib(IdeProgressBar.TITLE_COPYING, size);
5✔
709
  }
710

711
  /**
712
   * @param size the {@link IdeProgressBar#getMaxSize() expected maximum} plugin count.
713
   * @return the new {@link IdeProgressBar} to use.
714
   */
715
  default IdeProgressBar newProgressBarForPlugins(long size) {
716
    return newProgressBar(IdeProgressBar.TITLE_INSTALL_PLUGIN, size, IdeProgressBar.UNIT_NAME_PLUGIN, IdeProgressBar.UNIT_SIZE_PLUGIN);
×
717
  }
718

719
  /**
720
   * @return the {@link DirectoryMerger} used to configure and merge the workspace for an {@link com.devonfw.tools.ide.tool.ide.IdeToolCommandlet IDE}.
721
   */
722
  DirectoryMerger getWorkspaceMerger();
723

724
  /**
725
   * @return the {@link Path} to the working directory from where the command is executed.
726
   */
727
  Path getDefaultExecutionDirectory();
728

729
  /**
730
   * @return the {@link IdeSystem} instance wrapping {@link System}.
731
   */
732
  IdeSystem getSystem();
733

734
  /**
735
   * @return the {@link GitContext} used to run several git commands.
736
   */
737
  GitContext getGitContext();
738

739
  /**
740
   * @return the String value for the variable MAVEN_ARGS, or null if called outside an IDEasy installation.
741
   */
742
  default String getMavenArgs() {
743

744
    if (getIdeHome() == null) {
3✔
745
      return null;
2✔
746
    }
747
    Mvn mvn = getCommandletManager().getCommandlet(Mvn.class);
6✔
748
    return mvn.getMavenArgs();
3✔
749
  }
750

751
  /**
752
   * @return the path for the variable GRADLE_USER_HOME, or null if called outside an IDEasy installation.
753
   */
754
  default Path getGradleUserHome() {
755

756
    if (getIdeHome() == null) {
3✔
757
      return null;
2✔
758
    }
759
    Gradle gradle = getCommandletManager().getCommandlet(Gradle.class);
6✔
760
    return gradle.getOrCreateGradleConfFolder();
3✔
761
  }
762

763
  /**
764
   * @return the {@link Path} pointing to the maven configuration directory (where "settings.xml" or "settings-security.xml" are located).
765
   */
766
  default Path getMavenConfigurationFolder() {
767

768
    if (getIdeHome() == null) {
3✔
769
      // fallback to USER_HOME/.m2 folder if called outside an IDEasy project
770
      return getUserHome().resolve(Mvn.MVN_CONFIG_LEGACY_FOLDER);
5✔
771
    }
772
    Mvn mvn = getCommandletManager().getCommandlet(Mvn.class);
6✔
773
    return mvn.getMavenConfigurationFolder();
3✔
774
  }
775

776
  /**
777
   * Updates the current working directory (CWD) and configures the environment paths according to the specified parameters. This method is central to changing
778
   * the IDE's notion of where it operates, affecting where configurations, workspaces, settings, and other resources are located or loaded from.
779
   *
780
   * @return the current {@link Step} of processing.
781
   */
782
  Step getCurrentStep();
783

784
  /**
785
   * @param name the {@link Step#getName() name} of the new {@link Step}.
786
   * @return the new {@link Step} that has been created and started.
787
   */
788
  default Step newStep(String name) {
789

790
    return newStep(name, Step.NO_PARAMS);
5✔
791
  }
792

793
  /**
794
   * @param name the {@link Step#getName() name} of the new {@link Step}.
795
   * @param parameters the {@link Step#getParameter(int) parameters} of the {@link Step}.
796
   * @return the new {@link Step} that has been created and started.
797
   */
798
  default Step newStep(String name, Object... parameters) {
799

800
    return newStep(false, name, parameters);
6✔
801
  }
802

803
  /**
804
   * @param silent the {@link Step#isSilent() silent flag}.
805
   * @param name the {@link Step#getName() name} of the new {@link Step}.
806
   * @param parameters the {@link Step#getParameter(int) parameters} of the {@link Step}.
807
   * @return the new {@link Step} that has been created and started.
808
   */
809
  Step newStep(boolean silent, String name, Object... parameters);
810

811
  /**
812
   * @param lambda the {@link Runnable} to {@link Runnable#run() run} while the {@link com.devonfw.tools.ide.log.IdeLogger logging} is entirely disabled.
813
   *     After this the logging will be enabled again. Collected log messages will then be logged at the end.
814
   */
815
  default void runWithoutLogging(Runnable lambda) {
816

817
    runWithoutLogging(lambda, IdeLogLevel.TRACE);
×
818
  }
×
819

820
  /**
821
   * @param lambda the {@link Runnable} to {@link Runnable#run() run} while the {@link com.devonfw.tools.ide.log.IdeLogger logging} is entirely disabled.
822
   *     After this the logging will be enabled again. Collected log messages will then be logged at the end.
823
   * @param threshold the {@link IdeLogLevel} to use as threshold for filtering logs while logging is disabled and log messages are collected. Use
824
   *     {@link IdeLogLevel#TRACE} to collect all logs and ensure nothing gets lost (will still not log anything that is generally not active in regular
825
   *     logging) and e.g. use {@link IdeLogLevel#ERROR} to discard all logs except errors.
826
   */
827
  void runWithoutLogging(Runnable lambda, IdeLogLevel threshold);
828

829
  /**
830
   * Updates the current working directory (CWD) and configures the environment paths according to the specified parameters. This method is central to changing
831
   * the IDE's notion of where it operates, affecting where configurations, workspaces, settings, and other resources are located or loaded from.
832
   *
833
   * @param ideHome The path to the IDE home directory.
834
   */
835
  default void setIdeHome(Path ideHome) {
836

837
    setCwd(ideHome, WORKSPACE_MAIN, ideHome);
5✔
838
  }
1✔
839

840
  /**
841
   * Updates the current working directory (CWD) and configures the environment paths according to the specified parameters. This method is central to changing
842
   * the IDE's notion of where it operates, affecting where configurations, workspaces, settings, and other resources are located or loaded from.
843
   *
844
   * @param userDir The path to set as the current working directory.
845
   * @param workspace The name of the workspace within the IDE's environment.
846
   * @param ideHome The path to the IDE home directory.
847
   */
848
  void setCwd(Path userDir, String workspace, Path ideHome);
849

850
  /**
851
   * Finds the path to the Bash executable.
852
   *
853
   * @return the {@link Path} to the Bash executable, or {@code null} if Bash is not found.
854
   */
855
  Path findBash();
856

857
  /**
858
   * Finds the path to the Bash executable.
859
   *
860
   * @return the {@link Path} to the Bash executable. Throws a {@link CliException} if no bash was found.
861
   */
862
  default Path findBashRequired() {
863
    Path bash = findBash();
3✔
864
    if (bash == null) {
2!
865
      String message = "Bash " + IS_NOT_INSTALLED_BUT_REQUIRED;
×
866
      if (getSystemInfo().isWindows()) {
×
867
        message += " " + PLEASE_DOWNLOAD_AND_INSTALL_GIT + ":\n " + WINDOWS_GIT_DOWNLOAD_URL;
×
868
        throw new CliException(message);
×
869
      }
870
      bash = Path.of("bash");
×
871
    }
872

873
    return bash;
2✔
874
  }
875

876
  /**
877
   * @return the {@link WindowsPathSyntax} used for {@link Path} conversion or {@code null} for no such conversion (typically if not on Windows).
878
   */
879
  WindowsPathSyntax getPathSyntax();
880

881
  /**
882
   * logs the status of {@link #getIdeHome() IDE_HOME} and {@link #getIdeRoot() IDE_ROOT}.
883
   */
884
  void logIdeHomeAndRootStatus();
885

886
  /**
887
   * @param version the {@link VersionIdentifier} to write.
888
   * @param installationPath the {@link Path directory} where to write the version to a {@link #FILE_SOFTWARE_VERSION version file}.
889
   */
890
  void writeVersionFile(VersionIdentifier version, Path installationPath);
891

892
  /**
893
   * Verifies that current {@link IdeVersion} satisfies {@link IdeVariables#IDE_MIN_VERSION}.
894
   *
895
   * @param throwException whether to throw a {@link CliException} or just log a warning.
896
   */
897
  void verifyIdeMinVersion(boolean throwException);
898

899
  /**
900
   * @return the path for the variable COREPACK_HOME, or null if called outside an IDEasy installation.
901
   */
902
  default Path getCorePackHome() {
903
    if (getIdeHome() == null) {
×
904
      return null;
×
905
    }
906
    Corepack corepack = getCommandletManager().getCommandlet(Corepack.class);
×
907
    return corepack.getOrCreateCorepackHomeFolder();
×
908
  }
909

910
  /**
911
   * @return the path for the variable NPM_CONFIG_USERCONFIG, or null if called outside an IDEasy installation.
912
   */
913
  default Path getNpmConfigUserConfig() {
914
    if (getIdeHome() == null) {
3✔
915
      return null;
2✔
916
    }
917
    Npm npm = getCommandletManager().getCommandlet(Npm.class);
6✔
918
    return npm.getOrCreateNpmConfigUserConfig();
3✔
919
  }
920

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

© 2026 Coveralls, Inc