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

devonfw / IDEasy / 29848115811

21 Jul 2026 04:20PM UTC coverage: 72.514% (+0.03%) from 72.484%
29848115811

push

github

web-flow
#2100: Resolve python versions via uv instead of ide-urls (#2152)

Co-authored-by: Jörg Hohwiller <hohwille@users.noreply.github.com>
Co-authored-by: Philipp Hoang <115173117+Caylipp@users.noreply.github.com>

4973 of 7584 branches covered (65.57%)

Branch coverage included in aggregate %.

12824 of 16959 relevant lines covered (75.62%)

3.2 hits per line

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

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

3
import java.nio.file.Files;
4
import java.nio.file.Path;
5

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

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

64
  /**
65
   * The default settings URL.
66
   *
67
   * @see com.devonfw.tools.ide.commandlet.AbstractUpdateCommandlet
68
   */
69
  String DEFAULT_SETTINGS_REPO_URL = "https://github.com/devonfw/ide-settings.git";
70

71
  /** The name of the workspaces folder. */
72
  String FOLDER_WORKSPACES = "workspaces";
73

74
  /** The name of the {@link #getSettingsPath() settings} folder. */
75
  String FOLDER_SETTINGS = "settings";
76

77
  /** The name of the {@link #getSoftwarePath() software} folder. */
78
  String FOLDER_SOFTWARE = "software";
79

80
  /** The name of the {@link #getUrlsPath() urls} folder. */
81
  String FOLDER_URLS = "urls";
82

83
  /** The name of the conf folder for project specific user configurations. */
84
  String FOLDER_CONF = "conf";
85

86
  /**
87
   * 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,
88
   * maven filtering, .gitignore and to distinguish from {@link #FOLDER_DOT_IDE}.
89
   *
90
   * @see #getIdePath()
91
   */
92
  String FOLDER_UNDERSCORE_IDE = "_ide";
93

94
  /**
95
   * The name of the folder inside {@link #FOLDER_UNDERSCORE_IDE} with the current IDEasy installation.
96
   *
97
   * @see #getIdeInstallationPath()
98
   */
99
  String FOLDER_INSTALLATION = "installation";
100

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

108
  /** The name of the updates folder for temporary data and backup. */
109
  String FOLDER_UPDATES = "updates";
110

111
  /** The name of the volume folder for mounting archives like *.dmg. */
112
  String FOLDER_VOLUME = "volume";
113

114
  /** The name of the backups folder for backup. */
115
  String FOLDER_BACKUPS = "backups";
116

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

120
  /** The name of the downloads folder. */
121
  String FOLDER_DOWNLOADS = "Downloads";
122

123
  /** The name of the bin folder where executable files are found by default. */
124
  String FOLDER_BIN = "bin";
125

126
  /** The name of the repositories folder where properties files are stores for each repository */
127
  String FOLDER_REPOSITORIES = "repositories";
128

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

132
  /** The name of the Contents folder inside a MacOS app. */
133
  String FOLDER_CONTENTS = "Contents";
134

135
  /** The name of the Resources folder inside a MacOS app. */
136
  String FOLDER_RESOURCES = "Resources";
137

138
  /** The name of the app folder inside a MacOS app. */
139
  String FOLDER_APP = "app";
140

141
  /** The name of the extra folder inside the software folder */
142
  String FOLDER_EXTRA = "extra";
143

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

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

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

162
  /**
163
   * The name of the update folder inside the {@link #FOLDER_WORKSPACE workspace} folder containing the templates for the configuration templates for the update
164
   * 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
165
   * 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
166
   * for indentation and other code-formatting settings. If all developers in a project team use the same formatter settings, this will actively prevent
167
   * 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
168
   * 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
169
   * 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
170
   * user as needed.
171
   */
172
  String FOLDER_UPDATE = "update";
173

174
  /**
175
   * The name of the folder inside {@link #FOLDER_UNDERSCORE_IDE _ide} folder containing internal resources and scripts of IDEasy.
176
   */
177
  String FOLDER_INTERNAL = "internal";
178

179
  /** The file where the installed software version is written to as plain text. */
180
  String FILE_SOFTWARE_VERSION = ".ide.software.version";
181

182
  /** The file where the installed software version is written to as plain text. */
183
  String FILE_LEGACY_SOFTWARE_VERSION = ".devon.software.version";
184

185
  /** The file for the license agreement. */
186
  String FILE_LICENSE_AGREEMENT = ".license.agreement";
187

188
  /** The file extension for a {@link java.util.Properties} file. */
189
  String EXT_PROPERTIES = ".properties";
190

191
  /** The default for {@link #getWorkspaceName()}. */
192
  String WORKSPACE_MAIN = "main";
193

194
  /** The folder with the configuration template files from the settings. */
195
  String FOLDER_TEMPLATES = "templates";
196

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

200
  /** The default folder name for {@link #getIdeRoot() IDE_ROOT}. */
201
  String FOLDER_PROJECTS = "projects";
202

203
  /**
204
   * file containing the current local commit hash of the settings repository.
205
   */
206
  String SETTINGS_COMMIT_ID = ".commit.id";
207

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

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

225
  /**
226
   * @return the {@link NetworkStatus} for online check and related operations.
227
   */
228
  NetworkStatus getNetworkStatus();
229

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

236
    return getNetworkStatus().isOffline();
4✔
237
  }
238

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

245
    return getNetworkStatus().isOnline();
×
246
  }
247

248
  /**
249
   * Print the IDEasy {@link #LOGO logo}.
250
   */
251
  default void printLogo() {
252

253
    AbstractIdeContext.LOG.info(LOGO);
3✔
254
  }
1✔
255

256
  /**
257
   * Asks the user for a single string input.
258
   *
259
   * @param message The information message to display.
260
   * @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.
261
   * @return The string input from the user, or the default value if no input is provided.
262
   */
263
  String askForInput(String message, String defaultValue);
264

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

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

282
    String yes = "yes";
2✔
283
    String option = question(new String[] { yes, "no" }, question, args);
16✔
284
    if (yes.equals(option)) {
4✔
285
      return true;
2✔
286
    }
287
    return false;
2✔
288
  }
289

290
  /**
291
   * @param <O> type of the option. E.g. {@link String}.
292
   * @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.
293
   * @param question the question to ask.
294
   * @return the option selected by the user as answer.
295
   */
296
  @SuppressWarnings("unchecked")
297
  <O> O question(O[] options, String question, Object... args);
298

299
  /**
300
   * 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
301
   * exception is thrown to abort further processing.
302
   *
303
   * @param questionTemplate the yes/no question to {@link #question(String, Object...) ask}.
304
   * @param args the arguments to fill the placeholders in the question template.
305
   * @throws CliAbortException if the user answered with "no" and further processing shall be aborted.
306
   */
307
  default void askToContinue(String questionTemplate, Object... args) {
308
    boolean yesContinue = question(questionTemplate, args);
5✔
309
    if (!yesContinue) {
2✔
310
      throw new CliAbortException();
4✔
311
    }
312
  }
1✔
313

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

321
    if (explicitOnlineCheck) {
2✔
322
      if (isOffline()) {
3✔
323
        throw CliOfflineException.ofPurpose(purpose);
3✔
324
      }
325
    } else {
326
      if (isOfflineMode()) {
3!
327
        throw CliOfflineException.ofPurpose(purpose);
3✔
328
      }
329
    }
330
  }
1✔
331

332
  /**
333
   * @return the {@link SystemInfo}.
334
   */
335
  SystemInfo getSystemInfo();
336

337
  /**
338
   * @return the {@link EnvironmentVariables} with full inheritance.
339
   */
340
  EnvironmentVariables getVariables();
341

342
  /**
343
   * @return the {@link FileAccess}.
344
   */
345
  FileAccess getFileAccess();
346

347
  /**
348
   * @return the {@link CommandletManager}.
349
   */
350
  CommandletManager getCommandletManager();
351

352
  /**
353
   * @return the default {@link ToolRepository}.
354
   */
355
  ToolRepository getDefaultToolRepository();
356

357
  /**
358
   * @return the {@link CustomToolRepository}.
359
   */
360
  CustomToolRepository getCustomToolRepository();
361

362
  /**
363
   * @return the {@link MvnRepository}.
364
   */
365
  MvnRepository getMvnRepository();
366

367
  /**
368
   * @return the {@link NpmRepository}.
369
   */
370
  NpmRepository getNpmRepository();
371

372
  /**
373
   * @return the {@link PipRepository}.
374
   */
375
  PipRepository getPipRepository();
376

377
  /**
378
   * @return the {@link UvRepository}.
379
   */
380
  UvRepository getUvRepository();
381

382
  /**
383
   * @return the {@link PythonRepository}.
384
   */
385
  PythonRepository getPythonRepository();
386

387
  /**
388
   * @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
389
   *     isolated projects.
390
   * @see com.devonfw.tools.ide.variable.IdeVariables#IDE_HOME
391
   */
392
  Path getIdeHome();
393

394
  /**
395
   * @return the name of the current project.
396
   * @see com.devonfw.tools.ide.variable.IdeVariables#PROJECT_NAME
397
   */
398
  String getProjectName();
399

400
  /**
401
   * @return the IDEasy version the {@link #getIdeHome() current project} was created with or migrated to.
402
   */
403
  VersionIdentifier getProjectVersion();
404

405
  /**
406
   * @param version the new value of {@link #getProjectVersion()}.
407
   */
408
  void setProjectVersion(VersionIdentifier version);
409

410
  /**
411
   * @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
412
   *     sub-folder. There is a reserved ".ide" folder where central IDE data is stored such as the {@link #getUrlsPath() download metadata} and the central
413
   *     software repository.
414
   * @see com.devonfw.tools.ide.variable.IdeVariables#IDE_ROOT
415
   */
416
  Path getIdeRoot();
417

418
  /**
419
   * @param ideRoot the new value of {@link #getIdeRoot() IDE_ROOT}. Typically detected automatically from the environment and working directory, but may need
420
   *     to be set explicitly (e.g. during the initial installation where the {@code IDE_ROOT} environment variable is not yet available but the installation
421
   *     target is already known).
422
   */
423
  void setIdeRoot(Path ideRoot);
424

425
  /**
426
   * @return the {@link Path} to the {@link #FOLDER_UNDERSCORE_IDE}.
427
   * @see #getIdeRoot()
428
   * @see #FOLDER_UNDERSCORE_IDE
429
   */
430
  Path getIdePath();
431

432
  /**
433
   * @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
434
   *     upgrade a new release is installed and the link is switched to the new release.
435
   */
436
  default Path getIdeInstallationPath() {
437

438
    Path idePath = getIdePath();
3✔
439
    if (idePath == null) {
2!
440
      return null;
×
441
    }
442
    return idePath.resolve(FOLDER_INSTALLATION);
4✔
443
  }
444

445
  /**
446
   * @return the current working directory ("user.dir"). This is the directory where the user's shell was located when the IDE CLI was invoked.
447
   */
448
  Path getCwd();
449

450
  /**
451
   * @return the {@link Path} for the temporary directory to use. Will be different from the OS specific temporary directory (java.io.tmpDir).
452
   */
453
  Path getTempPath();
454

455
  /**
456
   * @return the {@link Path} for the temporary download directory to use.
457
   */
458
  Path getTempDownloadPath();
459

460
  /**
461
   * @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
462
   *     download tools.
463
   * @see com.devonfw.tools.ide.url.model.folder.UrlRepository
464
   */
465
  Path getUrlsPath();
466

467
  /**
468
   * @return the {@link UrlMetadata}. Will be lazily instantiated and thereby automatically be cloned or pulled (by default).
469
   */
470
  UrlMetadata getUrls();
471

472
  /**
473
   * @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
474
   *     the same artifact is requested again it will be taken from the cache to avoid downloading it again.
475
   */
476
  Path getDownloadPath();
477

478
  /**
479
   * @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
480
   *     {@link #getSoftwareRepositoryPath() software repository} as sub-folder named after the according tool.
481
   */
482
  Path getSoftwarePath();
483

484
  /**
485
   * @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
486
   *     here from the {@link #getSoftwareRepositoryPath() software repository} as sub-folder named after the according tool.
487
   */
488
  Path getSoftwareExtraPath();
489

490
  /**
491
   * @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
492
   *     are shared among all IDE instances (see {@link #getIdeHome() IDE_HOME}) via symbolic links (see {@link #getSoftwarePath()}). Therefore this repository
493
   *     follows the sub-folder structure {@code «repository»/«tool»/«edition»/«version»/}. So multiple versions of the same tool exist here as different
494
   *     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
495
   *     of the scope of this folders.
496
   */
497
  Path getSoftwareRepositoryPath();
498

499
  /**
500
   * @return the {@link Path} to the {@link #FOLDER_PLUGINS plugins folder} inside {@link #getIdeHome() IDE_HOME}. All plugins of the IDE instance will be
501
   *     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.
502
   */
503
  Path getPluginsPath();
504

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

514
  /**
515
   * @return the {@link Path} to the users home directory. Typically initialized via the {@link System#getProperty(String) system property} "user.home".
516
   * @see com.devonfw.tools.ide.variable.IdeVariables#HOME
517
   */
518
  Path getUserHome();
519

520
  /**
521
   * @return the {@link Path} to the ".ide" subfolder in the {@link #getUserHome() users home directory}.
522
   */
523
  Path getUserHomeIde();
524

525
  /**
526
   * @return the {@link Path} to the {@link #FOLDER_SETTINGS settings} folder with the cloned git repository containing the project configuration.
527
   */
528
  Path getSettingsPath();
529

530
  /**
531
   * @return the {@link Path} to the {@link #FOLDER_REPOSITORIES repositories} folder with legacy fallback if not present or {@code null} if not found.
532
   */
533
  default Path getRepositoriesPath() {
534

535
    Path settingsPath = getSettingsPath();
3✔
536
    if (settingsPath == null) {
2!
537
      return null;
×
538
    }
539
    Path repositoriesPath = settingsPath.resolve(IdeContext.FOLDER_REPOSITORIES);
4✔
540
    if (Files.isDirectory(repositoriesPath)) {
5✔
541
      return repositoriesPath;
2✔
542
    }
543
    Path legacyRepositoriesPath = settingsPath.resolve(IdeContext.FOLDER_LEGACY_REPOSITORIES);
4✔
544
    if (Files.isDirectory(legacyRepositoriesPath)) {
5!
545
      return legacyRepositoriesPath;
×
546
    }
547
    return null;
2✔
548
  }
549

550
  /**
551
   * @return the {@link Path} to the {@code settings} folder with the cloned git repository containing the project configuration only if the settings repository
552
   *     is in fact a git repository.
553
   */
554
  Path getSettingsGitRepository();
555

556
  /**
557
   * @return {@code true} if the settings repository is a symlink or a junction to a code-repository.
558
   */
559
  boolean isSettingsCodeRepository();
560

561
  /**
562
   * @return the {@link Path} to the file containing the last tracked commit Id of the settings repository.
563
   */
564
  Path getSettingsCommitIdPath();
565

566
  /**
567
   * @return the {@link Path} to the templates folder inside the {@link #getSettingsPath() settings}. The relative directory structure in this templates folder
568
   *     is to be applied to {@link #getIdeHome() IDE_HOME} when the project is set up.
569
   */
570
  default Path getSettingsTemplatePath() {
571
    Path settingsFolder = getSettingsPath();
3✔
572
    Path templatesFolder = settingsFolder.resolve(IdeContext.FOLDER_TEMPLATES);
4✔
573
    if (!Files.isDirectory(templatesFolder)) {
5✔
574
      Path templatesFolderLegacy = settingsFolder.resolve(IdeContext.FOLDER_LEGACY_TEMPLATES);
4✔
575
      if (Files.isDirectory(templatesFolderLegacy)) {
5!
576
        templatesFolder = templatesFolderLegacy;
×
577
      } else {
578
        AbstractIdeContext.LOG.warn("No templates found in settings git repo neither in {} nor in {} - configuration broken", templatesFolder,
5✔
579
            templatesFolderLegacy);
580
        return null;
2✔
581
      }
582
    }
583
    return templatesFolder;
2✔
584
  }
585

586
  /**
587
   * @return the {@link Path} to the {@code conf} folder with instance specific tool configurations and the
588
   *     {@link EnvironmentVariablesType#CONF user specific project configuration}.
589
   */
590
  Path getConfPath();
591

592
  /**
593
   * @return the {@link Path} to the workspaces base folder containing the individual {@link #getWorkspacePath(String) workspaces}.
594
   * @see #getWorkspacePath(String)
595
   */
596
  Path getWorkspacesBasePath();
597

598
  /**
599
   * @return the {@link Path} to the workspace.
600
   * @see #getWorkspaceName()
601
   */
602
  Path getWorkspacePath();
603

604
  /**
605
   * @param workspace the specific workspace name.
606
   * @return the {@link Path} to the specified workspace.
607
   */
608
  Path getWorkspacePath(String workspace);
609

610
  /**
611
   * @return the name of the workspace. Defaults to {@link #WORKSPACE_MAIN}.
612
   */
613
  String getWorkspaceName();
614

615
  /**
616
   * @return the value of the system {@link IdeVariables#PATH PATH} variable. It is automatically extended according to the tools available in
617
   *     {@link #getSoftwarePath() software path} unless {@link #getIdeHome() IDE_HOME} was not found.
618
   */
619
  SystemPath getPath();
620

621
  /**
622
   * @return a new {@link ProcessContext} to {@link ProcessContext#run() run} external commands.
623
   */
624
  ProcessContext newProcess();
625

626
  /**
627
   * @param title the {@link IdeProgressBar#getTitle() title}.
628
   * @param size the {@link IdeProgressBar#getMaxSize() expected maximum size}.
629
   * @param unitName the {@link IdeProgressBar#getUnitName() unit name}.
630
   * @param unitSize the {@link IdeProgressBar#getUnitSize() unit size}.
631
   * @return the new {@link IdeProgressBar} to use.
632
   */
633
  IdeProgressBar newProgressBar(String title, long size, String unitName, long unitSize);
634

635
  /**
636
   * @param title the {@link IdeProgressBar#getTitle() title}.
637
   * @param size the {@link IdeProgressBar#getMaxSize() expected maximum size} in bytes.
638
   * @return the new {@link IdeProgressBar} to use.
639
   */
640
  default IdeProgressBar newProgressBarInMib(String title, long size) {
641

642
    if ((size > 0) && (size < 1024)) {
8✔
643
      return new IdeProgressBarNone(title, size, IdeProgressBar.UNIT_NAME_MB, IdeProgressBar.UNIT_SIZE_MB);
8✔
644
    }
645
    return newProgressBar(title, size, IdeProgressBar.UNIT_NAME_MB, IdeProgressBar.UNIT_SIZE_MB);
7✔
646
  }
647

648
  /**
649
   * @param size the {@link IdeProgressBar#getMaxSize() expected maximum size} in bytes.
650
   * @return the new {@link IdeProgressBar} for copy.
651
   */
652
  default IdeProgressBar newProgressBarForDownload(long size) {
653

654
    return newProgressBarInMib(IdeProgressBar.TITLE_DOWNLOADING, size);
5✔
655
  }
656

657
  /**
658
   * @param size the {@link IdeProgressBar#getMaxSize() expected maximum size} in bytes.
659
   * @return the new {@link IdeProgressBar} for extracting.
660
   */
661
  default IdeProgressBar newProgressbarForExtracting(long size) {
662

663
    return newProgressBarInMib(IdeProgressBar.TITLE_EXTRACTING, size);
5✔
664
  }
665

666
  /**
667
   * @param size the {@link IdeProgressBar#getMaxSize() expected maximum size} in bytes.
668
   * @return the new {@link IdeProgressBar} for copy.
669
   */
670
  default IdeProgressBar newProgressbarForCopying(long size) {
671

672
    return newProgressBarInMib(IdeProgressBar.TITLE_COPYING, size);
5✔
673
  }
674

675
  /**
676
   * @param size the {@link IdeProgressBar#getMaxSize() expected maximum} plugin count.
677
   * @return the new {@link IdeProgressBar} to use.
678
   */
679
  default IdeProgressBar newProgressBarForPlugins(long size) {
680
    return newProgressBar(IdeProgressBar.TITLE_INSTALL_PLUGIN, size, IdeProgressBar.UNIT_NAME_PLUGIN, IdeProgressBar.UNIT_SIZE_PLUGIN);
×
681
  }
682

683
  /**
684
   * @return the {@link DirectoryMerger} used to configure and merge the workspace for an {@link com.devonfw.tools.ide.tool.ide.IdeToolCommandlet IDE}.
685
   */
686
  DirectoryMerger getWorkspaceMerger();
687

688
  /**
689
   * @return the {@link Path} to the working directory from where the command is executed.
690
   */
691
  Path getDefaultExecutionDirectory();
692

693
  /**
694
   * @return the {@link IdeSystem} instance wrapping {@link System}.
695
   */
696
  IdeSystem getSystem();
697

698
  /**
699
   * @return the {@link GitContext} used to run several git commands.
700
   */
701
  GitContext getGitContext();
702

703
  /**
704
   * @return the String value for the variable MAVEN_ARGS, or null if called outside an IDEasy installation.
705
   */
706
  default String getMavenArgs() {
707

708
    if (getIdeHome() == null) {
3✔
709
      return null;
2✔
710
    }
711
    Mvn mvn = getCommandletManager().getCommandlet(Mvn.class);
6✔
712
    return mvn.getMavenArgs();
3✔
713
  }
714

715
  /**
716
   * @return the path for the variable GRADLE_USER_HOME, or null if called outside an IDEasy installation.
717
   */
718
  default Path getGradleUserHome() {
719

720
    if (getIdeHome() == null) {
3✔
721
      return null;
2✔
722
    }
723
    Gradle gradle = getCommandletManager().getCommandlet(Gradle.class);
6✔
724
    return gradle.getOrCreateGradleConfFolder();
3✔
725
  }
726

727
  /**
728
   * @return the {@link Path} pointing to the maven configuration directory (where "settings.xml" or "settings-security.xml" are located).
729
   */
730
  default Path getMavenConfigurationFolder() {
731

732
    if (getIdeHome() == null) {
3✔
733
      // fallback to USER_HOME/.m2 folder if called outside an IDEasy project
734
      return getUserHome().resolve(Mvn.MVN_CONFIG_LEGACY_FOLDER);
5✔
735
    }
736
    Mvn mvn = getCommandletManager().getCommandlet(Mvn.class);
6✔
737
    return mvn.getMavenConfigurationFolder();
3✔
738
  }
739

740
  /**
741
   * Updates the current working directory (CWD) and configures the environment paths according to the specified parameters. This method is central to changing
742
   * the IDE's notion of where it operates, affecting where configurations, workspaces, settings, and other resources are located or loaded from.
743
   *
744
   * @return the current {@link Step} of processing.
745
   */
746
  Step getCurrentStep();
747

748
  /**
749
   * @param name the {@link Step#getName() name} of the new {@link Step}.
750
   * @return the new {@link Step} that has been created and started.
751
   */
752
  default Step newStep(String name) {
753

754
    return newStep(name, Step.NO_PARAMS);
5✔
755
  }
756

757
  /**
758
   * @param name the {@link Step#getName() name} of the new {@link Step}.
759
   * @param parameters the {@link Step#getParameter(int) parameters} of the {@link Step}.
760
   * @return the new {@link Step} that has been created and started.
761
   */
762
  default Step newStep(String name, Object... parameters) {
763

764
    return newStep(false, name, parameters);
6✔
765
  }
766

767
  /**
768
   * @param silent the {@link Step#isSilent() silent flag}.
769
   * @param name the {@link Step#getName() name} of the new {@link Step}.
770
   * @param parameters the {@link Step#getParameter(int) parameters} of the {@link Step}.
771
   * @return the new {@link Step} that has been created and started.
772
   */
773
  Step newStep(boolean silent, String name, Object... parameters);
774

775
  /**
776
   * @param lambda the {@link Runnable} to {@link Runnable#run() run} while the {@link com.devonfw.tools.ide.log.IdeLogger logging} is entirely disabled.
777
   *     After this the logging will be enabled again. Collected log messages will then be logged at the end.
778
   */
779
  default void runWithoutLogging(Runnable lambda) {
780

781
    runWithoutLogging(lambda, IdeLogLevel.TRACE);
×
782
  }
×
783

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

793
  /**
794
   * Updates the current working directory (CWD) and configures the environment paths according to the specified parameters. This method is central to changing
795
   * the IDE's notion of where it operates, affecting where configurations, workspaces, settings, and other resources are located or loaded from.
796
   *
797
   * @param ideHome The path to the IDE home directory.
798
   */
799
  default void setIdeHome(Path ideHome) {
800

801
    setCwd(ideHome, WORKSPACE_MAIN, ideHome);
5✔
802
  }
1✔
803

804
  /**
805
   * Updates the current working directory (CWD) and configures the environment paths according to the specified parameters. This method is central to changing
806
   * the IDE's notion of where it operates, affecting where configurations, workspaces, settings, and other resources are located or loaded from.
807
   *
808
   * @param userDir The path to set as the current working directory.
809
   * @param workspace The name of the workspace within the IDE's environment.
810
   * @param ideHome The path to the IDE home directory.
811
   */
812
  void setCwd(Path userDir, String workspace, Path ideHome);
813

814
  /**
815
   * Finds the path to the Bash executable.
816
   *
817
   * @return the {@link Path} to the Bash executable, or {@code null} if Bash is not found.
818
   */
819
  Path findBash();
820

821
  /**
822
   * Finds the path to the Bash executable.
823
   *
824
   * @return the {@link Path} to the Bash executable. Throws a {@link CliException} if no bash was found.
825
   */
826
  default Path findBashRequired() {
827
    Path bash = findBash();
3✔
828
    if (bash == null) {
2!
829
      String message = "Bash " + IS_NOT_INSTALLED_BUT_REQUIRED;
×
830
      if (getSystemInfo().isWindows()) {
×
831
        message += " " + PLEASE_DOWNLOAD_AND_INSTALL_GIT + ":\n " + WINDOWS_GIT_DOWNLOAD_URL;
×
832
        throw new CliException(message);
×
833
      }
834
      bash = Path.of("bash");
×
835
    }
836

837
    return bash;
2✔
838
  }
839

840
  /**
841
   * @return the {@link WindowsPathSyntax} used for {@link Path} conversion or {@code null} for no such conversion (typically if not on Windows).
842
   */
843
  WindowsPathSyntax getPathSyntax();
844

845
  /**
846
   * logs the status of {@link #getIdeHome() IDE_HOME} and {@link #getIdeRoot() IDE_ROOT}.
847
   */
848
  void logIdeHomeAndRootStatus();
849

850
  /**
851
   * @param version the {@link VersionIdentifier} to write.
852
   * @param installationPath the {@link Path directory} where to write the version to a {@link #FILE_SOFTWARE_VERSION version file}.
853
   */
854
  void writeVersionFile(VersionIdentifier version, Path installationPath);
855

856
  /**
857
   * Verifies that current {@link IdeVersion} satisfies {@link IdeVariables#IDE_MIN_VERSION}.
858
   *
859
   * @param throwException whether to throw a {@link CliException} or just log a warning.
860
   */
861
  void verifyIdeMinVersion(boolean throwException);
862

863
  /**
864
   * @return the path for the variable COREPACK_HOME, or null if called outside an IDEasy installation.
865
   */
866
  default Path getCorePackHome() {
867
    if (getIdeHome() == null) {
×
868
      return null;
×
869
    }
870
    Corepack corepack = getCommandletManager().getCommandlet(Corepack.class);
×
871
    return corepack.getOrCreateCorepackHomeFolder();
×
872
  }
873

874
  /**
875
   * @return the path for the variable NPM_CONFIG_USERCONFIG, or null if called outside an IDEasy installation.
876
   */
877
  default Path getNpmConfigUserConfig() {
878
    if (getIdeHome() == null) {
3✔
879
      return null;
2✔
880
    }
881
    Npm npm = getCommandletManager().getCommandlet(Npm.class);
6✔
882
    return npm.getOrCreateNpmConfigUserConfig();
3✔
883
  }
884

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