Repository navigation
#2273: add Git as global tool #2721
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
10dd94d
ca1d925
e9da9d1
7e3757b
ff14d3b
9e661b9
fa02095
14543a6
54515d4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,7 @@ | |
| import com.devonfw.tools.ide.commandlet.CommandletManagerImpl; | ||
| import com.devonfw.tools.ide.commandlet.ContextCommandlet; | ||
| import com.devonfw.tools.ide.commandlet.EnvironmentCommandlet; | ||
| import com.devonfw.tools.ide.commandlet.InstallCommandlet; | ||
| import com.devonfw.tools.ide.commandlet.UpgradeCommandlet; | ||
| import com.devonfw.tools.ide.commandlet.update.UpdateCommandlet; | ||
| import com.devonfw.tools.ide.common.SystemPath; | ||
|
|
@@ -76,6 +77,7 @@ | |
| import com.devonfw.tools.ide.tool.ToolInstallation; | ||
| import com.devonfw.tools.ide.tool.custom.CustomToolRepository; | ||
| import com.devonfw.tools.ide.tool.custom.CustomToolRepositoryImpl; | ||
| import com.devonfw.tools.ide.tool.git.Git; | ||
| import com.devonfw.tools.ide.tool.mvn.MvnRepository; | ||
| import com.devonfw.tools.ide.tool.npm.NpmRepository; | ||
| import com.devonfw.tools.ide.tool.pip.PipRepository; | ||
|
|
@@ -819,10 +821,11 @@ public UrlMetadata getUrls() { | |
|
|
||
| if (this.urlMetadata == null) { | ||
| if (!isTest()) { | ||
| getGitContext().pullOrCloneAndResetIfNeeded(IDE_URLS_GIT, getUrlsPath(), null); | ||
| updateUrlsRepository(); | ||
| } | ||
| this.urlMetadata = new UrlMetadata(this); | ||
| } | ||
|
|
||
| return this.urlMetadata; | ||
| } | ||
|
|
||
|
|
@@ -1461,20 +1464,24 @@ private ValidationResult applyAndRun(CliArguments arguments, AbstractCommandlet | |
| if (!(cmd instanceof UpgradeCommandlet)) { | ||
| verifyIdeMinVersion(false); | ||
| } | ||
| Path settingsRepository = getSettingsGitRepository(); | ||
| if (settingsRepository != null) { | ||
| if (getGitContext().isRepositoryUpdateAvailable(settingsRepository, getSettingsCommitIdPath()) || ( | ||
| getGitContext().fetchIfNeeded(settingsRepository) && getGitContext().isRepositoryUpdateAvailable( | ||
| settingsRepository, getSettingsCommitIdPath()))) { | ||
|
|
||
| // Inform the user that an update is available. The update message is suppressed if we are already running the update | ||
| String msg = determineSettingsUpdateMessage(cmd); | ||
| if (msg != null) { | ||
| IdeLogLevel.INTERACTION.log(LOG, msg); | ||
|
|
||
| if (!isInstallingGit(cmd)) { | ||
| Path settingsRepository = getSettingsGitRepository(); | ||
| if (settingsRepository != null) { | ||
| if (getGitContext().isRepositoryUpdateAvailable(settingsRepository, getSettingsCommitIdPath()) || ( | ||
| getGitContext().fetchIfNeeded(settingsRepository) && getGitContext().isRepositoryUpdateAvailable( | ||
| settingsRepository, getSettingsCommitIdPath()))) { | ||
|
|
||
| // Inform the user that an update is available. The update message is suppressed if we are already running the update | ||
| String msg = determineSettingsUpdateMessage(cmd); | ||
| if (msg != null) { | ||
| IdeLogLevel.INTERACTION.log(LOG, msg); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| boolean success = ensureLicenseAgreement(cmd); | ||
| if (!success) { | ||
| return ValidationResultValid.get(); | ||
|
|
@@ -1992,4 +1999,28 @@ public String getDefaultWindowsGitPath() { | |
| return DEFAULT_WINDOWS_GIT_PATH; | ||
| } | ||
|
|
||
| private boolean isInstallingGit(AbstractCommandlet cmd) { | ||
|
|
||
| if (cmd instanceof InstallCommandlet installCommandlet) { | ||
| return installCommandlet.tool.getValue() instanceof Git; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * Updates the local {@code ide-urls} repository or, if Git is not available, falls back to the existing local metadata. | ||
| */ | ||
| public void updateUrlsRepository() { | ||
|
|
||
| GitContext gitContext = getGitContext(); | ||
|
|
||
| Path urlsPath = getUrlsPath(); | ||
| if (gitContext.findGit() != null) { | ||
| gitContext.pullOrCloneAndResetIfNeeded(IDE_URLS_GIT, urlsPath, null); | ||
| } else if ((urlsPath != null) && Files.isDirectory(urlsPath)) { | ||
| LOG.debug("Git is not available. Using existing URL metadata without updating it."); | ||
| } else { | ||
| gitContext.findGitRequired(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On a machine without Git and without |
||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -144,8 +144,8 @@ protected boolean isExtract() { | |||||||||||
| protected ToolInstallation doInstall(ToolInstallRequest request) { | ||||||||||||
|
|
||||||||||||
| VersionIdentifier resolvedVersion = request.getRequested().getResolvedVersion(); | ||||||||||||
| if (this.context.getSystemInfo().isLinux()) { | ||||||||||||
| // on Linux global tools are typically installed via the package manager of the OS | ||||||||||||
| if (isPackageManagerBasedInstallation()) { | ||||||||||||
| // global tools are typically installed via the package manager of the OS (e.g. apt on Linux, Homebrew on macOS) | ||||||||||||
| // if a global tool implements getNativePackages() to return at least one NativePackage, then we will install this way. | ||||||||||||
| List<PackageManagerCommand> commands = getInstallPackageManagerCommands(resolvedVersion); | ||||||||||||
| if (!commands.isEmpty()) { | ||||||||||||
|
|
@@ -187,7 +187,7 @@ protected ToolInstallation doInstall(ToolInstallRequest request) { | |||||||||||
| fileAccess.extract(target, downloadBinaryPath); | ||||||||||||
| executable = fileAccess.findFirst(downloadBinaryPath, Files::isExecutable, false); | ||||||||||||
| } | ||||||||||||
| pc = this.context.newProcess().errorHandling(ProcessErrorHandling.LOG_WARNING).executable(executable); | ||||||||||||
| pc = this.context.newProcess().errorHandling(ProcessErrorHandling.LOG_WARNING).executable(executable).addArgs(getInstallerArguments()); | ||||||||||||
| int exitCode = pc.run(ProcessMode.BACKGROUND_SILENT).getExitCode(); | ||||||||||||
| if (tmpDir != null) { | ||||||||||||
| fileAccess.delete(tmpDir); | ||||||||||||
|
|
@@ -266,7 +266,7 @@ protected Path getMacApplicationsPath() { | |||||||||||
| @Override | ||||||||||||
| protected VersionIdentifier resolveVersionForInstall(String edition, GenericVersionRange version) { | ||||||||||||
|
|
||||||||||||
| if (this.context.getSystemInfo().isLinux() && !getNativePackages().isEmpty()) { | ||||||||||||
| if (isPackageManagerBasedInstallation() && !getNativePackages().isEmpty()) { | ||||||||||||
| if (version instanceof VersionIdentifier versionIdentifier && !versionIdentifier.isPattern()) { | ||||||||||||
| return versionIdentifier; | ||||||||||||
| } | ||||||||||||
|
|
@@ -286,6 +286,17 @@ protected List<NativePackage> getNativePackages() { | |||||||||||
| return List.of(); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| /** | ||||||||||||
| * @return {@code true} if this tool is installed via the OS native package manager (see {@link #getNativePackages()}), so that the install, version | ||||||||||||
| * resolution and installed-version detection flows of this class go through the package manager instead of the standard installer/artifact flow. | ||||||||||||
| * <p> | ||||||||||||
| * By default this is the case on Linux only, as that is where global tools are typically installed via the package manager of the OS. Subclasses may | ||||||||||||
| * override this to support the package manager on further operating systems. | ||||||||||||
| */ | ||||||||||||
| protected boolean isPackageManagerBasedInstallation() { | ||||||||||||
| return this.context.getSystemInfo().isLinux(); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| /** | ||||||||||||
| * @return the {@link List} of {@link PackageManagerCommand}s to use on Linux to install this tool. If empty, no package manager installation will be | ||||||||||||
| * triggered on Linux. | ||||||||||||
|
|
@@ -365,8 +376,8 @@ public Map<String, String> getWindowsRegistryAppNames() { | |||||||||||
| @Override | ||||||||||||
| protected EditionAndVersion computeInstalledEditionAndVersion() { | ||||||||||||
|
|
||||||||||||
| if (this.context.getSystemInfo().isLinux()) { | ||||||||||||
| // on Linux global tools are typically installed via the package manager of the OS | ||||||||||||
| if (isPackageManagerBasedInstallation()) { | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This branch conflicts with main: #2500 rewrote |
||||||||||||
| // global tools are typically installed via the package manager of the OS | ||||||||||||
| VersionIdentifier version = getNativePackageVersion(); | ||||||||||||
| return (version != null) ? new EditionAndVersion(this.tool, version) : null; | ||||||||||||
| } | ||||||||||||
|
|
@@ -491,4 +502,8 @@ private Path findMacApplicationBundle() { | |||||||||||
| public String getMacApplicationName() { | ||||||||||||
| return null; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| protected List<String> getInstallerArguments() { | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
| return List.of(); | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| package com.devonfw.tools.ide.tool.git; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Set; | ||
|
|
||
| import com.devonfw.tools.ide.common.Tag; | ||
| import com.devonfw.tools.ide.context.IdeContext; | ||
| import com.devonfw.tools.ide.tool.GlobalToolCommandlet; | ||
| import com.devonfw.tools.ide.tool.NativePackage; | ||
| import com.devonfw.tools.ide.tool.NativePackageManager; | ||
|
|
||
| /** | ||
| * {@link GlobalToolCommandlet} for <a href="https://git-scm.com/">Git</a>. | ||
| */ | ||
| public class Git extends GlobalToolCommandlet { | ||
|
|
||
| /** | ||
| * The constructor. | ||
| * | ||
| * @param context the {@link IdeContext}. | ||
| */ | ||
| public Git(IdeContext context) { | ||
| super(context, "git", Set.of(Tag.GIT)); | ||
| } | ||
|
|
||
| @Override | ||
| protected String getBinaryName() { | ||
| return "git"; | ||
| } | ||
|
|
||
| @Override | ||
| protected List<NativePackage> getNativePackages() { | ||
| return List.of( | ||
| NativePackage.of(NativePackageManager.APT, "git"), | ||
| NativePackage.of(NativePackageManager.ZYPPER, "git"), | ||
| NativePackage.of(NativePackageManager.BREW, "git")); | ||
| } | ||
|
|
||
| @Override | ||
| public String getWindowsRegistryAppName() { | ||
| return "Git"; | ||
| } | ||
|
|
||
| @Override | ||
| protected List<String> getInstallerArguments() { | ||
| if (this.context.getSystemInfo().isWindows()) { | ||
| return List.of( | ||
| "/VERYSILENT", | ||
| "/NORESTART", | ||
| "/NOCANCEL", | ||
| "/SP-" | ||
| ); | ||
| } | ||
| return List.of(); | ||
| } | ||
|
|
||
| /** | ||
| * On macOS Git is installed via Homebrew (see {@link #getNativePackages()}) rather than via the DMG installer artifact, so the package manager based | ||
| * installation flow is used there too - exactly like on Linux. On Windows the standard installer artifact is still used. | ||
| * | ||
| * @return {@code true} if Git is installed via the OS native package manager. | ||
| */ | ||
| @Override | ||
| protected boolean isPackageManagerBasedInstallation() { | ||
| return this.context.getSystemInfo().isLinux() || this.context.getSystemInfo().isMac(); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isInstallingGitputs tool-specific knowledge into the generic context and readsInstallCommandlet.tooldirectly. A generic guard such asgetGitContext().findGit() != nullaround the settings-update check would coveride install gitthe same way, without couplingAbstractIdeContexttoGit, and would also avoid the same failure for other commands run without Git.