diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java index 385778781..e8fbefaae 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java @@ -9,6 +9,7 @@ import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.property.KeywordProperty; import com.devonfw.tools.ide.property.Property; +import com.devonfw.tools.ide.tool.aws.Aws; import com.devonfw.tools.ide.tool.az.Azure; import com.devonfw.tools.ide.tool.eclipse.Eclipse; import com.devonfw.tools.ide.tool.gcviewer.GcViewer; @@ -75,6 +76,7 @@ public CommandletManagerImpl(IdeContext context) { add(new KotlincNative(context)); add(new Vscode(context)); add(new Azure(context)); + add(new Aws(context)); add(new Cobigen(context)); } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java index 971ae1f2a..4f8f0a0d8 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java @@ -89,7 +89,7 @@ public void run() { * Ensures the tool is installed and then runs this tool with the given arguments. * * @param toolVersion the explicit version (pattern) to run. Typically {@code null} to ensure the configured version - * is installed and use that one. Otherwise the specified version will be installed in the software repository + * is installed and use that one. Otherwise, the specified version will be installed in the software repository * without touching and IDE installation and used to run. * @param args the commandline arguments to run the tool. */ @@ -267,7 +267,7 @@ protected void extract(Path file, Path targetDir) { } else { throw new IllegalStateException("Unknown archive format " + extension + ". Can not extract " + file); } - fileAccess.move(getProperInstallationSubDirOf(tmpDir), targetDir); + moveAndProcessExtraction(getProperInstallationSubDirOf(tmpDir), targetDir); fileAccess.delete(tmpDir); } else { this.context.trace("Extraction is disabled for '{}' hence just moving the downloaded file {}.", getName(), file); @@ -285,6 +285,11 @@ protected void extract(Path file, Path targetDir) { } } + protected void moveAndProcessExtraction(Path from, Path to) { + + this.context.getFileAccess().move(from, to); + } + /** * @return {@code true} to extract (unpack) the downloaded binary file, {@code false} otherwise. */ diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/aws/Aws.java b/cli/src/main/java/com/devonfw/tools/ide/tool/aws/Aws.java new file mode 100644 index 000000000..d2257228f --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/aws/Aws.java @@ -0,0 +1,100 @@ +package com.devonfw.tools.ide.tool.aws; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.PosixFilePermission; +import java.util.Set; + +import com.devonfw.tools.ide.common.Tag; +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.environment.EnvironmentVariables; +import com.devonfw.tools.ide.environment.EnvironmentVariablesType; +import com.devonfw.tools.ide.process.ProcessContext; +import com.devonfw.tools.ide.tool.LocalToolCommandlet; + +/** + * {@link LocalToolCommandlet} for AWS CLI (aws). + * + * @see AWS CLI homepage + */ + +public class Aws extends LocalToolCommandlet { + + /** + * The constructor. + * + * @param context the {@link IdeContext}. + */ + public Aws(IdeContext context) { + + super(context, "aws", Set.of(Tag.CLOUD)); + } + + private void makeExecutable(Path file) { + + // TODO this can be removed if issue #132 is fixed. See https://github.com/devonfw/IDEasy/issues/132 + Set permissions = null; + try { + permissions = Files.getPosixFilePermissions(file); + permissions.add(PosixFilePermission.GROUP_EXECUTE); + permissions.add(PosixFilePermission.OWNER_EXECUTE); + permissions.add(PosixFilePermission.OTHERS_EXECUTE); + Files.setPosixFilePermissions(file, permissions); + } catch (IOException e) { + throw new RuntimeException("Adding execution permission for Group, Owner and Others did not work for " + file, e); + } + } + + @Override + protected void moveAndProcessExtraction(Path from, Path to) { + + if (this.context.getSystemInfo().isLinux()) { + // make binary executable using java nio because unpacking didn't preserve the file permissions + // TODO this can be removed if issue #132 is fixed + Path awsInDistPath = from.resolve("dist").resolve("aws"); + Path awsCompleterInDistPath = from.resolve("dist").resolve("aws_completer"); + makeExecutable(awsInDistPath); + makeExecutable(awsCompleterInDistPath); + + // running the install-script that aws shipped + ProcessContext pc = this.context.newProcess(); + Path linuxInstallScript = from.resolve("install"); + pc.executable(linuxInstallScript); + pc.addArgs("-i", from.toString(), "-b", from.toString()); + pc.run(); + + // The install-script that aws ships creates symbolic links to binaries but using absolute paths. + // Since the current process happens in a temporary dir, these links wouldn't be valid after moving the + // installation files to the target dir. So the absolute paths are replaced by relative ones. + for (String file : new String[] { "aws", "aws_completer", Path.of("v2").resolve("current").toString() }) { + Path link = from.resolve(file); + try { + this.context.getFileAccess().symlink(link.toRealPath(), link, true); + } catch (IOException e) { + throw new RuntimeException( + "Failed to replace absolute link (" + link + ") provided by AWS install script with relative link.", e); + } + } + this.context.getFileAccess().delete(linuxInstallScript); + this.context.getFileAccess().delete(from.resolve("dist")); + } + super.moveAndProcessExtraction(from, to); + } + + @Override + public void postInstall() { + + super.postInstall(); + + EnvironmentVariables variables = this.context.getVariables(); + EnvironmentVariables typeVariables = variables.getByType(EnvironmentVariablesType.CONF); + Path awsConfigDir = this.context.getConfPath().resolve("aws"); + this.context.getFileAccess().mkdirs(awsConfigDir); + Path awsConfigFile = awsConfigDir.resolve("config"); + Path awsCredentialsFile = awsConfigDir.resolve("credentials"); + typeVariables.set("AWS_CONFIG_FILE", awsConfigFile.toString(), true); + typeVariables.set("AWS_SHARED_CREDENTIALS_FILE", awsCredentialsFile.toString(), true); + typeVariables.save(); + } +} diff --git a/cli/src/main/resources/nls/Ide.properties b/cli/src/main/resources/nls/Ide.properties index bbe13b90e..a07f3d352 100644 --- a/cli/src/main/resources/nls/Ide.properties +++ b/cli/src/main/resources/nls/Ide.properties @@ -2,20 +2,21 @@ usage=Usage: values=Values: commandlets=Available commandlets: options=Options: +cmd-aws=Tool commandlet for AWS CLI. +cmd-az=Tool commandlet for Azure CLI. cmd---version=Print the version of IDEasy. -cmd-az=Tool commandlet for Azure CLI cmd-complete=Internal commandlet for bash auto-completion cmd-eclipse=Tool commandlet for Eclipse (IDE) cmd-env=Print the environment variables to set and export. cmd-get-version=Get the version of the selected tool. -cmd-gh=Tool commandlet for Github CLI +cmd-gh=Tool commandlet for Github CLI. cmd-gradle=Tool commandlet for Gradle (Build-Tool) cmd-helm=Tool commandlet for Helm (Kubernetes Package Manager) cmd-help=Prints this help. cmd-install=Install the selected tool. cmd-java=Tool commandlet for Java (OpenJDK) -cmd-kotlinc=Tool commandlet for Kotlin -cmd-kotlincnative=Tool commandlet for Kotlin-Native +cmd-kotlinc=Tool commandlet for Kotlin. +cmd-kotlincnative=Tool commandlet for Kotlin-Native. cmd-list-version=List the available versions of the selected tool. cmd-mvn=Tool commandlet for Maven (Build-Tool) cmd-node=Tool commandlet for Node.js (JavaScript runtime) diff --git a/cli/src/main/resources/nls/Ide_de.properties b/cli/src/main/resources/nls/Ide_de.properties index 56071158e..82b1711b8 100644 --- a/cli/src/main/resources/nls/Ide_de.properties +++ b/cli/src/main/resources/nls/Ide_de.properties @@ -2,18 +2,19 @@ usage=Verwendung: values=Werte: commandlets=Verfügbare Kommandos: options=Optionen: +cmd-aws=Werkzeug Kommando fuer AWS Kommandoschnittstelle. +cmd-az=Werkzeug Kommando fuer Azure Kommandoschnittstelle. cmd---version=Gibt die Version von IDEasy aus. -cmd-az=Werkzeug Kommando für die Azure Kommandoschnittstelle. cmd-eclipse=Werkzeug Kommando für Eclipse (IDE) cmd-env=Gibt die zu setztenden und exportierenden Umgebungsvariablen aus. cmd-get-version=Zeigt die Version des selektierten Werkzeugs an. -cmd-gh=Werkzeug Kommando für die Github Kommandoschnittstelle +cmd-gh=Werkzeug Kommando für die Github Kommandoschnittstelle. cmd-helm=Werkzeug Kommando für Helm (Kubernetes Package Manager) cmd-help=Zeigt diese Hilfe an. cmd-install=Installiert das selektierte Werkzeug. cmd-java=Werkzeug Kommando für Java (OpenJDK) -cmd-kotlinc=Werkzeug Kommando für Kotlin -cmd-kotlincnative=Werkzeug Kommando für Kotlin-Native +cmd-kotlinc=Werkzeug Kommando für Kotlin. +cmd-kotlincnative=Werkzeug Kommando für Kotlin-Native. cmd-list-version=Listet die verfügbaren Versionen des selektierten Werkzeugs auf. cmd-mvn=Werkzeug Kommando für Maven (Build-Werkzeug) cmd-node=Werkzeug Kommando für Node.js (JavaScript Laufzeitumgebung) diff --git a/cli/src/test/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesFileTest.java b/cli/src/test/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesFileTest.java index c7e0bbddb..7a8198b10 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesFileTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/environment/EnvironmentVariablesPropertiesFileTest.java @@ -10,6 +10,7 @@ import org.junit.jupiter.api.Test; import com.devonfw.tools.ide.context.IdeTestContextMock; +import org.junit.jupiter.api.io.TempDir; /** * Test of {@link EnvironmentVariablesPropertiesFile}. @@ -40,7 +41,7 @@ public void testLoad() { } @Test - void testSave() throws Exception { + void testSave(@TempDir Path tempDir) throws Exception { // arrange List linesToWrite = new ArrayList<>(); @@ -60,7 +61,7 @@ void testSave() throws Exception { linesToWrite.add("# 5th comment"); linesToWrite.add("var9=9"); - Path propertiesFilePath = Path.of("target/tmp-EnvironmentVariablesPropertiesFileTest-ide.properties"); + Path propertiesFilePath = tempDir.resolve("test.properties"); Files.write(propertiesFilePath, linesToWrite, StandardOpenOption.CREATE_NEW); // check if this writing was correct List lines = Files.readAllLines(propertiesFilePath); @@ -76,7 +77,7 @@ void testSave() throws Exception { variables.set("var5", "5", true); variables.set("var1", "1.0", false); variables.set("var10", "10", false); - variables.set("var11", "11", true); // var11 must be set after var 10, the other lines can be shuffled + variables.set("var11", "11", true); variables.set("var3", "3", false); variables.set("var7", "7", true); variables.set("var6", "6.0", true); @@ -107,7 +108,5 @@ void testSave() throws Exception { lines = Files.readAllLines(propertiesFilePath); assertThat(lines).containsExactlyElementsOf(linesAfterSave); - // clean up - Files.delete(propertiesFilePath); } } \ No newline at end of file